Skip to content

Commit 3fc0bed

Browse files
committed
QL: Remove some FPs.
1 parent be36de9 commit 3fc0bed

File tree

1 file changed

+28
-5
lines changed

1 file changed

+28
-5
lines changed

ql/src/queries/performance/AbstractClassImport.ql

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/**
22
* @name Bidirectional imports for abstract classes
3-
* @description An abstract class should import each of its subclasses, unless it is meant as an extension point, in which case it should import none of them.
3+
* @description An abstract class should import each of its subclasses, unless
4+
* it is meant as a configuration-style class, in which case it
5+
* should import none of them.
46
* @kind problem
57
* @problem.severity error
68
* @id ql/abstract-class-import
@@ -19,12 +21,31 @@ File imports(File file) {
1921
)
2022
}
2123

22-
/** Gets a non-abstract subclass of `ab` that is defined in a different file */
24+
predicate testFile(File f) { f.getRelativePath().matches("%/ql/test/%") }
25+
26+
predicate nonTestQuery(File f) { f.getBaseName().matches("%.ql") and not testFile(f) }
27+
28+
predicate liveNonTestFile(File f) {
29+
exists(File query | nonTestQuery(query) and f = imports*(query))
30+
}
31+
32+
predicate experimentalFile(File f) { f.getRelativePath().matches("%/experimental/%") }
33+
34+
Class getASubclassOfAbstract(Class ab) {
35+
ab.isAbstract() and
36+
result.getType().getASuperType() = ab.getType()
37+
}
38+
39+
/** Gets a non-abstract subclass of `ab` that contributes to the extent of `ab`. */
2340
Class concreteExternalSubclass(Class ab) {
2441
ab.isAbstract() and
2542
not result.isAbstract() and
26-
result.getType().getASuperType*() = ab.getType() and
27-
result.getLocation().getFile() != ab.getLocation().getFile()
43+
result = getASubclassOfAbstract+(ab) and
44+
// Heuristic: An abstract class with subclasses in the same file and no other
45+
// imported subclasses is likely intentional.
46+
result.getLocation().getFile() != ab.getLocation().getFile() and
47+
// Exclude subclasses in tests and libraries that are only used in tests.
48+
liveNonTestFile(result.getLocation().getFile())
2849
}
2950

3051
/** Holds if there is a bidirectional import between the abstract class `ab` and its subclass `sub` */
@@ -74,7 +95,9 @@ predicate alert(Class ab, string msg, Class sub, Class sub2) {
7495
"This abstract class imports its subclass $@ but doesn't import " + nonImports +
7596
" other subclasses, such as $@."
7697
)
77-
)
98+
) and
99+
// exclude results in experimental
100+
not experimentalFile(sub.getLocation().getFile())
78101
}
79102

80103
from Class ab, string msg, Class sub, Class sub2

0 commit comments

Comments
 (0)