Skip to content

Commit 2aaedac

Browse files
authored
Merge pull request #9593 from erik-krogh/param2
QL: followup fixes to parameterized modules
2 parents 5cbe01d + 89043ec commit 2aaedac

File tree

20 files changed

+248
-52
lines changed

20 files changed

+248
-52
lines changed

.github/workflows/ql-for-ql-build.yml

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@ jobs:
5050
path: ${{ runner.temp }}/query-pack.zip
5151

5252
extractors:
53-
strategy:
54-
fail-fast: false
55-
5653
runs-on: ubuntu-latest
5754

5855
steps:
@@ -195,9 +192,36 @@ jobs:
195192
category: "ql-for-ql-${{ matrix.folder }}"
196193
- name: Copy sarif file to CWD
197194
run: cp ../results/ql.sarif ./${{ matrix.folder }}.sarif
195+
- name: Fixup the $scema in sarif # Until https://github.com/microsoft/sarif-vscode-extension/pull/436/ is part in a stable release
196+
run: |
197+
sed -i 's/\$schema.*/\$schema": "https:\/\/raw.githubusercontent.com\/oasis-tcs\/sarif-spec\/master\/Schemata\/sarif-schema-2.1.0",/' ${{ matrix.folder }}.sarif
198198
- name: Sarif as artifact
199199
uses: actions/upload-artifact@v3
200200
with:
201201
name: ${{ matrix.folder }}.sarif
202202
path: ${{ matrix.folder }}.sarif
203203

204+
combine:
205+
runs-on: ubuntu-latest
206+
needs:
207+
- analyze
208+
209+
steps:
210+
- uses: actions/checkout@v3
211+
- name: Make a folder for artifacts.
212+
run: mkdir -p results
213+
- name: Download all sarif files
214+
uses: actions/download-artifact@v3
215+
with:
216+
path: results
217+
- uses: actions/setup-node@v3
218+
with:
219+
node-version: 16
220+
- name: Combine all sarif files
221+
run: |
222+
node ./ql/scripts/merge-sarif.js results/**/*.sarif combined.sarif
223+
- name: Upload combined sarif file
224+
uses: actions/upload-artifact@v3
225+
with:
226+
name: combined.sarif
227+
path: combined.sarif

.github/workflows/ql-for-ql-dataset_measure.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
ql/target
3737
key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
3838
- name: Build Extractor
39-
run: cd ql; env "PATH=$PATH:`dirname ${CODEQL}`" ./create-extractor-pack.sh
39+
run: cd ql; env "PATH=$PATH:`dirname ${CODEQL}`" ./scripts/create-extractor-pack.sh
4040
env:
4141
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
4242
- name: Checkout ${{ matrix.repo }}

.github/workflows/ql-for-ql-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
run: |
3737
cd ql;
3838
codeqlpath=$(dirname ${{ steps.find-codeql.outputs.codeql-path }});
39-
env "PATH=$PATH:$codeqlpath" ./create-extractor-pack.sh
39+
env "PATH=$PATH:$codeqlpath" ./scripts/create-extractor-pack.sh
4040
- name: Run QL tests
4141
run: |
4242
"${CODEQL}" test run --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --search-path "${{ github.workspace }}/ql/extractor-pack" --consistency-queries ql/ql/consistency-queries ql/ql/test

