mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-17 05:07:37 +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:
@@ -51,6 +51,12 @@ const MAX_VALUE_REF_NODES: usize = 20_000;
|
||||
/// `Widget build(…)`), so the docstring walk steps over them.
|
||||
const DOCSTRING_STEP_OVER: &[&str] = &["annotation"];
|
||||
|
||||
/// decoratorStepOverTypes (dart.ts) — an annotation belongs to the next
|
||||
/// declaration, whatever comments come between them (`@override`
|
||||
/// `// ignore: must_call_super` `void f()`), so the decorator scan steps over
|
||||
/// them.
|
||||
const DECORATOR_STEP_OVER: &[&str] = &["comment", "documentation_comment"];
|
||||
|
||||
/// NAME_STOPLIST (function-ref.ts).
|
||||
fn is_stoplisted(name: &str) -> bool {
|
||||
matches!(
|
||||
@@ -1457,7 +1463,8 @@ impl<'t> Walker<'t> {
|
||||
}
|
||||
// Scan 2: preceding siblings, backward, stop at the first
|
||||
// non-annotation — stacked annotations emit in REVERSE source order.
|
||||
// A `declaration`-wrapped member's annotations precede the wrapper.
|
||||
// A `declaration`-wrapped member's annotations precede the wrapper,
|
||||
// and the comments between annotations and declaration are stepped over.
|
||||
let anchor = self.declaration_wrapper(decl).unwrap_or(decl);
|
||||
if let Some(parent) = anchor.parent() {
|
||||
let decl_start = anchor.start_byte();
|
||||
@@ -1473,6 +1480,9 @@ impl<'t> Walker<'t> {
|
||||
if let Some(di) = decl_idx {
|
||||
for j in (0..di).rev() {
|
||||
let Some(sib) = parent.named_child(j) else { continue };
|
||||
if DECORATOR_STEP_OVER.contains(&sib.kind()) {
|
||||
continue;
|
||||
}
|
||||
if !matches!(sib.kind(), "decorator" | "annotation" | "marker_annotation") {
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user