Merge pull request #13536 from hvitved/ql/dead-code-fps

QL: Improve dead-code query
This commit is contained in:
Tom Hvitved
2023-06-27 09:01:59 +02:00
committed by GitHub
4 changed files with 95 additions and 3 deletions

View File

@@ -567,7 +567,7 @@ class ClasslessPredicate extends TClasslessPredicate, Predicate, ModuleDeclarati
override predicate isPrivate() { Predicate.super.isPrivate() }
/** Holds if this classless predicate is a signature predicate with no body. */
predicate isSignature() { not exists(this.getBody()) }
override predicate isSignature() { not exists(this.getBody()) }
override QLDoc getQLDoc() {
result = any(TopLevel m).getQLDocFor(this)
@@ -836,6 +836,12 @@ class Module extends TModule, ModuleDeclaration {
toMock(result) = mod.asRight().getMember(i)
}
pragma[nomagic]
Declaration getDeclaration(string name) {
result = this.getAMember() and
name = result.getName()
}
QLDoc getQLDocFor(AstNode m) {
exists(int i | result = this.getMember(i) and m = this.getMember(i + 1))
}
@@ -885,6 +891,33 @@ class ModuleMember extends TModuleMember, AstNode {
predicate isFinal() { this.hasAnnotation("final") }
}
private newtype TDeclarationKind =
TClassKind() or
TModuleKind() or
TPredicateKind(int arity) { arity = any(Predicate p).getArity() }
private TDeclarationKind getDeclarationKind(Declaration d) {
d instanceof Class and result = TClassKind()
or
d instanceof Module and result = TModuleKind()
or
d = any(Predicate p | result = TPredicateKind(p.getArity()))
}
/** Holds if module `m` must implement signature declaration `d` with name `name` and kind `kind`. */
pragma[nomagic]
private predicate mustImplement(Module m, string name, TDeclarationKind kind, Declaration d) {
d = m.getImplements(_).getResolvedType().getDeclaration().(Module).getAMember() and
name = d.getName() and
kind = getDeclarationKind(d)
}
pragma[nomagic]
private Declaration getDeclaration(Module m, string name, TDeclarationKind kind) {
result = m.getDeclaration(name) and
kind = getDeclarationKind(result)
}
/** A declaration. E.g. a class, type, predicate, newtype... */
class Declaration extends TDeclaration, AstNode {
/** Gets the name of this declaration. */
@@ -899,6 +932,16 @@ class Declaration extends TDeclaration, AstNode {
or
result = any(Class c).getQLDocFor(this)
}
predicate isSignature() { this.hasAnnotation("signature") }
/** Holds if this declaration implements `other`. */
predicate implements(Declaration other) {
exists(Module m, string name, TDeclarationKind kind |
this = getDeclaration(m, name, kind) and
mustImplement(m, name, kind, other)
)
}
}
/** An entity that can be declared in a module. */

View File

@@ -186,6 +186,16 @@ private AstNode aliveStep(AstNode prev) {
result = prev.(Module).getImplements(_)
or
result = prev.(PredicateExpr).getQualifier()
or
// a module argument is live if the constructed module is
result = prev.(ModuleExpr).getArgument(_)
or
// a type declaration is live if a reference to it is live
result = prev.(TypeExpr).getResolvedType().getDeclaration()
or
// a module member that implements a signature member is live if the module is
prev.(Module).getAMember() = result and
result.(Declaration).implements(_)
}
private AstNode deprecated() {

View File

@@ -1,2 +1,5 @@
| Foo.qll:2:21:2:25 | ClasslessPredicate dead1 | This code is never used, and it's not publicly exported. |
| Foo.qll:6:13:6:17 | ClasslessPredicate dead2 | This code is never used, and it's not publicly exported. |
| Foo.qll:4:21:4:25 | ClasslessPredicate dead1 | This code is never used, and it's not publicly exported. |
| Foo.qll:8:13:8:17 | ClasslessPredicate dead2 | This code is never used, and it's not publicly exported. |
| Foo.qll:46:16:46:21 | Module Input2 | This code is never used, and it's not publicly exported. |
| Foo.qll:56:16:56:17 | Module M2 | This code is never used, and it's not publicly exported. |
| Foo.qll:68:15:68:20 | Class CImpl2 | This code is never used, and it's not publicly exported. |

View File

@@ -1,3 +1,5 @@
import ql
private module Mixed {
private predicate dead1() { none() }
@@ -30,3 +32,37 @@ private module Foo {
module ValidationMethod<Foo::bar/0 sig> {
predicate impl() { sig() }
}
signature module InputSig {
predicate foo();
}
module ParameterizedModule<InputSig Input> { }
private module Input1 implements InputSig {
predicate foo() { any() }
}
private module Input2 implements InputSig {
predicate foo() { any() }
}
private module Input3 implements InputSig {
predicate foo() { any() }
}
module M1 = ParameterizedModule<Input1>;
private module M2 = ParameterizedModule<Input2>;
import ParameterizedModule<Input3>
private module MImpl { }
module MPublic = MImpl;
private class CImpl1 extends AstNode { }
final class CPublic1 = CImpl1;
private class CImpl2 extends AstNode { }