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
@@ -915,7 +915,15 @@ export class ReferenceResolver {
|
||||
const viaImport = this.gateLanguage(resolveViaImport(ref, this.context), ref);
|
||||
if (viaImport) {
|
||||
const target = this.queries.getNodeById(viaImport.targetNodeId);
|
||||
if (target && (target.kind === 'function' || target.kind === 'method')) {
|
||||
if (
|
||||
target &&
|
||||
(target.kind === 'function' ||
|
||||
target.kind === 'method' ||
|
||||
// Python (#1478): an imported class used as a value (`return
|
||||
// OrgSerializerFull`) resolves through its import like any
|
||||
// callback — mirrors matchFunctionRef's bareClassOk.
|
||||
(ref.language === 'python' && target.kind === 'class'))
|
||||
) {
|
||||
return viaImport;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,6 +232,16 @@ export function matchFunctionRef(
|
||||
ref.language === 'cpp' || ref.language === 'python' ||
|
||||
ref.language === 'php';
|
||||
|
||||
// Python additionally accepts CLASS targets for bare identifiers (#1478):
|
||||
// class-as-value is a core Python idiom (`return SomeSerializer`,
|
||||
// `Meta.model = Org`, registry dicts, `admin.site.register(Model, Admin)`)
|
||||
// and, unlike TS, Python has no type-annotation recovery path. The
|
||||
// false-positive mechanism behind the function-only rule was lowercase
|
||||
// locals colliding with same-named METHODS (docopt.py) — a candidate must
|
||||
// be an exact-name CLASS node here, and the extraction gate (same-file
|
||||
// class ∪ imports) plus unique-or-drop still apply. Methods stay excluded.
|
||||
const bareClassOk = ref.language === 'python';
|
||||
|
||||
// Qualified member-pointer (`&Widget::on_click` → "Widget::on_click"):
|
||||
// resolve the member ON THAT SCOPE — exempt from bareFnOnly (the `&Cls::m`
|
||||
// shape is an explicit member reference). Unique-or-drop like everything else.
|
||||
@@ -264,7 +274,9 @@ export function matchFunctionRef(
|
||||
.getNodesByName(ref.referenceName)
|
||||
.filter(
|
||||
(n) =>
|
||||
(n.kind === 'function' || (!bareFnOnly && n.kind === 'method')) &&
|
||||
(n.kind === 'function' ||
|
||||
(!bareFnOnly && n.kind === 'method') ||
|
||||
(bareClassOk && n.kind === 'class')) &&
|
||||
sameLanguageFamily(n.language, ref.language) &&
|
||||
n.id !== ref.fromNodeId // a function registering itself is not a dependency edge
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user