everything is a TypeRef, some TypeRefs just resolve to a module

This commit is contained in:
Erik Krogh Kristensen
2022-06-17 11:22:04 +02:00
parent 2b5af15d80
commit 13b743643e
5 changed files with 64 additions and 56 deletions

View File

@@ -640,7 +640,7 @@ class FieldDecl extends TFieldDecl, AstNode {
/**
* A type reference, such as `DataFlow::Node`.
*/
class TypeExpr extends TType, AstNode {
class TypeExpr extends TType, TypeRef {
QL::TypeExpr type;
TypeExpr() { this = TType(type) }
@@ -677,10 +677,14 @@ class TypeExpr extends TType, AstNode {
*/
ModuleExpr getModule() { toQL(result) = type.getQualifier() }
/**
* Gets the type that this type reference refers to.
*/
Type getResolvedType() { resolveTypeExpr(this, result) }
/** Gets the type that this type reference refers to. */
override Type getResolvedType() {
// resolve type
resolveTypeExpr(this, result)
or
// if it resolves to a module
exists(FileOrModule mod | resolveModuleRef(this, mod) | result = mod.toType())
}
override AstNode getAChild(string pred) {
result = super.getAChild(pred)
@@ -713,7 +717,7 @@ class Module extends TModule, ModuleDeclaration {
}
/** Gets a ref to the module that this module implements. */
ModuleParameterRef getImplements(int i) { toQL(result) = mod.getImplements(i).getTypeExpr() }
TypeExpr getImplements(int i) { toQL(result) = mod.getImplements(i).getTypeExpr() }
/** Gets the module expression that this module is an alias for, if any. */
ModuleExpr getAlias() { toQL(result) = mod.getAFieldOrChild().(QL::ModuleAliasBody).getChild() }
@@ -1111,18 +1115,18 @@ class InlineCast extends TInlineCast, Expr {
}
}
/** An entity that resolves to a module. */
class ModuleRef extends AstNode, TModuleRef {
/** Gets the module that this entity resolves to. */
FileOrModule getResolvedModule() { none() }
/** An entity that resolves to a type. */
class TypeRef extends AstNode, TTypeRef {
abstract Type getResolvedType();
string getName() { none() }
/** Gets the module that this entity resolves to, if this reference resolves to a module */
final FileOrModule getResolvedModule() { result.toType() = this.getResolvedType() }
}
/**
* An import statement.
*/
class Import extends TImport, ModuleMember, ModuleRef {
class Import extends TImport, ModuleMember, TypeRef {
QL::ImportDirective imp;
Import() { this = TImport(imp) }
@@ -1173,7 +1177,9 @@ class Import extends TImport, ModuleMember, ModuleRef {
)
}
final override FileOrModule getResolvedModule() { resolve(this, result) }
override Type getResolvedType() {
exists(FileOrModule mod | resolve(this, mod) | result = mod.toType())
}
}
/** A formula, such as `x = 6 and y < 5`. */
@@ -2191,18 +2197,8 @@ class DontCare extends TDontCare, Expr {
override string getAPrimaryQlClass() { result = "DontCare" }
}
/**
* A type expression seen as a reference to a module as part of a parameterized module (or it's instantiation).
* This might not be a reference to a module, but we assume so until we find out in the resolve phase.
*/
class ModuleParameterRef extends ModuleRef instanceof TypeExpr {
final override FileOrModule getResolvedModule() { resolveModuleRef(this, result) }
override string getName() { result = TypeExpr.super.getClassName() }
}
/** A module expression. Such as `DataFlow` in `DataFlow::Node` */
class ModuleExpr extends TModuleExpr, ModuleRef {
class ModuleExpr extends TModuleExpr, TypeRef {
QL::ModuleExpr me;
ModuleExpr() { this = TModuleExpr(me) }
@@ -2216,7 +2212,7 @@ class ModuleExpr extends TModuleExpr, ModuleRef {
*
* is `Bar`.
*/
override string getName() {
string getName() {
result = me.getName().(QL::SimpleId).getValue()
or
not exists(me.getName()) and result = me.getChild().(QL::SimpleId).getValue()
@@ -2237,7 +2233,9 @@ class ModuleExpr extends TModuleExpr, ModuleRef {
*/
ModuleExpr getQualifier() { result = TModuleExpr(me.getChild()) }
final override FileOrModule getResolvedModule() { resolveModuleRef(this, result) }
override Type getResolvedType() {
exists(FileOrModule mod | resolveModuleRef(this, mod) | result = mod.toType())
}
final override string toString() { result = this.getName() }
@@ -2269,7 +2267,7 @@ class SignatureExpr extends TSignatureExpr, AstNode {
SignatureExpr() {
toQL(this) = sig.getPredicate()
or
toQL(this) = sig.getTypeExpr() // both `TypeExpr` and `ModuleParameterRef`
toQL(this) = sig.getTypeExpr()
}
/** Gets the generated AST node that contains this signature expression. */
@@ -2280,8 +2278,6 @@ class SignatureExpr extends TSignatureExpr, AstNode {
/** Gets this signature expression if it represents a type expression. */
TypeExpr asType() { result = this }
ModuleParameterRef asModuleRef() { result = this }
}
/** An argument to an annotation. */

View File

@@ -83,7 +83,7 @@ class TExpr =
class TCall = TPredicateCall or TMemberCall or TNoneCall or TAnyCall;
class TModuleRef = TImport or TModuleExpr or TType;
class TTypeRef = TImport or TModuleExpr or TType;
class TYamlNode = TYamlCommemt or TYamlEntry or TYamlKey or TYamlListitem or TYamlValue;

View File

@@ -41,6 +41,12 @@ class FileOrModule extends TFileOrModule, ContainerOrModule {
or
result = this.asModule().getLocation().getFile()
}
Type toType() {
result.(FileType).getDeclaration().getLocation().getFile() = this.asFile()
or
result.(ModuleType).getDeclaration() = this.asModule()
}
}
private class File_ extends FileOrModule, TFile {
@@ -207,7 +213,7 @@ private module Cached {
/** Holds if module expression `me` resolves to `m`. */
cached
predicate resolveModuleRef(ModuleRef me, FileOrModule m) {
predicate resolveModuleRef(TypeRef me, FileOrModule m) {
not m = TFile(any(File f | f.getExtension() = "ql")) and
not exists(me.(ModuleExpr).getQualifier()) and
exists(ContainerOrModule enclosing, string name | resolveModuleRefHelper(me, enclosing, name) |
@@ -221,9 +227,9 @@ private module Cached {
}
pragma[noinline]
private predicate resolveModuleRefHelper(ModuleRef me, ContainerOrModule enclosing, string name) {
private predicate resolveModuleRefHelper(TypeRef me, ContainerOrModule enclosing, string name) {
enclosing = getEnclosingModule(me).getEnclosing*() and
name = me.getName()
name = [me.(ModuleExpr).getName(), me.(TypeExpr).getClassName()]
}
}
@@ -257,18 +263,18 @@ private predicate definesModule(
)
or
// signature module in a paramertized module
exists(Module mod, SignatureExpr sig, ModuleParameterRef ty, int i |
exists(Module mod, SignatureExpr sig, TypeExpr ty, int i |
mod = container.asModule() and
mod.hasParameter(i, name, sig) and
public = false and
ty = sig.asModuleRef()
ty = sig.asType()
|
// resolve to the signature module
m = ty.getResolvedModule()
or
// resolve to the arguments of the instantiated module
exists(ModuleExpr inst | inst.getResolvedModule().asModule() = mod |
m = inst.getArgument(i).asModuleRef().getResolvedModule()
m = inst.getArgument(i).asType().getResolvedModule()
)
)
or
@@ -307,16 +313,6 @@ module ModConsistency {
.regexpMatch(".*/(test|examples|ql-training|recorded-call-graph-metrics)/.*")
}
query predicate noResolveModuleRef(ModuleRef me) {
not exists(me.getResolvedModule()) and
not me.getLocation()
.getFile()
.getAbsolutePath()
.regexpMatch(".*/(test|examples|ql-training|recorded-call-graph-metrics)/.*") and
// this ModuleRef might really be a type.
not exists(me.(TypeExpr).getResolvedType())
}
query predicate multipleResolve(Import imp, int c, ContainerOrModule m) {
c = strictcount(ContainerOrModule m0 | resolve(imp, m0)) and
c > 1 and

View File

@@ -14,7 +14,9 @@ private newtype TType =
TDontCare() or
TClassChar(Class c) { isActualClass(c) } or
TClassDomain(Class c) { isActualClass(c) } or
TDatabase(string s) { exists(TypeExpr t | t.isDBType() and s = t.getClassName()) }
TDatabase(string s) { exists(TypeExpr t | t.isDBType() and s = t.getClassName()) } or
TFile(TopLevel t) or
TModule(Module m)
private predicate primTypeName(string s) { s = ["int", "float", "string", "boolean", "date"] }
@@ -110,6 +112,26 @@ class ClassType extends Type, TClass {
}
}
class FileType extends Type, TFile {
TopLevel decl;
FileType() { this = TFile(decl) }
override string getName() { result = decl.getLocation().getFile().getBaseName() }
override TopLevel getDeclaration() { result = decl }
}
class ModuleType extends Type, TModule {
Module decl;
ModuleType() { this = TModule(decl) }
override string getName() { result = decl.getName() }
override Module getDeclaration() { result = decl }
}
private PredicateOrBuiltin declaredPred(Type ty, string name, int arity) {
result.getDeclaringType() = ty and
result.getName() = name and
@@ -343,16 +365,12 @@ private predicate defines(FileOrModule m, string name, Type t, boolean public) {
}
module TyConsistency {
query predicate noResolve(TypeExpr te) {
not resolveTypeExpr(te, _) and
query predicate noResolve(TypeRef te) {
not exists(te.getResolvedType()) and
not te.getLocation()
.getFile()
.getAbsolutePath()
.regexpMatch(".*/(test|examples|ql-training|recorded-call-graph-metrics)/.*") and
// we have some duplicate with moduleRef, so that might be resolved correctly.
not exists(ModuleRef ref | AstNodes::toQL(te) = AstNodes::toQL(ref) |
exists(ref.getResolvedModule())
)
.regexpMatch(".*/(test|examples|ql-training|recorded-call-graph-metrics)/.*")
}
// This can happen with parameterized modules.

View File

@@ -39,8 +39,6 @@ where
or
ModConsistency::noResolve(node) and msg = "ModConsistency::noResolve"
or
ModConsistency::noResolveModuleRef(node) and msg = "ModConsistency::noResolveModuleRef"
or
ModConsistency::noName(node) and msg = "ModConsistency::noName"
or
ModConsistency::nonUniqueName(node) and msg = "ModConsistency::nonUniqueName"