fix/audit-findings #5
2 changed files with 74 additions and 2 deletions
fix(dart,cpp): generic type arguments are not base classes
The base walker descended into type-argument lists, so `class MyBloc extends Bloc<Ev, St>` emitted inherits edges to Bloc, Ev and St; on pipe, 39 of 145 Dart inherits edges (27%) pointed at type arguments (e.g. `Command<int>` -> `int`). C++ `: public Base<Arg>` shared the walker through `template_argument_list`. The walker stops at `type_arguments` / `template_argument_list` / `type_parameters`, and handles tree-sitter-dart's shape, where the arguments are sibling `type` fields of `superclass` (only the first names the base) and nested `type` children of a `type`. Test: languages::generic_type_arguments_are_not_base_classes fails before this change (["Bloc", "Ev", "St"]).
commit
46bd3f50f1
|
|
@ -933,7 +933,24 @@ fn bases(node: Node<'_>, source: &str) -> Vec<String> {
|
|||
child.kind(),
|
||||
"base_class_clause" | "class_heritage" | "superclass" | "extends_type_clause"
|
||||
) {
|
||||
let mut stack = vec![child];
|
||||
let mut stack = Vec::new();
|
||||
if child.kind() == "superclass" {
|
||||
// tree-sitter-dart gives `extends Bloc<Ev, St>` as sibling `type`
|
||||
// fields: the first is the base, later ones are its type arguments.
|
||||
let mut first_type = true;
|
||||
let mut c = child.walk();
|
||||
for part in child.named_children(&mut c) {
|
||||
if part.kind() == "type" {
|
||||
if !first_type {
|
||||
continue;
|
||||
}
|
||||
first_type = false;
|
||||
}
|
||||
stack.push(part);
|
||||
}
|
||||
} else {
|
||||
stack.push(child);
|
||||
}
|
||||
while let Some(base) = stack.pop() {
|
||||
if matches!(
|
||||
base.kind(),
|
||||
|
|
@ -946,8 +963,20 @@ fn bases(node: Node<'_>, source: &str) -> Vec<String> {
|
|||
result.push(base_type(base, source));
|
||||
continue;
|
||||
}
|
||||
// Type arguments name parameters of the base, not further bases:
|
||||
// `extends Bloc<Ev, St>` / `: public Base<Arg>` inherit only Bloc/Base.
|
||||
if matches!(
|
||||
base.kind(),
|
||||
"type_arguments" | "template_argument_list" | "type_parameters"
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
let mut c = base.walk();
|
||||
stack.extend(base.named_children(&mut c));
|
||||
let nested_type_arguments = base.kind() == "type";
|
||||
stack.extend(
|
||||
base.named_children(&mut c)
|
||||
.filter(|part| !(nested_type_arguments && part.kind() == "type")),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -539,3 +539,46 @@ fn cpp_parent_relative_includes_resolve_without_basename_fallback() {
|
|||
.any(|n| n.kind == NodeKind::External && n.name == "../missing/base.h")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generic_type_arguments_are_not_base_classes() {
|
||||
// `extends Bloc<Ev, St>` produced inherits edges to Ev and St: the base walker
|
||||
// descended into the type-argument list. On pipe 39 of 145 Dart inherits edges
|
||||
// (27%) pointed at type arguments. C++ `: public Base<Arg>` shared the walker.
|
||||
let (_, model) = project(&[
|
||||
(
|
||||
"lib/bloc.dart",
|
||||
"class Ev {}\nclass St {}\nclass Bloc<E, S> {}\nclass MyBloc extends Bloc<Ev, St> {}\n",
|
||||
),
|
||||
(
|
||||
"src/base.cpp",
|
||||
"template <class T> class Base {};\nclass Arg {};\nclass Derived : public Base<Arg> {};\n",
|
||||
),
|
||||
]);
|
||||
let inherits = |source: &Node| {
|
||||
let mut names: Vec<String> = model
|
||||
.edges
|
||||
.iter()
|
||||
.filter(|e| e.kind == EdgeKind::Inherits && e.source == source.id)
|
||||
.map(|e| {
|
||||
model
|
||||
.nodes
|
||||
.iter()
|
||||
.find(|n| n.id == e.target)
|
||||
.unwrap()
|
||||
.name
|
||||
.clone()
|
||||
})
|
||||
.collect();
|
||||
names.sort();
|
||||
names
|
||||
};
|
||||
assert_eq!(
|
||||
inherits(symbol(&model, "lib/bloc.dart", "MyBloc")),
|
||||
["Bloc"]
|
||||
);
|
||||
assert_eq!(
|
||||
inherits(symbol(&model, "src/base.cpp", "Derived")),
|
||||
["Base"]
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue