QL: Merge branch 'main' into tausbn/add-override-test

This commit is contained in:
Taus
2021-10-15 13:03:17 +02:00
committed by GitHub
35 changed files with 1753 additions and 418 deletions

View File

@@ -1,4 +1,4 @@
name: "CodeQL"
name: "CodeQL with bleeding edge queries and extractor"
on:
workflow_dispatch:
@@ -12,6 +12,30 @@ on:
jobs:
build_query_pack:
runs-on: ubuntu-latest-xl
steps:
- uses: actions/checkout@v2
- name: Find codeql
id: find-codeql
uses: github/codeql-action/init@esbena/ql
with:
languages: javascript # does not matter
- name: Build query pack
run: |
cd ql/src
"${CODEQL}" pack create
cd .codeql/pack/codeql/ql-all/0.0.0
zip "${PACKZIP}" -r .
env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
PACKZIP: ${{ runner.temp }}/query-pack.zip
- name: Upload query pack
uses: actions/upload-artifact@v2
with:
name: query-pack
path: ${{ runner.temp }}/query-pack.zip
# XXX this is mostly an inlined copy of the 'build' job in build.yml
build_extractor_pack:
strategy:
@@ -79,9 +103,11 @@ jobs:
analyze:
name: Analyze
needs: build_extractor_pack
needs:
- build_query_pack
- build_extractor_pack
runs-on: ubuntu-latest
runs-on: ubuntu-latest-xl
permissions:
actions: read
@@ -89,61 +115,55 @@ jobs:
security-events: write
steps:
- name: Download pack
- name: Download query pack
uses: actions/download-artifact@v2
with:
name: query-pack
path: ${{ runner.temp }}/query-pack-artifact
- name: Download extractor pack
uses: actions/download-artifact@v2
with:
name: extractor-pack
path: ${{ runner.temp }}/extractor-pack-artifact
- name: Unzip pack
- name: Prepare packs
id: prepare-packs
run: |
set -x
mkdir "${PACKTMP}"
cd "${PACKTMP}"
unzip "${PACKARTIFACT}/*.zip" -d unzipped
cp -r unzipped/ql "${PACK}"
mkdir -p "${COMPLETE_PACK}" "${PACKS_TMP}"
cd "${PACKS_TMP}"
unzip "${QUERY_PACK_ARTIFACT}/*.zip" -d query-pack-artifact-unzipped
cp -r query-pack-artifact-unzipped/. "${COMPLETE_PACK}"
unzip "${EXTRACTOR_PACK_ARTIFACT}/*.zip" -d extractor-pack-artifact-unzipped
cp -r extractor-pack-artifact-unzipped/ql/. "${COMPLETE_PACK}"
cd "${COMPLETE_PACK}"
zip "${COMPLETE_PACK_ZIP}" -r .
env:
PACKTMP: ${{ runner.temp }}/extractor-pack-artifact.tmp
PACKARTIFACT: ${{ runner.temp }}/extractor-pack-artifact
PACK: ${{ runner.temp }}/extractor-pack
- name: Checkout repository
uses: actions/checkout@v2
- name: Make config file
run: |
set -x
echo "name: CodeQL config for QL" >> "${CONFIG_FILE}"
echo "" >> "${CONFIG_FILE}"
echo "disable-default-queries: true" >> "${CONFIG_FILE}"
echo "" >> "${CONFIG_FILE}"
echo "queries: " >> "${CONFIG_FILE}"
echo " - name: Standard queries" >> "${CONFIG_FILE}"
echo " uses: ${SUITE}" >> "${CONFIG_FILE}"
cat "${CONFIG_FILE}"
env:
SUITE: ./ql/src/codeql-suites/ql-code-scanning.qls
CONFIG_FILE: ./.custom-codeql-actions-config.yml
PACKS_TMP: ${{ runner.temp }}/pack-artifacts.tmp
QUERY_PACK_ARTIFACT: ${{ runner.temp }}/query-pack-artifact
EXTRACTOR_PACK_ARTIFACT: ${{ runner.temp }}/extractor-pack-artifact
COMPLETE_PACK: ${{ runner.temp }}/pack
COMPLETE_PACK_ZIP: ${{ runner.temp }}/pack.zip
- name: Hack codeql-action options
run: |
JSON=$(jq -nc --arg pack "${PACK}" '.resolve.extractor=["--search-path", $pack] | .database.init=["--search-path", $pack]')
JSON=$(jq -nc --arg pack "${COMPLETE_PACK}" '.resolve.queries=["--search-path", $pack] | .resolve.extractor=["--search-path", $pack] | .database.init=["--search-path", $pack]')
echo "CODEQL_ACTION_EXTRA_OPTIONS=${JSON}" >> ${GITHUB_ENV}
env:
PACK: ${{ runner.temp }}/extractor-pack
COMPLETE_PACK: ${{ runner.temp }}/pack
- name: Checkout repository
uses: actions/checkout@v2
- name: Initialize CodeQL
uses: github/codeql-action/init@esbena/ql
with:
languages: ql
db-location: ${{ runner.temp }}/db
config-file: ./.custom-codeql-actions-config.yml
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@esbena/ql
with:
results: ${{ runner.temp }}/results
add-snippets: true
- name: Upload db
uses: actions/upload-artifact@v2
@@ -152,9 +172,9 @@ jobs:
path: ${{ runner.temp }}/db
retention-days: 1
- name: Upload results
- name: Upload complete pack
uses: actions/upload-artifact@v2
with:
name: results
path: ${{ runner.temp }}/results
name: complete-pack
path: ${{ runner.temp }}/pack.zip
retention-days: 1

View File

@@ -0,0 +1,53 @@
name: "CodeQL with published queries and extractor"
on:
workflow_dispatch:
push:
branches: [ main ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Download pack
run: |
# adjust this line to make the workflow work in other repositories
# the ql-qlpack.zip file can be downloaded at:
# - https://github.com/github/codeql-ql/releases
# - https://github.com/github/codeql-ql/actions/workflows/bleeding-codeql-analysis.yml
gh release download latest --pattern ql-qlpack.zip
unzip ql-qlpack.zip -d "${PACK}"
env:
PACK: ${{ runner.temp }}/ql-qlpack
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Hack codeql-action options
run: |
JSON=$(jq -nc --arg pack "${PACK}" '.resolve.queries=["--search-path", $pack] | .resolve.extractor=["--search-path", $pack] | .database.init=["--search-path", $pack]')
echo "CODEQL_ACTION_EXTRA_OPTIONS=${JSON}" >> ${GITHUB_ENV}
env:
PACK: ${{ runner.temp }}/ql-qlpack
- name: Initialize CodeQL
uses: github/codeql-action/init@esbena/ql
with:
languages: ql
db-location: ${{ runner.temp }}/db
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@esbena/ql

View File

@@ -0,0 +1 @@
import codeql_ql.ast.internal.Builtins::BuildinsConsistency

View File

@@ -0,0 +1,244 @@
private import ql
private import codeql_ql.ast.internal.Predicate
private import codeql_ql.ast.internal.Type
private import codeql_ql.ast.internal.Builtins
private newtype TValueNumber =
TVariableValueNumber(VarDecl var) { variableAccessValueNumber(_, var) } or
TFieldValueNumber(VarDecl var) { fieldAccessValueNumber(_, var) } or
TThisValueNumber(Predicate pred) { thisAccessValueNumber(_, pred) } or
TPredicateValueNumber(PredicateOrBuiltin pred, ValueNumberArgumentList args) {
predicateCallValueNumber(_, pred, args)
} or
TClassPredicateValueNumber(PredicateOrBuiltin pred, ValueNumber base, ValueNumberArgumentList args) {
classPredicateCallValueNumber(_, pred, base, args)
} or
TLiteralValueNumber(string value, Type t) { literalValueNumber(_, value, t) } or
TBinaryOpValueNumber(FunctionSymbol symbol, ValueNumber leftOperand, ValueNumber rightOperand) {
binaryOperandValueNumber(_, symbol, leftOperand, rightOperand)
} or
TUnaryOpValueNumber(FunctionSymbol symbol, ValueNumber operand) {
unaryOperandValueNumber(_, symbol, operand)
} or
TInlineCastValueNumber(ValueNumber operand, Type t) { inlineCastValueNumber(_, operand, t) } or
TDontCareValueNumber() or
TRangeValueNumber(ValueNumber lower, ValueNumber high) { rangeValueNumber(_, lower, high) } or
TSetValueNumber(ValueNumberElementList elements) { setValueNumber(_, elements) } or
TUniqueValueNumber(Expr e) { uniqueValueNumber(e) }
private newtype ValueNumberArgumentList =
MkArgsNil() or
MkArgsCons(ValueNumber head, ValueNumberArgumentList tail) {
argumentValueNumbers(_, _, head, tail)
}
private newtype ValueNumberElementList =
MkElementsNil() or
MkElementsCons(ValueNumber head, ValueNumberElementList tail) {
setValueNumbers(_, _, head, tail)
}
private ValueNumberArgumentList argumentValueNumbers(Call call, int start) {
start = call.getNumberOfArguments() and
result = MkArgsNil()
or
exists(ValueNumber head, ValueNumberArgumentList tail |
argumentValueNumbers(call, start, head, tail) and
result = MkArgsCons(head, tail)
)
}
private predicate argumentValueNumbers(
Call call, int start, ValueNumber head, ValueNumberArgumentList tail
) {
head = valueNumber(call.getArgument(start)) and
tail = argumentValueNumbers(call, start + 1)
}
private ValueNumberElementList setValueNumbers(Set set, int start) {
start = set.getNumberOfElements() and
result = MkElementsNil()
or
exists(ValueNumber head, ValueNumberElementList tail |
setValueNumbers(set, start, head, tail) and
result = MkElementsCons(head, tail)
)
}
private predicate setValueNumbers(Set set, int start, ValueNumber head, ValueNumberElementList tail) {
head = valueNumber(set.getElement(start)) and
tail = setValueNumbers(set, start + 1)
}
/**
* A value number. A value number represents a collection of expressions that compute to the same value
* at runtime.
*/
class ValueNumber extends TValueNumber {
string toString() { result = "GVN" }
/** Gets an expression that has this value number. */
final Expr getAnExpr() { this = valueNumber(result) }
}
private predicate uniqueValueNumber(Expr e) { not numberable(e) }
private predicate numberable(Expr e) {
e instanceof VarAccess or
e instanceof FieldAccess or
e instanceof ThisAccess or
e instanceof Call or
e instanceof Literal or
e instanceof BinOpExpr or
e instanceof UnaryExpr or
e instanceof InlineCast or
e instanceof ExprAnnotation or
e instanceof DontCare or
e instanceof Range or
e instanceof Set or
e instanceof AsExpr
}
private predicate variableAccessValueNumber(VarAccess access, VarDef var) {
access.getDeclaration() = var
}
private predicate fieldAccessValueNumber(FieldAccess access, VarDef var) {
access.getDeclaration() = var
}
private predicate thisAccessValueNumber(ThisAccess access, Predicate pred) {
access.getEnclosingPredicate() = pred
}
private predicate predicateCallValueNumber(
Call call, PredicateOrBuiltin pred, ValueNumberArgumentList args
) {
call.getTarget() = pred and
not exists(call.(MemberCall).getBase()) and
args = argumentValueNumbers(call, 0)
}
private predicate classPredicateCallValueNumber(
MemberCall call, PredicateOrBuiltin pred, ValueNumber base, ValueNumberArgumentList args
) {
call.getTarget() = pred and
valueNumber(call.getBase()) = base and
args = argumentValueNumbers(call, 0)
}
private predicate literalValueNumber(Literal lit, string value, Type t) {
lit.(String).getValue() = value and
t instanceof StringClass
or
lit.(Integer).getValue().toString() = value and
t instanceof IntClass
or
lit.(Float).getValue().toString() = value and
t instanceof FloatClass
or
lit.(Boolean).isFalse() and
value = "false" and
t instanceof BooleanClass
or
lit.(Boolean).isTrue() and
value = "true" and
t instanceof BooleanClass
}
private predicate binaryOperandValueNumber(
BinOpExpr e, FunctionSymbol symbol, ValueNumber leftOperand, ValueNumber rightOperand
) {
e.getOperator() = symbol and
valueNumber(e.getLeftOperand()) = leftOperand and
valueNumber(e.getRightOperand()) = rightOperand
}
private predicate unaryOperandValueNumber(UnaryExpr e, FunctionSymbol symbol, ValueNumber operand) {
e.getOperator() = symbol and
valueNumber(e.getOperand()) = operand
}
private predicate inlineCastValueNumber(InlineCast cast, ValueNumber operand, Type t) {
valueNumber(cast.getBase()) = operand and
cast.getTypeExpr().getResolvedType() = t
}
private predicate rangeValueNumber(Range range, ValueNumber lower, ValueNumber high) {
valueNumber(range.getLowEndpoint()) = lower and
valueNumber(range.getHighEndpoint()) = high
}
private predicate setValueNumber(Set set, ValueNumberElementList elements) {
elements = setValueNumbers(set, 0)
}
private TValueNumber nonUniqueValueNumber(Expr e) {
exists(VarDecl var |
variableAccessValueNumber(e, var) and
result = TVariableValueNumber(var)
)
or
exists(VarDecl var |
fieldAccessValueNumber(e, var) and
result = TFieldValueNumber(var)
)
or
exists(Predicate pred |
thisAccessValueNumber(e, pred) and
result = TThisValueNumber(pred)
)
or
exists(PredicateOrBuiltin pred, ValueNumberArgumentList args |
predicateCallValueNumber(e, pred, args) and
result = TPredicateValueNumber(pred, args)
)
or
exists(PredicateOrBuiltin pred, ValueNumber base, ValueNumberArgumentList args |
classPredicateCallValueNumber(e, pred, base, args) and
result = TClassPredicateValueNumber(pred, base, args)
)
or
exists(string value, Type t |
literalValueNumber(e, value, t) and
result = TLiteralValueNumber(value, t)
)
or
exists(FunctionSymbol symbol, ValueNumber leftOperand, ValueNumber rightOperand |
binaryOperandValueNumber(e, symbol, leftOperand, rightOperand) and
result = TBinaryOpValueNumber(symbol, leftOperand, rightOperand)
)
or
exists(FunctionSymbol symbol, ValueNumber operand |
unaryOperandValueNumber(e, symbol, operand) and
result = TUnaryOpValueNumber(symbol, operand)
)
or
exists(ValueNumber operand, Type t |
inlineCastValueNumber(e, operand, t) and
result = TInlineCastValueNumber(operand, t)
)
or
result = valueNumber([e.(ExprAnnotation).getExpression(), e.(AsExpr).getInnerExpr()])
or
e instanceof DontCare and result = TDontCareValueNumber()
or
exists(ValueNumber lower, ValueNumber high |
rangeValueNumber(e, lower, high) and
result = TRangeValueNumber(lower, high)
)
or
exists(ValueNumberElementList elements |
setValueNumber(e, elements) and
result = TSetValueNumber(elements)
)
}
/** Gets the value number of an expression `e`. */
cached
TValueNumber valueNumber(Expr e) {
result = nonUniqueValueNumber(e)
or
uniqueValueNumber(e) and
result = TUniqueValueNumber(e)
}

View File

@@ -9,10 +9,10 @@ abstract class Container extends @container {
Container getAChildContainer() { this = result.getParentContainer() }
/** Gets a file in this container. */
File getAFile() { result = getAChildContainer() }
File getAFile() { result = this.getAChildContainer() }
/** Gets a sub-folder in this container. */
Folder getAFolder() { result = getAChildContainer() }
Folder getAFolder() { result = this.getAChildContainer() }
/**
* Gets the absolute, canonical path of this container, using forward slashes
@@ -58,7 +58,7 @@ abstract class Container extends @container {
* </table>
*/
string getBaseName() {
result = getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1)
result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1)
}
/**
@@ -84,17 +84,19 @@ abstract class Container extends @container {
* <tr><td>"/tmp/x.tar.gz"</td><td>"gz"</td></tr>
* </table>
*/
string getExtension() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) }
string getExtension() {
result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3)
}
/** Gets the file in this container that has the given `baseName`, if any. */
File getFile(string baseName) {
result = getAFile() and
result = this.getAFile() and
result.getBaseName() = baseName
}
/** Gets the sub-folder in this container that has the given `baseName`, if any. */
Folder getFolder(string baseName) {
result = getAFolder() and
result = this.getAFolder() and
result.getBaseName() = baseName
}
@@ -111,7 +113,7 @@ abstract class Container extends @container {
*/
string getRelativePath() {
exists(string absPath, string pref |
absPath = getAbsolutePath() and sourceLocationPrefix(pref)
absPath = this.getAbsolutePath() and sourceLocationPrefix(pref)
|
absPath = pref and result = ""
or
@@ -137,7 +139,9 @@ abstract class Container extends @container {
* <tr><td>"/tmp/x.tar.gz"</td><td>"x.tar"</td></tr>
* </table>
*/
string getStem() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) }
string getStem() {
result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1)
}
/**
* Gets a URL representing the location of this container.
@@ -151,7 +155,7 @@ abstract class Container extends @container {
*
* This is the absolute path of the container.
*/
string toString() { result = getAbsolutePath() }
string toString() { result = this.getAbsolutePath() }
}
/** A folder. */
@@ -159,7 +163,7 @@ class Folder extends Container, @folder {
override string getAbsolutePath() { folders(this, result, _) }
/** Gets the URL of this folder. */
override string getURL() { result = "folder://" + getAbsolutePath() }
override string getURL() { result = "folder://" + this.getAbsolutePath() }
}
/** A file. */

