Skip to content

Commit 56a5a57

Browse files
authored
Merge pull request #13536 from hvitved/ql/dead-code-fps
QL: Improve dead-code query
2 parents 757f40c + 104dab4 commit 56a5a57

File tree

4 files changed

+95
-3
lines changed

4 files changed

+95
-3
lines changed

ql/ql/src/codeql_ql/ast/Ast.qll

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ class ClasslessPredicate extends TClasslessPredicate, Predicate, ModuleDeclarati
567567
override predicate isPrivate() { Predicate.super.isPrivate() }
568568

569569
/** Holds if this classless predicate is a signature predicate with no body. */
570-
predicate isSignature() { not exists(this.getBody()) }
570+
override predicate isSignature() { not exists(this.getBody()) }
571571

572572
override QLDoc getQLDoc() {
573573
result = any(TopLevel m).getQLDocFor(this)
@@ -836,6 +836,12 @@ class Module extends TModule, ModuleDeclaration {
836836
toMock(result) = mod.asRight().getMember(i)
837837
}
838838

839+
pragma[nomagic]
840+
Declaration getDeclaration(string name) {
841+
result = this.getAMember() and
842+
name = result.getName()
843+
}
844+
839845
QLDoc getQLDocFor(AstNode m) {
840846
exists(int i | result = this.getMember(i) and m = this.getMember(i + 1))
841847
}
@@ -885,6 +891,33 @@ class ModuleMember extends TModuleMember, AstNode {
885891
predicate isFinal() { this.hasAnnotation("final") }
886892
}
887893

894+
private newtype TDeclarationKind =
895+
TClassKind() or
896+
TModuleKind() or
897+
TPredicateKind(int arity) { arity = any(Predicate p).getArity() }
898+
899+
private TDeclarationKind getDeclarationKind(Declaration d) {
900+
d instanceof Class and result = TClassKind()
901+
or
902+
d instanceof Module and result = TModuleKind()
903+
or
904+
d = any(Predicate p | result = TPredicateKind(p.getArity()))
905+
}
906+
907+
/** Holds if module `m` must implement signature declaration `d` with name `name` and kind `kind`. */
908+
pragma[nomagic]
909+
private predicate mustImplement(Module m, string name, TDeclarationKind kind, Declaration d) {
910+
d = m.getImplements(_).getResolvedType().getDeclaration().(Module).getAMember() and
911+
name = d.getName() and
912+
kind = getDeclarationKind(d)
913+
}
914+
915+
pragma[nomagic]
916+
private Declaration getDeclaration(Module m, string name, TDeclarationKind kind) {
917+
result = m.getDeclaration(name) and
918+
kind = getDeclarationKind(result)
919+
}
920+
888921
/** A declaration. E.g. a class, type, predicate, newtype... */
889922
class Declaration extends TDeclaration, AstNode {
890923
/** Gets the name of this declaration. */
@@ -899,6 +932,16 @@ class Declaration extends TDeclaration, AstNode {
899932
or
900933
result = any(Class c).getQLDocFor(this)
901934
}
935+
936+
predicate isSignature() { this.hasAnnotation("signature") }
937+
938+
/** Holds if this declaration implements `other`. */
939+
predicate implements(Declaration other) {
940+
exists(Module m, string name, TDeclarationKind kind |
941+
this = getDeclaration(m, name, kind) and
942+
mustImplement(m, name, kind, other)
943+
)
944+
}
902945
}
903946

904947
/** An entity that can be declared in a module. */

ql/ql/src/codeql_ql/style/DeadCodeQuery.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,16 @@ private AstNode aliveStep(AstNode prev) {
186186
result = prev.(Module).getImplements(_)
187187
or
188188
result = prev.(PredicateExpr).getQualifier()
189+
or
190+
// a module argument is live if the constructed module is
191+
result = prev.(ModuleExpr).getArgument(_)
192+
or
193+
// a type declaration is live if a reference to it is live
194+
result = prev.(TypeExpr).getResolvedType().getDeclaration()
195+
or
196+
// a module member that implements a signature member is live if the module is
197+
prev.(Module).getAMember() = result and
198+
result.(Declaration).implements(_)
189199
}
190200

191201
private AstNode deprecated() {
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
1-
| Foo.qll:2:21:2:25 | ClasslessPredicate dead1 | This code is never used, and it's not publicly exported. |
2-
| Foo.qll:6:13:6:17 | ClasslessPredicate dead2 | This code is never used, and it's not publicly exported. |
1+
| Foo.qll:4:21:4:25 | ClasslessPredicate dead1 | This code is never used, and it's not publicly exported. |
2+
| Foo.qll:8:13:8:17 | ClasslessPredicate dead2 | This code is never used, and it's not publicly exported. |
3+
| Foo.qll:46:16:46:21 | Module Input2 | This code is never used, and it's not publicly exported. |
4+
| Foo.qll:56:16:56:17 | Module M2 | This code is never used, and it's not publicly exported. |
5+
| Foo.qll:68:15:68:20 | Class CImpl2 | This code is never used, and it's not publicly exported. |

ql/ql/test/queries/style/DeadCode/Foo.qll

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import ql
2+
13
private module Mixed {
24
private predicate dead1() { none() }
35

@@ -30,3 +32,37 @@ private module Foo {
3032
module ValidationMethod<Foo::bar/0 sig> {
3133
predicate impl() { sig() }
3234
}
35+
36+
signature module InputSig {
37+
predicate foo();
38+
}
39+
40+
module ParameterizedModule<InputSig Input> { }
41+
42+
private module Input1 implements InputSig {
43+
predicate foo() { any() }
44+
}
45+
46+
private module Input2 implements InputSig {
47+
predicate foo() { any() }
48+
}
49+
50+
private module Input3 implements InputSig {
51+
predicate foo() { any() }
52+
}
53+
54+
module M1 = ParameterizedModule<Input1>;
55+
56+
private module M2 = ParameterizedModule<Input2>;
57+
58+
import ParameterizedModule<Input3>
59+
60+
private module MImpl { }
61+
62+
module MPublic = MImpl;
63+
64+
private class CImpl1 extends AstNode { }
65+
66+
final class CPublic1 = CImpl1;
67+
68+
private class CImpl2 extends AstNode { }

0 commit comments

Comments
 (0)