mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-23 10:21:40 +08:00
When a generic call parses as a call (a named argument after a positional
one, as in `(context, listen: false)`, or a type argument like `<A?>`,
`<A, B>` or `<List<A>>`), the Dart extractor records a chain on it as
`BlocProvider.of().increment`. The resolver typed that receiver by what
`BlocProvider.of` is declared to return: `T` for `static T of<T>(…)`,
which names no type, and nothing at all when the lookup comes from a
package, as flutter_bloc and provider do in an app. So
`BlocProvider.of<CounterCubit>(context, listen: false).increment()` and
provider's `Provider.of<Cart>(context, listen: false).add(item)` linked
nothing.
The declared return type is still tried first, so `Foo.create().bar()`
with a concrete return type resolves as before. When it gives no edge,
the chain is read at the call site the way #2376 reads a later link of a
chain: the lookup's own type parameter is the type argument the call
gives, and an outside `of<T>(…)` lookup hands back its T. The edge stays
on the encoded ref, as in Go's fallback (the gin runaway).
The extractors are unchanged. A chain on a call parsed as two
comparisons keeps its bare name (#2375), and now reaches the same
method; the comments that gave the old reason are corrected.
Validated before/after with the native kernel at 3f96f80f, nothing
removed anywhere: felangel/bloc @b9be1e2 0 (its four such sites parse as
comparisons and already linked), rrousselGit/riverpod @4ba1be2 +6
(`X.family<…>(…).call(42)` to `ClassFamily::call`), flutter/samples
@63411527 +2 and brianegan/flutter_architecture_samples @d898d13 +6,
all `Provider.of<T>(context, listen: false).m()`. A bare-name fallback
(as Go does) added nothing on those repos, since the lookups are outside
the project, and linked 2 of the test's 8 chains wrong.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -105,10 +105,11 @@ interface DartMisparsedCall {
|
||||
* the callee and `(` against the `>`. A comparison is written `a < b`.
|
||||
*
|
||||
* A call chained on it keeps the bare name it had (`increment` in
|
||||
* `BlocProvider.of<CounterCubit>(context).increment()`) rather than taking
|
||||
* the `BlocProvider.of().increment` a parsed chain gets: that encoding
|
||||
* resolves through what `of` returns, and a generic factory like this one
|
||||
* returns its type parameter, so it would drop the edge the bare name finds.
|
||||
* `BlocProvider.of<CounterCubit>(context).increment()`), where a parsed
|
||||
* chain gets `BlocProvider.of().increment`. The resolver gives both the same
|
||||
* method: it types a bare link from the chain written before it, and an
|
||||
* encoded chain the same way when `of` declares no type of its own to return
|
||||
* (`static T of<T>(…)`, or a factory outside the project) (#750).
|
||||
*/
|
||||
export function dartMisparsedGenericCall(lt: SyntaxNode): DartMisparsedCall | undefined {
|
||||
if (lt.type !== 'relational_operator' || lt.firstChild?.type !== '<') return undefined;
|
||||
|
||||
@@ -8215,6 +8215,21 @@ export function matchDottedCallChain(
|
||||
const factoryMethod = inner.slice(lastDot + 1);
|
||||
if (!factoryClass || !factoryMethod) return null;
|
||||
const ret = lookupCalleeReturnType(`${factoryClass}::${factoryMethod}`, ref, context);
|
||||
if (ref.language === 'dart') {
|
||||
const declared = ret
|
||||
? resolveMethodOnType(ret, method, ref, context, 0.85, 'instance-method', importedFqnOf(ret, ref, context))
|
||||
: null;
|
||||
if (declared) return declared;
|
||||
// A generic factory returns its type parameter — `static T of<T>(…)` in
|
||||
// flutter_bloc's BlocProvider — and one outside the project declares
|
||||
// nothing here, so `BlocProvider.of<CounterCubit>(context).increment()`
|
||||
// had no type to look `increment` up on. The call site has it: read the
|
||||
// chain there as a later link of a chain is read (#750), where `of<T>`'s
|
||||
// T is the type argument the call gives. The edge belongs to this ref, not
|
||||
// to the bare name it was looked up by (see the gin runaway above).
|
||||
const link = matchDartChainLink({ ...ref, referenceName: method }, context);
|
||||
return link ? { ...link, original: ref } : null;
|
||||
}
|
||||
if (!ret) {
|
||||
// Objective-C: a class-message factory — `[X alloc]`, `[X new]`,
|
||||
// `[X sharedFoo]` — returns an instance of the RECEIVER class `X` by
|
||||
|
||||
Reference in New Issue
Block a user