Repository navigation
fix(dart): a call through an import prefix reaches only what that import exports - #2389
Merged
Merged
Conversation
…ort exports A Dart call written through an import prefix - `http.get(uri)` after `import 'package:http/http.dart' as http;` - was resolved like a method call on a receiver named `http`, so it linked to any project member that fit the name: riverpod's docs' `http.get(...)` / `http.post(...)` calls went to a docs example's `Http::get` / `Http::post` by the receiver's capitalized name, and `fmt.describe(...)` to a class's `describe` method. Now `p.name(...)` calls a top-level declaration a library imported with that prefix exports (export chains, show / hide and parts followed through the library model), or nothing when the prefixed library is a package outside the repository. A constructor call (`p.Widget()`) instantiates the prefixed library's class. The same holds where the prefix heads a chain - `p.Box.create()`, `p.Report.empty()` - and for `p.Box<int>.named(...)`, which arrives as `Box.named`: the type is the one the prefix brings in. A parameter, local or member named like the prefix still hides it, and `const p.Box.named()`, which the extractors record as `p.named`, links nothing. The library model's one prefix reader is `dartImportPrefixes`: Dart annotations (#2390's `matchDartAnnotation`) read prefixes through it too, in place of the `isDartImportPrefix` it had alongside. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
colbymchenry
force-pushed
the
claude/modest-elgamal-61b4df
branch
from
October 6, 2026 17:35
c0da73f to
0d6e90c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A Dart call written through an import prefix —
http.get(uri)afterimport 'package:http/http.dart' as http;— was resolved like a method call on a receiver namedhttp, so it linked to any project member that fit the name. On riverpod, 25 calls in the website docs (http.get×21,http.post×4) went to docs examples'Http::get/Http::postthroughmatchMethodCall's capitalized-receiver guess. Meanwhile calls through a prefix into the project's own libraries (utils.Listener(),create.main()) linked nothing, because only methods were considered.Builds on the Dart library model from #2386 (
dart-libraries.ts).Fix
p.y(…):matchDartPrefixedCallruns ahead of the name-matching strategies for a DartX.ycall ref. WhenXis an import prefix of the caller's library (as Xordeferred as X; apartuses its library's imports),ycan only be a top-level declaration exported by the imports with that prefix (dartPrefixSees: export chains,show/hide). That declaration is linked at 0.9 (resolvedBy: 'import'), or nothing is linked. There is no member guess.X.y. Both extractors recordconst p.Box.named()asp.namedbecause they take the firsttype_identifier, so that call now links nothing instead of a top-levelnamed.p.Box.create(),p.Report.empty()), which arrive as bare chain links: the head now resolves among the declarations the prefix brings in. A static member is looked up on that type's own declaration (DartValue.owner), not on any type of the same name. Before, the chain typer dropped the prefix and took any project type of that name, sohttp.Client.fromEnv()reached a projectClient::fromEnv.p.Box<int>.named(…)is aconstructor_invocationand arrives asBox.namedwith its column on the prefix.matchDartTypeMemberCallnow restricts the owner to the type the prefix brings in, or links nothing.dart-libraries.ts: newdartImportPrefixes(file), the prefixes declared by the file's library imports, following the part chain (also where no pubspec says what the package is) and memoized. It replaces name-matcher's regex reader (DartCode.prefixes), which missed a part's library prefixes and imports with conditional URIs. It also replaces fix(dart): an annotation links the constant or constructor it names, even behind a comment #2390'sisDartImportPrefix, which did the same job:matchDartAnnotationnow reads prefixes through it, so the library model has one prefix reader.dart-local-scope.ts: newisDartLocallyBound(file, name, offset).Validation
Native kernel loaded, main
d2fb323evs this branch, rrousselGit/riverpod @4ba1be2 and felangel/bloc @b9be1e2, edges paired by call site:http.get/http.postin riverpod's website docs, previously linked toHttp::get/Http::post(instance-method 0.8). package:http is not in the repository.dartPrefixSees.instantiates:internals.ElementId/ContainerId/OriginId/ProviderIdin riverpod_devtool, reached through hooks_riverpod's export of riverpod'sdevtool.dart. This includes a.g.dartpart using its library's prefix.utils.Listener/ErrorListener/DeferredNotifierin two transformer tests that import both../matrix.dart as utilsand../utils.dart as utils.calls:create.main()and similar in the benchmarks, andutils.throwsProviderException.calls:app.main()andreplay_*_test.main().internals.Notification.fromJson). Prefixed calls into external packages stay unlinked: 105 in riverpod, 120 in bloc.decorates) edge changes: usingdartImportPrefixesin place ofisDartImportPrefixleaves fix(dart): an annotation links the constant or constructor it names, even behind a comment #2390's results as they were.d2fb323e, on631df013, on99246848(where riverpod goes from 85,482 to 85,551 edges and bloc from 18,354 to 18,357) and on249d9a86plus fix(dart): a bare call or type name reaches only what its library can see #2386.Tests
__tests__/dart-import-prefix-calls.test.tsruns on both kernel and wasm. On main, 10 of its 12 tests fail; the two parameter-shadowing guards pass both before and after.CODEGRAPH_KERNEL_EXPECT=1), including fix(dart): an annotation links the constant or constructor it names, even behind a comment #2390'sdart-annotation-targetsanddart-annotation-comments: 491 files passed and 6 skipped.Not in this PR
const p.Foo.named()is recorded asp.named, andconst p.Foo()/new p.Foo()asp. Fixing it needs a kernel change. This PR only makes sure those refs link nothing.pubspec.yamlabove it, the library model can't say what a prefix imports. There, as for unprefixed calls, a prefixed call links a top-level declaration of that name when the project has exactly one. riverpod and bloc have no such files with prefixed imports.🤖 Generated with Claude Code