compiler/crates/react_compiler/src/entrypoint/gating.rs RUST 582 lines View on github.com → Search inside
1// Gating rewrite logic for compiled functions.2//3// When gating is enabled, the compiled function is wrapped in a conditional:4// `gating() ? optimized_fn : original_fn`5//6// For function declarations referenced before their declaration, a special7// hoisting pattern is used (see `insert_additional_function_declaration`).8//9// Ported from `Entrypoint/Gating.ts`.1011use react_compiler_ast::common::BaseNode;12use react_compiler_ast::expressions::*;13use react_compiler_ast::patterns::PatternLike;14use react_compiler_ast::statements::*;15use react_compiler_diagnostics::CompilerDiagnostic;16use react_compiler_diagnostics::ErrorCategory;1718use super::imports::ProgramContext;19use super::plugin_options::GatingConfig;2021/// A compiled function node, can be any function type.22#[derive(Debug, Clone)]23pub enum CompiledFunctionNode {24    FunctionDeclaration(FunctionDeclaration),25    FunctionExpression(FunctionExpression),26    ArrowFunctionExpression(ArrowFunctionExpression),27}2829/// Represents a compiled function that needs gating.30/// In the Rust version, we work with indices into the program body31/// rather than Babel paths.32pub struct GatingRewrite {33    /// Index in program.body where the original function is34    pub original_index: usize,35    /// The compiled function AST node36    pub compiled_fn: CompiledFunctionNode,37    /// The gating config38    pub gating: GatingConfig,39    /// Whether the function is referenced before its declaration at top level40    pub referenced_before_declared: bool,41    /// Whether the parent statement is an ExportDefaultDeclaration42    pub is_export_default: bool,43}4445/// Apply gating rewrites to the program.46/// This modifies program.body by replacing/inserting statements.47///48/// Corresponds to `insertGatedFunctionDeclaration` in the TS version,49/// but batched: all rewrites are collected first, then applied in reverse50/// index order to maintain validity of earlier indices.51pub fn apply_gating_rewrites(52    program: &mut react_compiler_ast::Program,53    mut rewrites: Vec<GatingRewrite>,54    context: &mut ProgramContext,55) -> Result<(), CompilerDiagnostic> {56    // Sort rewrites in reverse order by original_index so that insertions57    // at higher indices don't invalidate lower indices.58    rewrites.sort_by(|a, b| b.original_index.cmp(&a.original_index));5960    for rewrite in rewrites {61        let gating_imported_name = context62            .add_import_specifier(63                &rewrite.gating.source,64                &rewrite.gating.import_specifier_name,65                None,66            )67            .name68            .clone();6970        if rewrite.referenced_before_declared {71            // The referenced-before-declared case only applies to FunctionDeclarations72            if let CompiledFunctionNode::FunctionDeclaration(compiled) = rewrite.compiled_fn {73                insert_additional_function_declaration(74                    &mut program.body,75                    rewrite.original_index,76                    compiled,77                    context,78                    &gating_imported_name,79                )?;80            } else {81                return Err(CompilerDiagnostic::new(82                    ErrorCategory::Invariant,83                    "Expected compiled node type to match input type: \84                     got non-FunctionDeclaration but expected FunctionDeclaration",85                    None,86                ));87            }88        } else {89            let original_stmt = program.body[rewrite.original_index].clone();90            let original_fn = extract_function_node_from_stmt(&original_stmt)?;9192            let gating_expression =93                build_gating_expression(rewrite.compiled_fn, original_fn, &gating_imported_name);9495            // Determine how to rewrite based on context96            if !rewrite.is_export_default {97                if let Some(fn_name) = get_fn_decl_name(&original_stmt) {98                    // Convert function declaration to: const fnName = gating() ? compiled : original99                    let var_decl = Statement::VariableDeclaration(VariableDeclaration {100                        base: BaseNode::default(),101                        declarations: vec![VariableDeclarator {102                            base: BaseNode::default(),103                            id: PatternLike::Identifier(make_identifier(&fn_name)),104                            init: Some(Box::new(gating_expression)),105                            definite: None,106                        }],107                        kind: VariableDeclarationKind::Const,108                        declare: None,109                    });110                    program.body[rewrite.original_index] = var_decl;111                } else {112                    // Replace with the conditional expression directly (e.g. arrow/expression)113                    let expr_stmt = Statement::ExpressionStatement(ExpressionStatement {114                        base: BaseNode::default(),115                        expression: Box::new(gating_expression),116                    });117                    program.body[rewrite.original_index] = expr_stmt;118                }119            } else {120                // ExportDefaultDeclaration case121                if let Some(fn_name) = get_fn_decl_name_from_export_default(&original_stmt) {122                    // Named export default function: replace with const + re-export123                    //   const fnName = gating() ? compiled : original;124                    //   export default fnName;125                    let var_decl = Statement::VariableDeclaration(VariableDeclaration {126                        base: BaseNode::default(),127                        declarations: vec![VariableDeclarator {128                            base: BaseNode::default(),129                            id: PatternLike::Identifier(make_identifier(&fn_name)),130                            init: Some(Box::new(gating_expression)),131                            definite: None,132                        }],133                        kind: VariableDeclarationKind::Const,134                        declare: None,135                    });136                    let re_export = Statement::ExportDefaultDeclaration(137                        react_compiler_ast::declarations::ExportDefaultDeclaration {138                            base: BaseNode::default(),139                            declaration: Box::new(140                                react_compiler_ast::declarations::ExportDefaultDecl::Expression(141                                    Box::new(Expression::Identifier(make_identifier(&fn_name))),142                                ),143                            ),144                            export_kind: None,145                        },146                    );147                    // Replace the original statement with the var decl, then insert re-export after148                    program.body[rewrite.original_index] = var_decl;149                    program.body.insert(rewrite.original_index + 1, re_export);150                } else {151                    // Anonymous export default or arrow: replace the declaration content152                    // with the conditional expression153                    let export_default = Statement::ExportDefaultDeclaration(154                        react_compiler_ast::declarations::ExportDefaultDeclaration {155                            base: BaseNode::default(),156                            declaration: Box::new(157                                react_compiler_ast::declarations::ExportDefaultDecl::Expression(158                                    Box::new(gating_expression),159                                ),160                            ),161                            export_kind: None,162                        },163                    );164                    program.body[rewrite.original_index] = export_default;165                }166            }167        }168    }169    Ok(())170}171172/// Gating rewrite for function declarations which are referenced before their173/// declaration site.174///175/// ```js176/// // original177/// export default React.memo(Foo);178/// function Foo() { ... }179///180/// // React compiler optimized + gated181/// import {gating} from 'myGating';182/// export default React.memo(Foo);183/// const gating_result = gating();  // <- inserted184/// function Foo_optimized() {}      // <- inserted185/// function Foo_unoptimized() {}    // <- renamed from Foo186/// function Foo() {                 // <- inserted, hoistable by JS engines187///   if (gating_result) return Foo_optimized();188///   else return Foo_unoptimized();189/// }190/// ```191fn insert_additional_function_declaration(192    body: &mut Vec<Statement>,193    original_index: usize,194    mut compiled: FunctionDeclaration,195    context: &mut ProgramContext,196    gating_function_identifier_name: &str,197) -> Result<(), CompilerDiagnostic> {198    // Extract the original function declaration from body199    let original_fn = match &body[original_index] {200        Statement::FunctionDeclaration(fd) => fd.clone(),201        Statement::ExportNamedDeclaration(end) => {202            if let Some(decl) = &end.declaration {203                if let react_compiler_ast::declarations::Declaration::FunctionDeclaration(fd) =204                    decl.as_ref()205                {206                    fd.clone()207                } else {208                    return Err(CompilerDiagnostic::new(209                        ErrorCategory::Invariant,210                        "Expected function declaration in export",211                        None,212                    ));213                }214            } else {215                return Err(CompilerDiagnostic::new(216                    ErrorCategory::Invariant,217                    "Expected declaration in export",218                    None,219                ));220            }221        }222        _ => {223            return Err(CompilerDiagnostic::new(224                ErrorCategory::Invariant,225                "Expected function declaration at original_index",226                None,227            ));228        }229    };230231    let original_fn_name = original_fn232        .id233        .as_ref()234        .expect("Expected function declaration referenced elsewhere to have a named identifier");235    let compiled_id = compiled236        .id237        .as_ref()238        .expect("Expected compiled function declaration to have a named identifier");239    assert_eq!(240        original_fn.params.len(),241        compiled.params.len(),242        "Expected compiled function to have the same number of parameters as source"243    );244245    let _ = compiled_id; // used above for the assert246247    // Generate unique names248    let gating_condition_name =249        context.new_uid(&format!("{}_result", gating_function_identifier_name));250    let unoptimized_fn_name = context.new_uid(&format!("{}_unoptimized", original_fn_name.name));251    let optimized_fn_name = context.new_uid(&format!("{}_optimized", original_fn_name.name));252253    // Step 1: rename existing functions254    compiled.id = Some(make_identifier(&optimized_fn_name));255256    // Rename the original function in-place to *_unoptimized257    rename_fn_decl_at(body, original_index, &unoptimized_fn_name)?;258259    // Step 2: build new params and args for the dispatcher function260    let mut new_params: Vec<PatternLike> = Vec::new();261    let mut new_args_optimized: Vec<Expression> = Vec::new();262    let mut new_args_unoptimized: Vec<Expression> = Vec::new();263264    for (i, param) in original_fn.params.iter().enumerate() {265        let arg_name = format!("arg{}", i);266        match param {267            PatternLike::RestElement(_) => {268                new_params.push(PatternLike::RestElement(269                    react_compiler_ast::patterns::RestElement {270                        base: BaseNode::default(),271                        argument: Box::new(PatternLike::Identifier(make_identifier(&arg_name))),272                        type_annotation: None,273                        decorators: None,274                    },275                ));276                new_args_optimized.push(Expression::SpreadElement(SpreadElement {277                    base: BaseNode::default(),278                    argument: Box::new(Expression::Identifier(make_identifier(&arg_name))),279                }));280                new_args_unoptimized.push(Expression::SpreadElement(SpreadElement {281                    base: BaseNode::default(),282                    argument: Box::new(Expression::Identifier(make_identifier(&arg_name))),283                }));284            }285            _ => {286                new_params.push(PatternLike::Identifier(make_identifier(&arg_name)));287                new_args_optimized.push(Expression::Identifier(make_identifier(&arg_name)));288                new_args_unoptimized.push(Expression::Identifier(make_identifier(&arg_name)));289            }290        }291    }292293    // Build the dispatcher function:294    // function Foo(...args) {295    //   if (gating_result) return Foo_optimized(...args);296    //   else return Foo_unoptimized(...args);297    // }298    let dispatcher_fn = Statement::FunctionDeclaration(FunctionDeclaration {299        base: BaseNode::default(),300        id: Some(make_identifier(&original_fn_name.name)),301        params: new_params,302        body: BlockStatement {303            base: BaseNode::default(),304            body: vec![Statement::IfStatement(IfStatement {305                base: BaseNode::default(),306                test: Box::new(Expression::Identifier(make_identifier(307                    &gating_condition_name,308                ))),309                consequent: Box::new(Statement::ReturnStatement(ReturnStatement {310                    base: BaseNode::default(),311                    argument: Some(Box::new(Expression::CallExpression(CallExpression {312                        base: BaseNode::default(),313                        callee: Box::new(Expression::Identifier(make_identifier(314                            &optimized_fn_name,315                        ))),316                        arguments: new_args_optimized,317                        type_parameters: None,318                        type_arguments: None,319                        optional: None,320                    }))),321                })),322                alternate: Some(Box::new(Statement::ReturnStatement(ReturnStatement {323                    base: BaseNode::default(),324                    argument: Some(Box::new(Expression::CallExpression(CallExpression {325                        base: BaseNode::default(),326                        callee: Box::new(Expression::Identifier(make_identifier(327                            &unoptimized_fn_name,328                        ))),329                        arguments: new_args_unoptimized,330                        type_parameters: None,331                        type_arguments: None,332                        optional: None,333                    }))),334                }))),335            })],336            directives: vec![],337        },338        generator: false,339        is_async: false,340        declare: None,341        return_type: None,342        type_parameters: None,343        predicate: None,344        component_declaration: false,345        hook_declaration: false,346    });347348    // Build: const gating_result = gating();349    let gating_const = Statement::VariableDeclaration(VariableDeclaration {350        base: BaseNode::default(),351        declarations: vec![VariableDeclarator {352            base: BaseNode::default(),353            id: PatternLike::Identifier(make_identifier(&gating_condition_name)),354            init: Some(Box::new(Expression::CallExpression(CallExpression {355                base: BaseNode::default(),356                callee: Box::new(Expression::Identifier(make_identifier(357                    gating_function_identifier_name,358                ))),359                arguments: vec![],360                type_parameters: None,361                type_arguments: None,362                optional: None,363            }))),364            definite: None,365        }],366        kind: VariableDeclarationKind::Const,367        declare: None,368    });369370    // Build: the compiled (optimized) function declaration371    let compiled_stmt = Statement::FunctionDeclaration(compiled);372373    // Insert statements. In the TS version:374    //   fnPath.insertBefore(gating_const)375    //   fnPath.insertBefore(compiled)376    //   fnPath.insertAfter(dispatcher_fn)377    //378    // This means the final order is:379    //   [before original_index]: gating_const380    //   [before original_index]: compiled (optimized fn)381    //   [at original_index]:     original fn (renamed to *_unoptimized)382    //   [after original_index]:  dispatcher fn383    //384    // We insert in order: first the ones before, then the one after.385    // Insert before original_index: gating_const, compiled386    body.insert(original_index, compiled_stmt);387    body.insert(original_index, gating_const);388    // The original (now renamed) fn is now at original_index + 2389    // Insert dispatcher after it390    body.insert(original_index + 3, dispatcher_fn);391    Ok(())392}393394/// Build a gating conditional expression:395/// `gating_fn() ? build_fn_expr(compiled) : build_fn_expr(original)`396fn build_gating_expression(397    compiled: CompiledFunctionNode,398    original: CompiledFunctionNode,399    gating_name: &str,400) -> Expression {401    Expression::ConditionalExpression(ConditionalExpression {402        base: BaseNode::default(),403        test: Box::new(Expression::CallExpression(CallExpression {404            base: BaseNode::default(),405            callee: Box::new(Expression::Identifier(make_identifier(gating_name))),406            arguments: vec![],407            type_parameters: None,408            type_arguments: None,409            optional: None,410        })),411        consequent: Box::new(build_function_expression(compiled)),412        alternate: Box::new(build_function_expression(original)),413    })414}415416/// Convert a compiled function node to an expression.417/// Function declarations are converted to function expressions;418/// arrow functions and function expressions are returned as-is.419fn build_function_expression(node: CompiledFunctionNode) -> Expression {420    match node {421        CompiledFunctionNode::ArrowFunctionExpression(arrow) => {422            Expression::ArrowFunctionExpression(arrow)423        }424        CompiledFunctionNode::FunctionExpression(func_expr) => {425            Expression::FunctionExpression(func_expr)426        }427        CompiledFunctionNode::FunctionDeclaration(func_decl) => {428            // Convert FunctionDeclaration to FunctionExpression429            Expression::FunctionExpression(FunctionExpression {430                base: func_decl.base,431                params: func_decl.params,432                body: func_decl.body,433                id: func_decl.id,434                generator: func_decl.generator,435                is_async: func_decl.is_async,436                return_type: func_decl.return_type,437                type_parameters: func_decl.type_parameters,438                predicate: func_decl.predicate,439            })440        }441    }442}443444/// Helper to create a simple Identifier with the given name and default BaseNode.445fn make_identifier(name: &str) -> Identifier {446    Identifier {447        base: BaseNode::default(),448        name: name.to_string(),449        type_annotation: None,450        optional: None,451        decorators: None,452    }453}454455/// Extract the function name from a top-level Statement if it is a456/// FunctionDeclaration with an id.457fn get_fn_decl_name(stmt: &Statement) -> Option<String> {458    match stmt {459        Statement::FunctionDeclaration(fd) => fd.id.as_ref().map(|id| id.name.clone()),460        _ => None,461    }462}463464/// Extract the function name from an ExportDefaultDeclaration's declaration,465/// if it is a named FunctionDeclaration.466fn get_fn_decl_name_from_export_default(stmt: &Statement) -> Option<String> {467    match stmt {468        Statement::ExportDefaultDeclaration(ed) => match ed.declaration.as_ref() {469            react_compiler_ast::declarations::ExportDefaultDecl::FunctionDeclaration(fd) => {470                fd.id.as_ref().map(|id| id.name.clone())471            }472            _ => None,473        },474        _ => None,475    }476}477478/// Extract a CompiledFunctionNode from a statement (for building the479/// "original" side of the gating expression).480fn extract_function_node_from_stmt(481    stmt: &Statement,482) -> Result<CompiledFunctionNode, CompilerDiagnostic> {483    match stmt {484        Statement::FunctionDeclaration(fd) => {485            Ok(CompiledFunctionNode::FunctionDeclaration(fd.clone()))486        }487        Statement::ExpressionStatement(es) => match es.expression.as_ref() {488            Expression::ArrowFunctionExpression(arrow) => {489                Ok(CompiledFunctionNode::ArrowFunctionExpression(arrow.clone()))490            }491            Expression::FunctionExpression(fe) => {492                Ok(CompiledFunctionNode::FunctionExpression(fe.clone()))493            }494            _ => Err(CompilerDiagnostic::new(495                ErrorCategory::Invariant,496                "Expected function expression in expression statement for gating",497                None,498            )),499        },500        Statement::ExportDefaultDeclaration(ed) => match ed.declaration.as_ref() {501            react_compiler_ast::declarations::ExportDefaultDecl::FunctionDeclaration(fd) => {502                Ok(CompiledFunctionNode::FunctionDeclaration(fd.clone()))503            }504            react_compiler_ast::declarations::ExportDefaultDecl::Expression(expr) => {505                match expr.as_ref() {506                    Expression::ArrowFunctionExpression(arrow) => {507                        Ok(CompiledFunctionNode::ArrowFunctionExpression(arrow.clone()))508                    }509                    Expression::FunctionExpression(fe) => {510                        Ok(CompiledFunctionNode::FunctionExpression(fe.clone()))511                    }512                    _ => Err(CompilerDiagnostic::new(513                        ErrorCategory::Invariant,514                        "Expected function expression in export default for gating",515                        None,516                    )),517                }518            }519            _ => Err(CompilerDiagnostic::new(520                ErrorCategory::Invariant,521                "Expected function in export default declaration for gating",522                None,523            )),524        },525        Statement::VariableDeclaration(vd) => {526            let init = vd.declarations[0]527                .init528                .as_ref()529                .expect("Expected variable declarator to have an init for gating");530            match init.as_ref() {531                Expression::ArrowFunctionExpression(arrow) => {532                    Ok(CompiledFunctionNode::ArrowFunctionExpression(arrow.clone()))533                }534                Expression::FunctionExpression(fe) => {535                    Ok(CompiledFunctionNode::FunctionExpression(fe.clone()))536                }537                _ => Err(CompilerDiagnostic::new(538                    ErrorCategory::Invariant,539                    "Expected function expression in variable declaration for gating",540                    None,541                )),542            }543        }544        _ => Err(CompilerDiagnostic::new(545            ErrorCategory::Invariant,546            "Unexpected statement type for gating rewrite",547            None,548        )),549    }550}551552/// Rename the function declaration at `body[index]` in place.553/// Handles both bare FunctionDeclaration and ExportNamedDeclaration wrapping one.554fn rename_fn_decl_at(555    body: &mut [Statement],556    index: usize,557    new_name: &str,558) -> Result<(), CompilerDiagnostic> {559    match &mut body[index] {560        Statement::FunctionDeclaration(fd) => {561            fd.id = Some(make_identifier(new_name));562        }563        Statement::ExportNamedDeclaration(end) => {564            if let Some(decl) = &mut end.declaration {565                if let react_compiler_ast::declarations::Declaration::FunctionDeclaration(fd) =566                    decl.as_mut()567                {568                    fd.id = Some(make_identifier(new_name));569                }570            }571        }572        _ => {573            return Err(CompilerDiagnostic::new(574                ErrorCategory::Invariant,575                "Expected function declaration to rename",576                None,577            ));578        }579    }580    Ok(())581}

