mirror of
https://github.com/github/codeql.git
synced 2026-02-09 19:51:07 +01:00
253 lines
6.6 KiB
Plaintext
253 lines
6.6 KiB
Plaintext
import ql
|
|
private import codeql_ql.ast.internal.AstNodes as AstNodes
|
|
private import codeql_ql.ast.internal.TreeSitter
|
|
|
|
private class ContainerOrModule extends TContainerOrModule {
|
|
string getName() { none() }
|
|
|
|
ContainerOrModule getEnclosing() { none() }
|
|
|
|
string toString() { none() }
|
|
|
|
predicate hasLocationInfo(
|
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
) {
|
|
none()
|
|
}
|
|
}
|
|
|
|
private class TFileOrModule = TFile or TModule;
|
|
|
|
/** A file or a module. */
|
|
class FileOrModule extends TFileOrModule, ContainerOrModule { }
|
|
|
|
private class File_ extends FileOrModule, TFile {
|
|
File f;
|
|
|
|
File_() { this = TFile(f) }
|
|
|
|
override ContainerOrModule getEnclosing() { result = TFolder(f.getParentContainer()) }
|
|
|
|
override string getName() { result = f.getStem() }
|
|
|
|
override string toString() { result = f.toString() }
|
|
|
|
override predicate hasLocationInfo(
|
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
) {
|
|
filepath = f.getAbsolutePath() and
|
|
startline = 0 and
|
|
startcolumn = 0 and
|
|
endline = 0 and
|
|
endcolumn = 0
|
|
}
|
|
}
|
|
|
|
private class Folder_ extends ContainerOrModule, TFolder {
|
|
Folder f;
|
|
|
|
Folder_() { this = TFolder(f) }
|
|
|
|
override ContainerOrModule getEnclosing() { result = TFolder(f.getParentContainer()) }
|
|
|
|
override string getName() { result = f.getStem() }
|
|
|
|
override string toString() { result = f.toString() }
|
|
|
|
override predicate hasLocationInfo(
|
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
) {
|
|
filepath = f.getAbsolutePath() and
|
|
startline = 0 and
|
|
startcolumn = 0 and
|
|
endline = 0 and
|
|
endcolumn = 0
|
|
}
|
|
}
|
|
|
|
// TODO: Use `AstNode::getParent` once it is total
|
|
private Generated::AstNode parent(Generated::AstNode n) {
|
|
result = n.getParent() and
|
|
not n instanceof Generated::Module
|
|
}
|
|
|
|
private Module getEnclosingModule0(AstNode n) {
|
|
AstNodes::toGenerated(result) = parent*(AstNodes::toGenerated(n).getParent())
|
|
}
|
|
|
|
ContainerOrModule getEnclosingModule(AstNode n) {
|
|
result = TModule(getEnclosingModule0(n))
|
|
or
|
|
not exists(getEnclosingModule0(n)) and
|
|
result = TFile(n.getLocation().getFile())
|
|
}
|
|
|
|
class Module_ extends FileOrModule, TModule {
|
|
Module m;
|
|
|
|
Module_() { this = TModule(m) }
|
|
|
|
override ContainerOrModule getEnclosing() { result = getEnclosingModule(m) }
|
|
|
|
override string getName() { result = m.getName() }
|
|
|
|
override string toString() { result = m.toString() }
|
|
|
|
override predicate hasLocationInfo(
|
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
) {
|
|
m.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
|
}
|
|
}
|
|
|
|
private predicate resolveQualifiedName(Import imp, ContainerOrModule m, int i) {
|
|
not m = TFile(any(File f | f.getExtension() = "ql")) and
|
|
exists(string q | q = imp.getQualifiedName(i) |
|
|
i = 0 and
|
|
(
|
|
exists(Container c, Container parent |
|
|
// should ideally look at `qlpack.yml` files
|
|
parent = imp.getLocation().getFile().getParentContainer+() and
|
|
c.getParentContainer() = parent and
|
|
q = m.getName()
|
|
|
|
|
m = TFile(c)
|
|
or
|
|
m = TFolder(c)
|
|
)
|
|
or
|
|
definesModule(getEnclosingModule(imp).getEnclosing*(), q, m, _)
|
|
)
|
|
or
|
|
exists(Folder_ mid |
|
|
resolveQualifiedName(imp, mid, i - 1) and
|
|
m.getEnclosing() = mid and
|
|
q = m.getName()
|
|
)
|
|
)
|
|
}
|
|
|
|
private predicate resolveSelectionName(Import imp, ContainerOrModule m, int i) {
|
|
exists(int last |
|
|
resolveQualifiedName(imp, m, last) and
|
|
last = count(int j | exists(imp.getQualifiedName(j))) - 1
|
|
) and
|
|
not m instanceof Folder_ and
|
|
i = -1
|
|
or
|
|
exists(ContainerOrModule mid |
|
|
resolveSelectionName(imp, mid, i - 1) and
|
|
definesModule(mid, imp.getSelectionName(i), m, true)
|
|
)
|
|
}
|
|
|
|
cached
|
|
private module Cached {
|
|
cached
|
|
module NewType {
|
|
cached
|
|
newtype TContainerOrModule =
|
|
TFile(File f) or
|
|
TFolder(Folder f) or
|
|
TModule(Module m)
|
|
}
|
|
|
|
/** Holds if import statement `imp` resolves to `m`. */
|
|
cached
|
|
predicate resolve(Import imp, FileOrModule m) {
|
|
exists(int last |
|
|
resolveSelectionName(imp, m, last) and
|
|
last = count(int j | exists(imp.getSelectionName(j))) - 1
|
|
)
|
|
}
|
|
|
|
/** Holds if module expression `me` resolves to `m`. */
|
|
cached
|
|
predicate resolveModuleExpr(ModuleExpr me, FileOrModule m) {
|
|
not m = TFile(any(File f | f.getExtension() = "ql")) and
|
|
not exists(me.getQualifier()) and
|
|
definesModule(getEnclosingModule(me).getEnclosing*(), me.getName(), m, _)
|
|
or
|
|
exists(FileOrModule mid |
|
|
resolveModuleExpr(me.getQualifier(), mid) and
|
|
definesModule(mid, me.getName(), m, true)
|
|
)
|
|
}
|
|
}
|
|
|
|
import Cached
|
|
private import NewType
|
|
|
|
boolean getPublicBool(AstNode n) {
|
|
if n.(ModuleMember).isPrivate() or n.(NewTypeBranch).getNewType().isPrivate()
|
|
then result = false
|
|
else result = true
|
|
}
|
|
|
|
/**
|
|
* Holds if `container` defines module `m` with name `name`.
|
|
*
|
|
* `m` may be defined either directly or through `import`s.
|
|
*/
|
|
private predicate definesModule(
|
|
ContainerOrModule container, string name, ContainerOrModule m, boolean public
|
|
) {
|
|
container = m.getEnclosing() and
|
|
name = m.getName() and
|
|
(
|
|
(m instanceof File_ or m instanceof Folder_) and
|
|
public = true
|
|
or
|
|
m = TModule(any(Module mod | public = getPublicBool(mod)))
|
|
)
|
|
or
|
|
// import X
|
|
exists(Import imp, ContainerOrModule m0 |
|
|
container = getEnclosingModule(imp) and
|
|
resolve(imp, m0) and
|
|
not exists(imp.importedAs()) and
|
|
definesModule(m0, name, m, true) and
|
|
public = getPublicBool(imp)
|
|
)
|
|
or
|
|
// import X as Y
|
|
exists(Import imp |
|
|
container = getEnclosingModule(imp) and
|
|
name = imp.importedAs() and
|
|
resolve(imp, m) and
|
|
public = getPublicBool(imp)
|
|
)
|
|
or
|
|
// module X = Y
|
|
exists(Module alias |
|
|
container = getEnclosingModule(alias) and
|
|
name = alias.getName() and
|
|
resolveModuleExpr(alias.getAlias(), m) and
|
|
public = getPublicBool(alias)
|
|
)
|
|
}
|
|
|
|
module ModConsistency {
|
|
query predicate noResolve(Import imp) {
|
|
not resolve(imp, _) and
|
|
not imp.getLocation().getFile().getAbsolutePath().regexpMatch(".*/(test|examples)/.*")
|
|
}
|
|
|
|
query predicate noResolveModuleExpr(ModuleExpr me) {
|
|
not resolveModuleExpr(me, _) and
|
|
not me.getLocation().getFile().getAbsolutePath().regexpMatch(".*/(test|examples)/.*")
|
|
}
|
|
|
|
query predicate multipleResolve(Import imp, int c, ContainerOrModule m) {
|
|
c = strictcount(ContainerOrModule m0 | resolve(imp, m0)) and
|
|
c > 1 and
|
|
resolve(imp, m)
|
|
}
|
|
|
|
query predicate multipleResolveModuleExpr(ModuleExpr me, int c, ContainerOrModule m) {
|
|
c = strictcount(ContainerOrModule m0 | resolveModuleExpr(me, m0)) and
|
|
c > 1 and
|
|
resolveModuleExpr(me, m)
|
|
}
|
|
}
|