* Check if reference is to a built-in or external symbol
(ref: UnresolvedRef)
| 2316 | * Check if reference is to a built-in or external symbol |
| 2317 | */ |
| 2318 | private isBuiltInOrExternal(ref: UnresolvedRef): boolean { |
| 2319 | const name = ref.referenceName; |
| 2320 | const isJsTs = ref.language === 'typescript' || ref.language === 'javascript' |
| 2321 | || ref.language === 'tsx' || ref.language === 'jsx' || ref.language === 'arkts'; |
| 2322 | |
| 2323 | // JavaScript/TypeScript built-ins |
| 2324 | if (isJsTs && JS_BUILT_INS.has(name)) { |
| 2325 | return true; |
| 2326 | } |
| 2327 | |
| 2328 | // ArkTS resource-reference intrinsics — `$r('app.string.x')` / |
| 2329 | // `$rawfile('x.png')` are framework-provided and appear dozens of times |
| 2330 | // per UI file; without this they can resolve to a stray same-named |
| 2331 | // symbol (e.g. a checked-in hvigor wrapper's `$r`). |
| 2332 | if (ref.language === 'arkts' && (name === '$r' || name === '$rawfile')) { |
| 2333 | return true; |
| 2334 | } |
| 2335 | |
| 2336 | // Common JS/TS library calls (console.log, Math.floor, JSON.parse) |
| 2337 | if (isJsTs && (name.startsWith('console.') || name.startsWith('Math.') || name.startsWith('JSON.'))) { |
| 2338 | return true; |
| 2339 | } |
| 2340 | |
| 2341 | // React hooks from React itself |
| 2342 | if (isJsTs && REACT_HOOKS.has(name)) { |
| 2343 | return true; |
| 2344 | } |
| 2345 | |
| 2346 | // Python built-ins (bare calls only — dotted calls like console.print are method calls) |
| 2347 | if (ref.language === 'python' && PYTHON_BUILT_INS.has(name)) { |
| 2348 | return true; |
| 2349 | } |
| 2350 | |
| 2351 | // Python built-in method calls (e.g., list.extend, dict.update) |
| 2352 | if (ref.language === 'python') { |
| 2353 | const dotIdx = name.indexOf('.'); |
| 2354 | if (dotIdx > 0) { |
| 2355 | const receiver = name.substring(0, dotIdx); |
| 2356 | const method = name.substring(dotIdx + 1); |
| 2357 | // Filter calls on built-in types (list.append, dict.update, etc.) |
| 2358 | if (PYTHON_BUILT_IN_TYPES.has(receiver)) { |
| 2359 | return true; |
| 2360 | } |
| 2361 | // Filter built-in methods on non-class receivers |
| 2362 | // (e.g., items.append where items is a local list variable) |
| 2363 | // But allow if the capitalized receiver matches a known codebase class, |
| 2364 | // OR the receiver is itself an imported project module — a module can |
| 2365 | // export a top-level function sharing a common collection-method name |
| 2366 | // (`ledger.append`, `from . import ledger`), and that call is a real |
| 2367 | // project dependency, not `list.append` (#1681). Without this, the |
| 2368 | // qualified ref never reaches resolveViaImport / resolvePythonModuleMember. |
| 2369 | if (PYTHON_BUILT_IN_METHODS.has(method)) { |
| 2370 | // A module-scope collection binding is stronger evidence than a |
| 2371 | // coincidentally matching class name (#1652). Only use this file's |
| 2372 | // binding: an unrelated module may reuse the receiver for a collection. |
| 2373 | const isCollection = this.context.getNodesByName(receiver).some((node) => |
| 2374 | node.language === 'python' && node.filePath === ref.filePath && |
| 2375 | (node.kind === 'variable' || node.kind === 'constant') && |
no test coverage detected