Code quality findings 23

Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let original_stmt = program.body[rewrite.original_index].clone();
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
program.body[rewrite.original_index] = var_decl;
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
program.body[rewrite.original_index] = expr_stmt;
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
program.body[rewrite.original_index] = var_decl;
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
program.body[rewrite.original_index] = export_default;
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let original_fn = match &body[original_index] {
Warning: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning correctness expect-usage
.expect("Expected function declaration referenced elsewhere to have a named identifier");
Warning: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning correctness expect-usage
.expect("Expected compiled function declaration to have a named identifier");
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let init = vd.declarations[0]
Warning: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning correctness expect-usage
.expect("Expected variable declarator to have an init for gating");
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
/// Rename the function declaration at `body[index]` in place.
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
body: &mut [Statement],
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
match &mut body[index] {
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use react_compiler_ast::expressions::*;
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use react_compiler_ast::statements::*;
Performance Info: Frequent cloning, especially of Strings, Vecs, or other heap-allocated types inside loops, can be expensive. Consider using references/borrowing where possible.
info performance clone-in-loop
.clone();
Performance Info: Calling .push() repeatedly inside a loop without prior capacity reservation can lead to multiple reallocations. Consider using `Vec::with_capacity(n)` or `vec.reserve(n)` if the approximate number of elements is known.
info performance push-without-reserve
new_params.push(PatternLike::RestElement(
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match stmt {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match stmt {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
Statement::ExportDefaultDeclaration(ed) => match ed.declaration.as_ref() {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
Statement::ExpressionStatement(es) => match es.expression.as_ref() {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match expr.as_ref() {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match init.as_ref() {

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.