compiler/crates/react_compiler_hir/src/print.rs RUST 1,543 lines View on github.com → Search inside
1//! Shared formatting utilities for HIR debug printing.2//!3//! This module provides `PrintFormatter` — a stateful formatter that both4//! `react_compiler::debug_print` (HIR printer) and5//! `react_compiler_reactive_scopes::print_reactive_function` (reactive printer)6//! delegate to for shared formatting logic.7//!8//! It also exports standalone formatting functions (format_loc, format_primitive, etc.)9//! that require no state.1011use rustc_hash::FxHashSet;1213use react_compiler_diagnostics::CompilerError;14use react_compiler_diagnostics::CompilerErrorOrDiagnostic;15use react_compiler_diagnostics::SourceLocation;1617use crate::AliasingEffect;18use crate::HirFunction;19use crate::IdentifierId;20use crate::IdentifierName;21use crate::InstructionValue;22use crate::LValue;23use crate::MutationReason;24use crate::Pattern;25use crate::Place;26use crate::PlaceOrSpreadOrHole;27use crate::ScopeId;28use crate::Type;29use crate::environment::Environment;30use crate::type_config::ValueKind;31use crate::type_config::ValueReason;3233// =============================================================================34// Standalone formatting functions (no state needed)35// =============================================================================3637pub fn format_loc(loc: &Option<SourceLocation>) -> String {38    match loc {39        Some(l) => format_loc_value(l),40        None => "generated".to_string(),41    }42}4344pub fn format_loc_value(loc: &SourceLocation) -> String {45    format!(46        "{}:{}-{}:{}",47        loc.start.line, loc.start.column, loc.end.line, loc.end.column48    )49}5051/// Format a string like JS `JSON.stringify`: escape control chars and quotes52/// but preserve non-ASCII unicode (e.g. U+00A0 nbsp) as literal characters.53pub fn format_js_string(s: &str) -> String {54    let mut result = String::with_capacity(s.len() + 2);55    result.push('"');56    for c in s.chars() {57        match c {58            '"' => result.push_str("\\\""),59            '\\' => result.push_str("\\\\"),60            '\n' => result.push_str("\\n"),61            '\r' => result.push_str("\\r"),62            '\t' => result.push_str("\\t"),63            '\u{0008}' => result.push_str("\\b"),64            '\u{000c}' => result.push_str("\\f"),65            // Only escape C0 control chars (U+0000–U+001F), matching JS JSON.stringify.66            // Do NOT escape C1 controls (U+0080–U+009F) — JS outputs those as literal chars.67            c if (c as u32) <= 0x1F => {68                result.push_str(&format!("\\u{:04x}", c as u32));69            }70            c => result.push(c),71        }72    }73    result.push('"');74    result75}7677pub fn format_primitive(prim: &crate::PrimitiveValue) -> String {78    match prim {79        crate::PrimitiveValue::Null => "null".to_string(),80        crate::PrimitiveValue::Undefined => "undefined".to_string(),81        crate::PrimitiveValue::Boolean(b) => format!("{}", b),82        crate::PrimitiveValue::Number(n) => crate::format_js_number(n.value()),83        crate::PrimitiveValue::String(s) => match s.as_str() {84            Some(utf8) => format_js_string(utf8),85            // Ill-formed strings: escape the well-formed segments exactly like86            // format_js_string and render each unpaired surrogate as \uXXXX,87            // matching what TS's JSON.stringify-based printer emits.88            None => {89                let mut result = String::new();90                result.push('"');91                let mut units = s.code_units().into_iter().peekable();92                while let Some(unit) = units.next() {93                    let is_lead = (0xD800..=0xDBFF).contains(&unit);94                    let is_trail = (0xDC00..=0xDFFF).contains(&unit);95                    if is_lead {96                        if let Some(&next) = units.peek() {97                            if (0xDC00..=0xDFFF).contains(&next) {98                                units.next();99                                let cp = 0x10000100                                    + ((unit as u32 - 0xD800) << 10)101                                    + (next as u32 - 0xDC00);102                                result.push(char::from_u32(cp).expect("valid supplementary"));103                                continue;104                            }105                        }106                    }107                    if is_lead || is_trail {108                        result.push_str(&format!("\\u{unit:04x}"));109                        continue;110                    }111                    let c = char::from_u32(unit as u32).expect("BMP non-surrogate is a char");112                    match c {113                        '"' => result.push_str("\\\""),114                        '\\' => result.push_str("\\\\"),115                        '\n' => result.push_str("\\n"),116                        '\r' => result.push_str("\\r"),117                        '\t' => result.push_str("\\t"),118                        '\u{0008}' => result.push_str("\\b"),119                        '\u{000c}' => result.push_str("\\f"),120                        c if (c as u32) <= 0x1F => {121                            result.push_str(&format!("\\u{:04x}", c as u32));122                        }123                        c => result.push(c),124                    }125                }126                result.push('"');127                result128            }129        },130    }131}132133pub fn format_property_literal(prop: &crate::PropertyLiteral) -> String {134    match prop {135        crate::PropertyLiteral::String(s) => s.clone(),136        crate::PropertyLiteral::Number(n) => crate::format_js_number(n.value()),137    }138}139140pub fn format_object_property_key(key: &crate::ObjectPropertyKey) -> String {141    match key {142        crate::ObjectPropertyKey::String { name } => format!("String(\"{}\")", name),143        crate::ObjectPropertyKey::Identifier { name } => {144            format!("Identifier(\"{}\")", name)145        }146        crate::ObjectPropertyKey::Computed { name } => {147            format!("Computed({})", name.identifier.0)148        }149        crate::ObjectPropertyKey::Number { name } => {150            format!("Number({})", crate::format_js_number(name.value()))151        }152    }153}154155pub fn format_non_local_binding(binding: &crate::NonLocalBinding) -> String {156    match binding {157        crate::NonLocalBinding::Global { name } => {158            format!("Global {{ name: \"{}\" }}", name)159        }160        crate::NonLocalBinding::ModuleLocal { name } => {161            format!("ModuleLocal {{ name: \"{}\" }}", name)162        }163        crate::NonLocalBinding::ImportDefault { name, module } => {164            format!(165                "ImportDefault {{ name: \"{}\", module: \"{}\" }}",166                name, module167            )168        }169        crate::NonLocalBinding::ImportNamespace { name, module } => {170            format!(171                "ImportNamespace {{ name: \"{}\", module: \"{}\" }}",172                name, module173            )174        }175        crate::NonLocalBinding::ImportSpecifier {176            name,177            module,178            imported,179        } => {180            format!(181                "ImportSpecifier {{ name: \"{}\", module: \"{}\", imported: \"{}\" }}",182                name, module, imported183            )184        }185    }186}187188pub fn format_value_kind(kind: ValueKind) -> &'static str {189    match kind {190        ValueKind::Mutable => "mutable",191        ValueKind::Frozen => "frozen",192        ValueKind::Primitive => "primitive",193        ValueKind::MaybeFrozen => "maybe-frozen",194        ValueKind::Global => "global",195        ValueKind::Context => "context",196    }197}198199pub fn format_value_reason(reason: ValueReason) -> &'static str {200    match reason {201        ValueReason::KnownReturnSignature => "known-return-signature",202        ValueReason::State => "state",203        ValueReason::ReducerState => "reducer-state",204        ValueReason::Context => "context",205        ValueReason::Effect => "effect",206        ValueReason::HookCaptured => "hook-captured",207        ValueReason::HookReturn => "hook-return",208        ValueReason::Global => "global",209        ValueReason::JsxCaptured => "jsx-captured",210        ValueReason::StoreLocal => "store-local",211        ValueReason::ReactiveFunctionArgument => "reactive-function-argument",212        ValueReason::Other => "other",213    }214}215216// =============================================================================217// PrintFormatter — shared stateful formatter218// =============================================================================219220/// Shared formatter state used by both HIR and reactive printers.221///222/// Both `DebugPrinter` structs delegate to this for formatting shared constructs223/// like Places, Identifiers, Scopes, Types, InstructionValues, etc.224pub struct PrintFormatter<'a> {225    pub env: &'a Environment,226    pub seen_identifiers: FxHashSet<IdentifierId>,227    pub seen_scopes: FxHashSet<ScopeId>,228    pub output: Vec<String>,229    pub indent_level: usize,230}231232impl<'a> PrintFormatter<'a> {233    pub fn new(env: &'a Environment) -> Self {234        Self {235            env,236            seen_identifiers: FxHashSet::default(),237            seen_scopes: FxHashSet::default(),238            output: Vec::new(),239            indent_level: 0,240        }241    }242243    pub fn line(&mut self, text: &str) {244        let indent = "  ".repeat(self.indent_level);245        self.output.push(format!("{}{}", indent, text));246    }247248    /// Write a line without adding indentation (used when copying pre-formatted output)249    pub fn line_raw(&mut self, text: &str) {250        self.output.push(text.to_string());251    }252253    pub fn indent(&mut self) {254        self.indent_level += 1;255    }256257    pub fn dedent(&mut self) {258        self.indent_level -= 1;259    }260261    pub fn to_string_output(&self) -> String {262        self.output.join("\n")263    }264265    // =========================================================================266    // AliasingEffect267    // =========================================================================268269    pub fn format_effect(&self, effect: &AliasingEffect) -> String {270        match effect {271            AliasingEffect::Freeze { value, reason } => {272                format!(273                    "Freeze {{ value: {}, reason: {} }}",274                    value.identifier.0,275                    format_value_reason(*reason)276                )277            }278            AliasingEffect::Mutate { value, reason } => match reason {279                Some(MutationReason::AssignCurrentProperty) => {280                    format!(281                        "Mutate {{ value: {}, reason: AssignCurrentProperty }}",282                        value.identifier.0283                    )284                }285                None => format!("Mutate {{ value: {} }}", value.identifier.0),286            },287            AliasingEffect::MutateConditionally { value } => {288                format!("MutateConditionally {{ value: {} }}", value.identifier.0)289            }290            AliasingEffect::MutateTransitive { value } => {291                format!("MutateTransitive {{ value: {} }}", value.identifier.0)292            }293            AliasingEffect::MutateTransitiveConditionally { value } => {294                format!(295                    "MutateTransitiveConditionally {{ value: {} }}",296                    value.identifier.0297                )298            }299            AliasingEffect::Capture { from, into } => {300                format!(301                    "Capture {{ into: {}, from: {} }}",302                    into.identifier.0, from.identifier.0303                )304            }305            AliasingEffect::Alias { from, into } => {306                format!(307                    "Alias {{ into: {}, from: {} }}",308                    into.identifier.0, from.identifier.0309                )310            }311            AliasingEffect::MaybeAlias { from, into } => {312                format!(313                    "MaybeAlias {{ into: {}, from: {} }}",314                    into.identifier.0, from.identifier.0315                )316            }317            AliasingEffect::Assign { from, into } => {318                format!(319                    "Assign {{ into: {}, from: {} }}",320                    into.identifier.0, from.identifier.0321                )322            }323            AliasingEffect::Create {324                into,325                value,326                reason,327            } => {328                format!(329                    "Create {{ into: {}, value: {}, reason: {} }}",330                    into.identifier.0,331                    format_value_kind(*value),332                    format_value_reason(*reason)333                )334            }335            AliasingEffect::CreateFrom { from, into } => {336                format!(337                    "CreateFrom {{ into: {}, from: {} }}",338                    into.identifier.0, from.identifier.0339                )340            }341            AliasingEffect::ImmutableCapture { from, into } => {342                format!(343                    "ImmutableCapture {{ into: {}, from: {} }}",344                    into.identifier.0, from.identifier.0345                )346            }347            AliasingEffect::Apply {348                receiver,349                function,350                mutates_function,351                args,352                into,353                ..354            } => {355                let args_str: Vec<String> = args356                    .iter()357                    .map(|a| match a {358                        PlaceOrSpreadOrHole::Hole => "hole".to_string(),359                        PlaceOrSpreadOrHole::Place(p) => p.identifier.0.to_string(),360                        PlaceOrSpreadOrHole::Spread(s) => format!("...{}", s.place.identifier.0),361                    })362                    .collect();363                format!(364                    "Apply {{ into: {}, receiver: {}, function: {}, mutatesFunction: {}, args: [{}] }}",365                    into.identifier.0,366                    receiver.identifier.0,367                    function.identifier.0,368                    mutates_function,369                    args_str.join(", ")370                )371            }372            AliasingEffect::CreateFunction {373                captures,374                function_id: _,375                into,376            } => {377                let cap_str: Vec<String> = captures378                    .iter()379                    .map(|p| p.identifier.0.to_string())380                    .collect();381                format!(382                    "CreateFunction {{ into: {}, captures: [{}] }}",383                    into.identifier.0,384                    cap_str.join(", ")385                )386            }387            AliasingEffect::MutateFrozen { place, error } => {388                format!(389                    "MutateFrozen {{ place: {}, reason: {:?} }}",390                    place.identifier.0, error.reason391                )392            }393            AliasingEffect::MutateGlobal { place, error } => {394                format!(395                    "MutateGlobal {{ place: {}, reason: {:?} }}",396                    place.identifier.0, error.reason397                )398            }399            AliasingEffect::Impure { place, error } => {400                format!(401                    "Impure {{ place: {}, reason: {:?} }}",402                    place.identifier.0, error.reason403                )404            }405            AliasingEffect::Render { place } => {406                format!("Render {{ place: {} }}", place.identifier.0)407            }408        }409    }410411    // =========================================================================412    // Place (with identifier deduplication)413    // =========================================================================414415    pub fn format_place_field(&mut self, field_name: &str, place: &Place) {416        let is_seen = self.seen_identifiers.contains(&place.identifier);417        if is_seen {418            self.line(&format!(419                "{}: Place {{ identifier: Identifier({}), effect: {}, reactive: {}, loc: {} }}",420                field_name,421                place.identifier.0,422                place.effect,423                place.reactive,424                format_loc(&place.loc)425            ));426        } else {427            self.line(&format!("{}: Place {{", field_name));428            self.indent();429            self.line("identifier:");430            self.indent();431            self.format_identifier(place.identifier);432            self.dedent();433            self.line(&format!("effect: {}", place.effect));434            self.line(&format!("reactive: {}", place.reactive));435            self.line(&format!("loc: {}", format_loc(&place.loc)));436            self.dedent();437            self.line("}");438        }439    }440441    // =========================================================================442    // Identifier (first-seen expansion)443    // =========================================================================444445    pub fn format_identifier(&mut self, id: IdentifierId) {446        self.seen_identifiers.insert(id);447        let ident = &self.env.identifiers[id.0 as usize];448        self.line("Identifier {");449        self.indent();450        self.line(&format!("id: {}", ident.id.0));451        self.line(&format!("declarationId: {}", ident.declaration_id.0));452        match &ident.name {453            Some(name) => {454                let (kind, value) = match name {455                    IdentifierName::Named(n) => ("named", n.as_str()),456                    IdentifierName::Promoted(n) => ("promoted", n.as_str()),457                };458                self.line(&format!(459                    "name: {{ kind: \"{}\", value: \"{}\" }}",460                    kind, value461                ));462            }463            None => self.line("name: null"),464        }465        // Print the identifier's mutable_range directly, matching the TS466        // DebugPrintHIR which prints `identifier.mutableRange`. In TS,467        // InferReactiveScopeVariables sets identifier.mutableRange = scope.range468        // (shared reference), and AlignReactiveScopesToBlockScopesHIR syncs them.469        // After MergeOverlappingReactiveScopesHIR repoints scopes, the TS470        // identifier.mutableRange still references the OLD scope's range (stale),471        // so we match by using ident.mutable_range directly (which is synced472        // at the AlignReactiveScopesToBlockScopesHIR step but not re-synced473        // after scope repointing in merge passes).474        self.line(&format!(475            "mutableRange: [{}:{}]",476            ident.mutable_range.start.0, ident.mutable_range.end.0477        ));478        match ident.scope {479            Some(scope_id) => self.format_scope_field("scope", scope_id),480            None => self.line("scope: null"),481        }482        self.line(&format!("type: {}", self.format_type(ident.type_)));483        self.line(&format!("loc: {}", format_loc(&ident.loc)));484        self.dedent();485        self.line("}");486    }487488    // =========================================================================489    // Scope (with deduplication)490    // =========================================================================491492    pub fn format_scope_field(&mut self, field_name: &str, scope_id: ScopeId) {493        let is_seen = self.seen_scopes.contains(&scope_id);494        if is_seen {495            self.line(&format!("{}: Scope({})", field_name, scope_id.0));496        } else {497            self.seen_scopes.insert(scope_id);498            if let Some(scope) = self.env.scopes.iter().find(|s| s.id == scope_id) {499                let range_start = scope.range.start.0;500                let range_end = scope.range.end.0;501                let dependencies = scope.dependencies.clone();502                let declarations = scope.declarations.clone();503                let reassignments = scope.reassignments.clone();504                let early_return_value = scope.early_return_value.clone();505                let merged = scope.merged.clone();506                let loc = scope.loc;507508                self.line(&format!("{}: Scope {{", field_name));509                self.indent();510                self.line(&format!("id: {}", scope_id.0));511                self.line(&format!("range: [{}:{}]", range_start, range_end));512513                // dependencies514                self.line("dependencies:");515                self.indent();516                for (i, dep) in dependencies.iter().enumerate() {517                    let path_str: String = dep518                        .path519                        .iter()520                        .map(|p| {521                            let prop = match &p.property {522                                crate::PropertyLiteral::String(s) => s.clone(),523                                crate::PropertyLiteral::Number(n) => {524                                    crate::format_js_number(n.value())525                                }526                            };527                            format!("{}{}", if p.optional { "?." } else { "." }, prop)528                        })529                        .collect();530                    self.line(&format!(531                        "[{}] {{ identifier: {}, reactive: {}, path: \"{}\" }}",532                        i, dep.identifier.0, dep.reactive, path_str533                    ));534                }535                self.dedent();536537                // declarations538                self.line("declarations:");539                self.indent();540                for (ident_id, decl) in &declarations {541                    self.line(&format!(542                        "{}: {{ identifier: {}, scope: {} }}",543                        ident_id.0, decl.identifier.0, decl.scope.0544                    ));545                }546                self.dedent();547548                // reassignments549                self.line("reassignments:");550                self.indent();551                for ident_id in &reassignments {552                    self.line(&format!("{}", ident_id.0));553                }554                self.dedent();555556                // earlyReturnValue557                if let Some(early_return) = &early_return_value {558                    self.line("earlyReturnValue:");559                    self.indent();560                    self.line(&format!("value: {}", early_return.value.0));561                    self.line(&format!("loc: {}", format_loc(&early_return.loc)));562                    self.line(&format!("label: bb{}", early_return.label.0));563                    self.dedent();564                } else {565                    self.line("earlyReturnValue: null");566                }567568                // merged569                let merged_str: Vec<String> = merged.iter().map(|s| s.0.to_string()).collect();570                self.line(&format!("merged: [{}]", merged_str.join(", ")));571572                // loc573                self.line(&format!("loc: {}", format_loc(&loc)));574575                self.dedent();576                self.line("}");577            } else {578                self.line(&format!("{}: Scope({})", field_name, scope_id.0));579            }580        }581    }582583    // =========================================================================584    // Type585    // =========================================================================586587    pub fn format_type(&self, type_id: crate::TypeId) -> String {588        if let Some(ty) = self.env.types.get(type_id.0 as usize) {589            self.format_type_value(ty)590        } else {591            format!("Type({})", type_id.0)592        }593    }594595    pub fn format_type_value(&self, ty: &Type) -> String {596        match ty {597            Type::Primitive => "Primitive".to_string(),598            Type::Function {599                shape_id,600                return_type,601                is_constructor,602            } => {603                format!(604                    "Function {{ shapeId: {}, return: {}, isConstructor: {} }}",605                    match shape_id {606                        Some(s) => format!("\"{}\"", s),607                        None => "null".to_string(),608                    },609                    self.format_type_value(return_type),610                    is_constructor611                )612            }613            Type::Object { shape_id } => {614                format!(615                    "Object {{ shapeId: {} }}",616                    match shape_id {617                        Some(s) => format!("\"{}\"", s),618                        None => "null".to_string(),619                    }620                )621            }622            Type::TypeVar { id } => format!("Type({})", id.0),623            Type::Poly => "Poly".to_string(),624            Type::Phi { operands } => {625                let ops: Vec<String> = operands626                    .iter()627                    .map(|op| self.format_type_value(op))628                    .collect();629                format!("Phi {{ operands: [{}] }}", ops.join(", "))630            }631            Type::Property {632                object_type,633                object_name,634                property_name,635            } => {636                let prop_str = match property_name {637                    crate::PropertyNameKind::Literal { value } => {638                        format!("\"{}\"", format_property_literal(value))639                    }640                    crate::PropertyNameKind::Computed { value } => {641                        format!("computed({})", self.format_type_value(value))642                    }643                };644                format!(645                    "Property {{ objectType: {}, objectName: \"{}\", propertyName: {} }}",646                    self.format_type_value(object_type),647                    object_name,648                    prop_str649                )650            }651            Type::ObjectMethod => "ObjectMethod".to_string(),652        }653    }654655    // =========================================================================656    // LValue657    // =========================================================================658659    pub fn format_lvalue(&mut self, field_name: &str, lv: &LValue) {660        self.line(&format!("{}:", field_name));661        self.indent();662        self.line(&format!("kind: {:?}", lv.kind));663        self.format_place_field("place", &lv.place);664        self.dedent();665    }666667    // =========================================================================668    // Pattern669    // =========================================================================670671    pub fn format_pattern(&mut self, pattern: &Pattern) {672        match pattern {673            Pattern::Array(arr) => {674                self.line("pattern: ArrayPattern {");675                self.indent();676                self.line("items:");677                self.indent();678                for (i, item) in arr.items.iter().enumerate() {679                    match item {680                        crate::ArrayPatternElement::Hole => {681                            self.line(&format!("[{}] Hole", i));682                        }683                        crate::ArrayPatternElement::Place(p) => {684                            self.format_place_field(&format!("[{}]", i), p);685                        }686                        crate::ArrayPatternElement::Spread(s) => {687                            self.line(&format!("[{}] Spread:", i));688                            self.indent();689                            self.format_place_field("place", &s.place);690                            self.dedent();691                        }692                    }693                }694                self.dedent();695                self.line(&format!("loc: {}", format_loc(&arr.loc)));696                self.dedent();697                self.line("}");698            }699            Pattern::Object(obj) => {700                self.line("pattern: ObjectPattern {");701                self.indent();702                self.line("properties:");703                self.indent();704                for (i, prop) in obj.properties.iter().enumerate() {705                    match prop {706                        crate::ObjectPropertyOrSpread::Property(p) => {707                            self.line(&format!("[{}] ObjectProperty {{", i));708                            self.indent();709                            self.line(&format!("key: {}", format_object_property_key(&p.key)));710                            self.line(&format!("type: \"{}\"", p.property_type));711                            self.format_place_field("place", &p.place);712                            self.dedent();713                            self.line("}");714                        }715                        crate::ObjectPropertyOrSpread::Spread(s) => {716                            self.line(&format!("[{}] Spread:", i));717                            self.indent();718                            self.format_place_field("place", &s.place);719                            self.dedent();720                        }721                    }722                }723                self.dedent();724                self.line(&format!("loc: {}", format_loc(&obj.loc)));725                self.dedent();726                self.line("}");727            }728        }729    }730731    // =========================================================================732    // Arguments733    // =========================================================================734735    pub fn format_argument(&mut self, arg: &crate::PlaceOrSpread, index: usize) {736        match arg {737            crate::PlaceOrSpread::Place(p) => {738                self.format_place_field(&format!("[{}]", index), p);739            }740            crate::PlaceOrSpread::Spread(s) => {741                self.line(&format!("[{}] Spread:", index));742                self.indent();743                self.format_place_field("place", &s.place);744                self.dedent();745            }746        }747    }748749    // =========================================================================750    // InstructionValue751    // =========================================================================752753    /// Format an InstructionValue. The `inner_func_formatter` callback is invoked754    /// for FunctionExpression/ObjectMethod to format the inner HirFunction. If None,755    /// a placeholder is printed instead.756    pub fn format_instruction_value(757        &mut self,758        value: &InstructionValue,759        inner_func_formatter: Option<&dyn Fn(&mut PrintFormatter, &HirFunction)>,760    ) {761        match value {762            InstructionValue::ArrayExpression { elements, loc } => {763                self.line("ArrayExpression {");764                self.indent();765                self.line("elements:");766                self.indent();767                for (i, elem) in elements.iter().enumerate() {768                    match elem {769                        crate::ArrayElement::Place(p) => {770                            self.format_place_field(&format!("[{}]", i), p);771                        }772                        crate::ArrayElement::Hole => {773                            self.line(&format!("[{}] Hole", i));774                        }775                        crate::ArrayElement::Spread(s) => {776                            self.line(&format!("[{}] Spread:", i));777                            self.indent();778                            self.format_place_field("place", &s.place);779                            self.dedent();780                        }781                    }782                }783                self.dedent();784                self.line(&format!("loc: {}", format_loc(loc)));785                self.dedent();786                self.line("}");787            }788            InstructionValue::ObjectExpression { properties, loc } => {789                self.line("ObjectExpression {");790                self.indent();791                self.line("properties:");792                self.indent();793                for (i, prop) in properties.iter().enumerate() {794                    match prop {795                        crate::ObjectPropertyOrSpread::Property(p) => {796                            self.line(&format!("[{}] ObjectProperty {{", i));797                            self.indent();798                            self.line(&format!("key: {}", format_object_property_key(&p.key)));799                            self.line(&format!("type: \"{}\"", p.property_type));800                            self.format_place_field("place", &p.place);801                            self.dedent();802                            self.line("}");803                        }804                        crate::ObjectPropertyOrSpread::Spread(s) => {805                            self.line(&format!("[{}] Spread:", i));806                            self.indent();807                            self.format_place_field("place", &s.place);808                            self.dedent();809                        }810                    }811                }812                self.dedent();813                self.line(&format!("loc: {}", format_loc(loc)));814                self.dedent();815                self.line("}");816            }817            InstructionValue::UnaryExpression {818                operator,819                value: val,820                loc,821            } => {822                self.line("UnaryExpression {");823                self.indent();824                self.line(&format!("operator: \"{}\"", operator));825                self.format_place_field("value", val);826                self.line(&format!("loc: {}", format_loc(loc)));827                self.dedent();828                self.line("}");829            }830            InstructionValue::BinaryExpression {831                operator,832                left,833                right,834                loc,835            } => {836                self.line("BinaryExpression {");837                self.indent();838                self.line(&format!("operator: \"{}\"", operator));839                self.format_place_field("left", left);840                self.format_place_field("right", right);841                self.line(&format!("loc: {}", format_loc(loc)));842                self.dedent();843                self.line("}");844            }845            InstructionValue::NewExpression { callee, args, loc } => {846                self.line("NewExpression {");847                self.indent();848                self.format_place_field("callee", callee);849                self.line("args:");850                self.indent();851                for (i, arg) in args.iter().enumerate() {852                    self.format_argument(arg, i);853                }854                self.dedent();855                self.line(&format!("loc: {}", format_loc(loc)));856                self.dedent();857                self.line("}");858            }859            InstructionValue::CallExpression { callee, args, loc } => {860                self.line("CallExpression {");861                self.indent();862                self.format_place_field("callee", callee);863                self.line("args:");864                self.indent();865                for (i, arg) in args.iter().enumerate() {866                    self.format_argument(arg, i);867                }868                self.dedent();869                self.line(&format!("loc: {}", format_loc(loc)));870                self.dedent();871                self.line("}");872            }873            InstructionValue::MethodCall {874                receiver,875                property,876                args,877                loc,878            } => {879                self.line("MethodCall {");880                self.indent();881                self.format_place_field("receiver", receiver);882                self.format_place_field("property", property);883                self.line("args:");884                self.indent();885                for (i, arg) in args.iter().enumerate() {886                    self.format_argument(arg, i);887                }888                self.dedent();889                self.line(&format!("loc: {}", format_loc(loc)));890                self.dedent();891                self.line("}");892            }893            InstructionValue::JSXText { value: val, loc } => {894                self.line(&format!(895                    "JSXText {{ value: {}, loc: {} }}",896                    format_js_string(val),897                    format_loc(loc)898                ));899            }900            InstructionValue::Primitive { value: prim, loc } => {901                self.line(&format!(902                    "Primitive {{ value: {}, loc: {} }}",903                    format_primitive(prim),904                    format_loc(loc)905                ));906            }907            InstructionValue::TypeCastExpression {908                value: val,909                type_,910                type_annotation_name,911                type_annotation_kind,912                type_annotation: _,913                loc,914            } => {915                self.line("TypeCastExpression {");916                self.indent();917                self.format_place_field("value", val);918                self.line(&format!("type: {}", self.format_type_value(type_)));919                if let Some(annotation_name) = type_annotation_name {920                    self.line(&format!("typeAnnotation: {}", annotation_name));921                }922                if let Some(annotation_kind) = type_annotation_kind {923                    self.line(&format!("typeAnnotationKind: \"{}\"", annotation_kind));924                }925                self.line(&format!("loc: {}", format_loc(loc)));926                self.dedent();927                self.line("}");928            }929            InstructionValue::JsxExpression {930                tag,931                props,932                children,933                loc,934                opening_loc,935                closing_loc,936            } => {937                self.line("JsxExpression {");938                self.indent();939                match tag {940                    crate::JsxTag::Place(p) => {941                        self.format_place_field("tag", p);942                    }943                    crate::JsxTag::Builtin(b) => {944                        self.line(&format!("tag: BuiltinTag(\"{}\")", b.name));945                    }946                }947                self.line("props:");948                self.indent();949                for (i, prop) in props.iter().enumerate() {950                    match prop {951                        crate::JsxAttribute::Attribute { name, place } => {952                            self.line(&format!("[{}] JsxAttribute {{", i));953                            self.indent();954                            self.line(&format!("name: \"{}\"", name));955                            self.format_place_field("place", place);956                            self.dedent();957                            self.line("}");958                        }959                        crate::JsxAttribute::SpreadAttribute { argument } => {960                            self.line(&format!("[{}] JsxSpreadAttribute:", i));961                            self.indent();962                            self.format_place_field("argument", argument);963                            self.dedent();964                        }965                    }966                }967                self.dedent();968                match children {969                    Some(c) => {970                        self.line("children:");971                        self.indent();972                        for (i, child) in c.iter().enumerate() {973                            self.format_place_field(&format!("[{}]", i), child);974                        }975                        self.dedent();976                    }977                    None => self.line("children: null"),978                }979                self.line(&format!("openingLoc: {}", format_loc(opening_loc)));980                self.line(&format!("closingLoc: {}", format_loc(closing_loc)));981                self.line(&format!("loc: {}", format_loc(loc)));982                self.dedent();983                self.line("}");984            }985            InstructionValue::JsxFragment { children, loc } => {986                self.line("JsxFragment {");987                self.indent();988                self.line("children:");989                self.indent();990                for (i, child) in children.iter().enumerate() {991                    self.format_place_field(&format!("[{}]", i), child);992                }993                self.dedent();994                self.line(&format!("loc: {}", format_loc(loc)));995                self.dedent();996                self.line("}");997            }998            InstructionValue::UnsupportedNode { node_type, loc, .. } => match node_type {999                Some(t) => self.line(&format!(1000                    "UnsupportedNode {{ type: {:?}, loc: {} }}",1001                    t,1002                    format_loc(loc)1003                )),1004                None => self.line(&format!("UnsupportedNode {{ loc: {} }}", format_loc(loc))),1005            },1006            InstructionValue::LoadLocal { place, loc } => {1007                self.line("LoadLocal {");1008                self.indent();1009                self.format_place_field("place", place);1010                self.line(&format!("loc: {}", format_loc(loc)));1011                self.dedent();1012                self.line("}");1013            }1014            InstructionValue::DeclareLocal {1015                lvalue,1016                type_annotation,1017                loc,1018            } => {1019                self.line("DeclareLocal {");1020                self.indent();1021                self.format_lvalue("lvalue", lvalue);1022                self.line(&format!(1023                    "type: {}",1024                    match type_annotation {1025                        Some(t) => t.clone(),1026                        None => "null".to_string(),1027                    }1028                ));1029                self.line(&format!("loc: {}", format_loc(loc)));1030                self.dedent();1031                self.line("}");1032            }1033            InstructionValue::DeclareContext { lvalue, loc } => {1034                self.line("DeclareContext {");1035                self.indent();1036                self.line("lvalue:");1037                self.indent();1038                self.line(&format!("kind: {:?}", lvalue.kind));1039                self.format_place_field("place", &lvalue.place);1040                self.dedent();1041                self.line(&format!("loc: {}", format_loc(loc)));1042                self.dedent();1043                self.line("}");1044            }1045            InstructionValue::StoreLocal {1046                lvalue,1047                value: val,1048                type_annotation,1049                loc,1050            } => {1051                self.line("StoreLocal {");1052                self.indent();1053                self.format_lvalue("lvalue", lvalue);1054                self.format_place_field("value", val);1055                self.line(&format!(1056                    "type: {}",1057                    match type_annotation {1058                        Some(t) => t.clone(),1059                        None => "null".to_string(),1060                    }1061                ));1062                self.line(&format!("loc: {}", format_loc(loc)));1063                self.dedent();1064                self.line("}");1065            }1066            InstructionValue::LoadContext { place, loc } => {1067                self.line("LoadContext {");1068                self.indent();1069                self.format_place_field("place", place);1070                self.line(&format!("loc: {}", format_loc(loc)));1071                self.dedent();1072                self.line("}");1073            }1074            InstructionValue::StoreContext {1075                lvalue,1076                value: val,1077                loc,1078            } => {1079                self.line("StoreContext {");1080                self.indent();1081                self.line("lvalue:");1082                self.indent();1083                self.line(&format!("kind: {:?}", lvalue.kind));1084                self.format_place_field("place", &lvalue.place);1085                self.dedent();1086                self.format_place_field("value", val);1087                self.line(&format!("loc: {}", format_loc(loc)));1088                self.dedent();1089                self.line("}");1090            }1091            InstructionValue::Destructure {1092                lvalue,1093                value: val,1094                loc,1095            } => {1096                self.line("Destructure {");1097                self.indent();1098                self.line("lvalue:");1099                self.indent();1100                self.line(&format!("kind: {:?}", lvalue.kind));1101                self.format_pattern(&lvalue.pattern);1102                self.dedent();1103                self.format_place_field("value", val);1104                self.line(&format!("loc: {}", format_loc(loc)));1105                self.dedent();1106                self.line("}");1107            }1108            InstructionValue::PropertyLoad {1109                object,1110                property,1111                loc,1112            } => {1113                self.line("PropertyLoad {");1114                self.indent();1115                self.format_place_field("object", object);1116                self.line(&format!(1117                    "property: \"{}\"",1118                    format_property_literal(property)1119                ));1120                self.line(&format!("loc: {}", format_loc(loc)));1121                self.dedent();1122                self.line("}");1123            }1124            InstructionValue::PropertyStore {1125                object,1126                property,1127                value: val,1128                loc,1129            } => {1130                self.line("PropertyStore {");1131                self.indent();1132                self.format_place_field("object", object);1133                self.line(&format!(1134                    "property: \"{}\"",1135                    format_property_literal(property)1136                ));1137                self.format_place_field("value", val);1138                self.line(&format!("loc: {}", format_loc(loc)));1139                self.dedent();1140                self.line("}");1141            }1142            InstructionValue::PropertyDelete {1143                object,1144                property,1145                loc,1146            } => {1147                self.line("PropertyDelete {");1148                self.indent();1149                self.format_place_field("object", object);1150                self.line(&format!(1151                    "property: \"{}\"",1152                    format_property_literal(property)1153                ));1154                self.line(&format!("loc: {}", format_loc(loc)));1155                self.dedent();1156                self.line("}");1157            }1158            InstructionValue::ComputedLoad {1159                object,1160                property,1161                loc,1162            } => {1163                self.line("ComputedLoad {");1164                self.indent();1165                self.format_place_field("object", object);1166                self.format_place_field("property", property);1167                self.line(&format!("loc: {}", format_loc(loc)));1168                self.dedent();1169                self.line("}");1170            }1171            InstructionValue::ComputedStore {1172                object,1173                property,1174                value: val,1175                loc,1176            } => {1177                self.line("ComputedStore {");1178                self.indent();1179                self.format_place_field("object", object);1180                self.format_place_field("property", property);1181                self.format_place_field("value", val);1182                self.line(&format!("loc: {}", format_loc(loc)));1183                self.dedent();1184                self.line("}");1185            }1186            InstructionValue::ComputedDelete {1187                object,1188                property,1189                loc,1190            } => {1191                self.line("ComputedDelete {");1192                self.indent();1193                self.format_place_field("object", object);1194                self.format_place_field("property", property);1195                self.line(&format!("loc: {}", format_loc(loc)));1196                self.dedent();1197                self.line("}");1198            }1199            InstructionValue::LoadGlobal { binding, loc } => {1200                self.line("LoadGlobal {");1201                self.indent();1202                self.line(&format!("binding: {}", format_non_local_binding(binding)));1203                self.line(&format!("loc: {}", format_loc(loc)));1204                self.dedent();1205                self.line("}");1206            }1207            InstructionValue::StoreGlobal {1208                name,1209                value: val,1210                loc,1211            } => {1212                self.line("StoreGlobal {");1213                self.indent();1214                self.line(&format!("name: \"{}\"", name));1215                self.format_place_field("value", val);1216                self.line(&format!("loc: {}", format_loc(loc)));1217                self.dedent();1218                self.line("}");1219            }1220            InstructionValue::FunctionExpression {1221                name,1222                name_hint,1223                lowered_func,1224                expr_type,1225                loc,1226            } => {1227                self.line("FunctionExpression {");1228                self.indent();1229                self.line(&format!(1230                    "name: {}",1231                    match name {1232                        Some(n) => format!("\"{}\"", n),1233                        None => "null".to_string(),1234                    }1235                ));1236                self.line(&format!(1237                    "nameHint: {}",1238                    match name_hint {1239                        Some(h) => format!("\"{}\"", h),1240                        None => "null".to_string(),1241                    }1242                ));1243                self.line(&format!("type: \"{:?}\"", expr_type));1244                self.line("loweredFunc:");1245                let inner_func = &self.env.functions[lowered_func.func.0 as usize];1246                if let Some(formatter) = inner_func_formatter {1247                    formatter(self, inner_func);1248                } else {1249                    self.line(&format!("  <function {}>", lowered_func.func.0));1250                }1251                self.line(&format!("loc: {}", format_loc(loc)));1252                self.dedent();1253                self.line("}");1254            }1255            InstructionValue::ObjectMethod { loc, lowered_func } => {1256                self.line("ObjectMethod {");1257                self.indent();1258                self.line("loweredFunc:");1259                let inner_func = &self.env.functions[lowered_func.func.0 as usize];1260                if let Some(formatter) = inner_func_formatter {1261                    formatter(self, inner_func);1262                } else {1263                    self.line(&format!("  <function {}>", lowered_func.func.0));1264                }1265                self.line(&format!("loc: {}", format_loc(loc)));1266                self.dedent();1267                self.line("}");1268            }1269            InstructionValue::TaggedTemplateExpression {1270                tag,1271                value: val,1272                loc,1273            } => {1274                self.line("TaggedTemplateExpression {");1275                self.indent();1276                self.format_place_field("tag", tag);1277                self.line(&format!("raw: {}", format_js_string(&val.raw)));1278                self.line(&format!(1279                    "cooked: {}",1280                    match &val.cooked {1281                        Some(c) => format_js_string(c),1282                        None => "undefined".to_string(),1283                    }1284                ));1285                self.line(&format!("loc: {}", format_loc(loc)));1286                self.dedent();1287                self.line("}");1288            }1289            InstructionValue::TemplateLiteral {1290                subexprs,1291                quasis,1292                loc,1293            } => {1294                self.line("TemplateLiteral {");1295                self.indent();1296                self.line("subexprs:");1297                self.indent();1298                for (i, sub) in subexprs.iter().enumerate() {1299                    self.format_place_field(&format!("[{}]", i), sub);1300                }1301                self.dedent();1302                self.line("quasis:");1303                self.indent();1304                for (i, q) in quasis.iter().enumerate() {1305                    self.line(&format!(1306                        "[{}] {{ raw: {}, cooked: {} }}",1307                        i,1308                        format_js_string(&q.raw),1309                        match &q.cooked {1310                            Some(c) => format_js_string(c),1311                            None => "undefined".to_string(),1312                        }1313                    ));1314                }1315                self.dedent();1316                self.line(&format!("loc: {}", format_loc(loc)));1317                self.dedent();1318                self.line("}");1319            }1320            InstructionValue::RegExpLiteral {1321                pattern,1322                flags,1323                loc,1324            } => {1325                self.line(&format!(1326                    "RegExpLiteral {{ pattern: \"{}\", flags: \"{}\", loc: {} }}",1327                    pattern,1328                    flags,1329                    format_loc(loc)1330                ));1331            }1332            InstructionValue::MetaProperty {1333                meta,1334                property,1335                loc,1336            } => {1337                self.line(&format!(1338                    "MetaProperty {{ meta: \"{}\", property: \"{}\", loc: {} }}",1339                    meta,1340                    property,1341                    format_loc(loc)1342                ));1343            }1344            InstructionValue::Await { value: val, loc } => {1345                self.line("Await {");1346                self.indent();1347                self.format_place_field("value", val);1348                self.line(&format!("loc: {}", format_loc(loc)));1349                self.dedent();1350                self.line("}");1351            }1352            InstructionValue::GetIterator { collection, loc } => {1353                self.line("GetIterator {");1354                self.indent();1355                self.format_place_field("collection", collection);1356                self.line(&format!("loc: {}", format_loc(loc)));1357                self.dedent();1358                self.line("}");1359            }1360            InstructionValue::IteratorNext {1361                iterator,1362                collection,1363                loc,1364            } => {1365                self.line("IteratorNext {");1366                self.indent();1367                self.format_place_field("iterator", iterator);1368                self.format_place_field("collection", collection);1369                self.line(&format!("loc: {}", format_loc(loc)));1370                self.dedent();1371                self.line("}");1372            }1373            InstructionValue::NextPropertyOf { value: val, loc } => {1374                self.line("NextPropertyOf {");1375                self.indent();1376                self.format_place_field("value", val);1377                self.line(&format!("loc: {}", format_loc(loc)));1378                self.dedent();1379                self.line("}");1380            }1381            InstructionValue::Debugger { loc } => {1382                self.line(&format!("Debugger {{ loc: {} }}", format_loc(loc)));1383            }1384            InstructionValue::PostfixUpdate {1385                lvalue,1386                operation,1387                value: val,1388                loc,1389            } => {1390                self.line("PostfixUpdate {");1391                self.indent();1392                self.format_place_field("lvalue", lvalue);1393                self.line(&format!("operation: \"{}\"", operation));1394                self.format_place_field("value", val);1395                self.line(&format!("loc: {}", format_loc(loc)));1396                self.dedent();1397                self.line("}");1398            }1399            InstructionValue::PrefixUpdate {1400                lvalue,1401                operation,1402                value: val,1403                loc,1404            } => {1405                self.line("PrefixUpdate {");1406                self.indent();1407                self.format_place_field("lvalue", lvalue);1408                self.line(&format!("operation: \"{}\"", operation));1409                self.format_place_field("value", val);1410                self.line(&format!("loc: {}", format_loc(loc)));1411                self.dedent();1412                self.line("}");1413            }1414            InstructionValue::StartMemoize {1415                manual_memo_id,1416                deps,1417                deps_loc: _,1418                has_invalid_deps: _,1419                loc,1420            } => {1421                self.line("StartMemoize {");1422                self.indent();1423                self.line(&format!("manualMemoId: {}", manual_memo_id));1424                match deps {1425                    Some(d) => {1426                        self.line("deps:");1427                        self.indent();1428                        for (i, dep) in d.iter().enumerate() {1429                            let root_str = match &dep.root {1430                                crate::ManualMemoDependencyRoot::Global { identifier_name } => {1431                                    format!("Global(\"{}\")", identifier_name)1432                                }1433                                crate::ManualMemoDependencyRoot::NamedLocal {1434                                    value: val,1435                                    constant,1436                                } => {1437                                    format!(1438                                        "NamedLocal({}, constant={})",1439                                        val.identifier.0, constant1440                                    )1441                                }1442                            };1443                            let path_str: String = dep1444                                .path1445                                .iter()1446                                .map(|p| {1447                                    format!(1448                                        "{}.{}",1449                                        if p.optional { "?" } else { "" },1450                                        format_property_literal(&p.property)1451                                    )1452                                })1453                                .collect();1454                            self.line(&format!("[{}] {}{}", i, root_str, path_str));1455                        }1456                        self.dedent();1457                    }1458                    None => self.line("deps: null"),1459                }1460                self.line(&format!("loc: {}", format_loc(loc)));1461                self.dedent();1462                self.line("}");1463            }1464            InstructionValue::FinishMemoize {1465                manual_memo_id,1466                decl,1467                pruned,1468                loc,1469            } => {1470                self.line("FinishMemoize {");1471                self.indent();1472                self.line(&format!("manualMemoId: {}", manual_memo_id));1473                self.format_place_field("decl", decl);1474                self.line(&format!("pruned: {}", pruned));1475                self.line(&format!("loc: {}", format_loc(loc)));1476                self.dedent();1477                self.line("}");1478            }1479        }1480    }14811482    // =========================================================================1483    // Errors1484    // =========================================================================14851486    pub fn format_errors(&mut self, error: &CompilerError) {1487        if error.details.is_empty() {1488            self.line("Errors: []");1489            return;1490        }1491        self.line("Errors:");1492        self.indent();1493        for (i, detail) in error.details.iter().enumerate() {1494            self.line(&format!("[{}] {{", i));1495            self.indent();1496            match detail {1497                CompilerErrorOrDiagnostic::Diagnostic(d) => {1498                    self.line(&format!("severity: {:?}", d.severity()));1499                    self.line(&format!("reason: {:?}", d.reason));1500                    self.line(&format!(1501                        "description: {}",1502                        match &d.description {1503                            Some(desc) => format!("{:?}", desc),1504                            None => "null".to_string(),1505                        }1506                    ));1507                    self.line(&format!("category: {:?}", d.category));1508                    let loc = d.primary_location();1509                    self.line(&format!(1510                        "loc: {}",1511                        match loc {1512                            Some(l) => format_loc_value(l),1513                            None => "null".to_string(),1514                        }1515                    ));1516                }1517                CompilerErrorOrDiagnostic::ErrorDetail(d) => {1518                    self.line(&format!("severity: {:?}", d.severity()));1519                    self.line(&format!("reason: {:?}", d.reason));1520                    self.line(&format!(1521                        "description: {}",1522                        match &d.description {1523                            Some(desc) => format!("{:?}", desc),1524                            None => "null".to_string(),1525                        }1526                    ));1527                    self.line(&format!("category: {:?}", d.category));1528                    self.line(&format!(1529                        "loc: {}",1530                        match &d.loc {1531                            Some(l) => format_loc_value(l),1532                            None => "null".to_string(),1533                        }1534                    ));1535                }1536            }1537            self.dedent();1538            self.line("}");1539        }1540        self.dedent();1541    }1542}

Code quality findings 10

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
result.push(char::from_u32(cp).expect("valid supplementary"));
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
let c = char::from_u32(unit as u32).expect("BMP non-surrogate is a char");
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 ident = &self.env.identifiers[id.0 as usize];
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 inner_func = &self.env.functions[lowered_func.func.0 as usize];
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 inner_func = &self.env.functions[lowered_func.func.0 as usize];
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
result.push('"');
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
result.push('"');
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
result.push(char::from_u32(cp).expect("valid supplementary"));
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
crate::PropertyLiteral::String(s) => s.clone(),
Performance Info: Calling .to_string() (especially on &str) allocates a new String. If done repeatedly in loops, consider alternatives like working with &str or using crates like `itoa`/`ryu` for number-to-string conversion.
info performance to-string-in-loop
None => "undefined".to_string(),

Get this view in your editor

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