javascript/ql/src/Expressions/TypoDatabase.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5793,6 +5793,8 @@ predicate typos(string wrong, string right) {
57935793
or
57945794
wrong = "paramters" and right = "parameters"
57955795
or
5796+
wrong = "parametarized" and right = "parameterized"
5797+
or
57965798
wrong = "paranthesis" and right = "parenthesis"
57975799
or
57985800
wrong = "paraphenalia" and right = "paraphernalia"

ql/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@ cargo build --release
2121
The generated `ql/src/ql.dbscheme` and `ql/src/codeql_ql/ast/internal/TreeSitter.qll` files are included in the repository, but they can be re-generated as follows:
2222

2323
```bash
24-
./create-extractor-pack.sh
24+
./scripts/create-extractor-pack.sh
2525
```
2626

2727
## Building a CodeQL database for a QL program
2828

2929
First, get an extractor pack:
3030

31-
Run `./create-extractor-pack.sh` (Linux/Mac) or `.\create-extractor-pack.ps1` (Windows PowerShell) and the pack will be created in the `extractor-pack` directory.
31+
Run `./scripts/create-extractor-pack.sh` (Linux/Mac) or `.\scripts\create-extractor-pack.ps1` (Windows PowerShell) and the pack will be created in the `extractor-pack` directory.
3232

3333
Then run
3434

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

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ class TypeExpr extends TType, TypeRef {
688688
// resolve type
689689
resolveTypeExpr(this, result)
690690
or
691-
// if it resolves to a module
691+
// if it resolves to a module,
692692
exists(FileOrModule mod | resolveModuleRef(this, mod) | result = mod.toType())
693693
}
694694

@@ -1181,7 +1181,7 @@ class Import extends TImport, ModuleMember, TypeRef {
11811181
*/
11821182
string getImportString() {
11831183
exists(string selec |
1184-
not exists(getSelectionName(_)) and selec = ""
1184+
not exists(this.getSelectionName(_)) and selec = ""
11851185
or
11861186
selec =
11871187
"::" + strictconcat(int i, string q | q = this.getSelectionName(i) | q, "::" order by i)
@@ -2231,9 +2231,7 @@ class ModuleExpr extends TModuleExpr, TypeRef {
22312231
or
22322232
not exists(me.getName()) and result = me.getChild().(QL::SimpleId).getValue()
22332233
or
2234-
exists(QL::ModuleInstantiation instantiation | instantiation.getParent() = me |
2235-
result = instantiation.getName().getChild().getValue()
2236-
)
2234+
result = me.getAFieldOrChild().(QL::ModuleInstantiation).getName().getChild().getValue()
22372235
}
22382236

22392237
/**
@@ -2268,9 +2266,7 @@ class ModuleExpr extends TModuleExpr, TypeRef {
22682266
* The result is either a `PredicateExpr` or a `TypeExpr`.
22692267
*/
22702268
SignatureExpr getArgument(int i) {
2271-
exists(QL::ModuleInstantiation instantiation | instantiation.getParent() = me |
2272-
result.toQL() = instantiation.getChild(i)
2273-
)
2269+
result.toQL() = me.getAFieldOrChild().(QL::ModuleInstantiation).getChild(i)
22742270
}
22752271
}
22762272

ql/ql/src/codeql_ql/ast/internal/Module.qll

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,20 @@ private module Cached {
218218
not exists(me.(ModuleExpr).getQualifier()) and
219219
exists(ContainerOrModule enclosing, string name | resolveModuleRefHelper(me, enclosing, name) |
220220
definesModule(enclosing, name, m, _)
221+
) and
222+
(
223+
not me instanceof TypeExpr
224+
or
225+
// remove some spurious results that can happen with `TypeExpr`
226+
me instanceof TypeExpr and
227+
m instanceof Module_ and // TypeExpr can only resolve to a Module, and only in some scenarios
228+
(
229+
// only possible if this is inside a moduleInstantiation.
230+
me = any(ModuleExpr mod).getArgument(_).asType()
231+
or
232+
// or if it's a parameter to a parameterized module
233+
me = any(SignatureExpr sig, Module mod | mod.hasParameter(_, _, sig) | sig).asType()
234+
)
221235
)
222236
or
223237
exists(FileOrModule mid |
@@ -229,7 +243,8 @@ private module Cached {
229243
pragma[noinline]
230244
private predicate resolveModuleRefHelper(TypeRef me, ContainerOrModule enclosing, string name) {
231245
enclosing = getEnclosingModule(me).getEnclosing*() and
232-
name = [me.(ModuleExpr).getName(), me.(TypeExpr).getClassName()]
246+
name = [me.(ModuleExpr).getName(), me.(TypeExpr).getClassName()] and
247+
(not me instanceof ModuleExpr or not enclosing instanceof Folder_) // module expressions are not imports, so they can't resolve to a file (which is contained in a folder).
233248
}
234249
}
235250

@@ -332,7 +347,19 @@ module ModConsistency {
332347
* }
333348
*/
334349

335-
query predicate noName(Module mod) { not exists(mod.getName()) }
350+
query predicate noName(AstNode mod) {
351+
mod instanceof Module and
352+
not exists(mod.(Module).getName())
353+
or
354+
mod instanceof ModuleExpr and
355+
not exists(mod.(ModuleExpr).getName())
356+
}
336357

337-
query predicate nonUniqueName(Module mod) { count(mod.getName()) >= 2 }
358+
query predicate nonUniqueName(AstNode mod) {
359+
mod instanceof Module and
360+
count(mod.(Module).getName()) >= 2
361+
or
362+
mod instanceof ModuleExpr and
363+
count(mod.(ModuleExpr).getName()) >= 2
364+
}
338365
}

ql/ql/src/codeql_ql/ast/internal/Predicate.qll

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ private predicate definesPredicate(
3131
name = alias.getName() and
3232
resolvePredicateExpr(alias.getAlias(), p) and
3333
public = getPublicBool(alias) and
34-
arity = alias.getArity()
34+
arity = alias.getArity() and
35+
arity = p.getArity()
3536
)
3637
)
3738
}
@@ -48,15 +49,18 @@ private module Cached {
4849
m = pe.getQualifier().getResolvedModule() and
4950
public = true
5051
|
51-
definesPredicate(m, pe.getName(), p.getArity(), p, public)
52+
definesPredicate(m, pe.getName(), p.getArity(), p, public) and
53+
p.getArity() = pe.getArity()
5254
)
5355
}
5456

5557
private predicate resolvePredicateCall(PredicateCall pc, PredicateOrBuiltin p) {
58+
// calls to class methods
5659
exists(Class c, ClassType t |
5760
c = pc.getParent*() and
5861
t = c.getType() and
59-
p = t.getClassPredicate(pc.getPredicateName(), pc.getNumberOfArguments())
62+
p = t.getClassPredicate(pc.getPredicateName(), pc.getNumberOfArguments()) and
63+
not exists(pc.getQualifier()) // no module qualifier, because then it's not a call to a class method.
6064
)
6165
or
6266
exists(FileOrModule m, boolean public |
@@ -85,22 +89,47 @@ private module Cached {
8589
)
8690
}
8791

92+
/**
93+
* Holds if `mc` is a `this.method()` call to a predicate defined in the same class.
94+
* helps avoid spuriously resolving to predicates in super-classes.
95+
*/
96+
private predicate resolveSelfClassCalls(MemberCall mc, PredicateOrBuiltin p) {
97+
exists(Class c |
98+
mc.getBase() instanceof ThisAccess and
99+
c = mc.getEnclosingPredicate().getParent() and
100+
p = c.getClassPredicate(mc.getMemberName()) and
101+
p.getArity() = mc.getNumberOfArguments()
102+
)
103+
}
104+
88105
private predicate resolveMemberCall(MemberCall mc, PredicateOrBuiltin p) {
106+
resolveSelfClassCalls(mc, p)
107+
or
108+
not resolveSelfClassCalls(mc, _) and
89109
exists(Type t |
90110
t = mc.getBase().getType() and
91111
p = t.getClassPredicate(mc.getMemberName(), mc.getNumberOfArguments())
92112
)
93113
or
94114
// super calls - and `this.method()` calls in charpreds. (Basically: in charpreds there is no difference between super and this.)
95-
exists(AstNode sup, ClassType type, Type supertype |
115+
exists(AstNode sup, Type supertype |
96116
sup instanceof Super
97117
or
98118
sup.(ThisAccess).getEnclosingPredicate() instanceof CharPred
99119
|
100120
mc.getBase() = sup and
101-
sup.getEnclosingPredicate().getParent().(Class).getType() = type and
102-
supertype in [type.getASuperType(), type.getAnInstanceofType()] and
103-
p = supertype.getClassPredicate(mc.getMemberName(), mc.getNumberOfArguments())
121+
p = supertype.getClassPredicate(mc.getMemberName(), mc.getNumberOfArguments()) and
122+
(
123+
// super.method()
124+
not exists(mc.getSuperType()) and
125+
exists(ClassType type |
126+
sup.getEnclosingPredicate().getParent().(Class).getType() = type and
127+
supertype in [type.getASuperType(), type.getAnInstanceofType()]
128+
)
129+
or
130+
// Class.super.method()
131+
supertype = mc.getSuperType().getResolvedType()
132+
)
104133
)
105134
}
106135

@@ -172,24 +201,29 @@ module PredConsistency {
172201
}
173202

174203
query predicate multipleResolvePredicateExpr(PredicateExpr pe, int c, ClasslessPredicate p) {
175-
c = strictcount(ClasslessPredicate p0 | resolvePredicateExpr(pe, p0)) and
204+
c =
205+
strictcount(ClasslessPredicate p0 |
206+
resolvePredicateExpr(pe, p0) and
207+
// aliases are expected to resolve to multiple.
208+
not exists(p0.getAlias())
209+
) and
176210
c > 1 and
177211
resolvePredicateExpr(pe, p)
178212
}
179-
// This can happen with parametarized modules
180-
/*
181-
* query predicate multipleResolveCall(Call call, int c, PredicateOrBuiltin p) {
182-
* c =
183-
* strictcount(PredicateOrBuiltin p0 |
184-
* resolveCall(call, p0) and
185-
* // aliases are expected to resolve to multiple.
186-
* not exists(p0.(ClasslessPredicate).getAlias()) and
187-
* // overridden predicates may have multiple targets
188-
* not p0.(ClassPredicate).isOverride()
189-
* ) and
190-
* c > 1 and
191-
* resolveCall(call, p)
192-
* }
193-
*/
194213

214+
query predicate multipleResolveCall(Call call, int c, PredicateOrBuiltin p) {
215+
c =
216+
strictcount(PredicateOrBuiltin p0 |
217+
resolveCall(call, p0) and
218+
// aliases are expected to resolve to multiple.
219+
not exists(p0.(ClasslessPredicate).getAlias()) and
220+
// overridden predicates may have multiple targets
221+
not p0.(ClassPredicate).isOverride() and
222+
not p0 instanceof Relation // <- DB relations resolve to both a relation and a predicate.
223+
) and
224+
c > 1 and
225+
resolveCall(call, p) and
226+
// parameterized modules are expected to resolve to multiple.
227+
not exists(Predicate sig | not exists(sig.getBody()) and resolveCall(call, sig))
195228
}
229+
}

ql/ql/src/codeql_ql/dataflow/DataFlow.qll

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ class SuperNode extends LocalFlow::TSuperNode {
204204
Node getANode() { LocalFlow::getRepr(result) = repr }
205205

206206
/** Gets an AST node from any of the nodes in this super node. */
207-
AstNode asAstNode() { result = getANode().asAstNode() }
207+
AstNode asAstNode() { result = this.getANode().asAstNode() }
208208

209209
/**
210210
* Gets a single node from this super node.
@@ -214,23 +214,25 @@ class SuperNode extends LocalFlow::TSuperNode {
214214
* - An `AstNodeNode` is preferred over other nodes.
215215
* - A node occurring earlier is preferred over one occurring later.
216216
*/
217-
Node getArbitraryRepr() { result = min(Node n | n = getANode() | n order by getInternalId(n)) }
217+
Node getArbitraryRepr() {
218+
result = min(Node n | n = this.getANode() | n order by getInternalId(n))
219+
}
218220

219221
/**
220222
* Gets the predicate containing all nodes that are part of this super node.
221223
*/
222-
Predicate getEnclosingPredicate() { result = getANode().getEnclosingPredicate() }
224+
Predicate getEnclosingPredicate() { result = this.getANode().getEnclosingPredicate() }
223225

224226
/** Gets a string representation of this super node. */
225227
string toString() {
226228
exists(int c |
227-
c = strictcount(getANode()) and
228-
result = "Super node of " + c + " nodes in " + getEnclosingPredicate().getName()
229+
c = strictcount(this.getANode()) and
230+
result = "Super node of " + c + " nodes in " + this.getEnclosingPredicate().getName()
229231
)
230232
}
231233

232234
/** Gets the location of an arbitrary node in this super node. */
233-
Location getLocation() { result = getArbitraryRepr().getLocation() }
235+
Location getLocation() { result = this.getArbitraryRepr().getLocation() }
234236

235237
/** Gets any member call whose receiver is in the same super node. */
236238
MemberCall getALocalMemberCall() { superNode(result.getBase()) = this }
@@ -287,7 +289,7 @@ class SuperNode extends LocalFlow::TSuperNode {
287289
cached
288290
private string getAStringValue(Tracker t) {
289291
t.start() and
290-
result = asAstNode().(String).getValue()
292+
result = this.asAstNode().(String).getValue()
291293
or
292294
exists(SuperNode pred, Tracker t2 |
293295
this = pred.track(t2, t) and

ql/ql/src/codeql_ql/style/TypoDatabase.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5793,6 +5793,8 @@ predicate typos(string wrong, string right) {
57935793
or
57945794
wrong = "paramters" and right = "parameters"
57955795
or
5796+
wrong = "parametarized" and right = "parameterized"
5797+
or
57965798
wrong = "paranthesis" and right = "parenthesis"
57975799
or
57985800
wrong = "paraphenalia" and right = "paraphernalia"

0 commit comments

Comments
 (0)