mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-11-15 05:51:35 +08:00
fix(dart): an annotation links the constant or constructor it names, even behind a comment (#2390)
A Dart annotation is a constant expression: a const variable (`@riverpod`, `@meta.immutable`, a type's static constant or enum value) or a call of a const constructor (`@Riverpod(keepAlive: true)`, `@Foo.named(…)`). It was ranked like a Python decorator, which favours a function or method of that name over a class and scores a constant not at all, so riverpod's 506 `@riverpod` annotations went to riverpod_analyzer_utils' extension getter `riverpod` (0.4) instead of riverpod_annotation's `const riverpod = Riverpod();`. matchDartAnnotation (name-matcher.ts) now takes every Dart `decorates` ref before any other strategy, and nothing falls through. It reads the annotation as written from its `@` and links a constant or (called) a class the file's library can see, through the import prefix it is written with (isDartImportPrefix, dart-libraries.ts); a type's own static constant, enum value or (called) named constructor (isDartConstructor); or, on a member, a static constant of the type around it. Never a method, getter or function. The decorator scan also stopped at the first sibling that was not an annotation, so a comment between an annotation and its declaration (`@override` `// ignore: must_call_super` `void f()`, riverpod_lint's `@riverpod` `// expect_lint: …` fixtures) hid the annotation. Dart's decoratorStepOverTypes lists its two comment kinds, which the scan now steps over, and the kernel's extract_decorators_for steps over the same. Validated on rrousselGit/riverpod @4ba1be2 and felangel/bloc @b9be1e2 with the kernel loaded: riverpod's 506 `@riverpod` edges move to `const riverpod` and 16 annotations behind a comment add an edge each, with nothing removed; bloc gains 7 `@override` refs and no edge changes. Kernel and wasm full-index dumps are byte-identical, and the parity sweeps show 0 diffs. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
631df0138e
commit
d2fb323e51
@@ -539,6 +539,10 @@ export const dartExtractor: LanguageExtractor = {
|
||||
// this: its annotations open its own node, and the dartdoc above them is
|
||||
// that node's previous sibling.
|
||||
docstringStepOverTypes: ['annotation'],
|
||||
// An annotation belongs to the next declaration, whatever comments come
|
||||
// between them: `@override` `// ignore: must_call_super` `void f()`, or a
|
||||
// dartdoc written below the annotations. The decorator scan steps over them.
|
||||
decoratorStepOverTypes: ['comment', 'documentation_comment'],
|
||||
resolveBody: (node, bodyField) => {
|
||||
// Dart: function_body is a next sibling of function_signature/method_signature
|
||||
if (node.type === 'function_signature' || node.type === 'method_signature') {
|
||||
|
||||
@@ -181,6 +181,13 @@ export interface LanguageExtractor {
|
||||
* each one is stepped over, and comments on either side of it still join.
|
||||
*/
|
||||
docstringStepOverTypes?: string[];
|
||||
/**
|
||||
* Node types that may stand between a declaration and the decorators written
|
||||
* before it without ending the scan for them. Dart writes comments there
|
||||
* (`@override` `// ignore: must_call_super` `void f()`), and an annotation
|
||||
* always belongs to the declaration that follows it.
|
||||
*/
|
||||
decoratorStepOverTypes?: string[];
|
||||
/** Extract visibility from node */
|
||||
getVisibility?: (node: SyntaxNode) => 'public' | 'private' | 'protected' | 'internal' | undefined;
|
||||
/** Check if node is exported */
|
||||
|
||||
@@ -6213,8 +6213,10 @@ export class TreeSitterExtractor {
|
||||
//
|
||||
// A grammar that wraps the declaration (Dart's `declaration`
|
||||
// around a member with no body) puts the annotations before the
|
||||
// wrapper, so the scan starts there.
|
||||
// wrapper, so the scan starts there. One that lets comments sit
|
||||
// between the annotations and the declaration (Dart) steps over them.
|
||||
const anchor = this.extractor?.getDeclarationWrapper?.(declNode) ?? declNode;
|
||||
const stepOver = this.extractor?.decoratorStepOverTypes;
|
||||
const parent = anchor.parent;
|
||||
if (parent) {
|
||||
const declStart = anchor.startIndex;
|
||||
@@ -6230,6 +6232,7 @@ export class TreeSitterExtractor {
|
||||
for (let j = declIdx - 1; j >= 0; j--) {
|
||||
const sibling = parent.namedChild(j);
|
||||
if (!sibling) continue;
|
||||
if (stepOver?.includes(sibling.type)) continue;
|
||||
if (sibling.type !== 'decorator' && sibling.type !== 'annotation' && sibling.type !== 'marker_annotation') {
|
||||
break; // non-decorator separator → stop consuming
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user