View File

@@ -4,6 +4,7 @@ private import codeql_ql.ast.internal.Module
private import codeql_ql.ast.internal.Predicate
import codeql_ql.ast.internal.Type
private import codeql_ql.ast.internal.Variable
private import codeql_ql.ast.internal.Builtins
bindingset[name]
private string directMember(string name) { result = name + "()" }
@@ -16,18 +17,9 @@ private string stringIndexedMember(string name, string index) {
result = name + "(_)" and exists(index)
}
/**
* Holds if `node` has an annotation with `name`.
*/
private predicate hasAnnotation(AstNode node, string name) {
exists(Generated::Annotation annotation | annotation.getName().getValue() = name |
toGenerated(node).getParent() = annotation.getParent()
)
}
/** An AST node of a QL program */
class AstNode extends TAstNode {
string toString() { result = getAPrimaryQlClass() }
string toString() { result = this.getAPrimaryQlClass() }
/**
* Gets the location of the AST node.
@@ -40,6 +32,20 @@ class AstNode extends TAstNode {
)
}
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
if exists(this.getLocation())
then this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
else (
filepath = "" and
startline = 0 and
startcolumn = 0 and
endline = 0 and
endcolumn = 0
)
}
/**
* Gets the parent in the AST for this node.
*/
@@ -60,6 +66,12 @@ class AstNode extends TAstNode {
/** Gets the QLDoc comment for this AST node, if any. */
QLDoc getQLDoc() { none() }
/** Holds if `node` has an annotation with `name`. */
predicate hasAnnotation(string name) { this.getAnAnnotation().getName() = name }
/** Gets an annotation of this AST node. */
Annotation getAnAnnotation() { toGenerated(this).getParent() = toGenerated(result).getParent() }
/**
* Gets the predicate that contains this AST node.
*/
@@ -80,7 +92,7 @@ class TopLevel extends TTopLevel, AstNode {
* Gets a member from contained in this top-level module.
* Includes private members.
*/
ModuleMember getAMember() { result = getMember(_) }
ModuleMember getAMember() { result = this.getMember(_) }
/** Gets the `i`'th member of this top-level module. */
ModuleMember getMember(int i) {
@@ -180,11 +192,62 @@ class Select extends TSelect, AstNode {
override string getAPrimaryQlClass() { result = "Select" }
}
class PredicateOrBuiltin extends TPredOrBuiltin, AstNode {
string getName() { none() }
Type getDeclaringType() { none() }
Type getParameterType(int i) { none() }
Type getReturnType() { none() }
int getArity() { result = count(int i | exists(this.getParameterType(i))) }
predicate isPrivate() { none() }
}
class BuiltinPredicate extends PredicateOrBuiltin, TBuiltin {
override string toString() { result = this.getName() }
override string getAPrimaryQlClass() { result = "BuiltinPredicate" }
}
private class BuiltinClassless extends BuiltinPredicate, TBuiltinClassless {
string name;
string ret;
string args;
BuiltinClassless() { this = TBuiltinClassless(ret, name, args) }
override string getName() { result = name }
override PrimitiveType getReturnType() { result.getName() = ret }
override PrimitiveType getParameterType(int i) { result.getName() = getArgType(args, i) }
}
private class BuiltinMember extends BuiltinPredicate, TBuiltinMember {
string name;
string qual;
string ret;
string args;
BuiltinMember() { this = TBuiltinMember(qual, ret, name, args) }
override string getName() { result = name }
override PrimitiveType getReturnType() { result.getName() = ret }
override PrimitiveType getParameterType(int i) { result.getName() = getArgType(args, i) }
override PrimitiveType getDeclaringType() { result.getName() = qual }
}
/**
* A QL predicate.
* Either a classless predicate, a class predicate, or a characteristic predicate.
*/
class Predicate extends TPredicate, AstNode, Declaration {
class Predicate extends TPredicate, AstNode, PredicateOrBuiltin, Declaration {
/**
* Gets the body of the predicate.
*/
@@ -203,21 +266,28 @@ class Predicate extends TPredicate, AstNode, Declaration {
/**
* Gets the number of parameters.
*/
int getArity() {
override int getArity() {
not this.(ClasslessPredicate).getAlias() instanceof PredicateExpr and
result = count(getParameter(_))
result = count(this.getParameter(_))
or
exists(PredicateExpr alias | alias = this.(ClasslessPredicate).getAlias() |
result = alias.getArity()
)
}
/**
* Holds if this predicate is private.
*/
override predicate isPrivate() { this.hasAnnotation("private") }
/**
* Gets the return type (if any) of the predicate.
*/
TypeExpr getReturnTypeExpr() { none() }
Type getReturnType() { result = this.getReturnTypeExpr().getResolvedType() }
override Type getReturnType() { result = this.getReturnTypeExpr().getResolvedType() }
override Type getParameterType(int i) { result = this.getParameter(i).getType() }
override AstNode getAChild(string pred) {
result = super.getAChild(pred)
@@ -255,18 +325,18 @@ class Relation extends TDBRelation, AstNode, Declaration {
}
/** Gets the `i`th parameter name */
string getParameterName(int i) { result = getColumn(i).getColName().getValue() }
string getParameterName(int i) { result = this.getColumn(i).getColName().getValue() }
/** Gets the `i`th parameter type */
string getParameterType(int i) {
// TODO: This is just using the name of the type, not the actual type. Checkout Type.qll
result = getColumn(i).getColType().getChild().(Generated::Token).getValue()
result = this.getColumn(i).getColType().getChild().(Generated::Token).getValue()
}
/**
* Gets the number of parameters.
*/
int getArity() { result = count(getColumn(_)) }
int getArity() { result = count(this.getColumn(_)) }
override string getAPrimaryQlClass() { result = "Relation" }
}
@@ -379,6 +449,8 @@ class ClasslessPredicate extends TClasslessPredicate, Predicate, ModuleDeclarati
or
pred_name = directMember("getReturnTypeExpr") and result = this.getReturnTypeExpr()
}
override predicate isPrivate() { Predicate.super.isPrivate() }
}
/**
@@ -397,15 +469,10 @@ class ClassPredicate extends TClassPredicate, Predicate {
override Class getParent() { result.getAClassPredicate() = this }
/**
* Holds if this predicate is private.
*/
predicate isPrivate() { hasAnnotation(this, "private") }
/**
* Holds if this predicate is annotated as overriding another predicate.
*/
predicate isOverride() { hasAnnotation(this, "override") }
predicate isOverride() { this.hasAnnotation("override") }
override VarDecl getParameter(int i) {
toGenerated(result) =
@@ -419,7 +486,7 @@ class ClassPredicate extends TClassPredicate, Predicate {
/**
* Gets the type representing this class.
*/
ClassType getDeclaringType() { result.getDeclaration() = getParent() }
override ClassType getDeclaringType() { result.getDeclaration() = this.getParent() }
predicate overrides(ClassPredicate other) { predOverrides(this, other) }
@@ -448,7 +515,7 @@ class CharPred extends TCharPred, Predicate {
override Formula getBody() { toGenerated(result) = pred.getBody() }
override string getName() { result = getParent().(Class).getName() }
override string getName() { result = this.getParent().(Class).getName() }
override AstNode getAChild(string pred_name) {
result = super.getAChild(pred_name)
@@ -456,7 +523,7 @@ class CharPred extends TCharPred, Predicate {
pred_name = directMember("getBody") and result = this.getBody()
}
ClassType getDeclaringType() { result.getDeclaration() = getParent() }
override ClassType getDeclaringType() { result.getDeclaration() = this.getParent() }
}
/**
@@ -618,7 +685,7 @@ class Module extends TModule, ModuleDeclaration {
*/
class ModuleMember extends TModuleMember, AstNode {
/** Holds if this member is declared as `private`. */
predicate isPrivate() { hasAnnotation(this, "private") }
predicate isPrivate() { this.hasAnnotation("private") }
}
/** A declaration. E.g. a class, type, predicate, newtype... */
@@ -689,7 +756,7 @@ class Class extends TClass, TypeDeclaration, ModuleDeclaration {
* Gets predicate `name` implemented in this class.
*/
ClassPredicate getClassPredicate(string name) {
result = getAClassPredicate() and
result = this.getAClassPredicate() and
result.getName() = name
}
@@ -767,7 +834,7 @@ class NewType extends TNewType, TypeDeclaration, ModuleDeclaration {
* A branch in a `newtype`.
* E.g. `Bar()` or `Baz()` in `newtype Foo = Bar() or Baz()`.
*/
class NewTypeBranch extends TNewTypeBranch, TypeDeclaration {
class NewTypeBranch extends TNewTypeBranch, PredicateOrBuiltin, TypeDeclaration {
Generated::DatatypeBranch branch;
NewTypeBranch() { this = TNewTypeBranch(branch) }
@@ -789,6 +856,16 @@ class NewTypeBranch extends TNewTypeBranch, TypeDeclaration {
/** Gets the body of this branch. */
Formula getBody() { toGenerated(result) = branch.getChild(_).(Generated::Body).getChild() }
override NewTypeBranchType getReturnType() { result.getDeclaration() = this }
override Type getParameterType(int i) { result = this.getField(i).getType() }
override int getArity() { result = count(this.getField(_)) }
override Type getDeclaringType() { none() }
override predicate isPrivate() { this.getNewType().isPrivate() }
override QLDoc getQLDoc() { toGenerated(result) = branch.getChild(_) }
NewType getNewType() { result.getABranch() = this }
@@ -816,6 +893,9 @@ class Call extends TCall, Expr, Formula {
none() // overriden in sublcasses.
}
/** Gets an argument of this call, if any. */
final Expr getAnArgument() { result = this.getArgument(_) }
PredicateOrBuiltin getTarget() { resolveCall(this, result) }
override Type getType() { result = this.getTarget().getReturnType() }
@@ -1191,7 +1271,7 @@ class ComparisonFormula extends TComparisonFormula, Formula {
Expr getRightOperand() { toGenerated(result) = comp.getRight() }
/** Gets an operand of this comparison. */
Expr getAnOperand() { result in [getLeftOperand(), getRightOperand()] }
Expr getAnOperand() { result in [this.getLeftOperand(), this.getRightOperand()] }
/** Gets the operator of this comparison. */
ComparisonOp getOperator() { toGenerated(result) = comp.getChild() }
@@ -1249,7 +1329,7 @@ class Quantifier extends TQuantifier, Formula {
* Holds if this is the "expression only" form of an exists quantifier.
* In other words, the quantifier is of the form `exists( expr )`.
*/
predicate hasExpr() { exists(getExpr()) }
predicate hasExpr() { exists(this.getExpr()) }
override string getAPrimaryQlClass() { result = "Quantifier" }
@@ -1421,7 +1501,7 @@ class HigherOrderFormula extends THigherOrderFormula, Formula {
* Gets the `i`th argument to this higher-order formula.
* E.g. for `fastTC(pathSucc/2)(n1, n2)` the result is `n1` and `n2`.
*/
Expr getArgument(int i) { toGenerated(result) = hop.getChild(i + getNumInputs()) }
Expr getArgument(int i) { toGenerated(result) = hop.getChild(i + this.getNumInputs()) }
/**
* Gets the name of this higher-order predicate.
@@ -1510,7 +1590,7 @@ class ExprAggregate extends TExprAggregate, Aggregate {
)
or
not kind = ["count", "strictcount"] and
result = getExpr(0).getType()
result = this.getExpr(0).getType()
}
}
@@ -1574,11 +1654,11 @@ class FullAggregate extends TFullAggregate, Aggregate {
)
or
kind = ["any", "min", "max", "unique"] and
not exists(getExpr(_)) and
result = getArgument(0).getTypeExpr().getResolvedType()
not exists(this.getExpr(_)) and
result = this.getArgument(0).getTypeExpr().getResolvedType()
or
not kind = ["count", "strictcount"] and
result = getExpr(0).getType()
result = this.getExpr(0).getType()
}
override AstNode getAChild(string pred) {
@@ -1791,7 +1871,19 @@ class FunctionSymbol extends string {
/**
* A binary operation expression, such as `x + 3` or `y / 2`.
*/
class BinOpExpr extends TBinOpExpr, Expr { }
class BinOpExpr extends TBinOpExpr, Expr {
/** Gets the left operand of the binary expression. */
Expr getLeftOperand() { none() } // overriden in subclasses
/* Gets the right operand of the binary expression. */
Expr getRightOperand() { none() } // overriden in subclasses
/** Gets the operator of the binary expression. */
FunctionSymbol getOperator() { none() } // overriden in subclasses
/* Gets an operand of the binary expression. */
final Expr getAnOperand() { result = this.getLeftOperand() or result = this.getRightOperand() }
}
/**
* An addition or subtraction expression.
@@ -1802,17 +1894,11 @@ class AddSubExpr extends TAddSubExpr, BinOpExpr {
AddSubExpr() { this = TAddSubExpr(expr) and operator = expr.getChild().getValue() }
/** Gets the left operand of the binary expression. */
Expr getLeftOperand() { toGenerated(result) = expr.getLeft() }
override Expr getLeftOperand() { toGenerated(result) = expr.getLeft() }
/* Gets the right operand of the binary expression. */
Expr getRightOperand() { toGenerated(result) = expr.getRight() }
override Expr getRightOperand() { toGenerated(result) = expr.getRight() }
/* Gets an operand of the binary expression. */
Expr getAnOperand() { result = getLeftOperand() or result = getRightOperand() }
/** Gets the operator of the binary expression. */
FunctionSymbol getOperator() { result = operator }
override FunctionSymbol getOperator() { result = operator }
override PrimitiveType getType() {
// Both operands are the same type
@@ -1872,16 +1958,12 @@ class MulDivModExpr extends TMulDivModExpr, BinOpExpr {
MulDivModExpr() { this = TMulDivModExpr(expr) and operator = expr.getChild().getValue() }
/** Gets the left operand of the binary expression. */
Expr getLeftOperand() { toGenerated(result) = expr.getLeft() }
override Expr getLeftOperand() { toGenerated(result) = expr.getLeft() }
/** Gets the right operand of the binary expression. */
Expr getRightOperand() { toGenerated(result) = expr.getRight() }
override Expr getRightOperand() { toGenerated(result) = expr.getRight() }
/** Gets an operand of the binary expression. */
Expr getAnOperand() { result = getLeftOperand() or result = getRightOperand() }
/** Gets the operator of the binary expression. */
FunctionSymbol getOperator() { result = operator }
override FunctionSymbol getOperator() { result = operator }
override PrimitiveType getType() {
// Both operands are of the same type
@@ -1954,6 +2036,11 @@ class Range extends TRange, Expr {
*/
Expr getHighEndpoint() { toGenerated(result) = range.getUpper() }
/**
* Gets the lower and upper bounds of the range.
*/
Expr getAnEndpoint() { result = [this.getLowEndpoint(), this.getHighEndpoint()] }
override PrimitiveType getType() { result.getName() = "int" }
override string getAPrimaryQlClass() { result = "Range" }
@@ -1980,6 +2067,16 @@ class Set extends TSet, Expr {
*/
Expr getElement(int i) { toGenerated(result) = set.getChild(i) }
/**
* Gets an element in this set literal expression, if any.
*/
Expr getAnElement() { result = this.getElement(_) }
/**
* Gets the number of elements in this set literal expression.
*/
int getNumberOfElements() { result = count(this.getAnElement()) }
override Type getType() { result = this.getElement(0).getType() }
override string getAPrimaryQlClass() { result = "Set" }
@@ -1987,7 +2084,7 @@ class Set extends TSet, Expr {
override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
exists(int i | pred = indexedMember("getElement", i) and result = getElement(i))
exists(int i | pred = indexedMember("getElement", i) and result = this.getElement(i))
}
}
@@ -2070,6 +2167,112 @@ class ModuleExpr extends TModuleExpr, ModuleRef {
}
}
/** An argument to an annotation. */
private class AnnotationArg extends TAnnotationArg, AstNode {
Generated::AnnotArg arg;
AnnotationArg() { this = TAnnotationArg(arg) }
/** Gets the name of this argument. */
string getValue() {
result =
[
arg.getChild().(Generated::SimpleId).getValue(),
arg.getChild().(Generated::Result).getValue(), arg.getChild().(Generated::This).getValue()
]
}
override string toString() { result = this.getValue() }
}
private class NoInlineArg extends AnnotationArg {
NoInlineArg() { this.getValue() = "noinline" }
}
private class NoMagicArg extends AnnotationArg {
NoMagicArg() { this.getValue() = "nomagic" }
}
private class InlineArg extends AnnotationArg {
InlineArg() { this.getValue() = "inline" }
}
private class NoOptArg extends AnnotationArg {
NoOptArg() { this.getValue() = "noopt" }
}
private class MonotonicAggregatesArg extends AnnotationArg {
MonotonicAggregatesArg() { this.getValue() = "monotonicAggregates" }
}
/** An annotation on an element. */
class Annotation extends TAnnotation, AstNode {
Generated::Annotation annot;
Annotation() { this = TAnnotation(annot) }
override string toString() { result = "annotation" }
override string getAPrimaryQlClass() { result = "Annotation" }
override Location getLocation() { result = annot.getLocation() }
/** Gets the node corresponding to the field `args`. */
AnnotationArg getArgs(int i) { toGenerated(result) = annot.getArgs(i) }
/** Gets the node corresponding to the field `name`. */
string getName() { result = annot.getName().getValue() }
}
/** A `pragma[noinline]` annotation. */
class NoInline extends Annotation {
NoInline() { this.getArgs(0) instanceof NoInlineArg }
override string toString() { result = "noinline" }
}
/** A `pragma[inline]` annotation. */
class Inline extends Annotation {
Inline() { this.getArgs(0) instanceof InlineArg }
override string toString() { result = "inline" }
}
/** A `pragma[nomagic]` annotation. */
class NoMagic extends Annotation {
NoMagic() { this.getArgs(0) instanceof NoMagicArg }
override string toString() { result = "nomagic" }
}
/** A `pragma[noopt]` annotation. */
class NoOpt extends Annotation {
NoOpt() { this.getArgs(0) instanceof NoOptArg }
override string toString() { result = "noopt" }
}
/** A `language[monotonicAggregates]` annotation. */
class MonotonicAggregates extends Annotation {
MonotonicAggregates() { this.getArgs(0) instanceof MonotonicAggregatesArg }
override string toString() { result = "monotonicaggregates" }
}
/** A `bindingset` annotation. */
class BindingSet extends Annotation {
BindingSet() { this.getName() = "bindingset" }
/** Gets the `index`'th bound name in this bindingset. */
string getBoundName(int index) { result = this.getArgs(index).getValue() }
/** Gets a name bound by this bindingset, if any. */
string getABoundName() { result = this.getBoundName(_) }
/** Gets the number of names bound by this bindingset. */
int getNumberOfBoundNames() { result = count(this.getABoundName()) }
}
/**
* Classes modelling YAML AST nodes.
*/
@@ -2077,7 +2280,7 @@ module YAML {
/** A node in a YAML file */
class YAMLNode extends TYAMLNode, AstNode {
/** Holds if the predicate is a root node (has no parent) */
predicate isRoot() { not exists(getParent()) }
predicate isRoot() { not exists(this.getParent()) }
}
/** A YAML comment. */
@@ -2146,7 +2349,7 @@ module YAML {
* Dashes are replaced with `/` (because we don't have that information in the generated AST).
*/
string getQualifiedName() {
result = concat(string part, int i | part = getNamePart(i) | part, "/" order by i)
result = concat(string part, int i | part = this.getNamePart(i) | part, "/" order by i)
}
}
@@ -2179,8 +2382,6 @@ module YAML {
// to not expose the entire `File` API on `QlPack`.
private newtype TQLPack = MKQlPack(File file) { file.getBaseName() = "qlpack.yml" }
YAMLEntry test() { not result.isRoot() }
/**
* A `qlpack.yml` file.
*/
@@ -2199,15 +2400,15 @@ module YAML {
}
/** Gets the name of this qlpack */
string getName() { result = getProperty("name") }
string getName() { result = this.getProperty("name") }
/** Gets the version of this qlpack */
string getVersion() { result = getProperty("version") }
string getVersion() { result = this.getProperty("version") }
/** Gets the extractor of this qlpack */
string getExtractor() { result = getProperty("extractor") }
string getExtractor() { result = this.getProperty("extractor") }
string toString() { result = getName() }
string toString() { result = this.getName() }
/** Gets the file that this `QLPack` represents. */
File getFile() { result = file }
@@ -2222,7 +2423,7 @@ module YAML {
entry.getLocation().getStartColumn() > deps.getLocation().getStartColumn()
)
or
exists(YAMLEntry prev | isADependency(prev) |
exists(YAMLEntry prev | this.isADependency(prev) |
prev.getLocation().getFile() = file and
entry.getLocation().getFile() = file and
entry.getLocation().getStartLine() = 1 + prev.getLocation().getStartLine() and
@@ -2231,7 +2432,7 @@ module YAML {
}
predicate hasDependency(string name, string version) {
exists(YAMLEntry entry | isADependency(entry) |
exists(YAMLEntry entry | this.isADependency(entry) |
entry.getKey().getQualifiedName() = name and
entry.getValue().getValue() = version
)
@@ -2239,7 +2440,7 @@ module YAML {
/** Gets the database scheme of this qlpack */
File getDBScheme() {
result.getBaseName() = getProperty("dbscheme") and
result.getBaseName() = this.getProperty("dbscheme") and
result = file.getParentContainer().getFile(any(string s | s.matches("%.dbscheme")))
}
@@ -2247,14 +2448,16 @@ module YAML {
Container getAFileInPack() {
result.getParentContainer() = file.getParentContainer()
or
result = getAFileInPack().(Folder).getAChildContainer()
result = this.getAFileInPack().(Folder).getAChildContainer()
}
/**
* Gets a QLPack that this QLPack depends on.
*/
QLPack getADependency() {
exists(string name | hasDependency(name, _) | result.getName().replaceAll("-", "/") = name)
exists(string name | this.hasDependency(name, _) |
result.getName().replaceAll("-", "/") = name
)
}
Location getLocation() {

View File

@@ -1,5 +1,6 @@
import codeql_ql.ast.Ast as AST
import TreeSitter
private import Builtins
cached
newtype TAstNode =
@@ -59,11 +60,17 @@ newtype TAstNode =
TDontCare(Generated::Underscore dontcare) or
TModuleExpr(Generated::ModuleExpr me) or
TPredicateExpr(Generated::PredicateExpr pe) or
TAnnotation(Generated::Annotation annot) or
TAnnotationArg(Generated::AnnotArg arg) or
TYamlCommemt(Generated::YamlComment yc) or
TYamlEntry(Generated::YamlEntry ye) or
TYamlKey(Generated::YamlKey yk) or
TYamlListitem(Generated::YamlListitem yli) or
TYamlValue(Generated::YamlValue yv)
TYamlValue(Generated::YamlValue yv) or
TBuiltinClassless(string ret, string name, string args) { isBuiltinClassless(ret, name, args) } or
TBuiltinMember(string qual, string ret, string name, string args) {
isBuiltinMember(qual, ret, name, args)
}
class TFormula =
TDisjunction or TConjunction or TComparisonFormula or TQuantifier or TNegation or TIfFormula or
@@ -184,10 +191,18 @@ Generated::AstNode toGenerated(AST::AstNode n) {
n = TAnyCall(result)
or
n = TSuper(result)
or
n = TAnnotation(result)
or
n = TAnnotationArg(result)
}
class TPredicate = TCharPred or TClasslessPredicate or TClassPredicate or TDBRelation;
class TPredOrBuiltin = TPredicate or TNewTypeBranch or TBuiltin;
class TBuiltin = TBuiltinClassless or TBuiltinMember;
class TModuleMember = TModuleDeclaration or TImport or TSelect or TQLDoc;
class TDeclaration = TTypeDeclaration or TModuleDeclaration or TPredicate or TVarDecl;

View File

@@ -35,8 +35,8 @@ predicate isBuiltinMember(string sig) {
"string int.toString()", "string string.charAt(int)", "int string.indexOf(string)",
"int string.indexOf(string, int, int)", "predicate string.isLowercase()",
"predicate string.isUppercase()", "int string.length()", "predicate string.matches(string)",
"string string.prefix(int)", "string regexpCapture(string, int)",
"string regexpFind(string, int, int)", "predicate string.regexpMatch(string)",
"string string.prefix(int)", "string string.regexpCapture(string, int)",
"string string.regexpFind(string, int, int)", "predicate string.regexpMatch(string)",
"string string.regexpReplaceAll(string, string)", "string string.replaceAll(string, string)",
"string string.splitAt(string)", "string string.splitAt(string, int)",
"string string.substring(int, int)", "string string.suffix(int)", "date string.toDate()",
@@ -58,6 +58,18 @@ predicate isBuiltinMember(string qual, string ret, string name, string args) {
)
}
module BuildinsConsistency {
query predicate noBuildinParse(string sig) {
isBuiltinMember(sig) and
not exists(sig.regexpCapture("(\\w+) (\\w+)\\.(\\w+)\\(([\\w, ]*)\\)", _))
}
query predicate noBuildinClasslessParse(string sig) {
isBuiltinClassless(sig) and
not exists(sig.regexpCapture("(\\w+) (\\w+)\\(([\\w, ]*)\\)", _))
}
}
bindingset[args]
string getArgType(string args, int i) { result = args.splitAt(",", i).trim() }
@@ -65,3 +77,18 @@ string getArgType(string args, int i) { result = args.splitAt(",", i).trim() }
class StringClass extends PrimitiveType {
StringClass() { this.getName() = "string" }
}
/** The primitive 'int' class. */
class IntClass extends PrimitiveType {
IntClass() { this.getName() = "int" }
}
/** The primitive 'float' class. */
class FloatClass extends PrimitiveType {
FloatClass() { this.getName() = "float" }
}
/** The primitive 'boolean' class. */
class BooleanClass extends PrimitiveType {
BooleanClass() { this.getName() = "boolean" }
}

View File

@@ -1,12 +1,11 @@
import ql
private import Builtins
private import codeql_ql.ast.internal.Module
private import codeql_ql.ast.internal.AstNodes as AstNodes
private import codeql_ql.ast.internal.AstNodes
private class TClasslessPredicateOrNewTypeBranch =
AstNodes::TClasslessPredicate or AstNodes::TNewTypeBranch;
private class TClasslessPredicateOrNewTypeBranch = TClasslessPredicate or TNewTypeBranch;
string getPredicateName(TClasslessPredicateOrNewTypeBranch p) {
private string getPredicateName(TClasslessPredicateOrNewTypeBranch p) {
result = p.(ClasslessPredicate).getName() or
result = p.(NewTypeBranch).getName()
}
@@ -69,8 +68,7 @@ private module Cached {
m = pc.getQualifier().getResolvedModule() and
public = true
|
definesPredicate(m, pc.getPredicateName(), pc.getNumberOfArguments(), p.getDeclaration(),
public)
definesPredicate(m, pc.getPredicateName(), pc.getNumberOfArguments(), p, public)
)
}
@@ -93,8 +91,8 @@ private module Cached {
rel.getName() = pc.getPredicateName()
}
private predicate resolveDBRelation(PredicateCall pc, DefinedPredicate p) {
exists(Relation rel | p = TPred(rel) |
private predicate resolveDBRelation(PredicateCall pc, Predicate p) {
exists(Relation rel | p = rel |
candidate(rel, pc) and
rel.getArity() = pc.getNumberOfArguments() and
(
@@ -120,142 +118,9 @@ private module Cached {
not resolvePredicateCall(c, _) and
resolveDBRelation(c, p)
}
cached
module NewTypeDef {
cached
newtype TPredOrBuiltin =
TPred(Predicate p) or
TNewTypeBranch(NewTypeBranch b) or
TBuiltinClassless(string ret, string name, string args) {
isBuiltinClassless(ret, name, args)
} or
TBuiltinMember(string qual, string ret, string name, string args) {
isBuiltinMember(qual, ret, name, args)
}
}
}
import Cached
private import NewTypeDef
class PredicateOrBuiltin extends TPredOrBuiltin {
string getName() { none() }
string toString() { result = getName() }
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
if exists(getDeclaration())
then
getDeclaration()
.getLocation()
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
else (
filepath = "" and
startline = 0 and
startcolumn = 0 and
endline = 0 and
endcolumn = 0
)
}
AstNode getDeclaration() { none() }
Type getDeclaringType() { none() }
Type getParameterType(int i) { none() }
Type getReturnType() { none() }
int getArity() { result = count(getParameterType(_)) }
predicate isPrivate() { none() }
}
private class DefinedPredicate extends PredicateOrBuiltin, TPred {
Predicate decl;
DefinedPredicate() { this = TPred(decl) }
override Predicate getDeclaration() { result = decl }
override string getName() { result = decl.getName() }
override Type getReturnType() { result = decl.getReturnType() }
override Type getParameterType(int i) { result = decl.getParameter(i).getType() }
// Can be removed when all types can be resolved
override int getArity() { result = decl.getArity() }
override Type getDeclaringType() {
result = decl.(ClassPredicate).getDeclaringType()
or
result = decl.(CharPred).getDeclaringType()
}
override predicate isPrivate() {
decl.(ClassPredicate).isPrivate() or decl.(ClassPredicate).isPrivate()
}
}
private class DefinedNewTypeBranch extends PredicateOrBuiltin, TNewTypeBranch {
NewTypeBranch b;
DefinedNewTypeBranch() { this = TNewTypeBranch(b) }
override NewTypeBranch getDeclaration() { result = b }
override string getName() { result = b.getName() }
override NewTypeBranchType getReturnType() { result.getDeclaration() = b }
override Type getParameterType(int i) { result = b.getField(i).getType() }
// Can be removed when all types can be resolved
override int getArity() { result = count(b.getField(_)) }
override Type getDeclaringType() { none() }
override predicate isPrivate() { b.getNewType().isPrivate() }
}
private class TBuiltin = TBuiltinClassless or TBuiltinMember;
class BuiltinPredicate extends PredicateOrBuiltin, TBuiltin { }
private class BuiltinClassless extends BuiltinPredicate, TBuiltinClassless {
string name;
string ret;
string args;
BuiltinClassless() { this = TBuiltinClassless(ret, name, args) }
override string getName() { result = name }
override PrimitiveType getReturnType() { result.getName() = ret }
override PrimitiveType getParameterType(int i) { result.getName() = getArgType(args, i) }
}
private class BuiltinMember extends BuiltinPredicate, TBuiltinMember {
string name;
string qual;
string ret;
string args;
BuiltinMember() { this = TBuiltinMember(qual, ret, name, args) }
override string getName() { result = name }
override PrimitiveType getReturnType() { result.getName() = ret }
override PrimitiveType getParameterType(int i) { result.getName() = getArgType(args, i) }
override PrimitiveType getDeclaringType() { result.getName() = qual }
}
module PredConsistency {
query predicate noResolvePredicateExpr(PredicateExpr pe) {
@@ -287,9 +152,9 @@ module PredConsistency {
strictcount(PredicateOrBuiltin p0 |
resolveCall(call, p0) and
// aliases are expected to resolve to multiple.
not exists(p0.getDeclaration().(ClasslessPredicate).getAlias()) and
not exists(p0.(ClasslessPredicate).getAlias())
// overridden predicates may have multiple targets
not p0.getDeclaration().(ClassPredicate).isOverride()
not p0.(ClassPredicate).isOverride()
) and
c > 1 and
resolveCall(call, p)

View File

@@ -27,7 +27,7 @@ private predicate isActualClass(Class c) {
* A type, such as `int` or `Node`.
*/
class Type extends TType {
string toString() { result = getName() }
string toString() { result = this.getName() }
string getName() { result = "???" }
@@ -48,9 +48,9 @@ class Type extends TType {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
if exists(getDeclaration())
if exists(this.getDeclaration())
then
getDeclaration()
this.getDeclaration()
.getLocation()
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
else (
@@ -72,14 +72,14 @@ class Type extends TType {
private predicate getClassPredicate1(
string name, int arity, PredicateOrBuiltin p1, PredicateOrBuiltin p2
) {
getClassPredicate0(name, arity, p1, p2.getDeclaringType()) and
this.getClassPredicate0(name, arity, p1, p2.getDeclaringType()) and
p2 = classPredCandidate(this, name, arity)
}
cached
PredicateOrBuiltin getClassPredicate(string name, int arity) {
result = classPredCandidate(this, name, arity) and
not getClassPredicate1(name, arity, _, result)
not this.getClassPredicate1(name, arity, _, result)
}
}
@@ -114,6 +114,7 @@ private PredicateOrBuiltin declaredPred(Type ty, string name, int arity) {
result.getArity() = arity
}
pragma[nomagic]
private PredicateOrBuiltin classPredCandidate(Type ty, string name, int arity) {
result = declaredPred(ty, name, arity)
or
@@ -127,8 +128,7 @@ private PredicateOrBuiltin inherClassPredCandidate(Type ty, string name, int ari
}
predicate predOverrides(ClassPredicate sub, ClassPredicate sup) {
sup =
inherClassPredCandidate(sub.getDeclaringType(), sub.getName(), sub.getArity()).getDeclaration()
sup = inherClassPredCandidate(sub.getDeclaringType(), sub.getName(), sub.getArity())
}
private VarDecl declaredField(ClassType ty, string name) {
@@ -179,7 +179,7 @@ class ClassDomainType extends Type, TClassDomain {
ClassType getClassType() { result = TClass(decl) }
override Type getAnInternalSuperType() { result = getClassType().getASuperType() }
override Type getAnInternalSuperType() { result = this.getClassType().getASuperType() }
}
class PrimitiveType extends Type, TPrimitive {
@@ -192,7 +192,7 @@ class PrimitiveType extends Type, TPrimitive {
override Type getASuperType() { name = "int" and result.(PrimitiveType).getName() = "float" }
override Type getAnInternalSuperType() {
result = getASuperType()
result = this.getASuperType()
or
result = super.getAnInternalSuperType()
}
@@ -232,7 +232,7 @@ class NewTypeBranchType extends Type, TNewTypeBranch {
}
override Type getAnInternalSuperType() {
result = getASuperType()
result = this.getASuperType()
or
result = super.getAnInternalSuperType()
}
@@ -283,6 +283,7 @@ private predicate qualifier(TypeExpr te, FileOrModule m, boolean public, string
)
}
pragma[nomagic]
private predicate defines(FileOrModule m, string name, Type t, boolean public) {
exists(Class ty | t = TClass(ty) |
getEnclosingModule(ty) = m and

View File

@@ -54,7 +54,7 @@ private predicate resolveField(FieldAccess va, VarDecl decl, string kind) {
}
private predicate resolveCall(Call c, Predicate p, string kind) {
p = c.getTarget().getDeclaration() and
p = c.getTarget() and
kind = "call"
}

View File

@@ -2,4 +2,5 @@ name: codeql-ql
version: 0.0.0
dbscheme: ql.dbscheme
suites: codeql-suites
defaultSuiteFile: codeql-suites/ql-code-scanning.qls
extractor: ql

View File

@@ -0,0 +1,86 @@
/**
* @name Class predicate doesn't mention `this`
* @description A class predicate that doesn't use `this` (or a field) could instead be a classless predicate, and may cause a cartesian product.
* @kind problem
* @problem.severity warning
* @id ql/class-predicate-doesnt-use-this
* @tags performance
* @precision medium
*/
import ql
predicate usesThis(ClassPredicate pred) {
exists(ThisAccess th | th.getEnclosingPredicate() = pred)
or
exists(Super sup | sup.getEnclosingPredicate() = pred)
or
exists(FieldAccess f | f.getEnclosingPredicate() = pred)
or
// implicit this
exists(PredicateCall pc | pc.getEnclosingPredicate() = pred |
pc.getTarget() instanceof ClassPredicate
)
}
predicate isLiteralComparison(ComparisonFormula eq) {
exists(Expr lhs, Expr rhs |
eq.getSymbol() = "=" and
eq.getAnOperand() = lhs and
eq.getAnOperand() = rhs and
(
lhs instanceof ResultAccess
or
lhs instanceof ThisAccess
or
lhs instanceof VarAccess
) and
(
rhs instanceof Literal
or
exists(NewTypeBranch nt |
rhs.(Call).getTarget() = nt and
count(nt.getField(_)) = 0
)
)
)
}
predicate conjParent(Formula par, Formula child) { child = par.(Conjunction).getAnOperand() }
predicate isLiteralComparisons(Formula f) {
forex(ComparisonFormula child | conjParent*(f, child) | isLiteralComparison(child))
}
predicate isTrivialImplementation(Predicate pred) {
not exists(pred.getBody())
or
exists(Formula bod | bod = pred.getBody() |
bod instanceof AnyCall
or
bod instanceof NoneCall
or
isLiteralComparisons(bod)
)
}
predicate isSingleton(Type ty) {
isTrivialImplementation(ty.(ClassType).getDeclaration().getCharPred())
or
isSingleton(ty.getASuperType())
or
exists(NewTypeBranch br | count(br.getField(_)) = 0 |
ty.(NewTypeBranchType).getDeclaration() = br
or
br = unique(NewTypeBranch br2 | br2 = ty.(NewTypeType).getDeclaration().getABranch())
)
}
from ClassPredicate pred
where
not usesThis(pred) and
not isTrivialImplementation(pred) and
not isSingleton(pred.getDeclaringType()) and
not exists(ClassPredicate other | pred.overrides(other) or other.overrides(pred)) and
not pred.isOverride()
select pred, "This predicate could be a classless predicate, as it doesn't depend on `this`."

View File

@@ -0,0 +1,22 @@
/**
* @name Don't use getAQlClass.
* @description Any use of getAQlClass causes both compile-time and runtime to be significantly slower.
* @kind problem
* @problem.severity warning
* @id ql/dont-use-getaqlclass
* @tags performance
* @precision very-high
*/
import ql
from Call call
where
(
call.(PredicateCall).getPredicateName() = "getAQlClass" or
call.(MemberCall).getMemberName() = "getAQlClass"
) and
not call.getLocation().getFile().getAbsolutePath().matches("%/" + ["meta", "test"] + "/%") and
not call.getLocation().getFile().getBaseName().toLowerCase() =
["consistency.ql", "test.ql", "tst.ql", "tests.ql"]
select call, "Don't use .getAQlClass"

View File

@@ -0,0 +1,23 @@
/**
* @name Missing `noinline` or `nomagic` annotation
* @description When a predicate is factored out to improve join-ordering, it should be marked as `noinline` or `nomagic`.
* @kind problem
* @problem.severity error
* @id ql/missing-noinline
* @tags performance
* @precision high
*/
import ql
from QLDoc doc, Predicate decl
where
doc.getContents().matches(["%join order%", "%join-order%"]) and
decl.getQLDoc() = doc and
not decl.getAnAnnotation() instanceof NoInline and
not decl.getAnAnnotation() instanceof NoMagic and
not decl.getAnAnnotation() instanceof NoOpt and
// If it's marked as inline it's probably because the QLDoc says something like
// "this predicate is inlined because it gives a better join-order".
not decl.getAnAnnotation() instanceof Inline
select decl, "This predicate might be inlined."

View File

@@ -0,0 +1,30 @@
/**
* @name Standard library is not the first import
* @description Importing other libraries before the standard library can cause a change in
* evaluation order and may lead to performance errors.
* @kind problem
* @problem.severity error
* @id ql/noninitial-stdlib-import
* @tags performance
* @precision high
*/
import ql
predicate isStdLibImport(Import i, string name) {
name = i.getQualifiedName(0) and
i.getLocation().getFile().getRelativePath().matches(name + "%") and
not exists(i.getQualifiedName(1))
}
Import importBefore(Import i) {
exists(Module m, int bi, int ii |
result = m.getMember(bi) and
i = m.getMember(ii) and
bi < ii
)
}
from Import i
where isStdLibImport(i, _) and exists(importBefore(i))
select i, "This import may cause reevaluation to occur, as there are other imports preceding it"

View File

@@ -0,0 +1,165 @@
/**
* @name Transitively closed recursive delta
* @description Using a transitively closed relation as the step in a recursive
* delta can perform poorly as it is inherently quadratic and may
* force materialization of a fastTC. The transitively closed delta
* can usually just be replaced by the underlying step relation as
* the recursive context will provide transitive closure.
* @kind problem
* @problem.severity error
* @id ql/transitive-step
* @tags performance
* @precision high
*/
import ql
Expr getArg(Call c, int i) {
result = c.getArgument(i)
or
result = c.(MemberCall).getBase() and i = -1
or
exists(c.getType()) and result = c and i = -2
}
newtype TParameter =
TThisParam(ClassPredicate p) or
TResultParam(Predicate p) { exists(p.getReturnType()) } or
TVarParam(VarDecl v) { any(Predicate p).getParameter(_) = v }
class Parameter extends TParameter {
string toString() {
this instanceof TThisParam and result = "this"
or
this instanceof TResultParam and result = "result"
or
exists(VarDecl v | this = TVarParam(v) and result = v.toString())
}
Expr getAnAccess() {
result instanceof ThisAccess and this = TThisParam(result.getEnclosingPredicate())
or
result instanceof ResultAccess and this = TResultParam(result.getEnclosingPredicate())
or
this = TVarParam(result.(VarAccess).getDeclaration())
}
predicate isParameterOf(Predicate p, int i) {
this = TThisParam(p) and i = -1
or
this = TResultParam(p) and i = -2
or
this = TVarParam(p.getParameter(i))
}
}
predicate hasTwoArgs(Call c, Expr arg1, Expr arg2) {
exists(int i1, int i2 |
arg1 = getArg(c, i1) and
arg2 = getArg(c, i2) and
i1 != i2 and
strictcount(getArg(c, _)) = 2
)
}
predicate transitivePred(Predicate p, AstNode tc) {
exists(PredicateExpr pe |
p.(ClasslessPredicate).getAlias() = pe and
transitivePred(pe.getResolvedPredicate(), tc)
)
or
p.(ClasslessPredicate).getAlias().(HigherOrderFormula).getName() = "fastTC" and
tc = p
or
strictcount(Parameter par | par.isParameterOf(p, _)) = 2 and
exists(Formula body | p.getBody() = body |
transitiveCall(body, tc) and
hasTwoArgs(body, any(Identifier i1), any(Identifier i2))
or
exists(ComparisonFormula eq, Call c |
body = eq and
eq.getSymbol() = "=" and
transitiveCall(c, tc) and
getArg(c, _) instanceof Identifier and
eq.getAnOperand() = c and
eq.getAnOperand() instanceof Identifier
)
)
}
predicate transitiveCall(Call c, AstNode tc) {
c.isClosure(_) and tc = c
or
transitivePred(c.getTarget(), tc)
}
class TransitivelyClosedCall extends Call {
TransitivelyClosedCall() { transitiveCall(this, _) }
predicate hasArgs(Expr arg1, Expr arg2) { hasTwoArgs(this, arg1, arg2) }
AstNode getReason() { transitiveCall(this, result) }
}
AstNode getParentOfExpr(Expr e) { result = e.getParent() }
Formula getEnclosing(Expr e) { result = getParentOfExpr+(e) }
Formula enlargeScopeStep(Formula f) { result.(Conjunction).getAnOperand() = f }
Formula enlargeScope(Formula f) {
result = enlargeScopeStep*(f) and not exists(enlargeScopeStep(result))
}
predicate varaccesValue(VarAccess va, VarDecl v, Formula scope) {
va.getDeclaration() = v and
scope = enlargeScope(getEnclosing(va))
}
predicate thisValue(ThisAccess ta, Formula scope) { scope = enlargeScope(getEnclosing(ta)) }
predicate resultValue(ResultAccess ra, Formula scope) { scope = enlargeScope(getEnclosing(ra)) }
predicate valueStep(Expr e1, Expr e2) {
exists(VarDecl v, Formula scope |
varaccesValue(e1, v, scope) and
varaccesValue(e2, v, scope)
)
or
exists(Formula scope |
thisValue(e1, scope) and
thisValue(e2, scope)
or
resultValue(e1, scope) and
resultValue(e2, scope)
)
or
exists(InlineCast c |
e1 = c and e2 = c.getBase()
or
e2 = c and e1 = c.getBase()
)
or
exists(ComparisonFormula eq |
eq.getSymbol() = "=" and
eq.getAnOperand() = e1 and
eq.getAnOperand() = e2 and
e1 != e2
)
}
predicate transitiveDelta(Call rec, TransitivelyClosedCall tc) {
exists(Expr recarg, int i, Expr tcarg, Predicate pred, Parameter p |
rec.getTarget() = pred and
pred = rec.getEnclosingPredicate() and
recarg = getArg(rec, i) and
valueStep*(recarg, tcarg) and
tc.hasArgs(tcarg, p.getAnAccess()) and
p.isParameterOf(pred, i)
)
}
from Call rec, TransitivelyClosedCall tc, AstNode reason
where transitiveDelta(rec, tc) and reason = tc.getReason()
select tc, "This recursive delta is transively closed $@, which may be a performance problem.",
reason, "here"

View File

@@ -0,0 +1,96 @@
/**
* @name Superfluous 'exists' conjunct.
* @description Writing 'exists(x)' when the existence of X is implied by another conjunct is bad practice.
* @kind problem
* @problem.severity warning
* @precision high
* @id ql/superfluous-exists
* @tags maintainability
*/
import ql
import codeql.GlobalValueNumbering
/**
* Gets an operand of this conjunction (we need the restriction
* to `Conjunction` to get the correct transitive closure).
*/
Formula getAConjOperand(Conjunction conj) { result = conj.getAnOperand() }
/** A conjunction that is not a operand of another conjunction. */
class TopLevelConjunction extends Conjunction {
TopLevelConjunction() { not this = getAConjOperand(_) }
/** Gets a formula within this conjunction that is not itself a conjunction. */
Formula getAnAtom() {
not result instanceof Conjunction and
result = getAConjOperand*(this)
}
}
/**
* Holds if the existence of `e` implies the existence of `vn`. For instance, the existence of
* `1 + x` implies the existence of a value number `vn` such that `vn.getAnExpr() = x`.
*/
predicate exprImpliesExists(ValueNumber vn, Expr e) {
vn.getAnExpr() = e
or
exprImpliesExists(vn, e.(BinOpExpr).getAnOperand())
or
exprImpliesExists(vn, e.(InlineCast).getBase())
or
exprImpliesExists(vn, e.(PredicateCall).getAnArgument())
or
exprImpliesExists(vn, [e.(MemberCall).getAnArgument(), e.(MemberCall).getBase()])
or
exprImpliesExists(vn, e.(UnaryExpr).getOperand())
or
exprImpliesExists(vn, e.(ExprAnnotation).getExpression())
or
forex(Formula child | child = e.(Set).getAnElement() | exprImpliesExists(vn, child))
or
exprImpliesExists(vn, e.(AsExpr).getInnerExpr())
or
exists(ExprAggregate agg |
agg = e and
agg.getKind().matches(["strict%", "unique"]) and
exprImpliesExists(vn, agg.getExpr(0))
)
}
/**
* Holds if the satisfiability of `f` implies the existence of `vn`. For instance, if `x.foo()` is
* satisfied, the value number `vn` such that `vn.getAnExpr() = x` exists.
*/
predicate formulaImpliesExists(ValueNumber vn, Formula f) {
forex(Formula child | child = f.(Disjunction).getAnOperand() | formulaImpliesExists(vn, child))
or
formulaImpliesExists(vn, f.(Conjunction).getAnOperand())
or
exprImpliesExists(vn, f.(ComparisonFormula).getAnOperand())
or
exists(IfFormula ifFormula |
ifFormula = f and
formulaImpliesExists(vn, ifFormula.getThenPart()) and
formulaImpliesExists(vn, ifFormula.getElsePart())
)
or
exprImpliesExists(vn, f.(InstanceOf).getExpr())
or
exprImpliesExists(vn, f.(PredicateCall).getAnArgument())
or
exprImpliesExists(vn, [f.(MemberCall).getAnArgument(), f.(MemberCall).getBase()])
or
exists(InFormula inFormula | inFormula = f |
exprImpliesExists(vn, [inFormula.getExpr(), inFormula.getRange()])
)
}
from TopLevelConjunction toplevel, Exists existsFormula, ValueNumber vn, Formula conjunct
where
existsFormula = toplevel.getAnAtom() and
vn.getAnExpr() = existsFormula.getExpr() and
conjunct = toplevel.getAnAtom() and
formulaImpliesExists(vn, conjunct)
select existsFormula, "This conjunct is superfluous as the existence is implied by $@.", conjunct,
"this conjunct"

View File

@@ -0,0 +1,129 @@
/**
* @name Use a set literal in place of `or`
* @description A chain of `or`s can be replaced with a set literal, improving readability.
* @kind problem
* @problem.severity recommendation
* @id ql/use-set-literal
* @tags maintainability
* @precision high
*/
import ql
/**
* A chain of disjunctions treated as one object. For example the following is
* a chain of disjunctions with three operands:
* ```
* a or b or c
* ```
*/
class DisjunctionChain extends Disjunction {
DisjunctionChain() { not exists(Disjunction parent | parent.getAnOperand() = this) }
/**
* Gets any operand of the chain.
*/
Formula getAnOperandRec() {
result = getAnOperand*() and
not result instanceof Disjunction
}
}
/**
* An equality comparison with a `Literal`. For example:
* ```
* x = 4
* ```
*/
class EqualsLiteral extends ComparisonFormula {
EqualsLiteral() {
getSymbol() = "=" and
getAnOperand() instanceof Literal
}
}
/**
* A chain of disjunctions where each operand is an equality comparison between
* the same thing and various `Literal`s. For example:
* ```
* x = 4 or
* x = 5 or
* x = 6
* ```
*/
class DisjunctionEqualsLiteral extends DisjunctionChain {
DisjunctionEqualsLiteral() {
// VarAccess on the same variable
exists(VarDef v |
forex(Formula f | f = getAnOperandRec() |
f.(EqualsLiteral).getAnOperand().(VarAccess).getDeclaration() = v
)
)
or
// FieldAccess on the same variable
exists(VarDecl v |
forex(Formula f | f = getAnOperandRec() |
f.(EqualsLiteral).getAnOperand().(FieldAccess).getDeclaration() = v
)
)
or
// ThisAccess
forex(Formula f | f = getAnOperandRec() |
f.(EqualsLiteral).getAnOperand() instanceof ThisAccess
)
or
// ResultAccess
forex(Formula f | f = getAnOperandRec() |
f.(EqualsLiteral).getAnOperand() instanceof ResultAccess
)
// (in principle something like GlobalValueNumbering could be used to generalize this)
}
}
/**
* A call with a single `Literal` argument. For example:
* ```
* myPredicate(4)
* ```
*/
class CallLiteral extends Call {
CallLiteral() {
getNumberOfArguments() = 1 and
getArgument(0) instanceof Literal
}
}
/**
* A chain of disjunctions where each operand is a call to the same predicate
* using various `Literal`s. For example:
* ```
* myPredicate(4) or
* myPredicate(5) or
* myPredicate(6)
* ```
*/
class DisjunctionPredicateLiteral extends DisjunctionChain {
DisjunctionPredicateLiteral() {
// Call to the same target
exists(PredicateOrBuiltin target |
forex(Formula f | f = getAnOperandRec() | f.(CallLiteral).getTarget() = target)
)
}
}
from DisjunctionChain d, string msg, int c
where
(
d instanceof DisjunctionEqualsLiteral and
msg =
"This formula of " + c.toString() +
" comparisons can be replaced with a single equality on a set literal, improving readability."
or
d instanceof DisjunctionPredicateLiteral and
msg =
"This formula of " + c.toString() +
" predicate calls can be replaced with a single call on a set literal, improving readability."
) and
c = count(d.getAnOperandRec()) and
c >= 4
select d, msg

View File

@@ -0,0 +1,26 @@
/**
* @name Class QLDoc style.
* @description The QLDoc for a class should start with "A", "An", or "The".
* @kind problem
* @problem.severity warning
* @id ql/class-doc-style
* @tags maintainability
* @precision very-high
*/
import ql
bindingset[s]
predicate badStyle(string s) {
not s.replaceAll("/**", "")
.replaceAll("*", "")
.splitAt("\n")
.trim()
.matches(["A %", "An %", "The %", "INTERNAL%", "DEPRECATED%"])
}
from Class c
where
badStyle(c.getQLDoc().getContents()) and
not c.isPrivate()
select c.getQLDoc(), "The QLDoc for a class should start with 'A', 'An', or 'The'."

View File

@@ -0,0 +1,25 @@
/**
* @name Missing QLDoc.
* @description Library classes should have QLDoc.
* @kind problem
* @problem.severity recommendation
* @id ql/missing-qldoc
* @tags maintainability
* @precision high
*/
import ql
from File f, Class c
where
f = c.getLocation().getFile() and
not exists(c.getQLDoc()) and // no QLDoc
f.getExtension() = "qll" and // in a library
not c.isPrivate() and // class is public
not exists(Module m |
m.getAMember*() = c and
m.isPrivate() // modules containing the class are public
) and
not exists(c.getAliasType()) and // class is not just an alias
not f.getParentContainer*().getBaseName().toLowerCase() = ["internal", "experimental", "test"] // exclusions
select c, "This library class should have QLDoc."

View File

@@ -0,0 +1,38 @@
/**
* @name Non US spelling
* @description QLDocs shold use US spelling.
* @kind problem
* @problem.severity warning
* @id ql/non-us-spelling
* @tags maintainability
* @precision very-high
*/
import ql
predicate non_us_word(string wrong, string right) {
exists(string s |
wrong = s.splitAt("/", 0) and
right = s.splitAt("/", 1) and
s = ["colour/color", "authorise/authorize", "analyse/analyze"]
)
}
bindingset[s]
predicate contains_non_us_spelling(string s, string wrong, string right) {
non_us_word(wrong, right) and
(
s.matches("%" + wrong + "%") and
wrong != "analyse"
or
// analyses (as a noun) is fine
s.regexpMatch(".*analyse[^s].*") and
wrong = "analyse"
)
}
from QLDoc doc, string wrong, string right
where contains_non_us_spelling(doc.getContents().toLowerCase(), wrong, right)
select doc,
"This QLDoc comment contains the non-US spelling '" + wrong + "', which should instead be '" +
right + "'."

View File

@@ -31,3 +31,9 @@ module Aliases {
alias0() // <- works
}
}
module Buildins {
predicate replaceAll(string s) { "foo".replaceAll("foo", "bar") = s }
predicate regexpCapture(string s) { "foo".regexpCapture("\\w", 1) = s }
}

View File

@@ -1,3 +1,4 @@
getTarget
| Foo.qll:5:26:5:30 | PredicateCall | Foo.qll:3:1:3:26 | ClasslessPredicate foo |
| Foo.qll:10:21:10:25 | PredicateCall | Foo.qll:8:3:8:28 | ClassPredicate bar |
| Foo.qll:14:30:14:40 | MemberCall | Foo.qll:10:3:10:27 | ClassPredicate baz |
@@ -6,6 +7,8 @@
| Foo.qll:29:5:29:16 | PredicateCall | Foo.qll:26:3:26:32 | ClasslessPredicate alias2 |
| Foo.qll:31:5:31:12 | PredicateCall | Foo.qll:22:3:22:32 | ClasslessPredicate myThing0 |
| Foo.qll:31:5:31:12 | PredicateCall | Foo.qll:24:3:24:32 | ClasslessPredicate alias0 |
| Foo.qll:36:36:36:65 | MemberCall | file://:0:0:0:0 | replaceAll |
| Foo.qll:38:39:38:67 | MemberCall | file://:0:0:0:0 | regexpCapture |
| Overrides.qll:8:30:8:39 | MemberCall | Overrides.qll:6:3:6:29 | ClassPredicate bar |
| Overrides.qll:16:39:16:48 | MemberCall | Overrides.qll:6:3:6:29 | ClassPredicate bar |
| Overrides.qll:16:39:16:48 | MemberCall | Overrides.qll:14:12:14:43 | ClassPredicate bar |
@@ -13,3 +16,7 @@
| Overrides.qll:24:39:24:48 | MemberCall | Overrides.qll:22:12:22:44 | ClassPredicate bar |
| Overrides.qll:28:3:28:9 | MemberCall | Overrides.qll:6:3:6:29 | ClassPredicate bar |
| Overrides.qll:29:3:29:10 | MemberCall | Overrides.qll:8:3:8:41 | ClassPredicate baz |
| packs/src/SrcThing.qll:4:3:4:8 | PredicateCall | packs/lib/LibThing/Foo.qll:1:1:1:30 | ClasslessPredicate foo |
| packs/src/SrcThing.qll:5:3:5:8 | PredicateCall | packs/src/SrcThing.qll:8:1:8:30 | ClasslessPredicate bar |
dependsOn
| packs/src/qlpack.yml:1:1:1:4 | ql-testing-src-pack | packs/lib/qlpack.yml:1:1:1:4 | ql-testing-lib-pack |

View File

@@ -1,3 +1,5 @@
import ql
query AstNode getTarget(Call call) { result = call.getTarget().getDeclaration() }
query AstNode getTarget(Call call) { result = call.getTarget() }
query YAML::QLPack dependsOn(YAML::QLPack pack) { result = pack.getADependency() }

View File

@@ -0,0 +1 @@
predicate foo(int i) { i = 3 }

View File

@@ -0,0 +1,3 @@
name: ql-testing-lib-pack
version: 0.1.0
extractor: ql-test-stuff

View File

@@ -0,0 +1,8 @@
import LibThing.Foo
query predicate test(int i) {
foo(i) and
bar(i)
}
predicate bar(int i) { i = 4 }

View File

@@ -0,0 +1,4 @@
name: ql-testing-src-pack
version: 0.1.0
dependencies:
ql-testing-lib-pack: "*"

View File

@@ -29,159 +29,241 @@ nodes
| Foo.qll:6:30:6:30 | ComparisonOp | semmle.order | 14 |
| Foo.qll:6:32:6:36 | String | semmle.label | [String] String |
| Foo.qll:6:32:6:36 | String | semmle.order | 15 |
| Foo.qll:9:1:9:5 | annotation | semmle.label | [Annotation] annotation |
| Foo.qll:9:1:9:5 | annotation | semmle.order | 16 |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | semmle.label | [ClasslessPredicate] ClasslessPredicate foo |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | semmle.order | 16 |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | semmle.order | 17 |
| Foo.qll:9:21:9:23 | TypeExpr | semmle.label | [TypeExpr] TypeExpr |
| Foo.qll:9:21:9:23 | TypeExpr | semmle.order | 17 |
| Foo.qll:9:21:9:23 | TypeExpr | semmle.order | 18 |
| Foo.qll:9:21:9:25 | f | semmle.label | [VarDecl] f |
| Foo.qll:9:21:9:25 | f | semmle.order | 17 |
| Foo.qll:9:21:9:25 | f | semmle.order | 18 |
| Foo.qll:10:3:10:3 | f | semmle.label | [VarAccess] f |
| Foo.qll:10:3:10:3 | f | semmle.order | 19 |
| Foo.qll:10:3:10:3 | f | semmle.order | 20 |
| Foo.qll:10:3:10:85 | ComparisonFormula | semmle.label | [ComparisonFormula] ComparisonFormula |
| Foo.qll:10:3:10:85 | ComparisonFormula | semmle.order | 19 |
| Foo.qll:10:3:10:85 | ComparisonFormula | semmle.order | 20 |
| Foo.qll:10:5:10:5 | ComparisonOp | semmle.label | [ComparisonOp] ComparisonOp |
| Foo.qll:10:5:10:5 | ComparisonOp | semmle.order | 21 |
| Foo.qll:10:5:10:5 | ComparisonOp | semmle.order | 22 |
| Foo.qll:10:7:10:85 | Rank | semmle.label | [Rank] Rank |
| Foo.qll:10:7:10:85 | Rank | semmle.order | 22 |
| Foo.qll:10:7:10:85 | Rank | semmle.order | 23 |
| Foo.qll:10:12:10:12 | Integer | semmle.label | [Integer] Integer |
| Foo.qll:10:12:10:12 | Integer | semmle.order | 23 |
| Foo.qll:10:12:10:12 | Integer | semmle.order | 24 |
| Foo.qll:10:15:10:17 | TypeExpr | semmle.label | [TypeExpr] TypeExpr |
| Foo.qll:10:15:10:17 | TypeExpr | semmle.order | 24 |
| Foo.qll:10:15:10:17 | TypeExpr | semmle.order | 25 |
| Foo.qll:10:15:10:23 | inner | semmle.label | [VarDecl] inner |
| Foo.qll:10:15:10:23 | inner | semmle.order | 24 |
| Foo.qll:10:15:10:23 | inner | semmle.order | 25 |
| Foo.qll:10:27:10:31 | inner | semmle.label | [VarAccess] inner |
| Foo.qll:10:27:10:31 | inner | semmle.order | 26 |
| Foo.qll:10:27:10:31 | inner | semmle.order | 27 |
| Foo.qll:10:27:10:42 | MemberCall | semmle.label | [MemberCall] MemberCall |
| Foo.qll:10:27:10:42 | MemberCall | semmle.order | 26 |
| Foo.qll:10:27:10:42 | MemberCall | semmle.order | 27 |
| Foo.qll:10:27:10:50 | ComparisonFormula | semmle.label | [ComparisonFormula] ComparisonFormula |
| Foo.qll:10:27:10:50 | ComparisonFormula | semmle.order | 26 |
| Foo.qll:10:27:10:50 | ComparisonFormula | semmle.order | 27 |
| Foo.qll:10:44:10:44 | ComparisonOp | semmle.label | [ComparisonOp] ComparisonOp |
| Foo.qll:10:44:10:44 | ComparisonOp | semmle.order | 29 |
| Foo.qll:10:44:10:44 | ComparisonOp | semmle.order | 30 |
| Foo.qll:10:46:10:50 | String | semmle.label | [String] String |
| Foo.qll:10:46:10:50 | String | semmle.order | 30 |
| Foo.qll:10:46:10:50 | String | semmle.order | 31 |
| Foo.qll:10:54:10:58 | inner | semmle.label | [VarAccess] inner |
| Foo.qll:10:54:10:58 | inner | semmle.order | 31 |
| Foo.qll:10:54:10:58 | inner | semmle.order | 32 |
| Foo.qll:10:69:10:73 | inner | semmle.label | [VarAccess] inner |
| Foo.qll:10:69:10:73 | inner | semmle.order | 32 |
| Foo.qll:10:69:10:73 | inner | semmle.order | 33 |
| Foo.qll:10:69:10:84 | MemberCall | semmle.label | [MemberCall] MemberCall |
| Foo.qll:10:69:10:84 | MemberCall | semmle.order | 32 |
| Foo.qll:10:69:10:84 | MemberCall | semmle.order | 33 |
| Foo.qll:13:1:27:1 | ClasslessPredicate calls | semmle.label | [ClasslessPredicate] ClasslessPredicate calls |
| Foo.qll:13:1:27:1 | ClasslessPredicate calls | semmle.order | 34 |
| Foo.qll:13:1:27:1 | ClasslessPredicate calls | semmle.order | 35 |
| Foo.qll:13:17:13:19 | TypeExpr | semmle.label | [TypeExpr] TypeExpr |
| Foo.qll:13:17:13:19 | TypeExpr | semmle.order | 35 |
| Foo.qll:13:17:13:19 | TypeExpr | semmle.order | 36 |
| Foo.qll:13:17:13:21 | f | semmle.label | [VarDecl] f |
| Foo.qll:13:17:13:21 | f | semmle.order | 35 |
| Foo.qll:13:17:13:21 | f | semmle.order | 36 |
| Foo.qll:14:3:14:10 | PredicateCall | semmle.label | [PredicateCall] PredicateCall |
| Foo.qll:14:3:14:10 | PredicateCall | semmle.order | 37 |
| Foo.qll:14:3:14:10 | PredicateCall | semmle.order | 38 |
| Foo.qll:14:3:16:29 | Disjunction | semmle.label | [Disjunction] Disjunction |
| Foo.qll:14:3:16:29 | Disjunction | semmle.order | 37 |
| Foo.qll:14:3:16:29 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:18:28 | Disjunction | semmle.label | [Disjunction] Disjunction |
| Foo.qll:14:3:18:28 | Disjunction | semmle.order | 37 |
| Foo.qll:14:3:18:28 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:20:13 | Disjunction | semmle.label | [Disjunction] Disjunction |
| Foo.qll:14:3:20:13 | Disjunction | semmle.order | 37 |
| Foo.qll:14:3:20:13 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:22:16 | Disjunction | semmle.label | [Disjunction] Disjunction |
| Foo.qll:14:3:22:16 | Disjunction | semmle.order | 37 |
| Foo.qll:14:3:22:16 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:24:23 | Disjunction | semmle.label | [Disjunction] Disjunction |
| Foo.qll:14:3:24:23 | Disjunction | semmle.order | 37 |
| Foo.qll:14:3:24:23 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:26:14 | Disjunction | semmle.label | [Disjunction] Disjunction |
| Foo.qll:14:3:26:14 | Disjunction | semmle.order | 37 |
| Foo.qll:14:3:26:14 | Disjunction | semmle.order | 38 |
| Foo.qll:14:9:14:9 | f | semmle.label | [VarAccess] f |
| Foo.qll:14:9:14:9 | f | semmle.order | 44 |
| Foo.qll:14:9:14:9 | f | semmle.order | 45 |
| Foo.qll:16:3:16:7 | String | semmle.label | [String] String |
| Foo.qll:16:3:16:7 | String | semmle.order | 45 |
| Foo.qll:16:3:16:7 | String | semmle.order | 46 |
| Foo.qll:16:3:16:29 | ComparisonFormula | semmle.label | [ComparisonFormula] ComparisonFormula |
| Foo.qll:16:3:16:29 | ComparisonFormula | semmle.order | 45 |
| Foo.qll:16:3:16:29 | ComparisonFormula | semmle.order | 46 |
| Foo.qll:16:9:16:9 | ComparisonOp | semmle.label | [ComparisonOp] ComparisonOp |
| Foo.qll:16:9:16:9 | ComparisonOp | semmle.order | 47 |
| Foo.qll:16:9:16:9 | ComparisonOp | semmle.order | 48 |
| Foo.qll:16:11:16:11 | f | semmle.label | [VarAccess] f |
| Foo.qll:16:11:16:11 | f | semmle.order | 48 |
| Foo.qll:16:11:16:11 | f | semmle.order | 49 |
| Foo.qll:16:11:16:29 | MemberCall | semmle.label | [MemberCall] MemberCall |
| Foo.qll:16:11:16:29 | MemberCall | semmle.order | 48 |
| Foo.qll:16:11:16:29 | MemberCall | semmle.order | 49 |
| Foo.qll:16:22:16:22 | Integer | semmle.label | [Integer] Integer |
| Foo.qll:16:22:16:22 | Integer | semmle.order | 50 |
| Foo.qll:16:22:16:22 | Integer | semmle.order | 51 |
| Foo.qll:16:25:16:25 | Integer | semmle.label | [Integer] Integer |
| Foo.qll:16:25:16:25 | Integer | semmle.order | 51 |
| Foo.qll:16:25:16:25 | Integer | semmle.order | 52 |
| Foo.qll:16:28:16:28 | Integer | semmle.label | [Integer] Integer |
| Foo.qll:16:28:16:28 | Integer | semmle.order | 52 |
| Foo.qll:16:28:16:28 | Integer | semmle.order | 53 |
| Foo.qll:18:3:18:3 | f | semmle.label | [VarAccess] f |
| Foo.qll:18:3:18:3 | f | semmle.order | 53 |
| Foo.qll:18:3:18:3 | f | semmle.order | 54 |
| Foo.qll:18:3:18:9 | InlineCast | semmle.label | [InlineCast] InlineCast |
| Foo.qll:18:3:18:9 | InlineCast | semmle.order | 53 |
| Foo.qll:18:3:18:9 | InlineCast | semmle.order | 54 |
| Foo.qll:18:3:18:20 | MemberCall | semmle.label | [MemberCall] MemberCall |
| Foo.qll:18:3:18:20 | MemberCall | semmle.order | 53 |
| Foo.qll:18:3:18:20 | MemberCall | semmle.order | 54 |
| Foo.qll:18:3:18:28 | ComparisonFormula | semmle.label | [ComparisonFormula] ComparisonFormula |
| Foo.qll:18:3:18:28 | ComparisonFormula | semmle.order | 53 |
| Foo.qll:18:3:18:28 | ComparisonFormula | semmle.order | 54 |
| Foo.qll:18:6:18:8 | TypeExpr | semmle.label | [TypeExpr] TypeExpr |
| Foo.qll:18:6:18:8 | TypeExpr | semmle.order | 57 |
| Foo.qll:18:6:18:8 | TypeExpr | semmle.order | 58 |
| Foo.qll:18:22:18:22 | ComparisonOp | semmle.label | [ComparisonOp] ComparisonOp |
| Foo.qll:18:22:18:22 | ComparisonOp | semmle.order | 58 |
| Foo.qll:18:22:18:22 | ComparisonOp | semmle.order | 59 |
| Foo.qll:18:24:18:28 | String | semmle.label | [String] String |
| Foo.qll:18:24:18:28 | String | semmle.order | 59 |
| Foo.qll:18:24:18:28 | String | semmle.order | 60 |
| Foo.qll:20:3:20:3 | f | semmle.label | [VarAccess] f |
| Foo.qll:20:3:20:3 | f | semmle.order | 60 |
| Foo.qll:20:3:20:3 | f | semmle.order | 61 |
| Foo.qll:20:3:20:9 | InlineCast | semmle.label | [InlineCast] InlineCast |
| Foo.qll:20:3:20:9 | InlineCast | semmle.order | 60 |
| Foo.qll:20:3:20:9 | InlineCast | semmle.order | 61 |
| Foo.qll:20:3:20:13 | ComparisonFormula | semmle.label | [ComparisonFormula] ComparisonFormula |
| Foo.qll:20:3:20:13 | ComparisonFormula | semmle.order | 60 |
| Foo.qll:20:3:20:13 | ComparisonFormula | semmle.order | 61 |
| Foo.qll:20:6:20:8 | TypeExpr | semmle.label | [TypeExpr] TypeExpr |
| Foo.qll:20:6:20:8 | TypeExpr | semmle.order | 63 |
| Foo.qll:20:6:20:8 | TypeExpr | semmle.order | 64 |
| Foo.qll:20:11:20:11 | ComparisonOp | semmle.label | [ComparisonOp] ComparisonOp |
| Foo.qll:20:11:20:11 | ComparisonOp | semmle.order | 64 |
| Foo.qll:20:11:20:11 | ComparisonOp | semmle.order | 65 |
| Foo.qll:20:13:20:13 | f | semmle.label | [VarAccess] f |
| Foo.qll:20:13:20:13 | f | semmle.order | 65 |
| Foo.qll:20:13:20:13 | f | semmle.order | 66 |
| Foo.qll:22:3:22:3 | f | semmle.label | [VarAccess] f |
| Foo.qll:22:3:22:3 | f | semmle.order | 66 |
| Foo.qll:22:3:22:3 | f | semmle.order | 67 |
| Foo.qll:22:3:22:16 | ComparisonFormula | semmle.label | [ComparisonFormula] ComparisonFormula |
| Foo.qll:22:3:22:16 | ComparisonFormula | semmle.order | 66 |
| Foo.qll:22:3:22:16 | ComparisonFormula | semmle.order | 67 |
| Foo.qll:22:5:22:5 | ComparisonOp | semmle.label | [ComparisonOp] ComparisonOp |
| Foo.qll:22:5:22:5 | ComparisonOp | semmle.order | 68 |
| Foo.qll:22:5:22:5 | ComparisonOp | semmle.order | 69 |
| Foo.qll:22:7:22:16 | FullAggregate[any] | semmle.label | [FullAggregate[any]] FullAggregate[any] |
| Foo.qll:22:7:22:16 | FullAggregate[any] | semmle.order | 69 |
| Foo.qll:22:7:22:16 | FullAggregate[any] | semmle.order | 70 |
| Foo.qll:22:11:22:13 | TypeExpr | semmle.label | [TypeExpr] TypeExpr |
| Foo.qll:22:11:22:13 | TypeExpr | semmle.order | 70 |
| Foo.qll:22:11:22:13 | TypeExpr | semmle.order | 71 |
| Foo.qll:22:11:22:15 | f | semmle.label | [VarDecl] f |
| Foo.qll:22:11:22:15 | f | semmle.order | 70 |
| Foo.qll:22:11:22:15 | f | semmle.order | 71 |
| Foo.qll:24:3:24:3 | Integer | semmle.label | [Integer] Integer |
| Foo.qll:24:3:24:3 | Integer | semmle.order | 72 |
| Foo.qll:24:3:24:3 | Integer | semmle.order | 73 |
| Foo.qll:24:3:24:23 | ComparisonFormula | semmle.label | [ComparisonFormula] ComparisonFormula |
| Foo.qll:24:3:24:23 | ComparisonFormula | semmle.order | 72 |
| Foo.qll:24:3:24:23 | ComparisonFormula | semmle.order | 73 |
| Foo.qll:24:5:24:5 | ComparisonOp | semmle.label | [ComparisonOp] ComparisonOp |
| Foo.qll:24:5:24:5 | ComparisonOp | semmle.order | 74 |
| Foo.qll:24:5:24:5 | ComparisonOp | semmle.order | 75 |
| Foo.qll:24:7:24:7 | Integer | semmle.label | [Integer] Integer |
| Foo.qll:24:7:24:7 | Integer | semmle.order | 75 |
| Foo.qll:24:7:24:7 | Integer | semmle.order | 76 |
| Foo.qll:24:7:24:23 | AddExpr | semmle.label | [AddExpr] AddExpr |
| Foo.qll:24:7:24:23 | AddExpr | semmle.order | 75 |
| Foo.qll:24:7:24:23 | AddExpr | semmle.order | 76 |
| Foo.qll:24:12:24:12 | Integer | semmle.label | [Integer] Integer |
| Foo.qll:24:12:24:12 | Integer | semmle.order | 77 |
| Foo.qll:24:12:24:12 | Integer | semmle.order | 78 |
| Foo.qll:24:12:24:22 | AddExpr | semmle.label | [AddExpr] AddExpr |
| Foo.qll:24:12:24:22 | AddExpr | semmle.order | 77 |
| Foo.qll:24:12:24:22 | AddExpr | semmle.order | 78 |
| Foo.qll:24:17:24:17 | Integer | semmle.label | [Integer] Integer |
| Foo.qll:24:17:24:17 | Integer | semmle.order | 79 |
| Foo.qll:24:17:24:17 | Integer | semmle.order | 80 |
| Foo.qll:24:17:24:21 | AddExpr | semmle.label | [AddExpr] AddExpr |
| Foo.qll:24:17:24:21 | AddExpr | semmle.order | 79 |
| Foo.qll:24:17:24:21 | AddExpr | semmle.order | 80 |
| Foo.qll:24:21:24:21 | Integer | semmle.label | [Integer] Integer |
| Foo.qll:24:21:24:21 | Integer | semmle.order | 81 |
| Foo.qll:24:21:24:21 | Integer | semmle.order | 82 |
| Foo.qll:26:3:26:6 | Boolean | semmle.label | [Boolean] Boolean |
| Foo.qll:26:3:26:6 | Boolean | semmle.order | 82 |
| Foo.qll:26:3:26:6 | Boolean | semmle.order | 83 |
| Foo.qll:26:3:26:14 | ComparisonFormula | semmle.label | [ComparisonFormula] ComparisonFormula |
| Foo.qll:26:3:26:14 | ComparisonFormula | semmle.order | 82 |
| Foo.qll:26:3:26:14 | ComparisonFormula | semmle.order | 83 |
| Foo.qll:26:8:26:8 | ComparisonOp | semmle.label | [ComparisonOp] ComparisonOp |
| Foo.qll:26:8:26:8 | ComparisonOp | semmle.order | 84 |
| Foo.qll:26:8:26:8 | ComparisonOp | semmle.order | 85 |
| Foo.qll:26:10:26:14 | Boolean | semmle.label | [Boolean] Boolean |
| Foo.qll:26:10:26:14 | Boolean | semmle.order | 85 |
| Foo.qll:26:10:26:14 | Boolean | semmle.order | 86 |
| file://:0:0:0:0 | abs | semmle.label | [BuiltinPredicate] abs |
| file://:0:0:0:0 | abs | semmle.label | [BuiltinPredicate] abs |
| file://:0:0:0:0 | acos | semmle.label | [BuiltinPredicate] acos |
| file://:0:0:0:0 | any | semmle.label | [BuiltinPredicate] any |
| file://:0:0:0:0 | atan | semmle.label | [BuiltinPredicate] atan |
| file://:0:0:0:0 | bitAnd | semmle.label | [BuiltinPredicate] bitAnd |
| file://:0:0:0:0 | bitNot | semmle.label | [BuiltinPredicate] bitNot |
| file://:0:0:0:0 | bitOr | semmle.label | [BuiltinPredicate] bitOr |
| file://:0:0:0:0 | bitShiftLeft | semmle.label | [BuiltinPredicate] bitShiftLeft |
| file://:0:0:0:0 | bitShiftRight | semmle.label | [BuiltinPredicate] bitShiftRight |
| file://:0:0:0:0 | bitShiftRightSigned | semmle.label | [BuiltinPredicate] bitShiftRightSigned |
| file://:0:0:0:0 | bitXor | semmle.label | [BuiltinPredicate] bitXor |
| file://:0:0:0:0 | booleanAnd | semmle.label | [BuiltinPredicate] booleanAnd |
| file://:0:0:0:0 | booleanNot | semmle.label | [BuiltinPredicate] booleanNot |
| file://:0:0:0:0 | booleanOr | semmle.label | [BuiltinPredicate] booleanOr |
| file://:0:0:0:0 | booleanXor | semmle.label | [BuiltinPredicate] booleanXor |
| file://:0:0:0:0 | ceil | semmle.label | [BuiltinPredicate] ceil |
| file://:0:0:0:0 | charAt | semmle.label | [BuiltinPredicate] charAt |
| file://:0:0:0:0 | copySign | semmle.label | [BuiltinPredicate] copySign |
| file://:0:0:0:0 | cos | semmle.label | [BuiltinPredicate] cos |
| file://:0:0:0:0 | cosh | semmle.label | [BuiltinPredicate] cosh |
| file://:0:0:0:0 | daysTo | semmle.label | [BuiltinPredicate] daysTo |
| file://:0:0:0:0 | exp | semmle.label | [BuiltinPredicate] exp |
| file://:0:0:0:0 | floor | semmle.label | [BuiltinPredicate] floor |
| file://:0:0:0:0 | gcd | semmle.label | [BuiltinPredicate] gcd |
| file://:0:0:0:0 | getDay | semmle.label | [BuiltinPredicate] getDay |
| file://:0:0:0:0 | getHours | semmle.label | [BuiltinPredicate] getHours |
| file://:0:0:0:0 | getMinutes | semmle.label | [BuiltinPredicate] getMinutes |
| file://:0:0:0:0 | getMonth | semmle.label | [BuiltinPredicate] getMonth |
| file://:0:0:0:0 | getSeconds | semmle.label | [BuiltinPredicate] getSeconds |
| file://:0:0:0:0 | getYear | semmle.label | [BuiltinPredicate] getYear |
| file://:0:0:0:0 | indexOf | semmle.label | [BuiltinPredicate] indexOf |
| file://:0:0:0:0 | indexOf | semmle.label | [BuiltinPredicate] indexOf |
| file://:0:0:0:0 | isLowercase | semmle.label | [BuiltinPredicate] isLowercase |
| file://:0:0:0:0 | isUppercase | semmle.label | [BuiltinPredicate] isUppercase |
| file://:0:0:0:0 | length | semmle.label | [BuiltinPredicate] length |
| file://:0:0:0:0 | log | semmle.label | [BuiltinPredicate] log |
| file://:0:0:0:0 | log | semmle.label | [BuiltinPredicate] log |
| file://:0:0:0:0 | log2 | semmle.label | [BuiltinPredicate] log2 |
| file://:0:0:0:0 | log10 | semmle.label | [BuiltinPredicate] log10 |
| file://:0:0:0:0 | matches | semmle.label | [BuiltinPredicate] matches |
| file://:0:0:0:0 | maximum | semmle.label | [BuiltinPredicate] maximum |
| file://:0:0:0:0 | minimum | semmle.label | [BuiltinPredicate] minimum |
| file://:0:0:0:0 | nextAfter | semmle.label | [BuiltinPredicate] nextAfter |
| file://:0:0:0:0 | nextDown | semmle.label | [BuiltinPredicate] nextDown |
| file://:0:0:0:0 | nextUp | semmle.label | [BuiltinPredicate] nextUp |
| file://:0:0:0:0 | none | semmle.label | [BuiltinPredicate] none |
| file://:0:0:0:0 | pow | semmle.label | [BuiltinPredicate] pow |
| file://:0:0:0:0 | prefix | semmle.label | [BuiltinPredicate] prefix |
| file://:0:0:0:0 | regexpCapture | semmle.label | [BuiltinPredicate] regexpCapture |
| file://:0:0:0:0 | regexpFind | semmle.label | [BuiltinPredicate] regexpFind |
| file://:0:0:0:0 | regexpMatch | semmle.label | [BuiltinPredicate] regexpMatch |
| file://:0:0:0:0 | regexpReplaceAll | semmle.label | [BuiltinPredicate] regexpReplaceAll |
| file://:0:0:0:0 | replaceAll | semmle.label | [BuiltinPredicate] replaceAll |
| file://:0:0:0:0 | signum | semmle.label | [BuiltinPredicate] signum |
| file://:0:0:0:0 | sin | semmle.label | [BuiltinPredicate] sin |
| file://:0:0:0:0 | sinh | semmle.label | [BuiltinPredicate] sinh |
| file://:0:0:0:0 | splitAt | semmle.label | [BuiltinPredicate] splitAt |
| file://:0:0:0:0 | splitAt | semmle.label | [BuiltinPredicate] splitAt |
| file://:0:0:0:0 | sqrt | semmle.label | [BuiltinPredicate] sqrt |
| file://:0:0:0:0 | substring | semmle.label | [BuiltinPredicate] substring |
| file://:0:0:0:0 | suffix | semmle.label | [BuiltinPredicate] suffix |
| file://:0:0:0:0 | tan | semmle.label | [BuiltinPredicate] tan |
| file://:0:0:0:0 | tanh | semmle.label | [BuiltinPredicate] tanh |
| file://:0:0:0:0 | toDate | semmle.label | [BuiltinPredicate] toDate |
| file://:0:0:0:0 | toFloat | semmle.label | [BuiltinPredicate] toFloat |
| file://:0:0:0:0 | toISO | semmle.label | [BuiltinPredicate] toISO |
| file://:0:0:0:0 | toInt | semmle.label | [BuiltinPredicate] toInt |
| file://:0:0:0:0 | toLowerCase | semmle.label | [BuiltinPredicate] toLowerCase |
| file://:0:0:0:0 | toString | semmle.label | [BuiltinPredicate] toString |
| file://:0:0:0:0 | toString | semmle.label | [BuiltinPredicate] toString |
| file://:0:0:0:0 | toString | semmle.label | [BuiltinPredicate] toString |
| file://:0:0:0:0 | toString | semmle.label | [BuiltinPredicate] toString |
| file://:0:0:0:0 | toString | semmle.label | [BuiltinPredicate] toString |
| file://:0:0:0:0 | toUnicode | semmle.label | [BuiltinPredicate] toUnicode |
| file://:0:0:0:0 | toUpperCase | semmle.label | [BuiltinPredicate] toUpperCase |
| file://:0:0:0:0 | toUrl | semmle.label | [BuiltinPredicate] toUrl |
| file://:0:0:0:0 | toUrl | semmle.label | [BuiltinPredicate] toUrl |
| file://:0:0:0:0 | trim | semmle.label | [BuiltinPredicate] trim |
| file://:0:0:0:0 | ulp | semmle.label | [BuiltinPredicate] ulp |
| printAst.ql:1:1:1:28 | Import | semmle.label | [Import] Import |
| printAst.ql:1:1:1:28 | Import | semmle.order | 86 |
| printAst.ql:1:1:1:28 | Import | semmle.order | 87 |
| printAst.ql:1:1:1:29 | TopLevel | semmle.label | [TopLevel] TopLevel |
| printAst.ql:1:1:1:29 | TopLevel | semmle.order | 86 |
| printAst.ql:1:1:1:29 | TopLevel | semmle.order | 87 |
edges
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:1:1:1:17 | Import | semmle.label | getAnImport() |
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:1:1:1:17 | Import | semmle.order | 1 |
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:3:1:7:1 | Class Foo | semmle.label | getAClass() |
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:3:1:7:1 | Class Foo | semmle.order | 3 |
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:9:7:11:1 | ClasslessPredicate foo | semmle.label | getAPredicate() |
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:9:7:11:1 | ClasslessPredicate foo | semmle.order | 16 |
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:9:7:11:1 | ClasslessPredicate foo | semmle.order | 17 |
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:13:1:27:1 | ClasslessPredicate calls | semmle.label | getAPredicate() |
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:13:1:27:1 | ClasslessPredicate calls | semmle.order | 34 |
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:13:1:27:1 | ClasslessPredicate calls | semmle.order | 35 |
| Foo.qll:3:1:7:1 | Class Foo | Foo.qll:3:19:3:22 | TypeExpr | semmle.label | getASuperType() |
| Foo.qll:3:1:7:1 | Class Foo | Foo.qll:3:19:3:22 | TypeExpr | semmle.order | 4 |
| Foo.qll:3:1:7:1 | Class Foo | Foo.qll:4:3:4:17 | CharPred Foo | semmle.label | getCharPred() |
@@ -207,142 +289,142 @@ edges
| Foo.qll:6:23:6:36 | ComparisonFormula | Foo.qll:6:32:6:36 | String | semmle.label | getRightOperand() |
| Foo.qll:6:23:6:36 | ComparisonFormula | Foo.qll:6:32:6:36 | String | semmle.order | 15 |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | Foo.qll:9:21:9:25 | f | semmle.label | getParameter(_) |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | Foo.qll:9:21:9:25 | f | semmle.order | 17 |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | Foo.qll:9:21:9:25 | f | semmle.order | 18 |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | Foo.qll:10:3:10:85 | ComparisonFormula | semmle.label | getBody() |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | Foo.qll:10:3:10:85 | ComparisonFormula | semmle.order | 19 |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | Foo.qll:10:3:10:85 | ComparisonFormula | semmle.order | 20 |
| Foo.qll:9:21:9:25 | f | Foo.qll:9:21:9:23 | TypeExpr | semmle.label | getTypeExpr() |
| Foo.qll:9:21:9:25 | f | Foo.qll:9:21:9:23 | TypeExpr | semmle.order | 17 |
| Foo.qll:9:21:9:25 | f | Foo.qll:9:21:9:23 | TypeExpr | semmle.order | 18 |
| Foo.qll:10:3:10:85 | ComparisonFormula | Foo.qll:10:3:10:3 | f | semmle.label | getLeftOperand() |
| Foo.qll:10:3:10:85 | ComparisonFormula | Foo.qll:10:3:10:3 | f | semmle.order | 19 |
| Foo.qll:10:3:10:85 | ComparisonFormula | Foo.qll:10:3:10:3 | f | semmle.order | 20 |
| Foo.qll:10:3:10:85 | ComparisonFormula | Foo.qll:10:5:10:5 | ComparisonOp | semmle.label | getOperator() |
| Foo.qll:10:3:10:85 | ComparisonFormula | Foo.qll:10:5:10:5 | ComparisonOp | semmle.order | 21 |
| Foo.qll:10:3:10:85 | ComparisonFormula | Foo.qll:10:5:10:5 | ComparisonOp | semmle.order | 22 |
| Foo.qll:10:3:10:85 | ComparisonFormula | Foo.qll:10:7:10:85 | Rank | semmle.label | getRightOperand() |
| Foo.qll:10:3:10:85 | ComparisonFormula | Foo.qll:10:7:10:85 | Rank | semmle.order | 22 |
| Foo.qll:10:3:10:85 | ComparisonFormula | Foo.qll:10:7:10:85 | Rank | semmle.order | 23 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:12:10:12 | Integer | semmle.label | getRankExpr() |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:12:10:12 | Integer | semmle.order | 23 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:12:10:12 | Integer | semmle.order | 24 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:15:10:23 | inner | semmle.label | getArgument(_) |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:15:10:23 | inner | semmle.order | 24 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:15:10:23 | inner | semmle.order | 25 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:27:10:50 | ComparisonFormula | semmle.label | getRange() |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:27:10:50 | ComparisonFormula | semmle.order | 26 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:27:10:50 | ComparisonFormula | semmle.order | 27 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:54:10:58 | inner | semmle.label | getExpr(_) |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:54:10:58 | inner | semmle.order | 31 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:54:10:58 | inner | semmle.order | 32 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:69:10:84 | MemberCall | semmle.label | getOrderBy(_) |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:69:10:84 | MemberCall | semmle.order | 32 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:69:10:84 | MemberCall | semmle.order | 33 |
| Foo.qll:10:15:10:23 | inner | Foo.qll:10:15:10:17 | TypeExpr | semmle.label | getTypeExpr() |
| Foo.qll:10:15:10:23 | inner | Foo.qll:10:15:10:17 | TypeExpr | semmle.order | 24 |
| Foo.qll:10:15:10:23 | inner | Foo.qll:10:15:10:17 | TypeExpr | semmle.order | 25 |
| Foo.qll:10:27:10:42 | MemberCall | Foo.qll:10:27:10:31 | inner | semmle.label | getBase() |
| Foo.qll:10:27:10:42 | MemberCall | Foo.qll:10:27:10:31 | inner | semmle.order | 26 |
| Foo.qll:10:27:10:42 | MemberCall | Foo.qll:10:27:10:31 | inner | semmle.order | 27 |
| Foo.qll:10:27:10:50 | ComparisonFormula | Foo.qll:10:27:10:42 | MemberCall | semmle.label | getLeftOperand() |
| Foo.qll:10:27:10:50 | ComparisonFormula | Foo.qll:10:27:10:42 | MemberCall | semmle.order | 26 |
| Foo.qll:10:27:10:50 | ComparisonFormula | Foo.qll:10:27:10:42 | MemberCall | semmle.order | 27 |
| Foo.qll:10:27:10:50 | ComparisonFormula | Foo.qll:10:44:10:44 | ComparisonOp | semmle.label | getOperator() |
| Foo.qll:10:27:10:50 | ComparisonFormula | Foo.qll:10:44:10:44 | ComparisonOp | semmle.order | 29 |
| Foo.qll:10:27:10:50 | ComparisonFormula | Foo.qll:10:44:10:44 | ComparisonOp | semmle.order | 30 |
| Foo.qll:10:27:10:50 | ComparisonFormula | Foo.qll:10:46:10:50 | String | semmle.label | getRightOperand() |
| Foo.qll:10:27:10:50 | ComparisonFormula | Foo.qll:10:46:10:50 | String | semmle.order | 30 |
| Foo.qll:10:27:10:50 | ComparisonFormula | Foo.qll:10:46:10:50 | String | semmle.order | 31 |
| Foo.qll:10:69:10:84 | MemberCall | Foo.qll:10:69:10:73 | inner | semmle.label | getBase() |
| Foo.qll:10:69:10:84 | MemberCall | Foo.qll:10:69:10:73 | inner | semmle.order | 32 |
| Foo.qll:10:69:10:84 | MemberCall | Foo.qll:10:69:10:73 | inner | semmle.order | 33 |
| Foo.qll:13:1:27:1 | ClasslessPredicate calls | Foo.qll:13:17:13:21 | f | semmle.label | getParameter(_) |
| Foo.qll:13:1:27:1 | ClasslessPredicate calls | Foo.qll:13:17:13:21 | f | semmle.order | 35 |
| Foo.qll:13:1:27:1 | ClasslessPredicate calls | Foo.qll:13:17:13:21 | f | semmle.order | 36 |
| Foo.qll:13:1:27:1 | ClasslessPredicate calls | Foo.qll:14:3:26:14 | Disjunction | semmle.label | getBody() |
| Foo.qll:13:1:27:1 | ClasslessPredicate calls | Foo.qll:14:3:26:14 | Disjunction | semmle.order | 37 |
| Foo.qll:13:1:27:1 | ClasslessPredicate calls | Foo.qll:14:3:26:14 | Disjunction | semmle.order | 38 |
| Foo.qll:13:17:13:21 | f | Foo.qll:13:17:13:19 | TypeExpr | semmle.label | getTypeExpr() |
| Foo.qll:13:17:13:21 | f | Foo.qll:13:17:13:19 | TypeExpr | semmle.order | 35 |
| Foo.qll:13:17:13:21 | f | Foo.qll:13:17:13:19 | TypeExpr | semmle.order | 36 |
| Foo.qll:14:3:14:10 | PredicateCall | Foo.qll:14:9:14:9 | f | semmle.label | getArgument(_) |
| Foo.qll:14:3:14:10 | PredicateCall | Foo.qll:14:9:14:9 | f | semmle.order | 44 |
| Foo.qll:14:3:14:10 | PredicateCall | Foo.qll:14:9:14:9 | f | semmle.order | 45 |
| Foo.qll:14:3:16:29 | Disjunction | Foo.qll:14:3:14:10 | PredicateCall | semmle.label | getAnOperand() |
| Foo.qll:14:3:16:29 | Disjunction | Foo.qll:14:3:14:10 | PredicateCall | semmle.order | 37 |
| Foo.qll:14:3:16:29 | Disjunction | Foo.qll:14:3:14:10 | PredicateCall | semmle.order | 38 |
| Foo.qll:14:3:16:29 | Disjunction | Foo.qll:16:3:16:29 | ComparisonFormula | semmle.label | getAnOperand() |
| Foo.qll:14:3:16:29 | Disjunction | Foo.qll:16:3:16:29 | ComparisonFormula | semmle.order | 45 |
| Foo.qll:14:3:16:29 | Disjunction | Foo.qll:16:3:16:29 | ComparisonFormula | semmle.order | 46 |
| Foo.qll:14:3:18:28 | Disjunction | Foo.qll:14:3:16:29 | Disjunction | semmle.label | getAnOperand() |
| Foo.qll:14:3:18:28 | Disjunction | Foo.qll:14:3:16:29 | Disjunction | semmle.order | 37 |
| Foo.qll:14:3:18:28 | Disjunction | Foo.qll:14:3:16:29 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:18:28 | Disjunction | Foo.qll:18:3:18:28 | ComparisonFormula | semmle.label | getAnOperand() |
| Foo.qll:14:3:18:28 | Disjunction | Foo.qll:18:3:18:28 | ComparisonFormula | semmle.order | 53 |
| Foo.qll:14:3:18:28 | Disjunction | Foo.qll:18:3:18:28 | ComparisonFormula | semmle.order | 54 |
| Foo.qll:14:3:20:13 | Disjunction | Foo.qll:14:3:18:28 | Disjunction | semmle.label | getAnOperand() |
| Foo.qll:14:3:20:13 | Disjunction | Foo.qll:14:3:18:28 | Disjunction | semmle.order | 37 |
| Foo.qll:14:3:20:13 | Disjunction | Foo.qll:14:3:18:28 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:20:13 | Disjunction | Foo.qll:20:3:20:13 | ComparisonFormula | semmle.label | getAnOperand() |
| Foo.qll:14:3:20:13 | Disjunction | Foo.qll:20:3:20:13 | ComparisonFormula | semmle.order | 60 |
| Foo.qll:14:3:20:13 | Disjunction | Foo.qll:20:3:20:13 | ComparisonFormula | semmle.order | 61 |
| Foo.qll:14:3:22:16 | Disjunction | Foo.qll:14:3:20:13 | Disjunction | semmle.label | getAnOperand() |
| Foo.qll:14:3:22:16 | Disjunction | Foo.qll:14:3:20:13 | Disjunction | semmle.order | 37 |
| Foo.qll:14:3:22:16 | Disjunction | Foo.qll:14:3:20:13 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:22:16 | Disjunction | Foo.qll:22:3:22:16 | ComparisonFormula | semmle.label | getAnOperand() |
| Foo.qll:14:3:22:16 | Disjunction | Foo.qll:22:3:22:16 | ComparisonFormula | semmle.order | 66 |
| Foo.qll:14:3:22:16 | Disjunction | Foo.qll:22:3:22:16 | ComparisonFormula | semmle.order | 67 |
| Foo.qll:14:3:24:23 | Disjunction | Foo.qll:14:3:22:16 | Disjunction | semmle.label | getAnOperand() |
| Foo.qll:14:3:24:23 | Disjunction | Foo.qll:14:3:22:16 | Disjunction | semmle.order | 37 |
| Foo.qll:14:3:24:23 | Disjunction | Foo.qll:14:3:22:16 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:24:23 | Disjunction | Foo.qll:24:3:24:23 | ComparisonFormula | semmle.label | getAnOperand() |
| Foo.qll:14:3:24:23 | Disjunction | Foo.qll:24:3:24:23 | ComparisonFormula | semmle.order | 72 |
| Foo.qll:14:3:24:23 | Disjunction | Foo.qll:24:3:24:23 | ComparisonFormula | semmle.order | 73 |
| Foo.qll:14:3:26:14 | Disjunction | Foo.qll:14:3:24:23 | Disjunction | semmle.label | getAnOperand() |
| Foo.qll:14:3:26:14 | Disjunction | Foo.qll:14:3:24:23 | Disjunction | semmle.order | 37 |
| Foo.qll:14:3:26:14 | Disjunction | Foo.qll:14:3:24:23 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:26:14 | Disjunction | Foo.qll:26:3:26:14 | ComparisonFormula | semmle.label | getAnOperand() |
| Foo.qll:14:3:26:14 | Disjunction | Foo.qll:26:3:26:14 | ComparisonFormula | semmle.order | 82 |
| Foo.qll:14:3:26:14 | Disjunction | Foo.qll:26:3:26:14 | ComparisonFormula | semmle.order | 83 |
| Foo.qll:16:3:16:29 | ComparisonFormula | Foo.qll:16:3:16:7 | String | semmle.label | getLeftOperand() |
| Foo.qll:16:3:16:29 | ComparisonFormula | Foo.qll:16:3:16:7 | String | semmle.order | 45 |
| Foo.qll:16:3:16:29 | ComparisonFormula | Foo.qll:16:3:16:7 | String | semmle.order | 46 |
| Foo.qll:16:3:16:29 | ComparisonFormula | Foo.qll:16:9:16:9 | ComparisonOp | semmle.label | getOperator() |
| Foo.qll:16:3:16:29 | ComparisonFormula | Foo.qll:16:9:16:9 | ComparisonOp | semmle.order | 47 |
| Foo.qll:16:3:16:29 | ComparisonFormula | Foo.qll:16:9:16:9 | ComparisonOp | semmle.order | 48 |
| Foo.qll:16:3:16:29 | ComparisonFormula | Foo.qll:16:11:16:29 | MemberCall | semmle.label | getRightOperand() |
| Foo.qll:16:3:16:29 | ComparisonFormula | Foo.qll:16:11:16:29 | MemberCall | semmle.order | 48 |
| Foo.qll:16:3:16:29 | ComparisonFormula | Foo.qll:16:11:16:29 | MemberCall | semmle.order | 49 |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:11:16:11 | f | semmle.label | getBase() |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:11:16:11 | f | semmle.order | 48 |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:11:16:11 | f | semmle.order | 49 |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:22:16:22 | Integer | semmle.label | getArgument(_) |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:22:16:22 | Integer | semmle.order | 50 |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:22:16:22 | Integer | semmle.order | 51 |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:25:16:25 | Integer | semmle.label | getArgument(_) |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:25:16:25 | Integer | semmle.order | 51 |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:25:16:25 | Integer | semmle.order | 52 |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:28:16:28 | Integer | semmle.label | getArgument(_) |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:28:16:28 | Integer | semmle.order | 52 |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:28:16:28 | Integer | semmle.order | 53 |
| Foo.qll:18:3:18:9 | InlineCast | Foo.qll:18:3:18:3 | f | semmle.label | getBase() |
| Foo.qll:18:3:18:9 | InlineCast | Foo.qll:18:3:18:3 | f | semmle.order | 53 |
| Foo.qll:18:3:18:9 | InlineCast | Foo.qll:18:3:18:3 | f | semmle.order | 54 |
| Foo.qll:18:3:18:9 | InlineCast | Foo.qll:18:6:18:8 | TypeExpr | semmle.label | getTypeExpr() |
| Foo.qll:18:3:18:9 | InlineCast | Foo.qll:18:6:18:8 | TypeExpr | semmle.order | 57 |
| Foo.qll:18:3:18:9 | InlineCast | Foo.qll:18:6:18:8 | TypeExpr | semmle.order | 58 |
| Foo.qll:18:3:18:20 | MemberCall | Foo.qll:18:3:18:9 | InlineCast | semmle.label | getBase() |
| Foo.qll:18:3:18:20 | MemberCall | Foo.qll:18:3:18:9 | InlineCast | semmle.order | 53 |
| Foo.qll:18:3:18:20 | MemberCall | Foo.qll:18:3:18:9 | InlineCast | semmle.order | 54 |
| Foo.qll:18:3:18:28 | ComparisonFormula | Foo.qll:18:3:18:20 | MemberCall | semmle.label | getLeftOperand() |
| Foo.qll:18:3:18:28 | ComparisonFormula | Foo.qll:18:3:18:20 | MemberCall | semmle.order | 53 |
| Foo.qll:18:3:18:28 | ComparisonFormula | Foo.qll:18:3:18:20 | MemberCall | semmle.order | 54 |
| Foo.qll:18:3:18:28 | ComparisonFormula | Foo.qll:18:22:18:22 | ComparisonOp | semmle.label | getOperator() |
| Foo.qll:18:3:18:28 | ComparisonFormula | Foo.qll:18:22:18:22 | ComparisonOp | semmle.order | 58 |
| Foo.qll:18:3:18:28 | ComparisonFormula | Foo.qll:18:22:18:22 | ComparisonOp | semmle.order | 59 |
| Foo.qll:18:3:18:28 | ComparisonFormula | Foo.qll:18:24:18:28 | String | semmle.label | getRightOperand() |
| Foo.qll:18:3:18:28 | ComparisonFormula | Foo.qll:18:24:18:28 | String | semmle.order | 59 |
| Foo.qll:18:3:18:28 | ComparisonFormula | Foo.qll:18:24:18:28 | String | semmle.order | 60 |
| Foo.qll:20:3:20:9 | InlineCast | Foo.qll:20:3:20:3 | f | semmle.label | getBase() |
| Foo.qll:20:3:20:9 | InlineCast | Foo.qll:20:3:20:3 | f | semmle.order | 60 |
| Foo.qll:20:3:20:9 | InlineCast | Foo.qll:20:3:20:3 | f | semmle.order | 61 |
| Foo.qll:20:3:20:9 | InlineCast | Foo.qll:20:6:20:8 | TypeExpr | semmle.label | getTypeExpr() |
| Foo.qll:20:3:20:9 | InlineCast | Foo.qll:20:6:20:8 | TypeExpr | semmle.order | 63 |
| Foo.qll:20:3:20:9 | InlineCast | Foo.qll:20:6:20:8 | TypeExpr | semmle.order | 64 |
| Foo.qll:20:3:20:13 | ComparisonFormula | Foo.qll:20:3:20:9 | InlineCast | semmle.label | getLeftOperand() |
| Foo.qll:20:3:20:13 | ComparisonFormula | Foo.qll:20:3:20:9 | InlineCast | semmle.order | 60 |
| Foo.qll:20:3:20:13 | ComparisonFormula | Foo.qll:20:3:20:9 | InlineCast | semmle.order | 61 |
| Foo.qll:20:3:20:13 | ComparisonFormula | Foo.qll:20:11:20:11 | ComparisonOp | semmle.label | getOperator() |
| Foo.qll:20:3:20:13 | ComparisonFormula | Foo.qll:20:11:20:11 | ComparisonOp | semmle.order | 64 |
| Foo.qll:20:3:20:13 | ComparisonFormula | Foo.qll:20:11:20:11 | ComparisonOp | semmle.order | 65 |
| Foo.qll:20:3:20:13 | ComparisonFormula | Foo.qll:20:13:20:13 | f | semmle.label | getRightOperand() |
| Foo.qll:20:3:20:13 | ComparisonFormula | Foo.qll:20:13:20:13 | f | semmle.order | 65 |
| Foo.qll:20:3:20:13 | ComparisonFormula | Foo.qll:20:13:20:13 | f | semmle.order | 66 |
| Foo.qll:22:3:22:16 | ComparisonFormula | Foo.qll:22:3:22:3 | f | semmle.label | getLeftOperand() |
| Foo.qll:22:3:22:16 | ComparisonFormula | Foo.qll:22:3:22:3 | f | semmle.order | 66 |
| Foo.qll:22:3:22:16 | ComparisonFormula | Foo.qll:22:3:22:3 | f | semmle.order | 67 |
| Foo.qll:22:3:22:16 | ComparisonFormula | Foo.qll:22:5:22:5 | ComparisonOp | semmle.label | getOperator() |
| Foo.qll:22:3:22:16 | ComparisonFormula | Foo.qll:22:5:22:5 | ComparisonOp | semmle.order | 68 |
| Foo.qll:22:3:22:16 | ComparisonFormula | Foo.qll:22:5:22:5 | ComparisonOp | semmle.order | 69 |
| Foo.qll:22:3:22:16 | ComparisonFormula | Foo.qll:22:7:22:16 | FullAggregate[any] | semmle.label | getRightOperand() |
| Foo.qll:22:3:22:16 | ComparisonFormula | Foo.qll:22:7:22:16 | FullAggregate[any] | semmle.order | 69 |
| Foo.qll:22:3:22:16 | ComparisonFormula | Foo.qll:22:7:22:16 | FullAggregate[any] | semmle.order | 70 |
| Foo.qll:22:7:22:16 | FullAggregate[any] | Foo.qll:22:11:22:15 | f | semmle.label | getArgument(_) |
| Foo.qll:22:7:22:16 | FullAggregate[any] | Foo.qll:22:11:22:15 | f | semmle.order | 70 |
| Foo.qll:22:7:22:16 | FullAggregate[any] | Foo.qll:22:11:22:15 | f | semmle.order | 71 |
| Foo.qll:22:11:22:15 | f | Foo.qll:22:11:22:13 | TypeExpr | semmle.label | getTypeExpr() |
| Foo.qll:22:11:22:15 | f | Foo.qll:22:11:22:13 | TypeExpr | semmle.order | 70 |
| Foo.qll:22:11:22:15 | f | Foo.qll:22:11:22:13 | TypeExpr | semmle.order | 71 |
| Foo.qll:24:3:24:23 | ComparisonFormula | Foo.qll:24:3:24:3 | Integer | semmle.label | getLeftOperand() |
| Foo.qll:24:3:24:23 | ComparisonFormula | Foo.qll:24:3:24:3 | Integer | semmle.order | 72 |
| Foo.qll:24:3:24:23 | ComparisonFormula | Foo.qll:24:3:24:3 | Integer | semmle.order | 73 |
| Foo.qll:24:3:24:23 | ComparisonFormula | Foo.qll:24:5:24:5 | ComparisonOp | semmle.label | getOperator() |
| Foo.qll:24:3:24:23 | ComparisonFormula | Foo.qll:24:5:24:5 | ComparisonOp | semmle.order | 74 |
| Foo.qll:24:3:24:23 | ComparisonFormula | Foo.qll:24:5:24:5 | ComparisonOp | semmle.order | 75 |
| Foo.qll:24:3:24:23 | ComparisonFormula | Foo.qll:24:7:24:23 | AddExpr | semmle.label | getRightOperand() |
| Foo.qll:24:3:24:23 | ComparisonFormula | Foo.qll:24:7:24:23 | AddExpr | semmle.order | 75 |
| Foo.qll:24:3:24:23 | ComparisonFormula | Foo.qll:24:7:24:23 | AddExpr | semmle.order | 76 |
| Foo.qll:24:7:24:23 | AddExpr | Foo.qll:24:7:24:7 | Integer | semmle.label | getLeftOperand() |
| Foo.qll:24:7:24:23 | AddExpr | Foo.qll:24:7:24:7 | Integer | semmle.order | 75 |
| Foo.qll:24:7:24:23 | AddExpr | Foo.qll:24:7:24:7 | Integer | semmle.order | 76 |
| Foo.qll:24:7:24:23 | AddExpr | Foo.qll:24:12:24:22 | AddExpr | semmle.label | getRightOperand() |
| Foo.qll:24:7:24:23 | AddExpr | Foo.qll:24:12:24:22 | AddExpr | semmle.order | 77 |
| Foo.qll:24:7:24:23 | AddExpr | Foo.qll:24:12:24:22 | AddExpr | semmle.order | 78 |
| Foo.qll:24:12:24:22 | AddExpr | Foo.qll:24:12:24:12 | Integer | semmle.label | getLeftOperand() |
| Foo.qll:24:12:24:22 | AddExpr | Foo.qll:24:12:24:12 | Integer | semmle.order | 77 |
| Foo.qll:24:12:24:22 | AddExpr | Foo.qll:24:12:24:12 | Integer | semmle.order | 78 |
| Foo.qll:24:12:24:22 | AddExpr | Foo.qll:24:17:24:21 | AddExpr | semmle.label | getRightOperand() |
| Foo.qll:24:12:24:22 | AddExpr | Foo.qll:24:17:24:21 | AddExpr | semmle.order | 79 |
| Foo.qll:24:12:24:22 | AddExpr | Foo.qll:24:17:24:21 | AddExpr | semmle.order | 80 |
| Foo.qll:24:17:24:21 | AddExpr | Foo.qll:24:17:24:17 | Integer | semmle.label | getLeftOperand() |
| Foo.qll:24:17:24:21 | AddExpr | Foo.qll:24:17:24:17 | Integer | semmle.order | 79 |
| Foo.qll:24:17:24:21 | AddExpr | Foo.qll:24:17:24:17 | Integer | semmle.order | 80 |
| Foo.qll:24:17:24:21 | AddExpr | Foo.qll:24:21:24:21 | Integer | semmle.label | getRightOperand() |
| Foo.qll:24:17:24:21 | AddExpr | Foo.qll:24:21:24:21 | Integer | semmle.order | 81 |
| Foo.qll:24:17:24:21 | AddExpr | Foo.qll:24:21:24:21 | Integer | semmle.order | 82 |
| Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:3:26:6 | Boolean | semmle.label | getLeftOperand() |
| Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:3:26:6 | Boolean | semmle.order | 82 |
| Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:3:26:6 | Boolean | semmle.order | 83 |
| Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:8:26:8 | ComparisonOp | semmle.label | getOperator() |
| Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:8:26:8 | ComparisonOp | semmle.order | 84 |
| Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:8:26:8 | ComparisonOp | semmle.order | 85 |
| Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:10:26:14 | Boolean | semmle.label | getRightOperand() |
| Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:10:26:14 | Boolean | semmle.order | 85 |
| Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:10:26:14 | Boolean | semmle.order | 86 |
| printAst.ql:1:1:1:29 | TopLevel | printAst.ql:1:1:1:28 | Import | semmle.label | getAnImport() |
| printAst.ql:1:1:1:29 | TopLevel | printAst.ql:1:1:1:28 | Import | semmle.order | 86 |
| printAst.ql:1:1:1:29 | TopLevel | printAst.ql:1:1:1:28 | Import | semmle.order | 87 |
graphProperties
| semmle.graphKind | tree |

View File

@@ -0,0 +1,8 @@
| test.qll:4:3:7:7 | Disjunction | This formula of 4 comparisons can be replaced with a single equality on a set literal, improving readability. |
| test.qll:30:3:33:10 | Disjunction | This formula of 4 predicate calls can be replaced with a single call on a set literal, improving readability. |
| test.qll:44:3:47:12 | Disjunction | This formula of 4 comparisons can be replaced with a single equality on a set literal, improving readability. |
| test.qll:62:7:65:14 | Disjunction | This formula of 4 comparisons can be replaced with a single equality on a set literal, improving readability. |
| test.qll:68:7:71:13 | Disjunction | This formula of 4 comparisons can be replaced with a single equality on a set literal, improving readability. |
| test.qll:74:7:77:13 | Disjunction | This formula of 4 comparisons can be replaced with a single equality on a set literal, improving readability. |
| test.qll:87:3:90:9 | Disjunction | This formula of 4 predicate calls can be replaced with a single call on a set literal, improving readability. |
| test.qll:128:3:134:3 | Disjunction | This formula of 4 comparisons can be replaced with a single equality on a set literal, improving readability. |

View File

@@ -0,0 +1 @@
queries/style/UseSetLiteral.ql

View File

@@ -0,0 +1,135 @@
import ql
predicate test1(int a) {
a = 1 or // BAD
a = 2 or
a = 3 or
a = 4
}
predicate test2(int a) {
a = [1, 2, 3, 4] // GOOD
}
predicate test3(int a) {
a = 1 and // GOOD (for the purposes of this query)
a = 2 and
a = 3 and
a = 4
}
bindingset[a]
predicate test4(int a) {
a < 1 or // GOOD (for the purposes of this query)
a = 2 or
a >= 3 or
a > 4
}
predicate test5() {
test1(1) or // BAD
test1(2) or
test1(3) or
test1(4)
}
predicate test6() {
test1(1) or // GOOD
test2(2) or
test3(3) or
test4(4)
}
int test7() {
1 = result or // BAD
2 = result or
3 = result or
4 = result
}
predicate test8() {
test7() = 1 or // BAD [NOT DETECTED]
test7() = 2 or
test7() = 3 or
test7() = 4
}
class MyTest8Class extends int {
string s;
MyTest8Class() {
(
this = 1 or // BAD
this = 2 or
this = 3 or
this = 4
) and
(
s = "1" or // BAD
s = "2" or
s = "3" or
s = "4"
) and
exists(float f |
f = 1.0 or // BAD
f = 1.5 or
f = 2.0 or
f = 2.5
)
}
predicate is(int x) { x = this }
int get() { result = this }
}
predicate test9(MyTest8Class c) {
c.is(1) or // BAD
c.is(2) or
c.is(3) or
c.is(4)
}
predicate test10(MyTest8Class c) {
c.get() = 1 or // BAD [NOT DETECTED]
c.get() = 2 or
c.get() = 3 or
c.get() = 4
}
bindingset[a, b, c, d]
predicate test11(int a, int b, int c, int d) {
a = 1 or // GOOD
b = 2 or
c = 3 or
d = 4
}
bindingset[a, b]
predicate test12(int a, int b) {
a = 1 or // BAD [NOT DETECTED]
a = 2 or
a = 3 or
a = 4 or
b = 0
}
predicate test13(int a, int b) {
a = 1 and b = 1 // GOOD
or
a = 2 and b = 4
or
a = 3 and b = 9
or
a = 4 and b = 16
}
predicate test14(int a) {
a = 1 // BAD
or
(
(a = 2 or a = 3)
or
a = 4
)
}

View File

@@ -4,6 +4,8 @@ type NUL && "%CODEQL_DIST%\codeql.exe" database index-files ^
--prune=**/*.testproj ^
--include-extension=.ql ^
--include-extension=.qll ^
--include-extension=.dbscheme ^
--include-extension=.yml ^
--size-limit=5m ^
--language=ql ^
"%CODEQL_EXTRACTOR_QL_WIP_DATABASE%"

View File

@@ -6,6 +6,8 @@ exec "${CODEQL_DIST}/codeql" database index-files \
--prune="**/*.testproj" \
--include-extension=.ql \
--include-extension=.qll \
--include-extension=.dbscheme \
--include-extension=.yml \
--size-limit=5m \
--language=ql \
--working-dir=.\