Python's class-as-value idioms (return SomeClass, x = SomeClass, registry dicts, classes passed as arguments) produced no references edges, so callers/impact on a Django/DRF serializer missed the views that consume it. Three gates dropped them: - return_statement was never dispatched by PYTHON_SPEC (kernel mirrored) - the extraction gate (definedHere) collected function/method names only - resolution accepted function/method targets only (matchFunctionRef + the function_ref import fast path) Capture return_statement for Python (single expression; tuple returns not descended), admit same-file CLASS names to the gate, and accept class targets for Python bare identifiers — scoped to Python so the TS/JS KIND FILTER contract is untouched. The docopt false-positive mechanism behind the function-only rule (lowercase locals vs same-named methods) doesn't transfer: methods stay excluded for bare ids, and the same-file/import gate + unique-or-drop rules still apply. Probed on django-rest-framework (~250 files): 559 new references→class edges, 10/10 sampled genuine (serializer_class = AuthTokenSerializer, the ModelSerializer field-mapping registry, aliases, ctor args, isinstance). EXTRACTION_VERSION 24 → 25. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
f2a5df34de
commit
38580e0b04
@@ -21,4 +21,4 @@
|
||||
* turns the re-index hint into noise — keep it honest (see CLAUDE.md, "Honesty
|
||||
* in the product is load-bearing").
|
||||
*/
|
||||
export const EXTRACTION_VERSION = 24;
|
||||
export const EXTRACTION_VERSION = 25;
|
||||
|
||||
@@ -194,6 +194,12 @@ const PYTHON_SPEC: FnRefSpec = {
|
||||
['keyword_argument', { mode: 'value', field: 'value' }], // Thread(target=worker)
|
||||
['pair', { mode: 'value', field: 'value' }],
|
||||
['list', { mode: 'list' }],
|
||||
// `return SomeClass` / `return handler` — factory returns are how DRF
|
||||
// wires views to serializers (get_serializer_class) and how Python
|
||||
// factories hand back callables (#1478). A single returned expression is
|
||||
// a direct named child, so 'list' covers it; tuple returns (`return A, B`)
|
||||
// sit under an expression_list child and are deliberately not descended.
|
||||
['return_statement', { mode: 'list' }],
|
||||
]),
|
||||
special: new Set(['attribute']),
|
||||
};
|
||||
|
||||
@@ -649,6 +649,12 @@ export class TreeSitterExtractor {
|
||||
const definedHere = new Set<string>();
|
||||
for (const n of this.nodes) {
|
||||
if (n.kind === 'function' || n.kind === 'method') definedHere.add(n.name);
|
||||
// Python only (#1478): class-as-value is a first-class idiom (DRF
|
||||
// get_serializer_class, Meta.model, registry dicts), so same-file CLASS
|
||||
// names pass the gate too. Other languages keep the function/method
|
||||
// gate — TS/JS recover class references through type annotations, and
|
||||
// resolution's kind filter would drop their class candidates anyway.
|
||||
else if (this.language === 'python' && n.kind === 'class') definedHere.add(n.name);
|
||||
}
|
||||
|
||||
// Import-binding names only (all binding emitters push kind 'imports').
|
||||
|
||||
Reference in New Issue
Block a user