mirror of
https://github.com/github/codeql.git
synced 2026-07-07 12:35:33 +02:00
Compare commits
62 Commits
codeql-cli
...
smowton/ad
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b512d65918 | ||
|
|
ebdf553621 | ||
|
|
3e8274ede8 | ||
|
|
06e5962da7 | ||
|
|
03c0366fd4 | ||
|
|
789b0a46d1 | ||
|
|
8fcbaea273 | ||
|
|
c015ef6ef4 | ||
|
|
489355cdab | ||
|
|
093a3879be | ||
|
|
a737350f27 | ||
|
|
bf921177f4 | ||
|
|
0187e9a3b1 | ||
|
|
be5363ea53 | ||
|
|
650d57083b | ||
|
|
bcaba45202 | ||
|
|
059dea713d | ||
|
|
dca74a1f45 | ||
|
|
d309e15072 | ||
|
|
35471ff23c | ||
|
|
52dc016a7a | ||
|
|
e85cdf2ec3 | ||
|
|
a5189eae9f | ||
|
|
f4581ae866 | ||
|
|
83fdff54c4 | ||
|
|
c20ce62767 | ||
|
|
813de65118 | ||
|
|
a09fd8c35e | ||
|
|
8139e1a2a8 | ||
|
|
bd09c61504 | ||
|
|
0ec5aa6095 | ||
|
|
addb92f13b | ||
|
|
325b451288 | ||
|
|
6180970ae7 | ||
|
|
74906fcbaf | ||
|
|
c6e66edb97 | ||
|
|
ea229d361c | ||
|
|
b4542c58c2 | ||
|
|
44216b29a9 | ||
|
|
4c66f50352 | ||
|
|
fec2837c1e | ||
|
|
ddb682b181 | ||
|
|
37a76f4441 | ||
|
|
c9db6201ef | ||
|
|
7d5c80433d | ||
|
|
37b3a6e5c0 | ||
|
|
c79c9dd573 | ||
|
|
8726766465 | ||
|
|
f6fd401df1 | ||
|
|
f9e5c6b77d | ||
|
|
f533636ad7 | ||
|
|
90505949c7 | ||
|
|
27d87e9300 | ||
|
|
24697feebc | ||
|
|
197ea5b8f3 | ||
|
|
71f9b25500 | ||
|
|
64496b4c97 | ||
|
|
91fd83a554 | ||
|
|
ae3b32409a | ||
|
|
20599d1846 | ||
|
|
e79eecb640 | ||
|
|
c5fb19c377 |
@@ -2,28 +2,41 @@
|
|||||||
# See https://pre-commit.com/hooks.html for more hooks
|
# See https://pre-commit.com/hooks.html for more hooks
|
||||||
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)
|
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v3.2.0
|
rev: v3.2.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
|
|
||||||
- repo: local
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||||
|
rev: v13.0.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: codeql-format
|
- id: clang-format
|
||||||
|
files: ^swift/.*\.(h|c|cpp)$
|
||||||
|
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: codeql-format
|
||||||
name: Fix QL file formatting
|
name: Fix QL file formatting
|
||||||
files: \.qll?$
|
files: \.qll?$
|
||||||
language: system
|
language: system
|
||||||
entry: codeql query format --in-place
|
entry: codeql query format --in-place
|
||||||
|
|
||||||
- id: sync-files
|
- id: sync-files
|
||||||
name: Fix files required to be identical
|
name: Fix files required to be identical
|
||||||
language: system
|
language: system
|
||||||
entry: python3 config/sync-files.py --latest
|
entry: python3 config/sync-files.py --latest
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
|
|
||||||
- id: qhelp
|
- id: qhelp
|
||||||
name: Check query help generation
|
name: Check query help generation
|
||||||
files: \.qhelp$
|
files: \.qhelp$
|
||||||
language: system
|
language: system
|
||||||
entry: python3 misc/scripts/check-qhelp.py
|
entry: python3 misc/scripts/check-qhelp.py
|
||||||
|
|
||||||
|
- id: swift-codegen
|
||||||
|
name: Run Swift checked in code generation
|
||||||
|
files: ^swift/(codegen/|.*/generated/|ql/lib/swift\.dbscheme$)
|
||||||
|
language: system
|
||||||
|
entry: bazel run //swift/codegen
|
||||||
|
pass_filenames: false
|
||||||
|
|||||||
@@ -51,6 +51,7 @@
|
|||||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll",
|
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll",
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||||
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||||
|
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingImpl.qll",
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking1/TaintTrackingImpl.qll",
|
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking2/TaintTrackingImpl.qll",
|
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
|
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
|
||||||
|
|||||||
@@ -27,11 +27,11 @@ int getBufferSize(Expr bufferExpr, Element why) {
|
|||||||
result = bufferVar.getUnspecifiedType().(ArrayType).getSize() and
|
result = bufferVar.getUnspecifiedType().(ArrayType).getSize() and
|
||||||
why = bufferVar and
|
why = bufferVar and
|
||||||
not memberMayBeVarSize(_, bufferVar) and
|
not memberMayBeVarSize(_, bufferVar) and
|
||||||
not result = 0 // zero sized arrays are likely to have special usage, for example
|
// zero sized arrays are likely to have special usage, for example
|
||||||
or
|
|
||||||
// behaving a bit like a 'union' overlapping other fields.
|
// behaving a bit like a 'union' overlapping other fields.
|
||||||
// buffer is an initialized array
|
not result = 0
|
||||||
// e.g. int buffer[] = {1, 2, 3};
|
or
|
||||||
|
// buffer is an initialized array, e.g., int buffer[] = {1, 2, 3};
|
||||||
why = bufferVar.getInitializer().getExpr() and
|
why = bufferVar.getInitializer().getExpr() and
|
||||||
(
|
(
|
||||||
why instanceof AggregateLiteral or
|
why instanceof AggregateLiteral or
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ private predicate isOpaqueType(Type type) {
|
|||||||
* Holds if an `IROpaqueType` with the specified `tag` and `byteSize` should exist.
|
* Holds if an `IROpaqueType` with the specified `tag` and `byteSize` should exist.
|
||||||
*/
|
*/
|
||||||
predicate hasOpaqueType(Type tag, int byteSize) {
|
predicate hasOpaqueType(Type tag, int byteSize) {
|
||||||
isOpaqueType(tag) and byteSize = getTypeSize(tag)
|
isOpaqueType(tag) and byteSize = getTypeSize(tag.getUnspecifiedType())
|
||||||
or
|
or
|
||||||
tag instanceof UnknownType and Raw::needsUnknownOpaqueType(byteSize)
|
tag instanceof UnknownType and Raw::needsUnknownOpaqueType(byteSize)
|
||||||
}
|
}
|
||||||
@@ -153,17 +153,18 @@ private IRType getIRTypeForPRValue(Type type) {
|
|||||||
exists(Type unspecifiedType | unspecifiedType = type.getUnspecifiedType() |
|
exists(Type unspecifiedType | unspecifiedType = type.getUnspecifiedType() |
|
||||||
isOpaqueType(unspecifiedType) and
|
isOpaqueType(unspecifiedType) and
|
||||||
exists(IROpaqueType opaqueType | opaqueType = result |
|
exists(IROpaqueType opaqueType | opaqueType = result |
|
||||||
opaqueType.getByteSize() = getTypeSize(type) and
|
opaqueType.getByteSize() = getTypeSize(unspecifiedType) and
|
||||||
opaqueType.getTag() = unspecifiedType
|
opaqueType.getTag() = unspecifiedType
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
unspecifiedType instanceof BoolType and result.(IRBooleanType).getByteSize() = type.getSize()
|
unspecifiedType instanceof BoolType and
|
||||||
|
result.(IRBooleanType).getByteSize() = unspecifiedType.getSize()
|
||||||
or
|
or
|
||||||
isSignedIntegerType(unspecifiedType) and
|
isSignedIntegerType(unspecifiedType) and
|
||||||
result.(IRSignedIntegerType).getByteSize() = type.getSize()
|
result.(IRSignedIntegerType).getByteSize() = unspecifiedType.getSize()
|
||||||
or
|
or
|
||||||
isUnsignedIntegerType(unspecifiedType) and
|
isUnsignedIntegerType(unspecifiedType) and
|
||||||
result.(IRUnsignedIntegerType).getByteSize() = type.getSize()
|
result.(IRUnsignedIntegerType).getByteSize() = unspecifiedType.getSize()
|
||||||
or
|
or
|
||||||
exists(FloatingPointType floatType, IRFloatingPointType irFloatType |
|
exists(FloatingPointType floatType, IRFloatingPointType irFloatType |
|
||||||
floatType = unspecifiedType and
|
floatType = unspecifiedType and
|
||||||
@@ -173,7 +174,8 @@ private IRType getIRTypeForPRValue(Type type) {
|
|||||||
irFloatType.getDomain() = floatType.getDomain()
|
irFloatType.getDomain() = floatType.getDomain()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
isPointerIshType(unspecifiedType) and result.(IRAddressType).getByteSize() = getTypeSize(type)
|
isPointerIshType(unspecifiedType) and
|
||||||
|
result.(IRAddressType).getByteSize() = getTypeSize(unspecifiedType)
|
||||||
or
|
or
|
||||||
unspecifiedType instanceof FunctionPointerIshType and
|
unspecifiedType instanceof FunctionPointerIshType and
|
||||||
result.(IRFunctionAddressType).getByteSize() = getTypeSize(type)
|
result.(IRFunctionAddressType).getByteSize() = getTypeSize(type)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
| templates.cpp:9:5:9:14 | using c | UsingDeclarationEntry, enclosingElement:std |
|
| templates.cpp:9:14:9:14 | using c | UsingDeclarationEntry, enclosingElement:std |
|
||||||
| usings.cpp:8:1:8:11 | using nf | UsingDeclarationEntry, enclosingElement:(global namespace) |
|
| usings.cpp:8:10:8:11 | using nf | UsingDeclarationEntry, enclosingElement:(global namespace) |
|
||||||
| usings.cpp:9:1:9:17 | using namespace N | UsingDirectiveEntry, enclosingElement:(global namespace) |
|
| usings.cpp:9:1:9:17 | using namespace N | UsingDirectiveEntry, enclosingElement:(global namespace) |
|
||||||
| usings.cpp:18:3:18:13 | using bf | UsingDeclarationEntry, enclosingElement:D |
|
| usings.cpp:18:12:18:13 | using bf | UsingDeclarationEntry, enclosingElement:D |
|
||||||
| usings.cpp:21:5:21:14 | using gf | UsingDeclarationEntry, enclosingElement:{ ... } |
|
| usings.cpp:21:13:21:14 | using gf | UsingDeclarationEntry, enclosingElement:{ ... } |
|
||||||
| usings.cpp:34:3:34:20 | using tbf | UsingDeclarationEntry, enclosingElement:TD |
|
| usings.cpp:34:18:34:20 | using tbf | UsingDeclarationEntry, enclosingElement:TD |
|
||||||
| usings.cpp:42:5:42:22 | using foo | UsingDeclarationEntry, enclosingElement:nsbar |
|
| usings.cpp:42:20:42:22 | using foo | UsingDeclarationEntry, enclosingElement:nsbar |
|
||||||
|
|||||||
@@ -42,9 +42,7 @@ module AccessPath {
|
|||||||
* Parses a lower-bounded interval `n..` and gets the lower bound.
|
* Parses a lower-bounded interval `n..` and gets the lower bound.
|
||||||
*/
|
*/
|
||||||
bindingset[arg]
|
bindingset[arg]
|
||||||
private int parseLowerBound(string arg) {
|
int parseLowerBound(string arg) { result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt() }
|
||||||
result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses an integer constant or interval (bounded or unbounded) that explicitly
|
* Parses an integer constant or interval (bounded or unbounded) that explicitly
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ private import semmle.code.csharp.commons.Util as Util
|
|||||||
private import semmle.code.csharp.commons.Collections as Collections
|
private import semmle.code.csharp.commons.Collections as Collections
|
||||||
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
|
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
|
||||||
private import semmle.code.csharp.frameworks.System as System
|
private import semmle.code.csharp.frameworks.System as System
|
||||||
|
private import semmle.code.csharp.frameworks.system.linq.Expressions
|
||||||
import semmle.code.csharp.dataflow.ExternalFlow as ExternalFlow
|
import semmle.code.csharp.dataflow.ExternalFlow as ExternalFlow
|
||||||
import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
|
import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
|
||||||
import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
||||||
@@ -18,21 +19,11 @@ module TaintTracking = CS::TaintTracking;
|
|||||||
class Type = CS::Type;
|
class Type = CS::Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `api` is an override or an interface implementation that
|
* Holds if any of the parameters of `api` are `System.Func<>`.
|
||||||
* is irrelevant to the data flow analysis.
|
|
||||||
*/
|
*/
|
||||||
private predicate isIrrelevantOverrideOrImplementation(CS::Callable api) {
|
private predicate isHigherOrder(CS::Callable api) {
|
||||||
exists(CS::Callable exclude, CS::Method m |
|
exists(Type t | t = api.getAParameter().getType().getUnboundDeclaration() |
|
||||||
(
|
t instanceof SystemLinqExpressions::DelegateExtType
|
||||||
api = m.getAnOverrider*().getUnboundDeclaration()
|
|
||||||
or
|
|
||||||
api = m.getAnUltimateImplementor().getUnboundDeclaration()
|
|
||||||
) and
|
|
||||||
exclude = m.getUnboundDeclaration()
|
|
||||||
|
|
|
||||||
exists(System::SystemObjectClass c | exclude = [c.getGetHashCodeMethod(), c.getEqualsMethod()])
|
|
||||||
or
|
|
||||||
exists(System::SystemIEquatableTInterface i | exclude = i.getEqualsMethod())
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +35,7 @@ private predicate isRelevantForModels(CS::Callable api) {
|
|||||||
api.getDeclaringType().getNamespace().getQualifiedName() != "" and
|
api.getDeclaringType().getNamespace().getQualifiedName() != "" and
|
||||||
not api instanceof CS::ConversionOperator and
|
not api instanceof CS::ConversionOperator and
|
||||||
not api instanceof Util::MainMethod and
|
not api instanceof Util::MainMethod and
|
||||||
not isIrrelevantOverrideOrImplementation(api)
|
not isHigherOrder(api)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,8 +56,13 @@ predicate asPartialModel = DataFlowPrivate::Csv::asPartialModel/1;
|
|||||||
/**
|
/**
|
||||||
* Holds for type `t` for fields that are relevant as an intermediate
|
* Holds for type `t` for fields that are relevant as an intermediate
|
||||||
* read or write step in the data flow analysis.
|
* read or write step in the data flow analysis.
|
||||||
|
* That is, flow through any data-flow node that does not have a relevant type
|
||||||
|
* will be excluded.
|
||||||
*/
|
*/
|
||||||
predicate isRelevantType(CS::Type t) { not t instanceof CS::Enum }
|
predicate isRelevantType(CS::Type t) {
|
||||||
|
not t instanceof CS::SimpleType and
|
||||||
|
not t instanceof CS::Enum
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the CSV string representation of the qualifier.
|
* Gets the CSV string representation of the qualifier.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
| NoSummaries;PublicClassFlow;false;PublicReturn;(System.Int32);;Argument[0];ReturnValue;generated:taint |
|
| NoSummaries;PublicClassFlow;false;PublicReturn;(System.Object);;Argument[0];ReturnValue;generated:taint |
|
||||||
| Summaries;BaseClassFlow;true;ReturnParam;(System.Int32);;Argument[0];ReturnValue;generated:taint |
|
| Summaries;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;generated:taint |
|
||||||
| Summaries;BasicFlow;false;ReturnField;();;Argument[Qualifier];ReturnValue;generated:taint |
|
| Summaries;BasicFlow;false;ReturnField;();;Argument[Qualifier];ReturnValue;generated:taint |
|
||||||
| Summaries;BasicFlow;false;ReturnParam0;(System.String,System.Object);;Argument[0];ReturnValue;generated:taint |
|
| Summaries;BasicFlow;false;ReturnParam0;(System.String,System.Object);;Argument[0];ReturnValue;generated:taint |
|
||||||
| Summaries;BasicFlow;false;ReturnParam1;(System.String,System.Object);;Argument[1];ReturnValue;generated:taint |
|
| Summaries;BasicFlow;false;ReturnParam1;(System.String,System.Object);;Argument[1];ReturnValue;generated:taint |
|
||||||
@@ -11,14 +11,14 @@
|
|||||||
| Summaries;CollectionFlow;false;AddFieldToList;(System.Collections.Generic.List<System.String>);;Argument[Qualifier];Argument[0].Element;generated:taint |
|
| Summaries;CollectionFlow;false;AddFieldToList;(System.Collections.Generic.List<System.String>);;Argument[Qualifier];Argument[0].Element;generated:taint |
|
||||||
| Summaries;CollectionFlow;false;AddToList;(System.Collections.Generic.List<System.Object>,System.Object);;Argument[1];Argument[0].Element;generated:taint |
|
| Summaries;CollectionFlow;false;AddToList;(System.Collections.Generic.List<System.Object>,System.Object);;Argument[1];Argument[0].Element;generated:taint |
|
||||||
| Summaries;CollectionFlow;false;AssignFieldToArray;(System.Object[]);;Argument[Qualifier];Argument[0].Element;generated:taint |
|
| Summaries;CollectionFlow;false;AssignFieldToArray;(System.Object[]);;Argument[Qualifier];Argument[0].Element;generated:taint |
|
||||||
| Summaries;CollectionFlow;false;AssignToArray;(System.Int32,System.Int32[]);;Argument[0];Argument[1].Element;generated:taint |
|
| Summaries;CollectionFlow;false;AssignToArray;(System.Object,System.Object[]);;Argument[0];Argument[1].Element;generated:taint |
|
||||||
| Summaries;CollectionFlow;false;ReturnArrayElement;(System.Int32[]);;Argument[0].Element;ReturnValue;generated:taint |
|
| Summaries;CollectionFlow;false;ReturnArrayElement;(System.Object[]);;Argument[0].Element;ReturnValue;generated:taint |
|
||||||
| Summaries;CollectionFlow;false;ReturnFieldInAList;();;Argument[Qualifier];ReturnValue;generated:taint |
|
| Summaries;CollectionFlow;false;ReturnFieldInAList;();;Argument[Qualifier];ReturnValue;generated:taint |
|
||||||
| Summaries;CollectionFlow;false;ReturnListElement;(System.Collections.Generic.List<System.Object>);;Argument[0].Element;ReturnValue;generated:taint |
|
| Summaries;CollectionFlow;false;ReturnListElement;(System.Collections.Generic.List<System.Object>);;Argument[0].Element;ReturnValue;generated:taint |
|
||||||
| Summaries;DerivedClass1Flow;false;ReturnParam1;(System.Int32,System.Int32);;Argument[1];ReturnValue;generated:taint |
|
| Summaries;DerivedClass1Flow;false;ReturnParam1;(System.String,System.String);;Argument[1];ReturnValue;generated:taint |
|
||||||
| Summaries;DerivedClass2Flow;false;ReturnParam0;(System.Int32,System.Int32);;Argument[0];ReturnValue;generated:taint |
|
| Summaries;DerivedClass2Flow;false;ReturnParam0;(System.String,System.Int32);;Argument[0];ReturnValue;generated:taint |
|
||||||
| Summaries;DerivedClass2Flow;false;ReturnParam;(System.Int32);;Argument[0];ReturnValue;generated:taint |
|
| Summaries;DerivedClass2Flow;false;ReturnParam;(System.Object);;Argument[0];ReturnValue;generated:taint |
|
||||||
| Summaries;EqualsGetHashCodeNoFlow;false;Equals;(System.Int32);;Argument[0];ReturnValue;generated:taint |
|
| Summaries;EqualsGetHashCodeNoFlow;false;Equals;(System.String);;Argument[0];ReturnValue;generated:taint |
|
||||||
| Summaries;GenericFlow<>;false;AddFieldToGenericList;(System.Collections.Generic.List<T>);;Argument[Qualifier];Argument[0].Element;generated:taint |
|
| Summaries;GenericFlow<>;false;AddFieldToGenericList;(System.Collections.Generic.List<T>);;Argument[Qualifier];Argument[0].Element;generated:taint |
|
||||||
| Summaries;GenericFlow<>;false;AddToGenericList<>;(System.Collections.Generic.List<S>,S);;Argument[1];Argument[0].Element;generated:taint |
|
| Summaries;GenericFlow<>;false;AddToGenericList<>;(System.Collections.Generic.List<S>,S);;Argument[1];Argument[0].Element;generated:taint |
|
||||||
| Summaries;GenericFlow<>;false;ReturnFieldInGenericList;();;Argument[Qualifier];ReturnValue;generated:taint |
|
| Summaries;GenericFlow<>;false;ReturnFieldInGenericList;();;Argument[Qualifier];ReturnValue;generated:taint |
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace NoSummaries;
|
|||||||
// Just to prove that, if a method like this is correctly exposed, a flow summary will be captured.
|
// Just to prove that, if a method like this is correctly exposed, a flow summary will be captured.
|
||||||
public class PublicClassFlow
|
public class PublicClassFlow
|
||||||
{
|
{
|
||||||
public int PublicReturn(int input)
|
public object PublicReturn(object input)
|
||||||
{
|
{
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
@@ -14,19 +14,19 @@ public class PublicClassFlow
|
|||||||
|
|
||||||
public sealed class PublicClassNoFlow
|
public sealed class PublicClassNoFlow
|
||||||
{
|
{
|
||||||
private int PrivateReturn(int input)
|
private object PrivateReturn(object input)
|
||||||
{
|
{
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal int InternalReturn(int input)
|
internal object InternalReturn(object input)
|
||||||
{
|
{
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PrivateClassNoFlow
|
private class PrivateClassNoFlow
|
||||||
{
|
{
|
||||||
public int ReturnParam(int input)
|
public object ReturnParam(object input)
|
||||||
{
|
{
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,7 @@ public sealed class PublicClassNoFlow
|
|||||||
{
|
{
|
||||||
public class NestedPublicClassFlow
|
public class NestedPublicClassFlow
|
||||||
{
|
{
|
||||||
public int ReturnParam(int input)
|
public object ReturnParam(object input)
|
||||||
{
|
{
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
@@ -44,10 +44,10 @@ public sealed class PublicClassNoFlow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EquatableBound : IEquatable<int>
|
public class EquatableBound : IEquatable<object>
|
||||||
{
|
{
|
||||||
public readonly bool tainted;
|
public readonly bool tainted;
|
||||||
public bool Equals(int other)
|
public bool Equals(object other)
|
||||||
{
|
{
|
||||||
return tainted;
|
return tainted;
|
||||||
}
|
}
|
||||||
@@ -61,3 +61,41 @@ public class EquatableUnBound<T> : IEquatable<T>
|
|||||||
return tainted;
|
return tainted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No methods in this class will have generated flow summaries as
|
||||||
|
// simple types are used.
|
||||||
|
public class SimpleTypes
|
||||||
|
{
|
||||||
|
public bool M1(bool b)
|
||||||
|
{
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean M2(Boolean b)
|
||||||
|
{
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int M3(int i)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Int32 M4(Int32 i)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HigherOrderParameters
|
||||||
|
{
|
||||||
|
public string M1(string s, Func<string, string> map)
|
||||||
|
{
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object M2(Func<object, object> map, object o)
|
||||||
|
{
|
||||||
|
return map(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,12 +48,12 @@ public class CollectionFlow
|
|||||||
{
|
{
|
||||||
private string tainted;
|
private string tainted;
|
||||||
|
|
||||||
public int ReturnArrayElement(int[] input)
|
public object ReturnArrayElement(object[] input)
|
||||||
{
|
{
|
||||||
return input[0];
|
return input[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AssignToArray(int data, int[] target)
|
public void AssignToArray(object data, object[] target)
|
||||||
{
|
{
|
||||||
target[0] = data;
|
target[0] = data;
|
||||||
}
|
}
|
||||||
@@ -146,7 +146,7 @@ public class GenericFlow<T>
|
|||||||
|
|
||||||
public abstract class BaseClassFlow
|
public abstract class BaseClassFlow
|
||||||
{
|
{
|
||||||
public virtual int ReturnParam(int input)
|
public virtual object ReturnParam(object input)
|
||||||
{
|
{
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
@@ -154,7 +154,7 @@ public abstract class BaseClassFlow
|
|||||||
|
|
||||||
public class DerivedClass1Flow : BaseClassFlow
|
public class DerivedClass1Flow : BaseClassFlow
|
||||||
{
|
{
|
||||||
public int ReturnParam1(int input0, int input1)
|
public string ReturnParam1(string input0, string input1)
|
||||||
{
|
{
|
||||||
return input1;
|
return input1;
|
||||||
}
|
}
|
||||||
@@ -162,12 +162,12 @@ public class DerivedClass1Flow : BaseClassFlow
|
|||||||
|
|
||||||
public class DerivedClass2Flow : BaseClassFlow
|
public class DerivedClass2Flow : BaseClassFlow
|
||||||
{
|
{
|
||||||
public override int ReturnParam(int input)
|
public override object ReturnParam(object input)
|
||||||
{
|
{
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ReturnParam0(int input0, int input1)
|
public string ReturnParam0(string input0, int input1)
|
||||||
{
|
{
|
||||||
return input0;
|
return input0;
|
||||||
}
|
}
|
||||||
@@ -195,13 +195,13 @@ public class OperatorFlow
|
|||||||
}
|
}
|
||||||
|
|
||||||
// No flow summary as this is an implicit conversion operator.
|
// No flow summary as this is an implicit conversion operator.
|
||||||
public static implicit operator OperatorFlow(int i)
|
public static implicit operator OperatorFlow(string s)
|
||||||
{
|
{
|
||||||
return new OperatorFlow(i);
|
return new OperatorFlow(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// No flow summary as this is an explicit conversion operator.
|
// No flow summary as this is an explicit conversion operator.
|
||||||
public static explicit operator OperatorFlow(byte b)
|
public static explicit operator OperatorFlow(string[] b)
|
||||||
{
|
{
|
||||||
return new OperatorFlow(b);
|
return new OperatorFlow(b);
|
||||||
}
|
}
|
||||||
@@ -220,9 +220,9 @@ public class EqualsGetHashCodeNoFlow
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Flow summary as this is not an override of the object Equals method.
|
// Flow summary as this is not an override of the object Equals method.
|
||||||
public int Equals(int i)
|
public string Equals(string s)
|
||||||
{
|
{
|
||||||
return i;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No flow summary as this is an override of the GetHashCode method.
|
// No flow summary as this is an override of the GetHashCode method.
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
.NET 5, .NET 6","``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``"
|
.NET 5, .NET 6","``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``"
|
||||||
Go (aka Golang), "Go up to 1.17", "Go 1.11 or more recent", ``.go``
|
Go (aka Golang), "Go up to 1.17", "Go 1.11 or more recent", ``.go``
|
||||||
Java,"Java 7 to 17 [4]_","javac (OpenJDK and Oracle JDK),
|
Java,"Java 7 to 18 [4]_","javac (OpenJDK and Oracle JDK),
|
||||||
|
|
||||||
Eclipse compiler for Java (ECJ) [5]_",``.java``
|
Eclipse compiler for Java (ECJ) [5]_",``.java``
|
||||||
JavaScript,ECMAScript 2021 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [6]_"
|
JavaScript,ECMAScript 2021 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [6]_"
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
.. [1] C++20 support is currently in beta. Supported for GCC on Linux only. Modules are *not* supported.
|
.. [1] C++20 support is currently in beta. Supported for GCC on Linux only. Modules are *not* supported.
|
||||||
.. [2] Support for the clang-cl compiler is preliminary.
|
.. [2] Support for the clang-cl compiler is preliminary.
|
||||||
.. [3] Support for the Arm Compiler (armcc) is preliminary.
|
.. [3] Support for the Arm Compiler (armcc) is preliminary.
|
||||||
.. [4] Builds that execute on Java 7 to 17 can be analyzed. The analysis understands Java 17 standard language features.
|
.. [4] Builds that execute on Java 7 to 18 can be analyzed. The analysis understands Java 18 standard language features.
|
||||||
.. [5] ECJ is supported when the build invokes it via the Maven Compiler plugin or the Takari Lifecycle plugin.
|
.. [5] ECJ is supported when the build invokes it via the Maven Compiler plugin or the Takari Lifecycle plugin.
|
||||||
.. [6] JSX and Flow code, YAML, JSON, HTML, and XML files may also be analyzed with JavaScript files.
|
.. [6] JSX and Flow code, YAML, JSON, HTML, and XML files may also be analyzed with JavaScript files.
|
||||||
.. [7] Requires glibc 2.17.
|
.. [7] Requires glibc 2.17.
|
||||||
|
|||||||
7
java/ql/lib/semmle/code/java/dataflow/TaintTracking3.qll
Normal file
7
java/ql/lib/semmle/code/java/dataflow/TaintTracking3.qll
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* Provides classes for performing local (intra-procedural) and
|
||||||
|
* global (inter-procedural) taint-tracking analyses.
|
||||||
|
*/
|
||||||
|
module TaintTracking3 {
|
||||||
|
import semmle.code.java.dataflow.internal.tainttracking3.TaintTrackingImpl
|
||||||
|
}
|
||||||
@@ -42,9 +42,7 @@ module AccessPath {
|
|||||||
* Parses a lower-bounded interval `n..` and gets the lower bound.
|
* Parses a lower-bounded interval `n..` and gets the lower bound.
|
||||||
*/
|
*/
|
||||||
bindingset[arg]
|
bindingset[arg]
|
||||||
private int parseLowerBound(string arg) {
|
int parseLowerBound(string arg) { result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt() }
|
||||||
result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses an integer constant or interval (bounded or unbounded) that explicitly
|
* Parses an integer constant or interval (bounded or unbounded) that explicitly
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
/**
|
||||||
|
* Provides an implementation of global (interprocedural) taint tracking.
|
||||||
|
* This file re-exports the local (intraprocedural) taint-tracking analysis
|
||||||
|
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
|
||||||
|
* exposed through the `Configuration` class. For some languages, this file
|
||||||
|
* exists in several identical copies, allowing queries to use multiple
|
||||||
|
* `Configuration` classes that depend on each other without introducing
|
||||||
|
* mutual recursion among those configurations.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import TaintTrackingParameter::Public
|
||||||
|
private import TaintTrackingParameter::Private
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A configuration of interprocedural taint tracking analysis. This defines
|
||||||
|
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||||
|
* use of the taint tracking library must define its own unique extension of
|
||||||
|
* this abstract class.
|
||||||
|
*
|
||||||
|
* A taint-tracking configuration is a special data flow configuration
|
||||||
|
* (`DataFlow::Configuration`) that allows for flow through nodes that do not
|
||||||
|
* necessarily preserve values but are still relevant from a taint tracking
|
||||||
|
* perspective. (For example, string concatenation, where one of the operands
|
||||||
|
* is tainted.)
|
||||||
|
*
|
||||||
|
* To create a configuration, extend this class with a subclass whose
|
||||||
|
* characteristic predicate is a unique singleton string. For example, write
|
||||||
|
*
|
||||||
|
* ```ql
|
||||||
|
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
|
||||||
|
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||||
|
* // Override `isSource` and `isSink`.
|
||||||
|
* // Optionally override `isSanitizer`.
|
||||||
|
* // Optionally override `isSanitizerIn`.
|
||||||
|
* // Optionally override `isSanitizerOut`.
|
||||||
|
* // Optionally override `isSanitizerGuard`.
|
||||||
|
* // Optionally override `isAdditionalTaintStep`.
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Then, to query whether there is flow between some `source` and `sink`,
|
||||||
|
* write
|
||||||
|
*
|
||||||
|
* ```ql
|
||||||
|
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Multiple configurations can coexist, but it is unsupported to depend on
|
||||||
|
* another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the
|
||||||
|
* overridden predicates that define sources, sinks, or additional steps.
|
||||||
|
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
|
||||||
|
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
|
||||||
|
*/
|
||||||
|
abstract class Configuration extends DataFlow::Configuration {
|
||||||
|
bindingset[this]
|
||||||
|
Configuration() { any() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `source` is a relevant taint source.
|
||||||
|
*
|
||||||
|
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||||
|
*/
|
||||||
|
// overridden to provide taint-tracking specific qldoc
|
||||||
|
override predicate isSource(DataFlow::Node source) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `source` is a relevant taint source with the given initial
|
||||||
|
* `state`.
|
||||||
|
*
|
||||||
|
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||||
|
*/
|
||||||
|
// overridden to provide taint-tracking specific qldoc
|
||||||
|
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `sink` is a relevant taint sink
|
||||||
|
*
|
||||||
|
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||||
|
*/
|
||||||
|
// overridden to provide taint-tracking specific qldoc
|
||||||
|
override predicate isSink(DataFlow::Node sink) { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `sink` is a relevant taint sink accepting `state`.
|
||||||
|
*
|
||||||
|
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||||
|
*/
|
||||||
|
// overridden to provide taint-tracking specific qldoc
|
||||||
|
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
/** Holds if the node `node` is a taint sanitizer. */
|
||||||
|
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrier(DataFlow::Node node) {
|
||||||
|
this.isSanitizer(node) or
|
||||||
|
defaultTaintSanitizer(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the node `node` is a taint sanitizer when the flow state is
|
||||||
|
* `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizer(node, state)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if taint propagation into `node` is prohibited. */
|
||||||
|
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||||
|
|
||||||
|
/** Holds if taint propagation out of `node` is prohibited. */
|
||||||
|
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||||
|
|
||||||
|
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||||
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||||
|
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
||||||
|
* when the flow state is `state`.
|
||||||
|
*/
|
||||||
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
|
||||||
|
|
||||||
|
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
|
||||||
|
this.isSanitizerGuard(guard, state)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||||
|
*/
|
||||||
|
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||||
|
|
||||||
|
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
|
this.isAdditionalTaintStep(node1, node2) or
|
||||||
|
defaultAdditionalTaintStep(node1, node2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||||
|
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||||
|
*/
|
||||||
|
predicate isAdditionalTaintStep(
|
||||||
|
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||||
|
DataFlow::FlowState state2
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
final override predicate isAdditionalFlowStep(
|
||||||
|
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||||
|
DataFlow::FlowState state2
|
||||||
|
) {
|
||||||
|
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
|
||||||
|
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
|
||||||
|
defaultImplicitTaintRead(node, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if taint may flow from `source` to `sink` for this configuration.
|
||||||
|
*/
|
||||||
|
// overridden to provide taint-tracking specific qldoc
|
||||||
|
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
|
||||||
|
super.hasFlow(source, sink)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import semmle.code.java.dataflow.internal.TaintTrackingUtil as Public
|
||||||
|
|
||||||
|
module Private {
|
||||||
|
import semmle.code.java.dataflow.DataFlow3::DataFlow3 as DataFlow
|
||||||
|
}
|
||||||
@@ -30,7 +30,7 @@ class Yaml extends RefType {
|
|||||||
Yaml() { this.getAnAncestor().hasQualifiedName("org.yaml.snakeyaml", "Yaml") }
|
Yaml() { this.getAnAncestor().hasQualifiedName("org.yaml.snakeyaml", "Yaml") }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SafeYamlConstructionFlowConfig extends DataFlow2::Configuration {
|
private class SafeYamlConstructionFlowConfig extends DataFlow3::Configuration {
|
||||||
SafeYamlConstructionFlowConfig() { this = "SnakeYaml::SafeYamlConstructionFlowConfig" }
|
SafeYamlConstructionFlowConfig() { this = "SnakeYaml::SafeYamlConstructionFlowConfig" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) {
|
override predicate isSource(DataFlow::Node src) {
|
||||||
@@ -65,7 +65,7 @@ private class SnakeYamlParse extends MethodAccess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SafeYamlFlowConfig extends DataFlow3::Configuration {
|
private class SafeYamlFlowConfig extends DataFlow2::Configuration {
|
||||||
SafeYamlFlowConfig() { this = "SnakeYaml::SafeYamlFlowConfig" }
|
SafeYamlFlowConfig() { this = "SnakeYaml::SafeYamlFlowConfig" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeYaml }
|
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeYaml }
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
import java
|
import java
|
||||||
import semmle.code.java.dataflow.FlowSources
|
import semmle.code.java.dataflow.FlowSources
|
||||||
import semmle.code.java.dataflow.DataFlow3
|
import semmle.code.java.dataflow.DataFlow2
|
||||||
import semmle.code.java.dataflow.TaintTracking
|
import semmle.code.java.dataflow.TaintTracking
|
||||||
import semmle.code.java.dataflow.TaintTracking2
|
import semmle.code.java.dataflow.TaintTracking3
|
||||||
import semmle.code.java.security.AndroidIntentRedirection
|
import semmle.code.java.security.AndroidIntentRedirection
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,7 +38,7 @@ private class OriginalIntentSanitizer extends IntentRedirectionSanitizer {
|
|||||||
* Data flow configuration used to discard incoming Intents
|
* Data flow configuration used to discard incoming Intents
|
||||||
* flowing directly to sinks that start Android components.
|
* flowing directly to sinks that start Android components.
|
||||||
*/
|
*/
|
||||||
private class SameIntentBeingRelaunchedConfiguration extends DataFlow3::Configuration {
|
private class SameIntentBeingRelaunchedConfiguration extends DataFlow2::Configuration {
|
||||||
SameIntentBeingRelaunchedConfiguration() { this = "SameIntentBeingRelaunchedConfiguration" }
|
SameIntentBeingRelaunchedConfiguration() { this = "SameIntentBeingRelaunchedConfiguration" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||||
@@ -74,7 +74,7 @@ private class IntentWithTaintedComponent extends DataFlow::Node {
|
|||||||
/**
|
/**
|
||||||
* A taint tracking configuration for tainted data flowing to an `Intent`'s component.
|
* A taint tracking configuration for tainted data flowing to an `Intent`'s component.
|
||||||
*/
|
*/
|
||||||
private class TaintedIntentComponentConf extends TaintTracking2::Configuration {
|
private class TaintedIntentComponentConf extends TaintTracking3::Configuration {
|
||||||
TaintedIntentComponentConf() { this = "TaintedIntentComponentConf" }
|
TaintedIntentComponentConf() { this = "TaintedIntentComponentConf" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
import java
|
import java
|
||||||
import semmle.code.java.frameworks.JAXB
|
import semmle.code.java.frameworks.JAXB
|
||||||
import semmle.code.java.dataflow.DataFlow
|
import semmle.code.java.dataflow.DataFlow
|
||||||
import semmle.code.java.dataflow.DataFlow2
|
|
||||||
import semmle.code.java.security.CleartextStorageQuery
|
import semmle.code.java.security.CleartextStorageQuery
|
||||||
import semmle.code.java.security.CleartextStoragePropertiesQuery
|
import semmle.code.java.security.CleartextStoragePropertiesQuery
|
||||||
|
|
||||||
@@ -74,7 +73,7 @@ private Expr getInstanceInput(DataFlow::Node instance, RefType t) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ClassStoreFlowConfig extends DataFlow2::Configuration {
|
private class ClassStoreFlowConfig extends DataFlow::Configuration {
|
||||||
ClassStoreFlowConfig() { this = "ClassStoreFlowConfig" }
|
ClassStoreFlowConfig() { this = "ClassStoreFlowConfig" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ClassStore }
|
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ClassStore }
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import java
|
import java
|
||||||
private import semmle.code.java.dataflow.DataFlow4
|
private import semmle.code.java.dataflow.DataFlow4
|
||||||
private import semmle.code.java.dataflow.TaintTracking
|
private import semmle.code.java.dataflow.TaintTracking
|
||||||
|
private import semmle.code.java.dataflow.TaintTracking2
|
||||||
private import semmle.code.java.security.SensitiveActions
|
private import semmle.code.java.security.SensitiveActions
|
||||||
|
|
||||||
/** A sink representing persistent storage that saves data in clear text. */
|
/** A sink representing persistent storage that saves data in clear text. */
|
||||||
@@ -39,7 +40,7 @@ abstract class Storable extends Call {
|
|||||||
abstract Expr getAStore();
|
abstract Expr getAStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SensitiveSourceFlowConfig extends TaintTracking::Configuration {
|
private class SensitiveSourceFlowConfig extends TaintTracking2::Configuration {
|
||||||
SensitiveSourceFlowConfig() { this = "SensitiveSourceFlowConfig" }
|
SensitiveSourceFlowConfig() { this = "SensitiveSourceFlowConfig" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SensitiveExpr }
|
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SensitiveExpr }
|
||||||
|
|||||||
@@ -383,8 +383,8 @@ module API {
|
|||||||
exists(Node pred, Label::ApiLabel lbl, string predpath |
|
exists(Node pred, Label::ApiLabel lbl, string predpath |
|
||||||
Impl::edge(pred, lbl, this) and
|
Impl::edge(pred, lbl, this) and
|
||||||
predpath = pred.getAPath(length - 1) and
|
predpath = pred.getAPath(length - 1) and
|
||||||
exists(string space | if length = 1 then space = "" else space = " " |
|
exists(string dot | if length = 1 then dot = "" else dot = "." |
|
||||||
result = "(" + lbl + space + predpath + ")" and
|
result = predpath + dot + lbl and
|
||||||
// avoid producing strings longer than 1MB
|
// avoid producing strings longer than 1MB
|
||||||
result.length() < 1000 * 1000
|
result.length() < 1000 * 1000
|
||||||
)
|
)
|
||||||
@@ -1330,22 +1330,22 @@ module API {
|
|||||||
/** Gets the EntryPoint associated with this label. */
|
/** Gets the EntryPoint associated with this label. */
|
||||||
API::EntryPoint getEntryPoint() { result = e }
|
API::EntryPoint getEntryPoint() { result = e }
|
||||||
|
|
||||||
override string toString() { result = e }
|
override string toString() { result = "getASuccessor(Label::entryPoint(\"" + e + "\"))" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A label that gets a promised value. */
|
/** A label that gets a promised value. */
|
||||||
class LabelPromised extends ApiLabel, MkLabelPromised {
|
class LabelPromised extends ApiLabel, MkLabelPromised {
|
||||||
override string toString() { result = "promised" }
|
override string toString() { result = "getPromised()" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A label that gets a rejected promise. */
|
/** A label that gets a rejected promise. */
|
||||||
class LabelPromisedError extends ApiLabel, MkLabelPromisedError {
|
class LabelPromisedError extends ApiLabel, MkLabelPromisedError {
|
||||||
override string toString() { result = "promisedError" }
|
override string toString() { result = "getPromisedError()" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A label that gets the return value of a function. */
|
/** A label that gets the return value of a function. */
|
||||||
class LabelReturn extends ApiLabel, MkLabelReturn {
|
class LabelReturn extends ApiLabel, MkLabelReturn {
|
||||||
override string toString() { result = "return" }
|
override string toString() { result = "getReturn()" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A label for a module. */
|
/** A label for a module. */
|
||||||
@@ -1357,12 +1357,13 @@ module API {
|
|||||||
/** Gets the module associated with this label. */
|
/** Gets the module associated with this label. */
|
||||||
string getMod() { result = mod }
|
string getMod() { result = mod }
|
||||||
|
|
||||||
override string toString() { result = "module " + mod }
|
// moduleImport is not neccesarilly the predicate to use, but it's close enough for most cases.
|
||||||
|
override string toString() { result = "moduleImport(\"" + mod + "\")" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A label that gets an instance from a `new` call. */
|
/** A label that gets an instance from a `new` call. */
|
||||||
class LabelInstance extends ApiLabel, MkLabelInstance {
|
class LabelInstance extends ApiLabel, MkLabelInstance {
|
||||||
override string toString() { result = "instance" }
|
override string toString() { result = "getInstance()" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A label for the member named `prop`. */
|
/** A label for the member named `prop`. */
|
||||||
@@ -1374,14 +1375,14 @@ module API {
|
|||||||
/** Gets the property associated with this label. */
|
/** Gets the property associated with this label. */
|
||||||
string getProperty() { result = prop }
|
string getProperty() { result = prop }
|
||||||
|
|
||||||
override string toString() { result = "member " + prop }
|
override string toString() { result = "getMember(\"" + prop + "\")" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A label for a member with an unknown name. */
|
/** A label for a member with an unknown name. */
|
||||||
class LabelUnknownMember extends ApiLabel, MkLabelUnknownMember {
|
class LabelUnknownMember extends ApiLabel, MkLabelUnknownMember {
|
||||||
LabelUnknownMember() { this = MkLabelUnknownMember() }
|
LabelUnknownMember() { this = MkLabelUnknownMember() }
|
||||||
|
|
||||||
override string toString() { result = "member *" }
|
override string toString() { result = "getUnknownMember()" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A label for parameter `i`. */
|
/** A label for parameter `i`. */
|
||||||
@@ -1390,7 +1391,7 @@ module API {
|
|||||||
|
|
||||||
LabelParameter() { this = MkLabelParameter(i) }
|
LabelParameter() { this = MkLabelParameter(i) }
|
||||||
|
|
||||||
override string toString() { result = "parameter " + i }
|
override string toString() { result = "getParameter(" + i + ")" }
|
||||||
|
|
||||||
/** Gets the index of the parameter for this label. */
|
/** Gets the index of the parameter for this label. */
|
||||||
int getIndex() { result = i }
|
int getIndex() { result = i }
|
||||||
@@ -1398,22 +1399,22 @@ module API {
|
|||||||
|
|
||||||
/** A label for the receiver of call, that is, the value passed as `this`. */
|
/** A label for the receiver of call, that is, the value passed as `this`. */
|
||||||
class LabelReceiver extends ApiLabel, MkLabelReceiver {
|
class LabelReceiver extends ApiLabel, MkLabelReceiver {
|
||||||
override string toString() { result = "receiver" }
|
override string toString() { result = "getReceiver()" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A label for a class decorated by the current value. */
|
/** A label for a class decorated by the current value. */
|
||||||
class LabelDecoratedClass extends ApiLabel, MkLabelDecoratedClass {
|
class LabelDecoratedClass extends ApiLabel, MkLabelDecoratedClass {
|
||||||
override string toString() { result = "decorated-class" }
|
override string toString() { result = "getADecoratedClass()" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A label for a method, field, or accessor decorated by the current value. */
|
/** A label for a method, field, or accessor decorated by the current value. */
|
||||||
class LabelDecoratedMethod extends ApiLabel, MkLabelDecoratedMember {
|
class LabelDecoratedMethod extends ApiLabel, MkLabelDecoratedMember {
|
||||||
override string toString() { result = "decorated-member" }
|
override string toString() { result = "decoratedMember()" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A label for a parameter decorated by the current value. */
|
/** A label for a parameter decorated by the current value. */
|
||||||
class LabelDecoratedParameter extends ApiLabel, MkLabelDecoratedParameter {
|
class LabelDecoratedParameter extends ApiLabel, MkLabelDecoratedParameter {
|
||||||
override string toString() { result = "decorated-parameter" }
|
override string toString() { result = "decoratedParameter()" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -589,6 +589,13 @@ module DataFlow {
|
|||||||
* Gets the node where the property write happens in the control flow graph.
|
* Gets the node where the property write happens in the control flow graph.
|
||||||
*/
|
*/
|
||||||
abstract ControlFlowNode getWriteNode();
|
abstract ControlFlowNode getWriteNode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this installs an accessor on an object, as opposed to a regular property,
|
||||||
|
* gets the body of the accessor. `isSetter` is true if installing a setter, and
|
||||||
|
* false is installing a getter.
|
||||||
|
*/
|
||||||
|
DataFlow::FunctionNode getInstalledAccessor(boolean isSetter) { none() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -628,6 +635,17 @@ module DataFlow {
|
|||||||
|
|
||||||
override Node getRhs() { result = valueNode(prop.(ValueProperty).getInit()) }
|
override Node getRhs() { result = valueNode(prop.(ValueProperty).getInit()) }
|
||||||
|
|
||||||
|
override DataFlow::FunctionNode getInstalledAccessor(boolean isSetter) {
|
||||||
|
(
|
||||||
|
prop instanceof PropertySetter and
|
||||||
|
isSetter = true
|
||||||
|
or
|
||||||
|
prop instanceof PropertyGetter and
|
||||||
|
isSetter = false
|
||||||
|
) and
|
||||||
|
result = valueNode(prop.getInit())
|
||||||
|
}
|
||||||
|
|
||||||
override ControlFlowNode getWriteNode() { result = prop }
|
override ControlFlowNode getWriteNode() { result = prop }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -688,6 +706,17 @@ module DataFlow {
|
|||||||
result = valueNode(prop.getInit())
|
result = valueNode(prop.getInit())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override DataFlow::FunctionNode getInstalledAccessor(boolean isSetter) {
|
||||||
|
(
|
||||||
|
prop instanceof SetterMethodDefinition and
|
||||||
|
isSetter = true
|
||||||
|
or
|
||||||
|
prop instanceof GetterMethodDefinition and
|
||||||
|
isSetter = false
|
||||||
|
) and
|
||||||
|
result = valueNode(prop.getInit())
|
||||||
|
}
|
||||||
|
|
||||||
override ControlFlowNode getWriteNode() { result = prop }
|
override ControlFlowNode getWriteNode() { result = prop }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -711,6 +740,17 @@ module DataFlow {
|
|||||||
result = valueNode(prop.getInit())
|
result = valueNode(prop.getInit())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override DataFlow::FunctionNode getInstalledAccessor(boolean isSetter) {
|
||||||
|
(
|
||||||
|
prop instanceof SetterMethodDefinition and
|
||||||
|
isSetter = true
|
||||||
|
or
|
||||||
|
prop instanceof GetterMethodDefinition and
|
||||||
|
isSetter = false
|
||||||
|
) and
|
||||||
|
result = valueNode(prop.getInit())
|
||||||
|
}
|
||||||
|
|
||||||
override ControlFlowNode getWriteNode() { result = prop }
|
override ControlFlowNode getWriteNode() { result = prop }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -898,17 +898,31 @@ class ClassNode extends DataFlow::SourceNode instanceof ClassNode::Range {
|
|||||||
*/
|
*/
|
||||||
FunctionNode getAnInstanceMember() { result = super.getAnInstanceMember(_) }
|
FunctionNode getAnInstanceMember() { result = super.getAnInstanceMember(_) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the static method, getter, or setter declared in this class with the given name and kind.
|
||||||
|
*/
|
||||||
|
FunctionNode getStaticMember(string name, MemberKind kind) {
|
||||||
|
result = super.getStaticMember(name, kind)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the static method declared in this class with the given name.
|
* Gets the static method declared in this class with the given name.
|
||||||
*/
|
*/
|
||||||
FunctionNode getStaticMethod(string name) { result = super.getStaticMethod(name) }
|
FunctionNode getStaticMethod(string name) {
|
||||||
|
result = this.getStaticMember(name, MemberKind::method())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a static method, getter, or setter declared in this class with the given kind.
|
||||||
|
*/
|
||||||
|
FunctionNode getAStaticMember(MemberKind kind) { result = super.getAStaticMember(kind) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a static method declared in this class.
|
* Gets a static method declared in this class.
|
||||||
*
|
*
|
||||||
* The constructor is not considered a static method.
|
* The constructor is not considered a static method.
|
||||||
*/
|
*/
|
||||||
FunctionNode getAStaticMethod() { result = super.getAStaticMethod() }
|
FunctionNode getAStaticMethod() { result = this.getAStaticMember(MemberKind::method()) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a dataflow node that refers to the superclass of this class.
|
* Gets a dataflow node that refers to the superclass of this class.
|
||||||
@@ -1119,18 +1133,34 @@ module ClassNode {
|
|||||||
abstract FunctionNode getAnInstanceMember(MemberKind kind);
|
abstract FunctionNode getAnInstanceMember(MemberKind kind);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Gets the static member of this class with the given name and kind.
|
||||||
|
*/
|
||||||
|
cached
|
||||||
|
abstract FunctionNode getStaticMember(string name, MemberKind kind);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEPRECATED. Override `getStaticMember` instead.
|
||||||
|
*
|
||||||
* Gets the static method of this class with the given name.
|
* Gets the static method of this class with the given name.
|
||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
abstract FunctionNode getStaticMethod(string name);
|
deprecated FunctionNode getStaticMethod(string name) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Gets a static member of this class of the given kind.
|
||||||
|
*/
|
||||||
|
cached
|
||||||
|
abstract FunctionNode getAStaticMember(MemberKind kind);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEPRECATED. Override `getAStaticMember` instead.
|
||||||
|
*
|
||||||
* Gets a static method of this class.
|
* Gets a static method of this class.
|
||||||
*
|
*
|
||||||
* The constructor is not considered a static method.
|
* The constructor is not considered a static method.
|
||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
abstract FunctionNode getAStaticMethod();
|
deprecated FunctionNode getAStaticMethod() { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a dataflow node representing a class to be used as the super-class
|
* Gets a dataflow node representing a class to be used as the super-class
|
||||||
@@ -1186,23 +1216,27 @@ module ClassNode {
|
|||||||
result = this.getConstructor().getReceiver().getAPropertySource()
|
result = this.getConstructor().getReceiver().getAPropertySource()
|
||||||
}
|
}
|
||||||
|
|
||||||
override FunctionNode getStaticMethod(string name) {
|
override FunctionNode getStaticMember(string name, MemberKind kind) {
|
||||||
exists(MethodDeclaration method |
|
exists(MethodDeclaration method |
|
||||||
method = astNode.getMethod(name) and
|
method = astNode.getMethod(name) and
|
||||||
method.isStatic() and
|
method.isStatic() and
|
||||||
|
kind = MemberKind::of(method) and
|
||||||
result = method.getBody().flow()
|
result = method.getBody().flow()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
kind.isMethod() and
|
||||||
result = this.getAPropertySource(name)
|
result = this.getAPropertySource(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
override FunctionNode getAStaticMethod() {
|
override FunctionNode getAStaticMember(MemberKind kind) {
|
||||||
exists(MethodDeclaration method |
|
exists(MethodDeclaration method |
|
||||||
method = astNode.getAMethod() and
|
method = astNode.getAMethod() and
|
||||||
method.isStatic() and
|
method.isStatic() and
|
||||||
|
kind = MemberKind::of(method) and
|
||||||
result = method.getBody().flow()
|
result = method.getBody().flow()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
kind.isMethod() and
|
||||||
result = this.getAPropertySource()
|
result = this.getAPropertySource()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1300,9 +1334,15 @@ module ClassNode {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override FunctionNode getStaticMethod(string name) { result = this.getAPropertySource(name) }
|
override FunctionNode getStaticMember(string name, MemberKind kind) {
|
||||||
|
kind.isMethod() and
|
||||||
|
result = this.getAPropertySource(name)
|
||||||
|
}
|
||||||
|
|
||||||
override FunctionNode getAStaticMethod() { result = this.getAPropertySource() }
|
override FunctionNode getAStaticMember(MemberKind kind) {
|
||||||
|
kind.isMethod() and
|
||||||
|
result = this.getAPropertySource()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a reference to the prototype of this class.
|
* Gets a reference to the prototype of this class.
|
||||||
|
|||||||
@@ -189,25 +189,43 @@ module CallGraph {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `ref` installs an accessor on an object. Such property writes should not
|
||||||
|
* be considered calls to an accessor.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate isAccessorInstallation(DataFlow::PropWrite write) {
|
||||||
|
exists(write.getInstalledAccessor(_))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a getter or setter invoked as a result of the given property access.
|
* Gets a getter or setter invoked as a result of the given property access.
|
||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
DataFlow::FunctionNode getAnAccessorCallee(DataFlow::PropRef ref) {
|
DataFlow::FunctionNode getAnAccessorCallee(DataFlow::PropRef ref) {
|
||||||
exists(DataFlow::ClassNode cls, string name |
|
not isAccessorInstallation(ref) and
|
||||||
ref = cls.getAnInstanceMemberAccess(name) and
|
(
|
||||||
result = cls.getInstanceMember(name, DataFlow::MemberKind::getter())
|
exists(DataFlow::ClassNode cls, string name |
|
||||||
|
ref = cls.getAnInstanceMemberAccess(name) and
|
||||||
|
result = cls.getInstanceMember(name, DataFlow::MemberKind::getter())
|
||||||
|
or
|
||||||
|
ref = getAnInstanceMemberAssignment(cls, name) and
|
||||||
|
result = cls.getInstanceMember(name, DataFlow::MemberKind::setter())
|
||||||
|
or
|
||||||
|
ref = cls.getAClassReference().getAPropertyRead(name) and
|
||||||
|
result = cls.getStaticMember(name, DataFlow::MemberKind::getter())
|
||||||
|
or
|
||||||
|
ref = cls.getAClassReference().getAPropertyWrite(name) and
|
||||||
|
result = cls.getStaticMember(name, DataFlow::MemberKind::setter())
|
||||||
|
)
|
||||||
or
|
or
|
||||||
ref = getAnInstanceMemberAssignment(cls, name) and
|
exists(DataFlow::ObjectLiteralNode object, string name |
|
||||||
result = cls.getInstanceMember(name, DataFlow::MemberKind::setter())
|
ref = getAnAllocationSiteRef(object).getAPropertyRead(name) and
|
||||||
)
|
result = object.getPropertyGetter(name)
|
||||||
or
|
or
|
||||||
exists(DataFlow::ObjectLiteralNode object, string name |
|
ref = getAnAllocationSiteRef(object).getAPropertyWrite(name) and
|
||||||
ref = getAnAllocationSiteRef(object).getAPropertyRead(name) and
|
result = object.getPropertySetter(name)
|
||||||
result = object.getPropertyGetter(name)
|
)
|
||||||
or
|
|
||||||
ref = getAnAllocationSiteRef(object).getAPropertyWrite(name) and
|
|
||||||
result = object.getPropertySetter(name)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ private module CachedSteps {
|
|||||||
* Holds if `invk` may invoke `f`.
|
* Holds if `invk` may invoke `f`.
|
||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
predicate calls(DataFlow::SourceNode invk, Function f) {
|
predicate calls(DataFlow::Node invk, Function f) {
|
||||||
f = invk.(DataFlow::InvokeNode).getACallee(0)
|
f = invk.(DataFlow::InvokeNode).getACallee(0)
|
||||||
or
|
or
|
||||||
f = invk.(DataFlow::PropRef).getAnAccessorCallee().getFunction()
|
f = invk.(DataFlow::PropRef).getAnAccessorCallee().getFunction()
|
||||||
|
|||||||
@@ -42,9 +42,7 @@ module AccessPath {
|
|||||||
* Parses a lower-bounded interval `n..` and gets the lower bound.
|
* Parses a lower-bounded interval `n..` and gets the lower bound.
|
||||||
*/
|
*/
|
||||||
bindingset[arg]
|
bindingset[arg]
|
||||||
private int parseLowerBound(string arg) {
|
int parseLowerBound(string arg) { result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt() }
|
||||||
result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses an integer constant or interval (bounded or unbounded) that explicitly
|
* Parses an integer constant or interval (bounded or unbounded) that explicitly
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
let express = require('express');
|
let express = require('express');
|
||||||
|
let app = express()
|
||||||
|
|
||||||
express.put('/todos/:id', (req, res) => {
|
app.put('/todos/:id', (req, res) => {
|
||||||
let id = req.params.id;
|
let id = req.params.id;
|
||||||
let items = req.session.todos[id];
|
let items = req.session.todos[id];
|
||||||
if (!items) {
|
if (!items) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
let express = require('express');
|
let express = require('express');
|
||||||
|
let app = express()
|
||||||
|
|
||||||
express.put('/todos/:id', (req, res) => {
|
app.put('/todos/:id', (req, res) => {
|
||||||
let id = req.params.id;
|
let id = req.params.id;
|
||||||
let items = req.session.todos.get(id);
|
let items = req.session.todos.get(id);
|
||||||
if (!items) {
|
if (!items) {
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* The call graph now deals more precisely with calls to accessors (getters and setters).
|
||||||
|
Previously, calls to static accessors were not resolved, and some method calls were
|
||||||
|
incorrectly seen as calls to an accessor. Both issues have been fixed.
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
/**
|
/**
|
||||||
* A test query that verifies assertions about the API graph embedded in source-code comments.
|
* A test query that verifies assertions about the API graph embedded in source-code comments.
|
||||||
*
|
*
|
||||||
* An assertion is a comment of the form `def <path>` or `use <path>`, and asserts that
|
* An assertion is a comment of the form `def=<path>` or `use=<path>`, and asserts that
|
||||||
* there is a def/use feature reachable from the root along the given path (described using
|
* there is a def/use feature reachable from the root along the given path, and its
|
||||||
* s-expression syntax), and its associated data-flow node must start on the same line as the
|
* associated data-flow node must start on the same line as the comment.
|
||||||
* comment.
|
|
||||||
*
|
*
|
||||||
* We also support negative assertions of the form `!def <path>` or `!use <path>`, which assert
|
* We also support negative assertions of the form `MISSING: def <path>` or `MISSING: use <path>`, which assert
|
||||||
* that there _isn't_ a node with the given path on the same line.
|
* that there _isn't_ a node with the given path on the same line.
|
||||||
*
|
*
|
||||||
* The query only produces output for failed assertions, meaning that it should have no output
|
* The query only produces output for failed assertions, meaning that it should have no output
|
||||||
@@ -39,44 +38,55 @@ private string getLoc(DataFlow::Node nd) {
|
|||||||
* An assertion matching a data-flow node against an API-graph feature.
|
* An assertion matching a data-flow node against an API-graph feature.
|
||||||
*/
|
*/
|
||||||
class Assertion extends Comment {
|
class Assertion extends Comment {
|
||||||
string polarity;
|
|
||||||
string expectedKind;
|
string expectedKind;
|
||||||
string expectedLoc;
|
string expectedLoc;
|
||||||
|
string path;
|
||||||
|
string polarity;
|
||||||
|
|
||||||
Assertion() {
|
Assertion() {
|
||||||
exists(string txt, string rex |
|
exists(string txt, string rex |
|
||||||
txt = this.getText().trim() and
|
txt = this.getText().trim() and
|
||||||
rex = "(!?)(def|use) .*"
|
rex = ".*?((?:MISSING: )?)(def|use)=([\\w\\(\\)\"\\.\\-\\/\\@\\:]*).*"
|
||||||
|
|
|
|
||||||
polarity = txt.regexpCapture(rex, 1) and
|
polarity = txt.regexpCapture(rex, 1) and
|
||||||
expectedKind = txt.regexpCapture(rex, 2) and
|
expectedKind = txt.regexpCapture(rex, 2) and
|
||||||
|
path = txt.regexpCapture(rex, 3) and
|
||||||
expectedLoc = this.getFile().getAbsolutePath() + ":" + this.getLocation().getStartLine()
|
expectedLoc = this.getFile().getAbsolutePath() + ":" + this.getLocation().getStartLine()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
string getEdgeLabel(int i) { result = this.getText().regexpFind("(?<=\\()[^()]+", i, _).trim() }
|
string getEdgeLabel(int i) {
|
||||||
|
// matches a single edge. E.g. `getParameter(1)` or `getMember("foo")`.
|
||||||
|
// The lookbehind/lookahead ensure that the boundary is correct, that is
|
||||||
|
// either the edge is next to a ".", or it's the end of the string.
|
||||||
|
result = path.regexpFind("(?<=\\.|^)([\\w\\(\\)\"\\-\\/\\@\\:]+)(?=\\.|$)", i, _).trim()
|
||||||
|
}
|
||||||
|
|
||||||
int getPathLength() { result = max(int i | exists(this.getEdgeLabel(i))) + 1 }
|
int getPathLength() { result = max(int i | exists(this.getEdgeLabel(i))) + 1 }
|
||||||
|
|
||||||
|
predicate isNegative() { polarity = "MISSING: " }
|
||||||
|
|
||||||
API::Node lookup(int i) {
|
API::Node lookup(int i) {
|
||||||
i = this.getPathLength() and
|
i = 0 and
|
||||||
result = API::root()
|
result = API::root()
|
||||||
or
|
or
|
||||||
result =
|
result =
|
||||||
this.lookup(i + 1)
|
this.lookup(i - 1)
|
||||||
.getASuccessor(any(API::Label::ApiLabel label | label.toString() = this.getEdgeLabel(i)))
|
.getASuccessor(any(API::Label::ApiLabel label |
|
||||||
|
label.toString() = this.getEdgeLabel(i - 1)
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isNegative() { polarity = "!" }
|
API::Node lookup() { result = this.lookup(this.getPathLength()) }
|
||||||
|
|
||||||
predicate holds() { getLoc(getNode(this.lookup(0), expectedKind)) = expectedLoc }
|
predicate holds() { getLoc(getNode(this.lookup(), expectedKind)) = expectedLoc }
|
||||||
|
|
||||||
string tryExplainFailure() {
|
string tryExplainFailure() {
|
||||||
exists(int i, API::Node nd, string prefix, string suffix |
|
exists(int i, API::Node nd, string prefix, string suffix |
|
||||||
nd = this.lookup(i) and
|
nd = this.lookup(i) and
|
||||||
i > 0 and
|
i < getPathLength() and
|
||||||
not exists(this.lookup([0 .. i - 1])) and
|
not exists(this.lookup([i + 1 .. getPathLength()])) and
|
||||||
prefix = nd + " has no outgoing edge labelled " + this.getEdgeLabel(i - 1) + ";" and
|
prefix = nd + " has no outgoing edge labelled " + this.getEdgeLabel(i) + ";" and
|
||||||
if exists(nd.getASuccessor())
|
if exists(nd.getASuccessor())
|
||||||
then
|
then
|
||||||
suffix =
|
suffix =
|
||||||
@@ -91,13 +101,13 @@ class Assertion extends Comment {
|
|||||||
result = prefix + " " + suffix
|
result = prefix + " " + suffix
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(API::Node nd, string kind | nd = this.lookup(0) |
|
exists(API::Node nd, string kind | nd = this.lookup() |
|
||||||
exists(getNode(nd, kind)) and
|
exists(getNode(nd, kind)) and
|
||||||
not exists(getNode(nd, expectedKind)) and
|
not exists(getNode(nd, expectedKind)) and
|
||||||
result = "Expected " + expectedKind + " node, but found " + kind + " node."
|
result = "Expected " + expectedKind + " node, but found " + kind + " node."
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(DataFlow::Node nd | nd = getNode(this.lookup(0), expectedKind) |
|
exists(DataFlow::Node nd | nd = getNode(this.lookup(), expectedKind) |
|
||||||
not getLoc(nd) = expectedLoc and
|
not getLoc(nd) = expectedLoc and
|
||||||
result = "Node not found on this line (but there is one on line " + min(getLoc(nd)) + ")."
|
result = "Node not found on this line (but there is one on line " + min(getLoc(nd)) + ")."
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const assert = require("assert");
|
const assert = require("assert");
|
||||||
|
|
||||||
let o = {
|
let o = {
|
||||||
foo: 23 /* def (member foo (parameter 0 (member equal (member exports (module assert))))) */
|
foo: 23 // def=moduleImport("assert").getMember("exports").getMember("equal").getParameter(0).getMember("foo")
|
||||||
};
|
};
|
||||||
assert.equal(o, o);
|
assert.equal(o, o);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
|
|
||||||
module.exports.foo = async function foo() {
|
module.exports.foo = async function foo() {
|
||||||
return await fs.copy('/tmp/myfile', '/tmp/mynewfile'); /* use (promised (return (member copy (member exports (module fs-extra))))) */ /* def (promised (return (member foo (member exports (module async-await))))) */
|
return await fs.copy('/tmp/myfile', '/tmp/mynewfile'); /* use=moduleImport("fs-extra").getMember("exports").getMember("copy").getReturn().getPromised()*/ /* def=moduleImport("async-await").getMember("exports").getMember("foo").getReturn().getPromised() */
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,5 +5,5 @@ async function readFileUtf8(path: string): Promise<string> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function test(path: string) {
|
async function test(path: string) {
|
||||||
await readFileUtf8(path); /* use (promised (return (member readFile (member exports (module fs/promises))))) */
|
await readFileUtf8(path); /* use=moduleImport("fs/promises").getMember("exports").getMember("readFile").getReturn() */
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
import bar from 'foo';
|
import bar from 'foo';
|
||||||
|
|
||||||
let boundbar = bar.bind(
|
let boundbar = bar.bind(
|
||||||
"receiver", // def (receiver (member default (member exports (module foo))))
|
"receiver", // def=moduleImport("foo").getMember("exports").getMember("default").getReceiver()
|
||||||
"firstarg" // def (parameter 0 (member default (member exports (module foo))))
|
"firstarg" // def=moduleImport("foo").getMember("exports").getMember("default").getParameter(0)
|
||||||
);
|
);
|
||||||
boundbar(
|
boundbar(
|
||||||
"secondarg" // def (parameter 1 (member default (member exports (module foo))))
|
"secondarg" // def=moduleImport("foo").getMember("exports").getMember("default").getParameter(1)
|
||||||
)
|
)
|
||||||
|
|
||||||
let boundbar2 = boundbar.bind(
|
let boundbar2 = boundbar.bind(
|
||||||
"ignored", // !def (receiver (member default (member exports (module foo))))
|
"ignored", // MISSING: def=moduleImport("foo").getMember("exports)".getMember("default").getReceiver()
|
||||||
"othersecondarg" // def (parameter 1 (member default (member exports (module foo))))
|
"othersecondarg" // def=moduleImport("foo").getMember("exports").getMember("default").getParameter(1)
|
||||||
)
|
)
|
||||||
boundbar2(
|
boundbar2(
|
||||||
"thirdarg" // def (parameter 2 (member default (member exports (module foo))))
|
"thirdarg" // def=moduleImport("foo").getMember("exports").getMember("default").getParameter(2)
|
||||||
)
|
)
|
||||||
|
|
||||||
let bar2 = bar;
|
let bar2 = bar;
|
||||||
for (var i = 0; i < 2; ++i)
|
for (var i = 0; i < 2; ++i)
|
||||||
bar2 = bar2.bind(
|
bar2 = bar2.bind(
|
||||||
null,
|
null,
|
||||||
i /* def (parameter 1 (member default (member exports (module foo)))) */ /* def (parameter 9 (member default (member exports (module foo)))) */
|
i /* def=moduleImport("foo").getMember("exports").getMember("default").getParameter(1) */ /* def=moduleImport("foo").getMember("exports").getMember("default").getParameter(9) */
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ const fs = require('fs');
|
|||||||
exports.foo = function (cb) {
|
exports.foo = function (cb) {
|
||||||
if (!cb)
|
if (!cb)
|
||||||
cb = function () { };
|
cb = function () { };
|
||||||
cb(fs.readFileSync("/etc/passwd")); /* def (parameter 0 (parameter 0 (member foo (member exports (module branching-flow))))) */
|
cb(fs.readFileSync("/etc/passwd")); /* def=moduleImport("branching-flow").getMember("exports").getMember("foo").getParameter(0).getParameter(0) */
|
||||||
};
|
};
|
||||||
@@ -9,19 +9,19 @@ util.inherits(MyStream, EventEmitter);
|
|||||||
|
|
||||||
MyStream.prototype.write = (data) => this.emit('data', data);
|
MyStream.prototype.write = (data) => this.emit('data', data);
|
||||||
|
|
||||||
function MyOtherStream() { /* use (instance (member MyOtherStream (member exports (module classes)))) */
|
function MyOtherStream() { /* use=moduleImport("classes").getMember("exports").getMember("MyOtherStream").getInstance() */
|
||||||
EventEmitter.call(this);
|
EventEmitter.call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
util.inherits(MyOtherStream, EventEmitter);
|
util.inherits(MyOtherStream, EventEmitter);
|
||||||
|
|
||||||
MyOtherStream.prototype.write = function (data) { /* use (instance (member MyOtherStream (member exports (module classes)))) */
|
MyOtherStream.prototype.write = function (data) { /* use=moduleImport("classes").getMember("exports").getMember("MyOtherStream").getInstance() */
|
||||||
this.emit('data', data);
|
this.emit('data', data);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
MyOtherStream.prototype.instanceProp = 1; /* def (member instanceProp (instance (member MyOtherStream (member exports (module classes))))) */
|
MyOtherStream.prototype.instanceProp = 1; /* def=moduleImport("classes").getMember("exports").getMember("MyOtherStream").getInstance().getMember("instanceProp") */
|
||||||
|
|
||||||
MyOtherStream.classProp = 1; /* def (member classProp (member MyOtherStream (member exports (module classes)))) */
|
MyOtherStream.classProp = 1; /* def=moduleImport("classes").getMember("exports").getMember("MyOtherStream").getMember("classProp") */
|
||||||
|
|
||||||
module.exports.MyOtherStream = MyOtherStream;
|
module.exports.MyOtherStream = MyOtherStream;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export class A {
|
export class A {
|
||||||
constructor(x) { /* use (parameter 0 (member A (member exports (module ctor-arg)))) */
|
constructor(x) { /* use=moduleImport("ctor-arg").getMember("exports").getMember("A").getParameter(0) */
|
||||||
console.log(x);
|
console.log(x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1 +1 @@
|
|||||||
module.exports = CustomEntryPoint.foo; /* use (member foo (CustomEntryPoint)) */
|
module.exports = CustomEntryPoint.foo; /* use=getASuccessor(Label::entryPoint("CustomEntryPoint")) */
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const foo = require("foo");
|
const foo = require("foo");
|
||||||
|
|
||||||
while(foo)
|
while(foo)
|
||||||
foo = foo.foo; /* use (member foo (member exports (module foo))) */ /* use (member foo (member foo (member exports (module foo)))) */
|
foo = foo.foo; /* use=moduleImport("foo").getMember("exports").getMember("foo") */ /* use=moduleImport("foo").getMember("exports").getMember("foo").getMember("foo") */
|
||||||
|
|||||||
@@ -2,4 +2,4 @@ const MyStream = require('classes').MyStream;
|
|||||||
|
|
||||||
var s = new MyStream();
|
var s = new MyStream();
|
||||||
for (let m of ["write"])
|
for (let m of ["write"])
|
||||||
s[m]("Hello, world!"); /* use (member * (instance (member MyStream (member exports (module classes))))) */
|
s[m]("Hello, world!"); /* use=moduleImport("classes").getMember("exports").getMember("MyStream").getInstance().getUnknownMember() */
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
anotherUnknownFunction().foo = 42; /* !def (member foo (member exports (module imprecise-export))) */
|
anotherUnknownFunction().foo = 42; /* MISSING: def=moduleExport("imprecise-export").getMember("exports").getMember("foo") */
|
||||||
|
|
||||||
module.exports = unknownFunction();
|
module.exports = unknownFunction();
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
const http = require('http');
|
const http = require('http');
|
||||||
let req = http.get(url, cb);
|
let req = http.get(url, cb);
|
||||||
req.on('connect', (
|
req.on('connect', (
|
||||||
req, /* use (parameter 0 (parameter 1 (member on (return (member get (member exports (module http))))))) */
|
req, /* use=moduleImport("http").getMember("exports").getMember("get").getReturn().getMember("on").getParameter(1).getParameter(0) */
|
||||||
clientSocket, head) => { /* ... */ });
|
clientSocket, head) => { /* ... */ });
|
||||||
req.on('information', (
|
req.on('information', (
|
||||||
info /* use (parameter 0 (parameter 1 (member on (return (member get (member exports (module http))))))) */
|
info /* use=moduleImport("http").getMember("exports").getMember("get").getReturn().getMember("on").getParameter(1).getParameter(0) */
|
||||||
) => { /* ... */ });
|
) => { /* ... */ });
|
||||||
|
|
||||||
req.on('connect', () => { }) /* def (parameter 0 (member on (return (member get (member exports (module http)))))) */
|
req.on('connect', () => { }) /* def=moduleImport("http").getMember("exports").getMember("get").getReturn().getMember("on").getParameter(0) */
|
||||||
.on('information', () => { }) /* def (parameter 0 (member on (return (member on (return (member get (member exports (module http)))))))) */;
|
.on('information', () => { }) /* def=moduleImport("http").getMember("exports").getMember("get").getReturn().getMember("on").getReturn().getMember("on").getParameter(0) */;
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
import foo from "@myorg/myotherpkg";
|
import foo from "@myorg/myotherpkg";
|
||||||
foo(); /* use (member default (member exports (module @myorg/myotherpkg))) */
|
foo(); /* use=moduleImport("@myorg/myotherpkg").getMember("exports").getMember("default") */
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
module.exports.foo = function (x) { /* use (parameter 0 (member foo (member exports (module nested-property-export)))) */
|
module.exports.foo = function (x) { /* use=moduleImport("nested-property-export").getMember("exports").getMember("foo").getParameter(0) */
|
||||||
return x;
|
return x;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.foo.bar = function (y) { /* use (parameter 0 (member bar (member foo (member exports (module nested-property-export))))) */
|
module.exports.foo.bar = function (y) { /* use=moduleImport("nested-property-export").getMember("exports").getMember("foo").getMember("bar").getParameter(0) */
|
||||||
return y;
|
return y;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ const express = require('express');
|
|||||||
|
|
||||||
var app1 = new express();
|
var app1 = new express();
|
||||||
app1.get('/',
|
app1.get('/',
|
||||||
(req, res) => res.send('Hello World!') /* def (parameter 1 (member get (instance (member exports (module express))))) */
|
(req, res) => res.send('Hello World!') /* def=moduleImport("express").getMember("exports").getInstance().getMember("get").getParameter(1) */
|
||||||
);
|
);
|
||||||
|
|
||||||
function makeApp() {
|
function makeApp() {
|
||||||
@@ -11,5 +11,5 @@ function makeApp() {
|
|||||||
|
|
||||||
var app2 = makeApp();
|
var app2 = makeApp();
|
||||||
app2.get('/',
|
app2.get('/',
|
||||||
(req, res) => res.send('Hello World!') /* def (parameter 1 (member get (instance (member exports (module express))))) */
|
(req, res) => res.send('Hello World!') /* def=moduleImport("express").getMember("exports").getInstance().getMember("get").getParameter(1) */
|
||||||
);
|
);
|
||||||
@@ -2,7 +2,7 @@ const cp = require('child_process');
|
|||||||
|
|
||||||
module.exports = function () {
|
module.exports = function () {
|
||||||
return cp.spawn.bind(
|
return cp.spawn.bind(
|
||||||
cp, // def (receiver (member spawn (member exports (module child_process))))
|
cp, // def=moduleImport("child_process").getMember("exports").getMember("spawn").getReceiver()
|
||||||
"cat" // def (parameter 0 (member spawn (member exports (module child_process))))
|
"cat" // def=moduleImport("child_process").getMember("exports").getMember("spawn").getParameter(0)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -8,14 +8,14 @@ module.exports.readFile = function (f) {
|
|||||||
if (err)
|
if (err)
|
||||||
rej(err);
|
rej(err);
|
||||||
else
|
else
|
||||||
res(data); /* def (promised (return (member readFile (member exports (module promises))))) */
|
res(data); /* def=moduleImport("promises").getMember("exports").getMember("readFile").getReturn().getPromised() */
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.readFileAndEncode = function (f) {
|
module.exports.readFileAndEncode = function (f) {
|
||||||
return fse.readFile(f)
|
return fse.readFile(f)
|
||||||
.then((data) => /* use (promised (return (member readFile (member exports (module fs-extra))))) */
|
.then((data) => /* use=moduleImport("fs-extra").getMember("exports").getMember("readFile").getReturn().getPromised() */
|
||||||
base64.encode(data) /* def (promised (return (member readFileAndEncode (member exports (module promises))))) */
|
base64.encode(data) /* def=moduleImport("promises").getMember("exports").getMember("readFileAndEncode").getReturn().getPromised() */
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -4,25 +4,25 @@ var readFile = require("fs").readFile;
|
|||||||
var readFileAsync = bluebird.promisify(readFile);
|
var readFileAsync = bluebird.promisify(readFile);
|
||||||
|
|
||||||
readFile(
|
readFile(
|
||||||
"tst.txt", // def (parameter 0 (member readFile (member exports (module fs))))
|
"tst.txt", // def=moduleImport("fs").getMember("exports").getMember("readFile").getParameter(0)
|
||||||
"utf8", // def (parameter 1 (member readFile (member exports (module fs))))
|
"utf8", // def=moduleImport("fs").getMember("exports").getMember("readFile").getParameter(1)
|
||||||
function (
|
function (
|
||||||
err, // use (parameter 0 (parameter 2 (member readFile (member exports (module fs)))))
|
err, // use=moduleImport("fs").getMember("exports").getMember("readFile").getParameter(2).getParameter(0)
|
||||||
contents // use (parameter 1 (parameter 2 (member readFile (member exports (module fs)))))
|
contents // use=moduleImport("fs").getMember("exports").getMember("readFile").getParameter(2).getParameter(1)
|
||||||
) { });
|
) { });
|
||||||
|
|
||||||
readFileAsync(
|
readFileAsync(
|
||||||
"tst.txt" // def (parameter 0 (member readFile (member exports (module fs))))
|
"tst.txt" // def=moduleImport("fs").getMember("exports").getMember("readFile").getParameter(0)
|
||||||
).then(
|
).then(
|
||||||
function (buf) { } // use (parameter 1 (parameter 1 (member readFile (member exports (module fs)))))
|
function (buf) { } // use=moduleImport("fs").getMember("exports").getMember("readFile").getParameter(1).getParameter(1)
|
||||||
).catch(
|
).catch(
|
||||||
function (err) { } // not yet modelled: (parameter 0 (parameter 1 (member readFile (member exports (module fs)))))
|
function (err) { } // not yet modelled: (parameter 0 (parameter 1 (member readFile (member exports (module fs)))))
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let p = readFileAsync(
|
let p = readFileAsync(
|
||||||
"tst.txt", // def (parameter 0 (member readFile (member exports (module fs))))
|
"tst.txt", // def=moduleImport("fs").getMember("exports").getMember("readFile").getParameter(0)
|
||||||
"utf8" // def (parameter 1 (member readFile (member exports (module fs))))
|
"utf8" // def=moduleImport("fs").getMember("exports").getMember("readFile").getParameter(1)
|
||||||
);
|
);
|
||||||
let data = await p; // use (parameter 1 (parameter 2 (member readFile (member exports (module fs)))))
|
let data = await p; // use=moduleImport("fs").getMember("exports").getMember("readFile").getParameter(2).getParameter(1)
|
||||||
} catch (e) { } // not yet modelled: (parameter 0 (parameter 2 (member readFile (member exports (module fs)))))
|
} catch (e) { } // not yet modelled: (parameter 0 (parameter 2 (member readFile (member exports (module fs)))))
|
||||||
|
|||||||
@@ -5,5 +5,5 @@ exports.assertNotNull = function (x) {
|
|||||||
|
|
||||||
exports.foo = function(x) {
|
exports.foo = function(x) {
|
||||||
exports.assertNotNull(x);
|
exports.assertNotNull(x);
|
||||||
sink(x.f); /* !use (member f (parameter 0 (member assertNotNull (member exports (module property-read-from-argument))))) */ /* use (member f (parameter 0 (member foo (member exports (module property-read-from-argument))))) */
|
sink(x.f); /* MISSING: use=moduleImport("property-read-from-argument").getMember("exports").getMember("assertNotNull").getParameter(0).getMember("f") */ /* use=moduleImport("property-read-from-argument").getMember("exports").getMember("foo").getParameter(0).getMember("f") */
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module.exports = function () {
|
module.exports = function () {
|
||||||
return 42; /* def (return (member impl (member exports (module reexport)))) */
|
return 42; /* def=moduleImport("reexport").getMember("exports").getMember("impl").getReturn() */
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
function foo(x) { /* use (parameter 0 (member bar (member other (member exports (module reexport)))) */
|
function foo(x) { /* use=moduleImport("reexport").getMember("exports").getMember("other").getMember("bar").getParameter(0) */
|
||||||
return x + 1;
|
return x + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module.exports.id = function id(x) { /* use (parameter 0 (member id (member util (member exports (module reexport)))) */
|
module.exports.id = function id(x) { /* use=moduleImport("reexport").getMember("exports").getMember("util").getMember("id").getParameter(0) */
|
||||||
return x;
|
return x;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
id: function id(x) { /* use (parameter 0 (member id (member util2 (member exports (module reexport)))) */
|
id: function id(x) { /* use=moduleImport("reexport").getMember("exports").getMember("util2").getMember("id").getParameter(0) */
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export class A {
|
export class A {
|
||||||
foo() {
|
foo() {
|
||||||
return this; /* def (return (member foo (instance (member A (member exports (module return-self)))))) */
|
return this; /* def=moduleImport("return-self").getMember("exports").getMember("A").getInstance().getMember("foo").getReturn() */
|
||||||
}
|
}
|
||||||
bar(x) { } /* use (parameter 0 (member bar (instance (member A (member exports (module return-self)))))) */
|
bar(x) { } /* use=moduleImport("return-self").getMember("exports").getMember("A").getInstance().getMember("bar").getParameter(0) */
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ const lib = require('something');
|
|||||||
|
|
||||||
function f() {
|
function f() {
|
||||||
return {
|
return {
|
||||||
x: new Object() /* def (member x (parameter 0 (member m1 (member exports (module something))))) */
|
x: new Object() /* def=moduleImport("something").getMember("exports").getMember("m1").getParameter(0).getMember("x") */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ app.use(bodyParser.json());
|
|||||||
|
|
||||||
app.post("/find", (req, res) => {
|
app.post("/find", (req, res) => {
|
||||||
let v = JSON.parse(req.body.x);
|
let v = JSON.parse(req.body.x);
|
||||||
getCollection().find({ id: v }); /* use (member find (instance (member Collection (member exports (module mongodb))))) */
|
getCollection().find({ id: v }); // use=moduleImport("mongodb").getMember("exports").getMember("Collection").getInstance().getMember("find")
|
||||||
});
|
});
|
||||||
|
|
||||||
import * as mongoose from "mongoose";
|
import * as mongoose from "mongoose";
|
||||||
@@ -19,14 +19,14 @@ declare function getMongooseModel(): mongoose.Model;
|
|||||||
declare function getMongooseQuery(): mongoose.Query;
|
declare function getMongooseQuery(): mongoose.Query;
|
||||||
app.post("/find", (req, res) => {
|
app.post("/find", (req, res) => {
|
||||||
let v = JSON.parse(req.body.x);
|
let v = JSON.parse(req.body.x);
|
||||||
getMongooseModel().find({ id: v }); /* def (parameter 0 (member find (instance (member Model (member exports (module mongoose)))))) */
|
getMongooseModel().find({ id: v }); // def=moduleImport("mongoose").getMember("exports").getMember("Model").getInstance().getMember("find").getParameter(0)
|
||||||
getMongooseQuery().find({ id: v }); /* def (parameter 0 (member find (instance (member Query (member exports (module mongoose)))))) */
|
getMongooseQuery().find({ id: v }); // def=moduleImport("mongoose").getMember("exports").getMember("Query").getInstance().getMember("find").getParameter(0)
|
||||||
});
|
});
|
||||||
|
|
||||||
import * as puppeteer from 'puppeteer';
|
import * as puppeteer from 'puppeteer';
|
||||||
class Renderer {
|
class Renderer {
|
||||||
private browser: puppeteer.Browser;
|
private browser: puppeteer.Browser;
|
||||||
foo(): void {
|
foo(): void {
|
||||||
const page = this.browser.newPage(); /* use (instance (member Browser (member exports (module puppeteer)))) */
|
const page = this.browser.newPage(); /* use=moduleImport("puppeteer").getMember("exports").getMember("Browser").getInstance() */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,15 @@
|
|||||||
spuriousCallee
|
spuriousCallee
|
||||||
missingCallee
|
missingCallee
|
||||||
| constructor-field.ts:40:5:40:14 | f3.build() | constructor-field.ts:13:3:13:12 | build() {} | -1 |
|
| constructor-field.ts:40:5:40:14 | f3.build() | constructor-field.ts:13:3:13:12 | build() {} | -1 | calls |
|
||||||
| constructor-field.ts:71:1:71:11 | bf3.build() | constructor-field.ts:13:3:13:12 | build() {} | -1 |
|
| constructor-field.ts:71:1:71:11 | bf3.build() | constructor-field.ts:13:3:13:12 | build() {} | -1 | calls |
|
||||||
badAnnotation
|
badAnnotation
|
||||||
|
accessorCall
|
||||||
|
| accessors.js:12:1:12:5 | obj.f | accessors.js:5:8:5:12 | () {} |
|
||||||
|
| accessors.js:15:1:15:5 | obj.f | accessors.js:8:8:8:13 | (x) {} |
|
||||||
|
| accessors.js:26:1:26:3 | C.f | accessors.js:19:15:19:19 | () {} |
|
||||||
|
| accessors.js:29:1:29:3 | C.f | accessors.js:22:15:22:20 | (x) {} |
|
||||||
|
| accessors.js:41:1:41:9 | new D().f | accessors.js:34:8:34:12 | () {} |
|
||||||
|
| accessors.js:44:1:44:9 | new D().f | accessors.js:37:8:37:13 | (x) {} |
|
||||||
|
| accessors.js:48:1:48:5 | obj.f | accessors.js:5:8:5:12 | () {} |
|
||||||
|
| accessors.js:51:1:51:3 | C.f | accessors.js:19:15:19:19 | () {} |
|
||||||
|
| accessors.js:54:1:54:9 | new D().f | accessors.js:34:8:34:12 | () {} |
|
||||||
|
|||||||
@@ -25,16 +25,28 @@ class AnnotatedFunction extends Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A function annotated with `calls:NAME` */
|
/** A function annotated with `calls:NAME` */
|
||||||
class AnnotatedCall extends InvokeExpr {
|
class AnnotatedCall extends DataFlow::Node {
|
||||||
string calls;
|
string calls;
|
||||||
|
string kind;
|
||||||
|
|
||||||
AnnotatedCall() { calls = getAnnotation(this, "calls") }
|
AnnotatedCall() {
|
||||||
|
this instanceof DataFlow::InvokeNode and
|
||||||
|
calls = getAnnotation(this.asExpr(), kind) and
|
||||||
|
kind = "calls"
|
||||||
|
or
|
||||||
|
this instanceof DataFlow::PropRef and
|
||||||
|
calls = getAnnotation(this.getAstNode(), kind) and
|
||||||
|
kind = "callsAccessor"
|
||||||
|
}
|
||||||
|
|
||||||
string getCallTargetName() { result = calls }
|
string getCallTargetName() { result = calls }
|
||||||
|
|
||||||
AnnotatedFunction getAnExpectedCallee() { result.getCalleeName() = getCallTargetName() }
|
AnnotatedFunction getAnExpectedCallee(string kind_) {
|
||||||
|
result.getCalleeName() = getCallTargetName() and
|
||||||
|
kind = kind_
|
||||||
|
}
|
||||||
|
|
||||||
int getBoundArgs() { result = getAnnotation(this, "boundArgs").toInt() }
|
int getBoundArgs() { result = getAnnotation(this.getAstNode(), "boundArgs").toInt() }
|
||||||
|
|
||||||
int getBoundArgsOrMinusOne() {
|
int getBoundArgsOrMinusOne() {
|
||||||
result = getBoundArgs()
|
result = getBoundArgs()
|
||||||
@@ -42,25 +54,33 @@ class AnnotatedCall extends InvokeExpr {
|
|||||||
not exists(getBoundArgs()) and
|
not exists(getBoundArgs()) and
|
||||||
result = -1
|
result = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string getKind() { result = kind }
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate callEdge(AnnotatedCall call, AnnotatedFunction target, int boundArgs) {
|
predicate callEdge(AnnotatedCall call, AnnotatedFunction target, int boundArgs) {
|
||||||
FlowSteps::calls(call.flow(), target) and boundArgs = -1
|
FlowSteps::calls(call, target) and boundArgs = -1
|
||||||
or
|
or
|
||||||
FlowSteps::callsBound(call.flow(), target, boundArgs)
|
FlowSteps::callsBound(call, target, boundArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
query predicate spuriousCallee(AnnotatedCall call, AnnotatedFunction target, int boundArgs) {
|
query predicate spuriousCallee(
|
||||||
|
AnnotatedCall call, AnnotatedFunction target, int boundArgs, string kind
|
||||||
|
) {
|
||||||
callEdge(call, target, boundArgs) and
|
callEdge(call, target, boundArgs) and
|
||||||
|
kind = call.getKind() and
|
||||||
not (
|
not (
|
||||||
target = call.getAnExpectedCallee() and
|
target = call.getAnExpectedCallee(kind) and
|
||||||
boundArgs = call.getBoundArgsOrMinusOne()
|
boundArgs = call.getBoundArgsOrMinusOne()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
query predicate missingCallee(AnnotatedCall call, AnnotatedFunction target, int boundArgs) {
|
query predicate missingCallee(
|
||||||
|
AnnotatedCall call, AnnotatedFunction target, int boundArgs, string kind
|
||||||
|
) {
|
||||||
not callEdge(call, target, boundArgs) and
|
not callEdge(call, target, boundArgs) and
|
||||||
target = call.getAnExpectedCallee() and
|
kind = call.getKind() and
|
||||||
|
target = call.getAnExpectedCallee(kind) and
|
||||||
boundArgs = call.getBoundArgsOrMinusOne()
|
boundArgs = call.getBoundArgsOrMinusOne()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,3 +92,7 @@ query predicate badAnnotation(string name) {
|
|||||||
not name = any(AnnotatedCall cl).getCallTargetName() and
|
not name = any(AnnotatedCall cl).getCallTargetName() and
|
||||||
name = any(AnnotatedFunction cl).getCalleeName()
|
name = any(AnnotatedFunction cl).getCalleeName()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query predicate accessorCall(DataFlow::PropRef ref, Function target) {
|
||||||
|
FlowSteps::calls(ref, target)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import 'dummy';
|
||||||
|
|
||||||
|
let obj = {
|
||||||
|
/** name:obj.f.get */
|
||||||
|
get f() {},
|
||||||
|
|
||||||
|
/** name:obj.f.set */
|
||||||
|
set f(x) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** callsAccessor:obj.f.get */
|
||||||
|
obj.f;
|
||||||
|
|
||||||
|
/** callsAccessor:obj.f.set */
|
||||||
|
obj.f = 1;
|
||||||
|
|
||||||
|
class C {
|
||||||
|
/** name:C.f.get */
|
||||||
|
static get f() {}
|
||||||
|
|
||||||
|
/** name:C.f.set */
|
||||||
|
static set f(x) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** callsAccessor:C.f.get */
|
||||||
|
C.f;
|
||||||
|
|
||||||
|
/** callsAccessor:C.f.set */
|
||||||
|
C.f = 1;
|
||||||
|
|
||||||
|
|
||||||
|
class D {
|
||||||
|
/** name:D.f.get */
|
||||||
|
get f() {}
|
||||||
|
|
||||||
|
/** name:D.f.set */
|
||||||
|
set f(x) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** callsAccessor:D.f.get */
|
||||||
|
new D().f;
|
||||||
|
|
||||||
|
/** callsAccessor:D.f.set */
|
||||||
|
new D().f = 1;
|
||||||
|
|
||||||
|
// Avoid regular calls being seen as calls to the accessor itself
|
||||||
|
/** calls:NONE */
|
||||||
|
obj.f();
|
||||||
|
|
||||||
|
/** calls:NONE */
|
||||||
|
C.f();
|
||||||
|
|
||||||
|
/** calls:NONE */
|
||||||
|
new D().f();
|
||||||
@@ -24,6 +24,7 @@ getAReceiverNode
|
|||||||
| tst.js:23:1:23:15 | function D() {} | tst.js:25:13:25:12 | this |
|
| tst.js:23:1:23:15 | function D() {} | tst.js:25:13:25:12 | this |
|
||||||
| tst.js:23:1:23:15 | function D() {} | tst.js:26:13:26:12 | this |
|
| tst.js:23:1:23:15 | function D() {} | tst.js:26:13:26:12 | this |
|
||||||
| tst.js:23:1:23:15 | function D() {} | tst.js:27:4:27:3 | this |
|
| tst.js:23:1:23:15 | function D() {} | tst.js:27:4:27:3 | this |
|
||||||
|
| tst.js:30:1:34:1 | class S ... x) {}\\n} | tst.js:30:21:30:20 | this |
|
||||||
getFieldTypeAnnotation
|
getFieldTypeAnnotation
|
||||||
| fields.ts:1:1:3:1 | class B ... mber;\\n} | baseField | fields.ts:2:16:2:21 | number |
|
| fields.ts:1:1:3:1 | class B ... mber;\\n} | baseField | fields.ts:2:16:2:21 | number |
|
||||||
| fields.ts:5:1:13:1 | class F ... > {};\\n} | x | fields.ts:6:27:6:32 | number |
|
| fields.ts:5:1:13:1 | class F ... > {};\\n} | x | fields.ts:6:27:6:32 | number |
|
||||||
@@ -53,6 +54,11 @@ instanceMethod
|
|||||||
| tst.js:15:1:15:15 | function B() {} | foo | tst.js:17:19:17:31 | function() {} | B |
|
| tst.js:15:1:15:15 | function B() {} | foo | tst.js:17:19:17:31 | function() {} | B |
|
||||||
| tst.js:19:1:19:15 | function C() {} | bar | tst.js:21:19:21:31 | function() {} | C |
|
| tst.js:19:1:19:15 | function C() {} | bar | tst.js:21:19:21:31 | function() {} | C |
|
||||||
| tst.js:23:1:23:15 | function D() {} | m | tst.js:27:4:27:8 | () {} | D |
|
| tst.js:23:1:23:15 | function D() {} | m | tst.js:27:4:27:8 | () {} | D |
|
||||||
|
staticMember
|
||||||
|
| tst.js:3:1:10:1 | class A ... () {}\\n} | staticMethod | method | tst.js:5:22:5:26 | () {} | A |
|
||||||
|
| tst.js:30:1:34:1 | class S ... x) {}\\n} | getter | getter | tst.js:32:20:32:24 | () {} | StaticMembers |
|
||||||
|
| tst.js:30:1:34:1 | class S ... x) {}\\n} | method | method | tst.js:31:16:31:20 | () {} | StaticMembers |
|
||||||
|
| tst.js:30:1:34:1 | class S ... x) {}\\n} | setter | setter | tst.js:33:20:33:25 | (x) {} | StaticMembers |
|
||||||
superClass
|
superClass
|
||||||
| fields.ts:5:1:13:1 | class F ... > {};\\n} | fields.ts:1:1:3:1 | class B ... mber;\\n} | Foo | Base |
|
| fields.ts:5:1:13:1 | class F ... > {};\\n} | fields.ts:1:1:3:1 | class B ... mber;\\n} | Foo | Base |
|
||||||
| tst.js:13:1:13:21 | class A ... ds A {} | tst.js:3:1:10:1 | class A ... () {}\\n} | A2 | A |
|
| tst.js:13:1:13:21 | class A ... ds A {} | tst.js:3:1:10:1 | class A ... () {}\\n} | A2 | A |
|
||||||
|
|||||||
@@ -24,6 +24,12 @@ query predicate instanceMethod(
|
|||||||
cls.getInstanceMethod(name) = inst and clsName = cls.getName()
|
cls.getInstanceMethod(name) = inst and clsName = cls.getName()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query predicate staticMember(
|
||||||
|
DataFlow::ClassNode cls, string name, string kind, DataFlow::FunctionNode inst, string clsName
|
||||||
|
) {
|
||||||
|
cls.getStaticMember(name, kind) = inst and clsName = cls.getName()
|
||||||
|
}
|
||||||
|
|
||||||
query predicate superClass(
|
query predicate superClass(
|
||||||
DataFlow::ClassNode cls, DataFlow::ClassNode sup, string clsName, string supName
|
DataFlow::ClassNode cls, DataFlow::ClassNode sup, string clsName, string supName
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -26,3 +26,9 @@ D.prototype = {
|
|||||||
set setter(x) {},
|
set setter(x) {},
|
||||||
m() {}
|
m() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StaticMembers {
|
||||||
|
static method() {}
|
||||||
|
static get getter() {}
|
||||||
|
static set setter(x) {}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
underlyingTypeNode
|
underlyingTypeNode
|
||||||
| foo | Bar | foo.ts:3:1:5:1 | use (instance (member Bar (member exports (module foo)))) |
|
| foo | Bar | foo.ts:3:1:5:1 | use moduleImport("foo").getMember("exports").getMember("Bar").getInstance() |
|
||||||
| foo | Bar | foo.ts:3:12:3:12 | use (instance (member Bar (member exports (module foo)))) |
|
| foo | Bar | foo.ts:3:12:3:12 | use moduleImport("foo").getMember("exports").getMember("Bar").getInstance() |
|
||||||
#select
|
#select
|
||||||
| foo.ts:3:12:3:12 | x | foo.Bar in unknown scope |
|
| foo.ts:3:12:3:12 | x | foo.Bar in unknown scope |
|
||||||
| foo.ts:4:10:4:10 | x | foo.Bar in unknown scope |
|
| foo.ts:4:10:4:10 | x | foo.Bar in unknown scope |
|
||||||
|
|||||||
@@ -25,208 +25,208 @@ sqlString
|
|||||||
| tst.js:166:43:166:63 | 'col DE ... S LAST' |
|
| tst.js:166:43:166:63 | 'col DE ... S LAST' |
|
||||||
| tst.js:178:14:178:24 | 'count > ?' |
|
| tst.js:178:14:178:24 | 'count > ?' |
|
||||||
knexLibrary
|
knexLibrary
|
||||||
| file://:0:0:0:0 | use (member exports (module knex)) |
|
| file://:0:0:0:0 | use moduleImport("knex").getMember("exports") |
|
||||||
knexObject
|
knexObject
|
||||||
| tst.js:3:14:3:30 | use (return (member exports (module knex))) |
|
| tst.js:3:14:3:30 | use moduleImport("knex").getMember("exports").getReturn() |
|
||||||
| tst.js:5:1:5:32 | use (return (return (member exports (module knex)))) |
|
| tst.js:5:1:5:32 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:5:1:9:4 | use (return (member select (return (return (member exports (module knex)))))) |
|
| tst.js:5:1:9:4 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:5:1:10:52 | use (return (member whereRaw (return (member select (return (return (member exports (module knex)))))))) |
|
| tst.js:5:1:10:52 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("select").getReturn().getMember("whereRaw").getReturn() |
|
||||||
| tst.js:12:1:12:48 | use (return (member withUserParams (return (member exports (module knex))))) |
|
| tst.js:12:1:12:48 | use moduleImport("knex").getMember("exports").getReturn().getMember("withUserParams").getReturn() |
|
||||||
| tst.js:12:1:12:59 | use (return (member table (return (member withUserParams (return (member exports (module knex))))))) |
|
| tst.js:12:1:12:59 | use moduleImport("knex").getMember("exports").getReturn().getMember("withUserParams").getReturn().getMember("table").getReturn() |
|
||||||
| tst.js:12:1:12:71 | use (return (member select (return (member table (return (member withUserParams (return (member exports (module knex))))))))) |
|
| tst.js:12:1:12:71 | use moduleImport("knex").getMember("exports").getReturn().getMember("withUserParams").getReturn().getMember("table").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:14:1:14:13 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:14:1:14:13 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:14:1:14:27 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:14:1:14:27 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:14:1:14:41 | use (return (member timeout (return (member from (return (member select (return (member exports (module knex))))))))) |
|
| tst.js:14:1:14:41 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("timeout").getReturn() |
|
||||||
| tst.js:15:1:15:38 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:15:1:15:38 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:15:1:15:52 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:15:1:15:52 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:17:1:17:23 | use (return (member avg (return (member exports (module knex))))) |
|
| tst.js:17:1:17:23 | use moduleImport("knex").getMember("exports").getReturn().getMember("avg").getReturn() |
|
||||||
| tst.js:17:1:19:4 | use (return (member from (return (member avg (return (member exports (module knex))))))) |
|
| tst.js:17:1:19:4 | use moduleImport("knex").getMember("exports").getReturn().getMember("avg").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:17:1:19:24 | use (return (member as (return (member from (return (member avg (return (member exports (module knex))))))))) |
|
| tst.js:17:1:19:24 | use moduleImport("knex").getMember("exports").getReturn().getMember("avg").getReturn().getMember("from").getReturn().getMember("as").getReturn() |
|
||||||
| tst.js:17:30:17:29 | use (receiver (parameter 0 (member from (return (member avg (return (member exports (module knex)))))))) |
|
| tst.js:17:30:17:29 | use moduleImport("knex").getMember("exports").getReturn().getMember("avg").getReturn().getMember("from").getParameter(0).getReceiver() |
|
||||||
| tst.js:18:5:18:38 | use (return (member sum (receiver (parameter 0 (member from (return (member avg (return (member exports (module knex)))))))))) |
|
| tst.js:18:5:18:38 | use moduleImport("knex").getMember("exports").getReturn().getMember("avg").getReturn().getMember("from").getParameter(0).getReceiver().getMember("sum").getReturn() |
|
||||||
| tst.js:18:5:18:49 | use (return (member from (return (member sum (receiver (parameter 0 (member from (return (member avg (return (member exports (module knex)))))))))))) |
|
| tst.js:18:5:18:49 | use moduleImport("knex").getMember("exports").getReturn().getMember("avg").getReturn().getMember("from").getParameter(0).getReceiver().getMember("sum").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:18:5:18:68 | use (return (member groupBy (return (member from (return (member sum (receiver (parameter 0 (member from (return (member avg (return (member exports (module knex)))))))))))))) |
|
| tst.js:18:5:18:68 | use moduleImport("knex").getMember("exports").getReturn().getMember("avg").getReturn().getMember("from").getParameter(0).getReceiver().getMember("sum").getReturn().getMember("from").getReturn().getMember("groupBy").getReturn() |
|
||||||
| tst.js:18:5:18:77 | use (return (member as (return (member groupBy (return (member from (return (member sum (receiver (parameter 0 (member from (return (member avg (return (member exports (module knex)))))))))))))))) |
|
| tst.js:18:5:18:77 | use moduleImport("knex").getMember("exports").getReturn().getMember("avg").getReturn().getMember("from").getParameter(0).getReceiver().getMember("sum").getReturn().getMember("from").getReturn().getMember("groupBy").getReturn().getMember("as").getReturn() |
|
||||||
| tst.js:21:1:21:38 | use (return (member column (return (member exports (module knex))))) |
|
| tst.js:21:1:21:38 | use moduleImport("knex").getMember("exports").getReturn().getMember("column").getReturn() |
|
||||||
| tst.js:21:1:21:47 | use (return (member select (return (member column (return (member exports (module knex))))))) |
|
| tst.js:21:1:21:47 | use moduleImport("knex").getMember("exports").getReturn().getMember("column").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:21:1:21:61 | use (return (member from (return (member select (return (member column (return (member exports (module knex))))))))) |
|
| tst.js:21:1:21:61 | use moduleImport("knex").getMember("exports").getReturn().getMember("column").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:23:1:23:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:23:1:23:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:23:1:23:30 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:23:1:23:30 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:25:1:25:85 | use (return (member with (return (member exports (module knex))))) |
|
| tst.js:25:1:25:85 | use moduleImport("knex").getMember("exports").getReturn().getMember("with").getReturn() |
|
||||||
| tst.js:25:1:25:97 | use (return (member select (return (member with (return (member exports (module knex))))))) |
|
| tst.js:25:1:25:97 | use moduleImport("knex").getMember("exports").getReturn().getMember("with").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:25:1:25:116 | use (return (member from (return (member select (return (member with (return (member exports (module knex))))))))) |
|
| tst.js:25:1:25:116 | use moduleImport("knex").getMember("exports").getReturn().getMember("with").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:25:25:25:84 | use (return (member raw (return (member exports (module knex))))) |
|
| tst.js:25:25:25:84 | use moduleImport("knex").getMember("exports").getReturn().getMember("raw").getReturn() |
|
||||||
| tst.js:27:1:31:4 | use (return (member withRecursive (return (member exports (module knex))))) |
|
| tst.js:27:1:31:4 | use moduleImport("knex").getMember("exports").getReturn().getMember("withRecursive").getReturn() |
|
||||||
| tst.js:27:1:31:16 | use (return (member select (return (member withRecursive (return (member exports (module knex))))))) |
|
| tst.js:27:1:31:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("withRecursive").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:27:1:31:34 | use (return (member from (return (member select (return (member withRecursive (return (member exports (module knex))))))))) |
|
| tst.js:27:1:31:34 | use moduleImport("knex").getMember("exports").getReturn().getMember("withRecursive").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:33:1:33:25 | use (return (member withSchema (return (member exports (module knex))))) |
|
| tst.js:33:1:33:25 | use moduleImport("knex").getMember("exports").getReturn().getMember("withSchema").getReturn() |
|
||||||
| tst.js:33:1:33:37 | use (return (member select (return (member withSchema (return (member exports (module knex))))))) |
|
| tst.js:33:1:33:37 | use moduleImport("knex").getMember("exports").getReturn().getMember("withSchema").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:33:1:33:51 | use (return (member from (return (member select (return (member withSchema (return (member exports (module knex))))))))) |
|
| tst.js:33:1:33:51 | use moduleImport("knex").getMember("exports").getReturn().getMember("withSchema").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:35:1:35:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:35:1:35:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:35:1:38:4 | use (return (member where (return (return (member exports (module knex)))))) |
|
| tst.js:35:1:38:4 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn() |
|
||||||
| tst.js:35:1:38:17 | use (return (member select (return (member where (return (return (member exports (module knex)))))))) |
|
| tst.js:35:1:38:17 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:40:1:40:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:40:1:40:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:40:1:40:28 | use (return (member where (return (return (member exports (module knex)))))) |
|
| tst.js:40:1:40:28 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn() |
|
||||||
| tst.js:42:1:42:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:42:1:42:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:42:1:45:3 | use (return (member where (return (return (member exports (module knex)))))) |
|
| tst.js:42:1:45:3 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn() |
|
||||||
| tst.js:42:1:48:4 | use (return (member andWhere (return (member where (return (return (member exports (module knex)))))))) |
|
| tst.js:42:1:48:4 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn().getMember("andWhere").getReturn() |
|
||||||
| tst.js:46:13:46:12 | use (receiver (parameter 0 (member andWhere (return (member where (return (return (member exports (module knex))))))))) |
|
| tst.js:46:13:46:12 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn().getMember("andWhere").getParameter(0).getReceiver() |
|
||||||
| tst.js:47:5:47:29 | use (return (member where (receiver (parameter 0 (member andWhere (return (member where (return (return (member exports (module knex))))))))))) |
|
| tst.js:47:5:47:29 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn().getMember("andWhere").getParameter(0).getReceiver().getMember("where").getReturn() |
|
||||||
| tst.js:50:1:50:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:50:1:50:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:50:1:52:2 | use (return (member where (return (return (member exports (module knex)))))) |
|
| tst.js:50:1:52:2 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn() |
|
||||||
| tst.js:50:1:52:28 | use (return (member orWhere (return (member where (return (return (member exports (module knex)))))))) |
|
| tst.js:50:1:52:28 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn().getMember("orWhere").getReturn() |
|
||||||
| tst.js:50:21:50:20 | use (receiver (parameter 0 (member where (return (return (member exports (module knex))))))) |
|
| tst.js:50:21:50:20 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getParameter(0).getReceiver() |
|
||||||
| tst.js:51:3:51:21 | use (return (member where (receiver (parameter 0 (member where (return (return (member exports (module knex))))))))) |
|
| tst.js:51:3:51:21 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getParameter(0).getReceiver().getMember("where").getReturn() |
|
||||||
| tst.js:51:3:51:44 | use (return (member orWhere (return (member where (receiver (parameter 0 (member where (return (return (member exports (module knex))))))))))) |
|
| tst.js:51:3:51:44 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getParameter(0).getReceiver().getMember("where").getReturn().getMember("orWhere").getReturn() |
|
||||||
| tst.js:54:1:54:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:54:1:54:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:54:1:54:56 | use (return (member where (return (return (member exports (module knex)))))) |
|
| tst.js:54:1:54:56 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn() |
|
||||||
| tst.js:56:1:56:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:56:1:56:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:56:1:56:38 | use (return (member where (return (return (member exports (module knex)))))) |
|
| tst.js:56:1:56:38 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn() |
|
||||||
| tst.js:58:18:58:30 | use (return (return (member exports (module knex)))) |
|
| tst.js:58:18:58:30 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:58:18:58:55 | use (return (member where (return (return (member exports (module knex)))))) |
|
| tst.js:58:18:58:55 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn() |
|
||||||
| tst.js:58:18:58:84 | use (return (member andWhere (return (member where (return (return (member exports (module knex)))))))) |
|
| tst.js:58:18:58:84 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn().getMember("andWhere").getReturn() |
|
||||||
| tst.js:58:18:58:108 | use (return (member orWhere (return (member andWhere (return (member where (return (return (member exports (module knex)))))))))) |
|
| tst.js:58:18:58:108 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn().getMember("andWhere").getReturn().getMember("orWhere").getReturn() |
|
||||||
| tst.js:58:18:58:121 | use (return (member select (return (member orWhere (return (member andWhere (return (member where (return (return (member exports (module knex)))))))))))) |
|
| tst.js:58:18:58:121 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn().getMember("andWhere").getReturn().getMember("orWhere").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:59:1:59:16 | use (return (return (member exports (module knex)))) |
|
| tst.js:59:1:59:16 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:59:1:59:44 | use (return (member where (return (return (member exports (module knex)))))) |
|
| tst.js:59:1:59:44 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn() |
|
||||||
| tst.js:61:1:61:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:61:1:61:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:61:1:61:28 | use (return (member where (return (return (member exports (module knex)))))) |
|
| tst.js:61:1:61:28 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn() |
|
||||||
| tst.js:61:1:61:64 | use (return (member orWhere (return (member where (return (return (member exports (module knex)))))))) |
|
| tst.js:61:1:61:64 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn().getMember("orWhere").getReturn() |
|
||||||
| tst.js:63:1:63:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:63:1:63:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:63:1:66:2 | use (return (member whereNot (return (return (member exports (module knex)))))) |
|
| tst.js:63:1:66:2 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNot").getReturn() |
|
||||||
| tst.js:63:1:66:15 | use (return (member select (return (member whereNot (return (return (member exports (module knex)))))))) |
|
| tst.js:63:1:66:15 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNot").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:68:1:68:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:68:1:68:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:68:1:68:31 | use (return (member whereNot (return (return (member exports (module knex)))))) |
|
| tst.js:68:1:68:31 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNot").getReturn() |
|
||||||
| tst.js:70:1:70:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:70:1:70:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:70:1:72:2 | use (return (member whereNot (return (return (member exports (module knex)))))) |
|
| tst.js:70:1:72:2 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNot").getReturn() |
|
||||||
| tst.js:70:1:72:31 | use (return (member orWhereNot (return (member whereNot (return (return (member exports (module knex)))))))) |
|
| tst.js:70:1:72:31 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNot").getReturn().getMember("orWhereNot").getReturn() |
|
||||||
| tst.js:70:24:70:23 | use (receiver (parameter 0 (member whereNot (return (return (member exports (module knex))))))) |
|
| tst.js:70:24:70:23 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNot").getParameter(0).getReceiver() |
|
||||||
| tst.js:71:3:71:21 | use (return (member where (receiver (parameter 0 (member whereNot (return (return (member exports (module knex))))))))) |
|
| tst.js:71:3:71:21 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNot").getParameter(0).getReceiver().getMember("where").getReturn() |
|
||||||
| tst.js:71:3:71:47 | use (return (member orWhereNot (return (member where (receiver (parameter 0 (member whereNot (return (return (member exports (module knex))))))))))) |
|
| tst.js:71:3:71:47 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNot").getParameter(0).getReceiver().getMember("where").getReturn().getMember("orWhereNot").getReturn() |
|
||||||
| tst.js:74:19:74:31 | use (return (return (member exports (module knex)))) |
|
| tst.js:74:19:74:31 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:74:19:75:30 | use (return (member whereNot (return (return (member exports (module knex)))))) |
|
| tst.js:74:19:75:30 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNot").getReturn() |
|
||||||
| tst.js:74:19:76:31 | use (return (member andWhere (return (member whereNot (return (return (member exports (module knex)))))))) |
|
| tst.js:74:19:76:31 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNot").getReturn().getMember("andWhere").getReturn() |
|
||||||
| tst.js:74:19:77:26 | use (return (member orWhere (return (member andWhere (return (member whereNot (return (return (member exports (module knex)))))))))) |
|
| tst.js:74:19:77:26 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNot").getReturn().getMember("andWhere").getReturn().getMember("orWhere").getReturn() |
|
||||||
| tst.js:74:19:78:15 | use (return (member select (return (member orWhere (return (member andWhere (return (member whereNot (return (return (member exports (module knex)))))))))))) |
|
| tst.js:74:19:78:15 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNot").getReturn().getMember("andWhere").getReturn().getMember("orWhere").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:80:1:80:16 | use (return (return (member exports (module knex)))) |
|
| tst.js:80:1:80:16 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:80:1:80:49 | use (return (member where (return (return (member exports (module knex)))))) |
|
| tst.js:80:1:80:49 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn() |
|
||||||
| tst.js:82:1:82:19 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:82:1:82:19 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:82:1:82:33 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:82:1:82:33 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:82:1:83:27 | use (return (member whereIn (return (member from (return (member select (return (member exports (module knex))))))))) |
|
| tst.js:82:1:83:27 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("whereIn").getReturn() |
|
||||||
| tst.js:82:1:84:29 | use (return (member orWhereIn (return (member whereIn (return (member from (return (member select (return (member exports (module knex))))))))))) |
|
| tst.js:82:1:84:29 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("whereIn").getReturn().getMember("orWhereIn").getReturn() |
|
||||||
| tst.js:86:1:86:19 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:86:1:86:19 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:86:1:86:33 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:86:1:86:33 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:86:1:89:4 | use (return (member whereIn (return (member from (return (member select (return (member exports (module knex))))))))) |
|
| tst.js:86:1:89:4 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("whereIn").getReturn() |
|
||||||
| tst.js:91:1:91:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:91:1:91:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:91:1:91:41 | use (return (member whereNotIn (return (return (member exports (module knex)))))) |
|
| tst.js:91:1:91:41 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNotIn").getReturn() |
|
||||||
| tst.js:93:1:93:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:93:1:93:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:93:1:93:45 | use (return (member where (return (return (member exports (module knex)))))) |
|
| tst.js:93:1:93:45 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn() |
|
||||||
| tst.js:93:1:93:75 | use (return (member orWhereNotIn (return (member where (return (return (member exports (module knex)))))))) |
|
| tst.js:93:1:93:75 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("where").getReturn().getMember("orWhereNotIn").getReturn() |
|
||||||
| tst.js:95:1:95:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:95:1:95:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:95:1:95:37 | use (return (member whereNull (return (return (member exports (module knex)))))) |
|
| tst.js:95:1:95:37 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNull").getReturn() |
|
||||||
| tst.js:97:1:97:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:97:1:97:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:97:1:97:40 | use (return (member whereNotNull (return (return (member exports (module knex)))))) |
|
| tst.js:97:1:97:40 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNotNull").getReturn() |
|
||||||
| tst.js:99:1:99:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:99:1:99:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:99:1:101:2 | use (return (member whereExists (return (return (member exports (module knex)))))) |
|
| tst.js:99:1:101:2 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereExists").getReturn() |
|
||||||
| tst.js:99:27:99:26 | use (receiver (parameter 0 (member whereExists (return (return (member exports (module knex))))))) |
|
| tst.js:99:27:99:26 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereExists").getParameter(0).getReceiver() |
|
||||||
| tst.js:100:3:100:18 | use (return (member select (receiver (parameter 0 (member whereExists (return (return (member exports (module knex))))))))) |
|
| tst.js:100:3:100:18 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereExists").getParameter(0).getReceiver().getMember("select").getReturn() |
|
||||||
| tst.js:100:3:100:35 | use (return (member from (return (member select (receiver (parameter 0 (member whereExists (return (return (member exports (module knex))))))))))) |
|
| tst.js:100:3:100:35 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereExists").getParameter(0).getReceiver().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:100:3:100:78 | use (return (member whereRaw (return (member from (return (member select (receiver (parameter 0 (member whereExists (return (return (member exports (module knex))))))))))))) |
|
| tst.js:100:3:100:78 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereExists").getParameter(0).getReceiver().getMember("select").getReturn().getMember("from").getReturn().getMember("whereRaw").getReturn() |
|
||||||
| tst.js:103:1:103:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:103:1:103:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:103:1:103:103 | use (return (member whereExists (return (return (member exports (module knex)))))) |
|
| tst.js:103:1:103:103 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereExists").getReturn() |
|
||||||
| tst.js:103:27:103:42 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:103:27:103:42 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:103:27:103:59 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:103:27:103:59 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:103:27:103:102 | use (return (member whereRaw (return (member from (return (member select (return (member exports (module knex))))))))) |
|
| tst.js:103:27:103:102 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("whereRaw").getReturn() |
|
||||||
| tst.js:105:1:105:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:105:1:105:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:105:1:107:2 | use (return (member whereNotExists (return (return (member exports (module knex)))))) |
|
| tst.js:105:1:107:2 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNotExists").getReturn() |
|
||||||
| tst.js:105:30:105:29 | use (receiver (parameter 0 (member whereNotExists (return (return (member exports (module knex))))))) |
|
| tst.js:105:30:105:29 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNotExists").getParameter(0).getReceiver() |
|
||||||
| tst.js:106:3:106:18 | use (return (member select (receiver (parameter 0 (member whereNotExists (return (return (member exports (module knex))))))))) |
|
| tst.js:106:3:106:18 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNotExists").getParameter(0).getReceiver().getMember("select").getReturn() |
|
||||||
| tst.js:106:3:106:35 | use (return (member from (return (member select (receiver (parameter 0 (member whereNotExists (return (return (member exports (module knex))))))))))) |
|
| tst.js:106:3:106:35 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNotExists").getParameter(0).getReceiver().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:106:3:106:78 | use (return (member whereRaw (return (member from (return (member select (receiver (parameter 0 (member whereNotExists (return (return (member exports (module knex))))))))))))) |
|
| tst.js:106:3:106:78 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNotExists").getParameter(0).getReceiver().getMember("select").getReturn().getMember("from").getReturn().getMember("whereRaw").getReturn() |
|
||||||
| tst.js:109:1:109:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:109:1:109:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:109:1:109:45 | use (return (member whereBetween (return (return (member exports (module knex)))))) |
|
| tst.js:109:1:109:45 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereBetween").getReturn() |
|
||||||
| tst.js:111:1:111:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:111:1:111:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:111:1:111:48 | use (return (member whereNotBetween (return (return (member exports (module knex)))))) |
|
| tst.js:111:1:111:48 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereNotBetween").getReturn() |
|
||||||
| tst.js:113:1:113:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:113:1:113:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:113:1:113:37 | use (return (member whereRaw (return (return (member exports (module knex)))))) |
|
| tst.js:113:1:113:37 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("whereRaw").getReturn() |
|
||||||
| tst.js:115:1:115:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:115:1:115:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:115:1:116:56 | use (return (member join (return (return (member exports (module knex)))))) |
|
| tst.js:115:1:116:56 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("join").getReturn() |
|
||||||
| tst.js:115:1:117:39 | use (return (member select (return (member join (return (return (member exports (module knex)))))))) |
|
| tst.js:115:1:117:39 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("join").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:119:1:119:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:119:1:119:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:119:1:120:51 | use (return (member join (return (return (member exports (module knex)))))) |
|
| tst.js:119:1:120:51 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("join").getReturn() |
|
||||||
| tst.js:119:1:121:39 | use (return (member select (return (member join (return (return (member exports (module knex)))))))) |
|
| tst.js:119:1:121:39 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("join").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:123:1:123:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:123:1:123:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:123:1:123:30 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:123:1:123:30 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:123:1:125:2 | use (return (member join (return (member from (return (member select (return (member exports (module knex))))))))) |
|
| tst.js:123:1:125:2 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("join").getReturn() |
|
||||||
| tst.js:127:1:127:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:127:1:127:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:127:1:127:30 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:127:1:127:30 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:127:1:132:2 | use (return (member join (return (member from (return (member select (return (member exports (module knex))))))))) |
|
| tst.js:127:1:132:2 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("join").getReturn() |
|
||||||
| tst.js:134:1:134:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:134:1:134:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:134:1:134:30 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:134:1:134:30 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:134:1:134:90 | use (return (member join (return (member from (return (member select (return (member exports (module knex))))))))) |
|
| tst.js:134:1:134:90 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("join").getReturn() |
|
||||||
| tst.js:134:66:134:89 | use (return (member raw (return (member exports (module knex))))) |
|
| tst.js:134:66:134:89 | use moduleImport("knex").getMember("exports").getReturn().getMember("raw").getReturn() |
|
||||||
| tst.js:136:1:136:18 | use (return (member from (return (member exports (module knex))))) |
|
| tst.js:136:1:136:18 | use moduleImport("knex").getMember("exports").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:136:1:136:72 | use (return (member innerJoin (return (member from (return (member exports (module knex))))))) |
|
| tst.js:136:1:136:72 | use moduleImport("knex").getMember("exports").getReturn().getMember("from").getReturn().getMember("innerJoin").getReturn() |
|
||||||
| tst.js:138:1:138:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:138:1:138:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:138:1:138:30 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:138:1:138:30 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:138:1:138:83 | use (return (member leftJoin (return (member from (return (member select (return (member exports (module knex))))))))) |
|
| tst.js:138:1:138:83 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("leftJoin").getReturn() |
|
||||||
| tst.js:140:1:140:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:140:1:140:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:140:1:140:30 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:140:1:140:30 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:140:1:140:88 | use (return (member leftOuterJoin (return (member from (return (member select (return (member exports (module knex))))))))) |
|
| tst.js:140:1:140:88 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("leftOuterJoin").getReturn() |
|
||||||
| tst.js:142:1:142:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:142:1:142:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:142:1:142:30 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:142:1:142:30 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:142:1:142:84 | use (return (member rightJoin (return (member from (return (member select (return (member exports (module knex))))))))) |
|
| tst.js:142:1:142:84 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("rightJoin").getReturn() |
|
||||||
| tst.js:144:1:144:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:144:1:144:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:144:1:144:30 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:144:1:144:30 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:144:1:144:89 | use (return (member rightOuterJoin (return (member from (return (member select (return (member exports (module knex))))))))) |
|
| tst.js:144:1:144:89 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("rightOuterJoin").getReturn() |
|
||||||
| tst.js:146:1:146:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:146:1:146:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:146:1:146:30 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:146:1:146:30 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:146:1:146:88 | use (return (member fullOuterJoin (return (member from (return (member select (return (member exports (module knex))))))))) |
|
| tst.js:146:1:146:88 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("fullOuterJoin").getReturn() |
|
||||||
| tst.js:148:1:148:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:148:1:148:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:148:1:148:30 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:148:1:148:30 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:148:1:148:52 | use (return (member crossJoin (return (member from (return (member select (return (member exports (module knex))))))))) |
|
| tst.js:148:1:148:52 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("crossJoin").getReturn() |
|
||||||
| tst.js:150:1:150:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:150:1:150:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:150:1:150:33 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:150:1:150:33 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:150:1:150:69 | use (return (member joinRaw (return (member from (return (member select (return (member exports (module knex))))))))) |
|
| tst.js:150:1:150:69 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("joinRaw").getReturn() |
|
||||||
| tst.js:150:1:150:84 | use (return (member where (return (member joinRaw (return (member from (return (member select (return (member exports (module knex))))))))))) |
|
| tst.js:150:1:150:84 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("joinRaw").getReturn().getMember("where").getReturn() |
|
||||||
| tst.js:152:1:152:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:152:1:152:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:152:1:152:30 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:152:1:152:30 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:152:1:154:2 | use (return (member join (return (member from (return (member select (return (member exports (module knex))))))))) |
|
| tst.js:152:1:154:2 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("join").getReturn() |
|
||||||
| tst.js:156:1:156:28 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:156:1:156:28 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:156:1:156:42 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:156:1:156:42 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:156:1:156:63 | use (return (member where (return (member from (return (member select (return (member exports (module knex))))))))) |
|
| tst.js:156:1:156:63 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("where").getReturn() |
|
||||||
| tst.js:156:1:156:79 | use (return (member clear (return (member where (return (member from (return (member select (return (member exports (module knex))))))))))) |
|
| tst.js:156:1:156:79 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("where").getReturn().getMember("clear").getReturn() |
|
||||||
| tst.js:156:1:156:94 | use (return (member clear (return (member clear (return (member where (return (member from (return (member select (return (member exports (module knex))))))))))))) |
|
| tst.js:156:1:156:94 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("where").getReturn().getMember("clear").getReturn().getMember("clear").getReturn() |
|
||||||
| tst.js:158:1:158:17 | use (return (return (member exports (module knex)))) |
|
| tst.js:158:1:158:17 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:158:1:158:53 | use (return (member distinct (return (return (member exports (module knex)))))) |
|
| tst.js:158:1:158:53 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("distinct").getReturn() |
|
||||||
| tst.js:160:1:160:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:160:1:160:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:160:1:160:31 | use (return (member distinctOn (return (return (member exports (module knex)))))) |
|
| tst.js:160:1:160:31 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("distinctOn").getReturn() |
|
||||||
| tst.js:162:1:162:44 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:162:1:162:44 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:162:1:162:58 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:162:1:162:58 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:162:1:162:89 | use (return (member groupByRaw (return (member from (return (member select (return (member exports (module knex))))))))) |
|
| tst.js:162:1:162:89 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("groupByRaw").getReturn() |
|
||||||
| tst.js:162:21:162:43 | use (return (member raw (return (member exports (module knex))))) |
|
| tst.js:162:21:162:43 | use moduleImport("knex").getMember("exports").getReturn().getMember("raw").getReturn() |
|
||||||
| tst.js:164:1:164:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:164:1:164:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:164:1:164:30 | use (return (member orderBy (return (return (member exports (module knex)))))) |
|
| tst.js:164:1:164:30 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("orderBy").getReturn() |
|
||||||
| tst.js:166:1:166:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:166:1:166:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:166:1:166:30 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:166:1:166:30 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:166:1:166:64 | use (return (member orderByRaw (return (member from (return (member select (return (member exports (module knex))))))))) |
|
| tst.js:166:1:166:64 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("orderByRaw").getReturn() |
|
||||||
| tst.js:168:1:168:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:168:1:168:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:168:1:169:19 | use (return (member groupBy (return (return (member exports (module knex)))))) |
|
| tst.js:168:1:169:19 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("groupBy").getReturn() |
|
||||||
| tst.js:168:1:170:26 | use (return (member orderBy (return (member groupBy (return (return (member exports (module knex)))))))) |
|
| tst.js:168:1:170:26 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("groupBy").getReturn().getMember("orderBy").getReturn() |
|
||||||
| tst.js:168:1:171:28 | use (return (member having (return (member orderBy (return (member groupBy (return (return (member exports (module knex)))))))))) |
|
| tst.js:168:1:171:28 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("groupBy").getReturn().getMember("orderBy").getReturn().getMember("having").getReturn() |
|
||||||
| tst.js:173:1:173:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:173:1:173:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:173:1:173:30 | use (return (member from (return (member select (return (member exports (module knex))))))) |
|
| tst.js:173:1:173:30 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn() |
|
||||||
| tst.js:173:1:173:61 | use (return (member havingIn (return (member from (return (member select (return (member exports (module knex))))))))) |
|
| tst.js:173:1:173:61 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn().getMember("from").getReturn().getMember("havingIn").getReturn() |
|
||||||
| tst.js:175:1:175:13 | use (return (return (member exports (module knex)))) |
|
| tst.js:175:1:175:13 | use moduleImport("knex").getMember("exports").getReturn().getReturn() |
|
||||||
| tst.js:175:1:176:19 | use (return (member groupBy (return (return (member exports (module knex)))))) |
|
| tst.js:175:1:176:19 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("groupBy").getReturn() |
|
||||||
| tst.js:175:1:177:26 | use (return (member orderBy (return (member groupBy (return (return (member exports (module knex)))))))) |
|
| tst.js:175:1:177:26 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("groupBy").getReturn().getMember("orderBy").getReturn() |
|
||||||
| tst.js:175:1:178:32 | use (return (member havingRaw (return (member orderBy (return (member groupBy (return (return (member exports (module knex)))))))))) |
|
| tst.js:175:1:178:32 | use moduleImport("knex").getMember("exports").getReturn().getReturn().getMember("groupBy").getReturn().getMember("orderBy").getReturn().getMember("havingRaw").getReturn() |
|
||||||
| tst.js:180:1:180:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:180:1:180:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:181:1:181:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:181:1:181:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:182:1:182:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:182:1:182:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:183:1:183:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:183:1:183:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:184:1:184:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:184:1:184:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:185:1:185:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:185:1:185:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:186:1:186:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:186:1:186:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:187:1:187:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:187:1:187:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
| tst.js:188:1:188:16 | use (return (member select (return (member exports (module knex))))) |
|
| tst.js:188:1:188:16 | use moduleImport("knex").getMember("exports").getReturn().getMember("select").getReturn() |
|
||||||
|
|||||||
@@ -123,11 +123,11 @@ getAffectedStateAccessPath
|
|||||||
| react-redux.jsx:61:13:61:25 | manualReducer | manual |
|
| react-redux.jsx:61:13:61:25 | manualReducer | manual |
|
||||||
| trivial.js:130:14:130:46 | wrapper ... state) | wrapped |
|
| trivial.js:130:14:130:46 | wrapper ... state) | wrapped |
|
||||||
getADispatchFunctionNode
|
getADispatchFunctionNode
|
||||||
| react-redux.jsx:65:20:65:32 | use (return (member useDispatch (member exports (module react-redux)))) |
|
| react-redux.jsx:65:20:65:32 | use moduleImport("react-redux").getMember("exports").getMember("useDispatch").getReturn() |
|
||||||
getADispatchedValueNode
|
getADispatchedValueNode
|
||||||
| react-redux.jsx:27:12:30:5 | def (return (member manualAction (parameter 1 (react-redux-connect)))) |
|
| react-redux.jsx:27:12:30:5 | def getASuccessor(Label::entryPoint("react-redux-connect")).getParameter(1).getMember("manualAction").getReturn() |
|
||||||
| react-redux.jsx:69:18:69:39 | def (parameter 0 (return (member useDispatch (member exports (module react-redux))))) |
|
| react-redux.jsx:69:18:69:39 | def moduleImport("react-redux").getMember("exports").getMember("useDispatch").getReturn().getParameter(0) |
|
||||||
| react-redux.jsx:70:18:70:38 | def (parameter 0 (return (member useDispatch (member exports (module react-redux))))) |
|
| react-redux.jsx:70:18:70:38 | def moduleImport("react-redux").getMember("exports").getMember("useDispatch").getReturn().getParameter(0) |
|
||||||
getAnUntypedActionInReducer
|
getAnUntypedActionInReducer
|
||||||
| exportedReducer.js:12:20:12:25 | action |
|
| exportedReducer.js:12:20:12:25 | action |
|
||||||
| react-redux.jsx:32:31:32:36 | action |
|
| react-redux.jsx:32:31:32:36 | action |
|
||||||
|
|||||||
@@ -25,3 +25,4 @@
|
|||||||
query path:
|
query path:
|
||||||
- /^experimental\/.*/
|
- /^experimental\/.*/
|
||||||
- Metrics/Summaries/FrameworkCoverage.ql
|
- Metrics/Summaries/FrameworkCoverage.ql
|
||||||
|
- /Diagnostics/Internal/.*/
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
query path:
|
query path:
|
||||||
- /^experimental\/.*/
|
- /^experimental\/.*/
|
||||||
- Metrics/Summaries/FrameworkCoverage.ql
|
- Metrics/Summaries/FrameworkCoverage.ql
|
||||||
|
- /Diagnostics/Internal/.*/
|
||||||
- exclude:
|
- exclude:
|
||||||
tags contain:
|
tags contain:
|
||||||
- model-generator
|
- model-generator
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
query path:
|
query path:
|
||||||
- /^experimental\/.*/
|
- /^experimental\/.*/
|
||||||
- Metrics/Summaries/FrameworkCoverage.ql
|
- Metrics/Summaries/FrameworkCoverage.ql
|
||||||
|
- /Diagnostics/Internal/.*/
|
||||||
- exclude:
|
- exclude:
|
||||||
tags contain:
|
tags contain:
|
||||||
- model-generator
|
- model-generator
|
||||||
|
|||||||
@@ -959,13 +959,18 @@ private module StdlibPrivate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A call to `os.path.samefile` will raise an exception if an `os.stat()` call on either pathname fails. */
|
/**
|
||||||
|
* A call to `os.path.samefile` will raise an exception if an `os.stat()` call on either pathname fails.
|
||||||
|
*
|
||||||
|
* See https://docs.python.org/3.10/library/os.path.html#os.path.samefile
|
||||||
|
*/
|
||||||
private class OsPathSamefileCall extends FileSystemAccess::Range, DataFlow::CallCfgNode {
|
private class OsPathSamefileCall extends FileSystemAccess::Range, DataFlow::CallCfgNode {
|
||||||
OsPathSamefileCall() { this = OS::path().getMember("samefile").getACall() }
|
OsPathSamefileCall() { this = OS::path().getMember("samefile").getACall() }
|
||||||
|
|
||||||
override DataFlow::Node getAPathArgument() {
|
override DataFlow::Node getAPathArgument() {
|
||||||
result in [
|
result in [
|
||||||
this.getArg(0), this.getArgByName("path1"), this.getArg(1), this.getArgByName("path2")
|
// note that the f1/f2 names doesn't match the documentation, but is what actually works (tested on 3.8.10)
|
||||||
|
this.getArg(0), this.getArgByName("f1"), this.getArg(1), this.getArgByName("f2")
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2534,6 +2539,56 @@ private module StdlibPrivate {
|
|||||||
PathLibOpenCall() { attrbuteName = "open" }
|
PathLibOpenCall() { attrbuteName = "open" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A call to the `link_to`, `hardlink_to`, or `symlink_to` method on a `pathlib.Path` instance.
|
||||||
|
*
|
||||||
|
* See
|
||||||
|
* - https://docs.python.org/3/library/pathlib.html#pathlib.Path.link_to
|
||||||
|
* - https://docs.python.org/3/library/pathlib.html#pathlib.Path.hardlink_to
|
||||||
|
* - https://docs.python.org/3/library/pathlib.html#pathlib.Path.symlink_to
|
||||||
|
*/
|
||||||
|
private class PathLibLinkToCall extends PathlibFileAccess, API::CallNode {
|
||||||
|
PathLibLinkToCall() { attrbuteName in ["link_to", "hardlink_to", "symlink_to"] }
|
||||||
|
|
||||||
|
override DataFlow::Node getAPathArgument() {
|
||||||
|
result = super.getAPathArgument()
|
||||||
|
or
|
||||||
|
result = this.getParameter(0, "target").getARhs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A call to the `replace` or `rename` method on a `pathlib.Path` instance.
|
||||||
|
*
|
||||||
|
* See
|
||||||
|
* - https://docs.python.org/3/library/pathlib.html#pathlib.Path.replace
|
||||||
|
* - https://docs.python.org/3/library/pathlib.html#pathlib.Path.rename
|
||||||
|
*/
|
||||||
|
private class PathLibReplaceCall extends PathlibFileAccess, API::CallNode {
|
||||||
|
PathLibReplaceCall() { attrbuteName in ["replace", "rename"] }
|
||||||
|
|
||||||
|
override DataFlow::Node getAPathArgument() {
|
||||||
|
result = super.getAPathArgument()
|
||||||
|
or
|
||||||
|
result = this.getParameter(0, "target").getARhs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A call to the `samefile` method on a `pathlib.Path` instance.
|
||||||
|
*
|
||||||
|
* See https://docs.python.org/3/library/pathlib.html#pathlib.Path.samefile
|
||||||
|
*/
|
||||||
|
private class PathLibSameFileCall extends PathlibFileAccess, API::CallNode {
|
||||||
|
PathLibSameFileCall() { attrbuteName = "samefile" }
|
||||||
|
|
||||||
|
override DataFlow::Node getAPathArgument() {
|
||||||
|
result = super.getAPathArgument()
|
||||||
|
or
|
||||||
|
result = this.getParameter(0, "other_path").getARhs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** An additional taint steps for objects of type `pathlib.Path` */
|
/** An additional taint steps for objects of type `pathlib.Path` */
|
||||||
private class PathlibPathTaintStep extends TaintTracking::AdditionalTaintStep {
|
private class PathlibPathTaintStep extends TaintTracking::AdditionalTaintStep {
|
||||||
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
* there is a def/use feature reachable from the root along the given path, and its
|
* there is a def/use feature reachable from the root along the given path, and its
|
||||||
* associated data-flow node must start on the same line as the comment.
|
* associated data-flow node must start on the same line as the comment.
|
||||||
*
|
*
|
||||||
|
* We also support negative assertions of the form `MISSING: def <path>` or `MISSING: use <path>`, which assert
|
||||||
|
* that there _isn't_ a node with the given path on the same line.
|
||||||
|
*
|
||||||
* The query only produces output for failed assertions, meaning that it should have no output
|
* The query only produces output for failed assertions, meaning that it should have no output
|
||||||
* under normal circumstances.
|
* under normal circumstances.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -21,3 +21,15 @@ o(name) # $ getAPathArgument=name
|
|||||||
|
|
||||||
wb = p.write_bytes
|
wb = p.write_bytes
|
||||||
wb(b"hello") # $ getAPathArgument=p fileWriteData=b"hello"
|
wb(b"hello") # $ getAPathArgument=p fileWriteData=b"hello"
|
||||||
|
|
||||||
|
p.link_to("target") # $ getAPathArgument=p getAPathArgument="target"
|
||||||
|
p.link_to(target="target") # $ getAPathArgument=p getAPathArgument="target"
|
||||||
|
|
||||||
|
p.samefile("other_path") # $ getAPathArgument=p getAPathArgument="other_path"
|
||||||
|
p.samefile(other_path="other_path") # $ getAPathArgument=p getAPathArgument="other_path"
|
||||||
|
|
||||||
|
p.rename("target") # $ getAPathArgument=p getAPathArgument="target"
|
||||||
|
p.rename(target="target") # $ getAPathArgument=p getAPathArgument="target"
|
||||||
|
|
||||||
|
p.replace("target") # $ getAPathArgument=p getAPathArgument="target"
|
||||||
|
p.replace(target="target") # $ getAPathArgument=p getAPathArgument="target"
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ os.path.islink(path="path") # $ getAPathArgument="path"
|
|||||||
os.path.ismount("path") # $ getAPathArgument="path"
|
os.path.ismount("path") # $ getAPathArgument="path"
|
||||||
os.path.ismount(path="path") # $ getAPathArgument="path"
|
os.path.ismount(path="path") # $ getAPathArgument="path"
|
||||||
|
|
||||||
|
os.path.samefile("f1", "f2") # $ getAPathArgument="f1" getAPathArgument="f2"
|
||||||
|
os.path.samefile(f1="f1", f2="f2") # $ getAPathArgument="f1" getAPathArgument="f2"
|
||||||
|
|
||||||
# actual os.path implementations
|
# actual os.path implementations
|
||||||
import posixpath
|
import posixpath
|
||||||
import ntpath
|
import ntpath
|
||||||
|
|||||||
@@ -42,9 +42,7 @@ module AccessPath {
|
|||||||
* Parses a lower-bounded interval `n..` and gets the lower bound.
|
* Parses a lower-bounded interval `n..` and gets the lower bound.
|
||||||
*/
|
*/
|
||||||
bindingset[arg]
|
bindingset[arg]
|
||||||
private int parseLowerBound(string arg) {
|
int parseLowerBound(string arg) { result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt() }
|
||||||
result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses an integer constant or interval (bounded or unbounded) that explicitly
|
* Parses an integer constant or interval (bounded or unbounded) that explicitly
|
||||||
|
|||||||
@@ -268,15 +268,17 @@ private module Cached {
|
|||||||
TPositionalParameterPosition(int pos) {
|
TPositionalParameterPosition(int pos) {
|
||||||
pos = any(Parameter p).getPosition()
|
pos = any(Parameter p).getPosition()
|
||||||
or
|
or
|
||||||
pos in [0 .. 100] // TODO: remove once `Argument[_]` summaries are replaced with `Argument[i..]`
|
|
||||||
or
|
|
||||||
FlowSummaryImplSpecific::ParsePositions::isParsedArgumentPosition(_, pos)
|
FlowSummaryImplSpecific::ParsePositions::isParsedArgumentPosition(_, pos)
|
||||||
} or
|
} or
|
||||||
|
TPositionalParameterLowerBoundPosition(int pos) {
|
||||||
|
FlowSummaryImplSpecific::ParsePositions::isParsedArgumentLowerBoundPosition(_, pos)
|
||||||
|
} or
|
||||||
TKeywordParameterPosition(string name) {
|
TKeywordParameterPosition(string name) {
|
||||||
name = any(KeywordParameter kp).getName()
|
name = any(KeywordParameter kp).getName()
|
||||||
or
|
or
|
||||||
FlowSummaryImplSpecific::ParsePositions::isParsedKeywordArgumentPosition(_, name)
|
FlowSummaryImplSpecific::ParsePositions::isParsedKeywordArgumentPosition(_, name)
|
||||||
}
|
} or
|
||||||
|
TAnyParameterPosition()
|
||||||
}
|
}
|
||||||
|
|
||||||
import Cached
|
import Cached
|
||||||
@@ -468,9 +470,18 @@ class ParameterPosition extends TParameterPosition {
|
|||||||
/** Holds if this position represents a positional parameter at position `pos`. */
|
/** Holds if this position represents a positional parameter at position `pos`. */
|
||||||
predicate isPositional(int pos) { this = TPositionalParameterPosition(pos) }
|
predicate isPositional(int pos) { this = TPositionalParameterPosition(pos) }
|
||||||
|
|
||||||
|
/** Holds if this position represents any positional parameter starting from position `pos`. */
|
||||||
|
predicate isPositionalLowerBound(int pos) { this = TPositionalParameterLowerBoundPosition(pos) }
|
||||||
|
|
||||||
/** Holds if this position represents a keyword parameter named `name`. */
|
/** Holds if this position represents a keyword parameter named `name`. */
|
||||||
predicate isKeyword(string name) { this = TKeywordParameterPosition(name) }
|
predicate isKeyword(string name) { this = TKeywordParameterPosition(name) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if this position represents any parameter. This includes both positional
|
||||||
|
* and named parameters.
|
||||||
|
*/
|
||||||
|
predicate isAny() { this = TAnyParameterPosition() }
|
||||||
|
|
||||||
/** Gets a textual representation of this position. */
|
/** Gets a textual representation of this position. */
|
||||||
string toString() {
|
string toString() {
|
||||||
this.isSelf() and result = "self"
|
this.isSelf() and result = "self"
|
||||||
@@ -479,7 +490,11 @@ class ParameterPosition extends TParameterPosition {
|
|||||||
or
|
or
|
||||||
exists(int pos | this.isPositional(pos) and result = "position " + pos)
|
exists(int pos | this.isPositional(pos) and result = "position " + pos)
|
||||||
or
|
or
|
||||||
|
exists(int pos | this.isPositionalLowerBound(pos) and result = "position " + pos + "..")
|
||||||
|
or
|
||||||
exists(string name | this.isKeyword(name) and result = "keyword " + name)
|
exists(string name | this.isKeyword(name) and result = "keyword " + name)
|
||||||
|
or
|
||||||
|
this.isAny() and result = "any"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,5 +533,11 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
|
|||||||
or
|
or
|
||||||
exists(int pos | ppos.isPositional(pos) and apos.isPositional(pos))
|
exists(int pos | ppos.isPositional(pos) and apos.isPositional(pos))
|
||||||
or
|
or
|
||||||
|
exists(int pos1, int pos2 |
|
||||||
|
ppos.isPositionalLowerBound(pos1) and apos.isPositional(pos2) and pos2 >= pos1
|
||||||
|
)
|
||||||
|
or
|
||||||
exists(string name | ppos.isKeyword(name) and apos.isKeyword(name))
|
exists(string name | ppos.isKeyword(name) and apos.isKeyword(name))
|
||||||
|
or
|
||||||
|
ppos.isAny() and exists(apos)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -767,10 +767,10 @@ private module OutNodes {
|
|||||||
import OutNodes
|
import OutNodes
|
||||||
|
|
||||||
predicate jumpStep(Node pred, Node succ) {
|
predicate jumpStep(Node pred, Node succ) {
|
||||||
SsaImpl::captureFlowIn(pred.(SsaDefinitionNode).getDefinition(),
|
SsaImpl::captureFlowIn(_, pred.(SsaDefinitionNode).getDefinition(),
|
||||||
succ.(SsaDefinitionNode).getDefinition())
|
succ.(SsaDefinitionNode).getDefinition())
|
||||||
or
|
or
|
||||||
SsaImpl::captureFlowOut(pred.(SsaDefinitionNode).getDefinition(),
|
SsaImpl::captureFlowOut(_, pred.(SsaDefinitionNode).getDefinition(),
|
||||||
succ.(SsaDefinitionNode).getDefinition())
|
succ.(SsaDefinitionNode).getDefinition())
|
||||||
or
|
or
|
||||||
succ.asExpr().getExpr().(ConstantReadAccess).getValue() = pred.asExpr().getExpr()
|
succ.asExpr().getExpr().(ConstantReadAccess).getValue() = pred.asExpr().getExpr()
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ private import codeql.ruby.CFG
|
|||||||
private import codeql.ruby.typetracking.TypeTracker
|
private import codeql.ruby.typetracking.TypeTracker
|
||||||
private import codeql.ruby.dataflow.SSA
|
private import codeql.ruby.dataflow.SSA
|
||||||
private import FlowSummaryImpl as FlowSummaryImpl
|
private import FlowSummaryImpl as FlowSummaryImpl
|
||||||
|
private import SsaImpl as SsaImpl
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An element, viewed as a node in a data flow graph. Either an expression
|
* An element, viewed as a node in a data flow graph. Either an expression
|
||||||
@@ -256,6 +257,26 @@ abstract class BarrierGuard extends CfgNodes::ExprCfgNode {
|
|||||||
*/
|
*/
|
||||||
abstract predicate checks(CfgNode expr, boolean branch);
|
abstract predicate checks(CfgNode expr, boolean branch);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an implicit entry definition for a captured variable that
|
||||||
|
* may be guarded, because a call to the capturing callable is guarded.
|
||||||
|
*
|
||||||
|
* This is restricted to calls where the variable is captured inside a
|
||||||
|
* block.
|
||||||
|
*/
|
||||||
|
private Ssa::Definition getAMaybeGuardedCapturedDef() {
|
||||||
|
exists(
|
||||||
|
boolean branch, CfgNodes::ExprCfgNode testedNode, Ssa::Definition def,
|
||||||
|
CfgNodes::ExprNodes::CallCfgNode call
|
||||||
|
|
|
||||||
|
def.getARead() = testedNode and
|
||||||
|
this.checks(testedNode, branch) and
|
||||||
|
SsaImpl::captureFlowIn(call, def, result) and
|
||||||
|
this.controlsBlock(call.getBasicBlock(), branch) and
|
||||||
|
result.getBasicBlock().getScope() = call.getExpr().(MethodCall).getBlock()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
final Node getAGuardedNode() {
|
final Node getAGuardedNode() {
|
||||||
exists(boolean branch, CfgNodes::ExprCfgNode testedNode, Ssa::Definition def |
|
exists(boolean branch, CfgNodes::ExprCfgNode testedNode, Ssa::Definition def |
|
||||||
def.getARead() = testedNode and
|
def.getARead() = testedNode and
|
||||||
@@ -263,5 +284,7 @@ abstract class BarrierGuard extends CfgNodes::ExprCfgNode {
|
|||||||
this.checks(testedNode, branch) and
|
this.checks(testedNode, branch) and
|
||||||
this.controlsBlock(result.asExpr().getBasicBlock(), branch)
|
this.controlsBlock(result.asExpr().getBasicBlock(), branch)
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
result.asExpr() = this.getAMaybeGuardedCapturedDef().getARead()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,21 +61,32 @@ predicate summaryElement(
|
|||||||
*
|
*
|
||||||
* This covers all the Ruby-specific components of a flow summary.
|
* This covers all the Ruby-specific components of a flow summary.
|
||||||
*/
|
*/
|
||||||
bindingset[c]
|
|
||||||
SummaryComponent interpretComponentSpecific(AccessPathToken c) {
|
SummaryComponent interpretComponentSpecific(AccessPathToken c) {
|
||||||
c = "Argument[_]" and
|
c.getName() = "Argument" and
|
||||||
result = FlowSummary::SummaryComponent::argument(any(ParameterPosition pos | pos.isPositional(_)))
|
exists(string arg, ParameterPosition ppos |
|
||||||
|
arg = c.getAnArgument() and
|
||||||
|
result = FlowSummary::SummaryComponent::argument(ppos)
|
||||||
|
|
|
||||||
|
arg = "any" and
|
||||||
|
ppos.isAny()
|
||||||
|
or
|
||||||
|
ppos.isPositionalLowerBound(AccessPath::parseLowerBound(arg))
|
||||||
|
)
|
||||||
or
|
or
|
||||||
c = "ArrayElement" and
|
c.getName() = "ArrayElement" and
|
||||||
result = FlowSummary::SummaryComponent::arrayElementAny()
|
(
|
||||||
or
|
c.getNumArgument() = 0 and
|
||||||
c = "ArrayElement[?]" and
|
result = FlowSummary::SummaryComponent::arrayElementAny()
|
||||||
result = FlowSummary::SummaryComponent::arrayElementUnknown()
|
or
|
||||||
or
|
exists(string arg | arg = c.getAnArgument() |
|
||||||
exists(int i |
|
arg = "?" and
|
||||||
c.getName() = "ArrayElement" and
|
result = FlowSummary::SummaryComponent::arrayElementUnknown()
|
||||||
i = AccessPath::parseInt(c.getAnArgument()) and
|
or
|
||||||
result = FlowSummary::SummaryComponent::arrayElementKnown(i)
|
exists(int i |
|
||||||
|
i = AccessPath::parseInt(c.getAnArgument()) and
|
||||||
|
result = FlowSummary::SummaryComponent::arrayElementKnown(i)
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,6 +212,11 @@ module ParsePositions {
|
|||||||
i = AccessPath::parseInt(c)
|
i = AccessPath::parseInt(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
predicate isParsedArgumentLowerBoundPosition(string c, int i) {
|
||||||
|
isArgBody(c) and
|
||||||
|
i = AccessPath::parseLowerBound(c)
|
||||||
|
}
|
||||||
|
|
||||||
predicate isParsedKeywordParameterPosition(string c, string paramName) {
|
predicate isParsedKeywordParameterPosition(string c, string paramName) {
|
||||||
isParamBody(c) and
|
isParamBody(c) and
|
||||||
c = paramName + ":"
|
c = paramName + ":"
|
||||||
@@ -238,6 +254,11 @@ ParameterPosition parseArgBody(string s) {
|
|||||||
result.isPositional(i)
|
result.isPositional(i)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
exists(int i |
|
||||||
|
ParsePositions::isParsedArgumentLowerBoundPosition(s, i) and
|
||||||
|
result.isPositionalLowerBound(i)
|
||||||
|
)
|
||||||
|
or
|
||||||
exists(string name |
|
exists(string name |
|
||||||
ParsePositions::isParsedKeywordArgumentPosition(s, name) and
|
ParsePositions::isParsedKeywordArgumentPosition(s, name) and
|
||||||
result.isKeyword(name)
|
result.isKeyword(name)
|
||||||
|
|||||||
@@ -72,16 +72,18 @@ private predicate hasVariableWriteWithCapturedRead(BasicBlock bb, LocalVariable
|
|||||||
* Holds if the call `call` at index `i` in basic block `bb` may reach
|
* Holds if the call `call` at index `i` in basic block `bb` may reach
|
||||||
* a callable that reads captured variable `v`.
|
* a callable that reads captured variable `v`.
|
||||||
*/
|
*/
|
||||||
private predicate capturedCallRead(Call call, BasicBlock bb, int i, LocalVariable v) {
|
private predicate capturedCallRead(
|
||||||
|
CfgNodes::ExprNodes::CallCfgNode call, BasicBlock bb, int i, LocalVariable v
|
||||||
|
) {
|
||||||
exists(CfgScope scope |
|
exists(CfgScope scope |
|
||||||
hasVariableWriteWithCapturedRead(bb.getAPredecessor*(), v, scope) and
|
hasVariableWriteWithCapturedRead(bb.getAPredecessor*(), v, scope) and
|
||||||
call = bb.getNode(i).getNode()
|
call = bb.getNode(i)
|
||||||
|
|
|
|
||||||
// If the read happens inside a block, we restrict to the call that
|
// If the read happens inside a block, we restrict to the call that
|
||||||
// contains the block
|
// contains the block
|
||||||
not scope instanceof Block
|
not scope instanceof Block
|
||||||
or
|
or
|
||||||
scope = call.(MethodCall).getBlock()
|
scope = call.getExpr().(MethodCall).getBlock()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,16 +150,18 @@ private module Cached {
|
|||||||
* that writes captured variable `v`.
|
* that writes captured variable `v`.
|
||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
predicate capturedCallWrite(Call call, BasicBlock bb, int i, LocalVariable v) {
|
predicate capturedCallWrite(
|
||||||
|
CfgNodes::ExprNodes::CallCfgNode call, BasicBlock bb, int i, LocalVariable v
|
||||||
|
) {
|
||||||
exists(CfgScope scope |
|
exists(CfgScope scope |
|
||||||
hasVariableReadWithCapturedWrite(bb.getASuccessor*(), v, scope) and
|
hasVariableReadWithCapturedWrite(bb.getASuccessor*(), v, scope) and
|
||||||
call = bb.getNode(i).getNode()
|
call = bb.getNode(i)
|
||||||
|
|
|
|
||||||
// If the write happens inside a block, we restrict to the call that
|
// If the write happens inside a block, we restrict to the call that
|
||||||
// contains the block
|
// contains the block
|
||||||
not scope instanceof Block
|
not scope instanceof Block
|
||||||
or
|
or
|
||||||
scope = call.(MethodCall).getBlock()
|
scope = call.getExpr().(MethodCall).getBlock()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +193,7 @@ private module Cached {
|
|||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate defReachesCallReadInOuterScope(
|
private predicate defReachesCallReadInOuterScope(
|
||||||
Definition def, Call call, LocalVariable v, CfgScope scope
|
Definition def, CfgNodes::ExprNodes::CallCfgNode call, LocalVariable v, CfgScope scope
|
||||||
) {
|
) {
|
||||||
exists(BasicBlock bb, int i |
|
exists(BasicBlock bb, int i |
|
||||||
ssaDefReachesRead(v, def, bb, i) and
|
ssaDefReachesRead(v, def, bb, i) and
|
||||||
@@ -217,8 +221,8 @@ private module Cached {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
predicate captureFlowIn(Definition def, Definition entry) {
|
predicate captureFlowIn(CfgNodes::ExprNodes::CallCfgNode call, Definition def, Definition entry) {
|
||||||
exists(Call call, LocalVariable v, CfgScope scope |
|
exists(LocalVariable v, CfgScope scope |
|
||||||
defReachesCallReadInOuterScope(def, call, v, scope) and
|
defReachesCallReadInOuterScope(def, call, v, scope) and
|
||||||
hasCapturedEntryWrite(entry, v, scope)
|
hasCapturedEntryWrite(entry, v, scope)
|
||||||
|
|
|
|
||||||
@@ -226,7 +230,7 @@ private module Cached {
|
|||||||
// contains the block
|
// contains the block
|
||||||
not scope instanceof Block
|
not scope instanceof Block
|
||||||
or
|
or
|
||||||
scope = call.(MethodCall).getBlock()
|
scope = call.getExpr().(MethodCall).getBlock()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,7 +246,9 @@ private module Cached {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate hasCapturedExitRead(Definition exit, Call call, LocalVariable v, CfgScope scope) {
|
private predicate hasCapturedExitRead(
|
||||||
|
Definition exit, CfgNodes::ExprNodes::CallCfgNode call, LocalVariable v, CfgScope scope
|
||||||
|
) {
|
||||||
exists(BasicBlock bb, int i |
|
exists(BasicBlock bb, int i |
|
||||||
capturedCallWrite(call, bb, i, v) and
|
capturedCallWrite(call, bb, i, v) and
|
||||||
exit.definesAt(v, bb, i) and
|
exit.definesAt(v, bb, i) and
|
||||||
@@ -261,8 +267,8 @@ private module Cached {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
predicate captureFlowOut(Definition def, Definition exit) {
|
predicate captureFlowOut(CfgNodes::ExprNodes::CallCfgNode call, Definition def, Definition exit) {
|
||||||
exists(Call call, LocalVariable v, CfgScope scope |
|
exists(LocalVariable v, CfgScope scope |
|
||||||
defReachesExitReadInInnerScope(def, v, scope) and
|
defReachesExitReadInInnerScope(def, v, scope) and
|
||||||
hasCapturedExitRead(exit, call, v, _)
|
hasCapturedExitRead(exit, call, v, _)
|
||||||
|
|
|
|
||||||
@@ -270,7 +276,7 @@ private module Cached {
|
|||||||
// contains the block
|
// contains the block
|
||||||
not scope instanceof Block
|
not scope instanceof Block
|
||||||
or
|
or
|
||||||
scope = call.(MethodCall).getBlock()
|
scope = call.getExpr().(MethodCall).getBlock()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,11 @@ private module Cached {
|
|||||||
exists(CfgNodes::ExprNodes::OperationCfgNode op |
|
exists(CfgNodes::ExprNodes::OperationCfgNode op |
|
||||||
op = nodeTo.asExpr() and
|
op = nodeTo.asExpr() and
|
||||||
op.getAnOperand() = nodeFrom.asExpr() and
|
op.getAnOperand() = nodeFrom.asExpr() and
|
||||||
not op.getExpr() instanceof AssignExpr
|
not op.getExpr() =
|
||||||
|
any(Expr e |
|
||||||
|
e instanceof AssignExpr or
|
||||||
|
e instanceof SplatExpr
|
||||||
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// string interpolation of `nodeFrom` into `nodeTo`
|
// string interpolation of `nodeFrom` into `nodeTo`
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ module File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||||
input = "Argument[_]" and
|
input = "Argument[0..]" and
|
||||||
output = "ReturnValue" and
|
output = "ReturnValue" and
|
||||||
preservesValue = false
|
preservesValue = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -507,7 +507,7 @@ module Array {
|
|||||||
ConcatSummary() { this = "concat" }
|
ConcatSummary() { this = "concat" }
|
||||||
|
|
||||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||||
input = "Argument[_].ArrayElement" and
|
input = "Argument[0..].ArrayElement" and
|
||||||
output = "Argument[self].ArrayElement[?]" and
|
output = "Argument[self].ArrayElement[?]" and
|
||||||
preservesValue = true
|
preservesValue = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ module String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||||
input = ["Argument[self]", "Argument[_]"] and
|
input = "Argument[self,0..]" and
|
||||||
output = ["ReturnValue", "Argument[self]"] and
|
output = ["ReturnValue", "Argument[self]"] and
|
||||||
preservesValue = false
|
preservesValue = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
* otherwise `CodeInjectionCustomizations` should be imported instead.
|
* otherwise `CodeInjectionCustomizations` should be imported instead.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import codeql.ruby.DataFlow::DataFlow::PathGraph
|
|
||||||
import codeql.ruby.DataFlow
|
import codeql.ruby.DataFlow
|
||||||
import codeql.ruby.TaintTracking
|
import codeql.ruby.TaintTracking
|
||||||
import CodeInjectionCustomizations::CodeInjection
|
import CodeInjectionCustomizations::CodeInjection
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
* otherwise `ServerSideRequestForgeryCustomizations` should be imported instead.
|
* otherwise `ServerSideRequestForgeryCustomizations` should be imported instead.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import codeql.ruby.DataFlow::DataFlow::PathGraph
|
|
||||||
import codeql.ruby.DataFlow
|
import codeql.ruby.DataFlow
|
||||||
import codeql.ruby.TaintTracking
|
import codeql.ruby.TaintTracking
|
||||||
import ServerSideRequestForgeryCustomizations::ServerSideRequestForgery
|
import ServerSideRequestForgeryCustomizations::ServerSideRequestForgery
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
private import ruby
|
private import ruby
|
||||||
import codeql.ruby.DataFlow::DataFlow::PathGraph
|
|
||||||
import codeql.ruby.DataFlow
|
import codeql.ruby.DataFlow
|
||||||
import codeql.ruby.TaintTracking
|
import codeql.ruby.TaintTracking
|
||||||
import UrlRedirectCustomizations
|
import UrlRedirectCustomizations
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
* otherwise `RegExpInjectionCustomizations` should be imported instead.
|
* otherwise `RegExpInjectionCustomizations` should be imported instead.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import codeql.ruby.DataFlow::DataFlow::PathGraph
|
|
||||||
import codeql.ruby.DataFlow
|
import codeql.ruby.DataFlow
|
||||||
import codeql.ruby.TaintTracking
|
import codeql.ruby.TaintTracking
|
||||||
import RegExpInjectionCustomizations
|
import RegExpInjectionCustomizations
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
import ruby
|
import ruby
|
||||||
import codeql.ruby.DataFlow
|
import codeql.ruby.DataFlow
|
||||||
import codeql.ruby.security.ServerSideRequestForgeryQuery
|
import codeql.ruby.security.ServerSideRequestForgeryQuery
|
||||||
|
import DataFlow::PathGraph
|
||||||
|
|
||||||
from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink
|
from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||||
where config.hasFlowPath(source, sink)
|
where config.hasFlowPath(source, sink)
|
||||||
|
|||||||
@@ -10,9 +10,6 @@ edges
|
|||||||
| array_flow.rb:2:10:2:20 | call to source : | array_flow.rb:2:9:2:20 | * ... : |
|
| array_flow.rb:2:10:2:20 | call to source : | array_flow.rb:2:9:2:20 | * ... : |
|
||||||
| array_flow.rb:2:10:2:20 | call to source : | array_flow.rb:2:9:2:20 | * ... [array element 0] : |
|
| array_flow.rb:2:10:2:20 | call to source : | array_flow.rb:2:9:2:20 | * ... [array element 0] : |
|
||||||
| array_flow.rb:2:10:2:20 | call to source : | array_flow.rb:2:9:2:20 | * ... [array element 0] : |
|
| array_flow.rb:2:10:2:20 | call to source : | array_flow.rb:2:9:2:20 | * ... [array element 0] : |
|
||||||
| array_flow.rb:2:10:2:20 | call to source : | array_flow.rb:3:10:3:10 | a : |
|
|
||||||
| array_flow.rb:2:10:2:20 | call to source : | array_flow.rb:4:10:4:10 | a : |
|
|
||||||
| array_flow.rb:2:10:2:20 | call to source : | array_flow.rb:5:10:5:10 | a : |
|
|
||||||
| array_flow.rb:3:10:3:10 | a : | array_flow.rb:3:10:3:13 | ...[...] |
|
| array_flow.rb:3:10:3:10 | a : | array_flow.rb:3:10:3:13 | ...[...] |
|
||||||
| array_flow.rb:3:10:3:10 | a [array element 0] : | array_flow.rb:3:10:3:13 | ...[...] |
|
| array_flow.rb:3:10:3:10 | a [array element 0] : | array_flow.rb:3:10:3:13 | ...[...] |
|
||||||
| array_flow.rb:3:10:3:10 | a [array element 0] : | array_flow.rb:3:10:3:13 | ...[...] |
|
| array_flow.rb:3:10:3:10 | a [array element 0] : | array_flow.rb:3:10:3:13 | ...[...] |
|
||||||
|
|||||||
@@ -4,3 +4,4 @@
|
|||||||
| barrier-guards.rb:21:8:21:19 | ... == ... | barrier-guards.rb:24:5:24:7 | foo | barrier-guards.rb:21:8:21:10 | foo | true |
|
| barrier-guards.rb:21:8:21:19 | ... == ... | barrier-guards.rb:24:5:24:7 | foo | barrier-guards.rb:21:8:21:10 | foo | true |
|
||||||
| barrier-guards.rb:27:8:27:19 | ... != ... | barrier-guards.rb:28:5:28:7 | foo | barrier-guards.rb:27:8:27:10 | foo | false |
|
| barrier-guards.rb:27:8:27:19 | ... != ... | barrier-guards.rb:28:5:28:7 | foo | barrier-guards.rb:27:8:27:10 | foo | false |
|
||||||
| barrier-guards.rb:37:4:37:20 | call to include? | barrier-guards.rb:38:5:38:7 | foo | barrier-guards.rb:37:17:37:19 | foo | true |
|
| barrier-guards.rb:37:4:37:20 | call to include? | barrier-guards.rb:38:5:38:7 | foo | barrier-guards.rb:37:17:37:19 | foo | true |
|
||||||
|
| barrier-guards.rb:43:4:43:15 | ... == ... | barrier-guards.rb:45:9:45:11 | foo | barrier-guards.rb:43:4:43:6 | foo | true |
|
||||||
|
|||||||
@@ -39,3 +39,26 @@ if FOO.include?(foo)
|
|||||||
else
|
else
|
||||||
foo
|
foo
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if foo == "foo"
|
||||||
|
capture {
|
||||||
|
foo # guarded
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
if foo == "foo"
|
||||||
|
capture {
|
||||||
|
foo = "bar"
|
||||||
|
foo # not guarded
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
if foo == "foo"
|
||||||
|
my_lambda = -> () {
|
||||||
|
foo # not guarded
|
||||||
|
}
|
||||||
|
|
||||||
|
foo = "bar"
|
||||||
|
|
||||||
|
my_lambda()
|
||||||
|
end
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ edges
|
|||||||
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:37:36:37:42 | tainted |
|
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:37:36:37:42 | tainted |
|
||||||
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:37:36:37:42 | tainted |
|
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:37:36:37:42 | tainted |
|
||||||
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:51:24:51:30 | tainted : |
|
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:51:24:51:30 | tainted : |
|
||||||
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:54:23:54:29 | tainted : |
|
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:54:22:54:28 | tainted : |
|
||||||
|
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:55:17:55:23 | tainted : |
|
||||||
|
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:58:32:58:38 | tainted : |
|
||||||
|
| summaries.rb:1:11:1:36 | call to identity : | summaries.rb:60:23:60:29 | tainted : |
|
||||||
| summaries.rb:1:20:1:36 | call to source : | summaries.rb:1:11:1:36 | call to identity : |
|
| summaries.rb:1:20:1:36 | call to source : | summaries.rb:1:11:1:36 | call to identity : |
|
||||||
| summaries.rb:1:20:1:36 | call to source : | summaries.rb:1:11:1:36 | call to identity : |
|
| summaries.rb:1:20:1:36 | call to source : | summaries.rb:1:11:1:36 | call to identity : |
|
||||||
| summaries.rb:4:12:7:3 | call to apply_block : | summaries.rb:9:6:9:13 | tainted2 |
|
| summaries.rb:4:12:7:3 | call to apply_block : | summaries.rb:9:6:9:13 | tainted2 |
|
||||||
@@ -52,10 +55,13 @@ edges
|
|||||||
| summaries.rb:44:8:44:8 | t : | summaries.rb:44:8:44:27 | call to matchedByNameRcv |
|
| summaries.rb:44:8:44:8 | t : | summaries.rb:44:8:44:27 | call to matchedByNameRcv |
|
||||||
| summaries.rb:48:24:48:41 | call to source : | summaries.rb:48:8:48:42 | call to preserveTaint |
|
| summaries.rb:48:24:48:41 | call to source : | summaries.rb:48:8:48:42 | call to preserveTaint |
|
||||||
| summaries.rb:51:24:51:30 | tainted : | summaries.rb:51:6:51:31 | call to namedArg |
|
| summaries.rb:51:24:51:30 | tainted : | summaries.rb:51:6:51:31 | call to namedArg |
|
||||||
| summaries.rb:54:23:54:29 | tainted : | summaries.rb:54:40:54:40 | x : |
|
| summaries.rb:54:22:54:28 | tainted : | summaries.rb:54:6:54:29 | call to anyArg |
|
||||||
| summaries.rb:54:40:54:40 | x : | summaries.rb:55:8:55:8 | x |
|
| summaries.rb:55:17:55:23 | tainted : | summaries.rb:55:6:55:24 | call to anyArg |
|
||||||
| summaries.rb:62:24:62:53 | call to source : | summaries.rb:62:8:62:54 | call to preserveTaint |
|
| summaries.rb:58:32:58:38 | tainted : | summaries.rb:58:6:58:39 | call to anyPositionFromOne |
|
||||||
| summaries.rb:65:26:65:56 | call to source : | summaries.rb:65:8:65:57 | call to preserveTaint |
|
| summaries.rb:60:23:60:29 | tainted : | summaries.rb:60:40:60:40 | x : |
|
||||||
|
| summaries.rb:60:40:60:40 | x : | summaries.rb:61:8:61:8 | x |
|
||||||
|
| summaries.rb:68:24:68:53 | call to source : | summaries.rb:68:8:68:54 | call to preserveTaint |
|
||||||
|
| summaries.rb:71:26:71:56 | call to source : | summaries.rb:71:8:71:57 | call to preserveTaint |
|
||||||
nodes
|
nodes
|
||||||
| summaries.rb:1:11:1:36 | call to identity : | semmle.label | call to identity : |
|
| summaries.rb:1:11:1:36 | call to identity : | semmle.label | call to identity : |
|
||||||
| summaries.rb:1:11:1:36 | call to identity : | semmle.label | call to identity : |
|
| summaries.rb:1:11:1:36 | call to identity : | semmle.label | call to identity : |
|
||||||
@@ -112,13 +118,19 @@ nodes
|
|||||||
| summaries.rb:48:24:48:41 | call to source : | semmle.label | call to source : |
|
| summaries.rb:48:24:48:41 | call to source : | semmle.label | call to source : |
|
||||||
| summaries.rb:51:6:51:31 | call to namedArg | semmle.label | call to namedArg |
|
| summaries.rb:51:6:51:31 | call to namedArg | semmle.label | call to namedArg |
|
||||||
| summaries.rb:51:24:51:30 | tainted : | semmle.label | tainted : |
|
| summaries.rb:51:24:51:30 | tainted : | semmle.label | tainted : |
|
||||||
| summaries.rb:54:23:54:29 | tainted : | semmle.label | tainted : |
|
| summaries.rb:54:6:54:29 | call to anyArg | semmle.label | call to anyArg |
|
||||||
| summaries.rb:54:40:54:40 | x : | semmle.label | x : |
|
| summaries.rb:54:22:54:28 | tainted : | semmle.label | tainted : |
|
||||||
| summaries.rb:55:8:55:8 | x | semmle.label | x |
|
| summaries.rb:55:6:55:24 | call to anyArg | semmle.label | call to anyArg |
|
||||||
| summaries.rb:62:8:62:54 | call to preserveTaint | semmle.label | call to preserveTaint |
|
| summaries.rb:55:17:55:23 | tainted : | semmle.label | tainted : |
|
||||||
| summaries.rb:62:24:62:53 | call to source : | semmle.label | call to source : |
|
| summaries.rb:58:6:58:39 | call to anyPositionFromOne | semmle.label | call to anyPositionFromOne |
|
||||||
| summaries.rb:65:8:65:57 | call to preserveTaint | semmle.label | call to preserveTaint |
|
| summaries.rb:58:32:58:38 | tainted : | semmle.label | tainted : |
|
||||||
| summaries.rb:65:26:65:56 | call to source : | semmle.label | call to source : |
|
| summaries.rb:60:23:60:29 | tainted : | semmle.label | tainted : |
|
||||||
|
| summaries.rb:60:40:60:40 | x : | semmle.label | x : |
|
||||||
|
| summaries.rb:61:8:61:8 | x | semmle.label | x |
|
||||||
|
| summaries.rb:68:8:68:54 | call to preserveTaint | semmle.label | call to preserveTaint |
|
||||||
|
| summaries.rb:68:24:68:53 | call to source : | semmle.label | call to source : |
|
||||||
|
| summaries.rb:71:8:71:57 | call to preserveTaint | semmle.label | call to preserveTaint |
|
||||||
|
| summaries.rb:71:26:71:56 | call to source : | semmle.label | call to source : |
|
||||||
subpaths
|
subpaths
|
||||||
invalidSpecComponent
|
invalidSpecComponent
|
||||||
invalidOutputSpecComponent
|
invalidOutputSpecComponent
|
||||||
@@ -150,9 +162,12 @@ invalidOutputSpecComponent
|
|||||||
| summaries.rb:44:8:44:27 | call to matchedByNameRcv | summaries.rb:40:7:40:17 | call to source : | summaries.rb:44:8:44:27 | call to matchedByNameRcv | $@ | summaries.rb:40:7:40:17 | call to source : | call to source : |
|
| summaries.rb:44:8:44:27 | call to matchedByNameRcv | summaries.rb:40:7:40:17 | call to source : | summaries.rb:44:8:44:27 | call to matchedByNameRcv | $@ | summaries.rb:40:7:40:17 | call to source : | call to source : |
|
||||||
| summaries.rb:48:8:48:42 | call to preserveTaint | summaries.rb:48:24:48:41 | call to source : | summaries.rb:48:8:48:42 | call to preserveTaint | $@ | summaries.rb:48:24:48:41 | call to source : | call to source : |
|
| summaries.rb:48:8:48:42 | call to preserveTaint | summaries.rb:48:24:48:41 | call to source : | summaries.rb:48:8:48:42 | call to preserveTaint | $@ | summaries.rb:48:24:48:41 | call to source : | call to source : |
|
||||||
| summaries.rb:51:6:51:31 | call to namedArg | summaries.rb:1:20:1:36 | call to source : | summaries.rb:51:6:51:31 | call to namedArg | $@ | summaries.rb:1:20:1:36 | call to source : | call to source : |
|
| summaries.rb:51:6:51:31 | call to namedArg | summaries.rb:1:20:1:36 | call to source : | summaries.rb:51:6:51:31 | call to namedArg | $@ | summaries.rb:1:20:1:36 | call to source : | call to source : |
|
||||||
| summaries.rb:55:8:55:8 | x | summaries.rb:1:20:1:36 | call to source : | summaries.rb:55:8:55:8 | x | $@ | summaries.rb:1:20:1:36 | call to source : | call to source : |
|
| summaries.rb:54:6:54:29 | call to anyArg | summaries.rb:1:20:1:36 | call to source : | summaries.rb:54:6:54:29 | call to anyArg | $@ | summaries.rb:1:20:1:36 | call to source : | call to source : |
|
||||||
| summaries.rb:62:8:62:54 | call to preserveTaint | summaries.rb:62:24:62:53 | call to source : | summaries.rb:62:8:62:54 | call to preserveTaint | $@ | summaries.rb:62:24:62:53 | call to source : | call to source : |
|
| summaries.rb:55:6:55:24 | call to anyArg | summaries.rb:1:20:1:36 | call to source : | summaries.rb:55:6:55:24 | call to anyArg | $@ | summaries.rb:1:20:1:36 | call to source : | call to source : |
|
||||||
| summaries.rb:65:8:65:57 | call to preserveTaint | summaries.rb:65:26:65:56 | call to source : | summaries.rb:65:8:65:57 | call to preserveTaint | $@ | summaries.rb:65:26:65:56 | call to source : | call to source : |
|
| summaries.rb:58:6:58:39 | call to anyPositionFromOne | summaries.rb:1:20:1:36 | call to source : | summaries.rb:58:6:58:39 | call to anyPositionFromOne | $@ | summaries.rb:1:20:1:36 | call to source : | call to source : |
|
||||||
|
| summaries.rb:61:8:61:8 | x | summaries.rb:1:20:1:36 | call to source : | summaries.rb:61:8:61:8 | x | $@ | summaries.rb:1:20:1:36 | call to source : | call to source : |
|
||||||
|
| summaries.rb:68:8:68:54 | call to preserveTaint | summaries.rb:68:24:68:53 | call to source : | summaries.rb:68:8:68:54 | call to preserveTaint | $@ | summaries.rb:68:24:68:53 | call to source : | call to source : |
|
||||||
|
| summaries.rb:71:8:71:57 | call to preserveTaint | summaries.rb:71:26:71:56 | call to source : | summaries.rb:71:8:71:57 | call to preserveTaint | $@ | summaries.rb:71:26:71:56 | call to source : | call to source : |
|
||||||
warning
|
warning
|
||||||
| CSV type row should have 5 columns but has 2: test;TooFewColumns |
|
| CSV type row should have 5 columns but has 2: test;TooFewColumns |
|
||||||
| CSV type row should have 5 columns but has 8: test;TooManyColumns;;;Member[Foo].Instance;too;many;columns |
|
| CSV type row should have 5 columns but has 8: test;TooManyColumns;;;Member[Foo].Instance;too;many;columns |
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ private class StepsFromModel extends ModelInput::SummaryModelCsv {
|
|||||||
";;Member[Foo].Method[onlyWithBlock].WithBlock;Argument[0];ReturnValue;taint",
|
";;Member[Foo].Method[onlyWithBlock].WithBlock;Argument[0];ReturnValue;taint",
|
||||||
";;Member[Foo].Method[blockArg].Argument[block].Parameter[0].Method[preserveTaint];Argument[0];ReturnValue;taint",
|
";;Member[Foo].Method[blockArg].Argument[block].Parameter[0].Method[preserveTaint];Argument[0];ReturnValue;taint",
|
||||||
";;Member[Foo].Method[namedArg];Argument[foo:];ReturnValue;taint",
|
";;Member[Foo].Method[namedArg];Argument[foo:];ReturnValue;taint",
|
||||||
|
";;Member[Foo].Method[anyArg];Argument[any];ReturnValue;taint",
|
||||||
|
";;Member[Foo].Method[anyPositionFromOne];Argument[1..];ReturnValue;taint",
|
||||||
";;Member[Foo].Method[intoNamedCallback];Argument[0];Argument[foo:].Parameter[0];taint",
|
";;Member[Foo].Method[intoNamedCallback];Argument[0];Argument[foo:].Parameter[0];taint",
|
||||||
";;Member[Foo].Method[intoNamedParameter];Argument[0];Argument[0].Parameter[foo:];taint",
|
";;Member[Foo].Method[intoNamedParameter];Argument[0];Argument[0].Parameter[foo:];taint",
|
||||||
";;Member[Foo].Method[startInNamedCallback].Argument[foo:].Parameter[0].Method[preserveTaint];Argument[0];ReturnValue;taint",
|
";;Member[Foo].Method[startInNamedCallback].Argument[foo:].Parameter[0].Method[preserveTaint];Argument[0];ReturnValue;taint",
|
||||||
|
|||||||
@@ -51,6 +51,12 @@ end
|
|||||||
sink(Foo.namedArg(foo: tainted)) # $ hasTaintFlow=tainted
|
sink(Foo.namedArg(foo: tainted)) # $ hasTaintFlow=tainted
|
||||||
sink(Foo.namedArg(tainted))
|
sink(Foo.namedArg(tainted))
|
||||||
|
|
||||||
|
sink(Foo.anyArg(foo: tainted)) # $ hasTaintFlow=tainted
|
||||||
|
sink(Foo.anyArg(tainted)) # $ hasTaintFlow=tainted
|
||||||
|
|
||||||
|
sink(Foo.anyPositionFromOne(tainted))
|
||||||
|
sink(Foo.anyPositionFromOne(0, tainted)) # $ hasTaintFlow=tainted
|
||||||
|
|
||||||
Foo.intoNamedCallback(tainted, foo: ->(x) {
|
Foo.intoNamedCallback(tainted, foo: ->(x) {
|
||||||
sink(x) # $ hasTaintFlow=tainted
|
sink(x) # $ hasTaintFlow=tainted
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,6 +4,32 @@ The Swift codeql package is an experimental and unsupported work in progress.
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Run `bazel run //swift:create-extractor-pack`, which will install `swift/extractor-pack`.
|
Run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bazel run //swift:create-extractor-pack
|
||||||
|
```
|
||||||
|
|
||||||
|
which will install `swift/extractor-pack`.
|
||||||
|
|
||||||
Using `--search-path=swift/extractor-pack` will then pick up the Swift extractor. You can also use
|
Using `--search-path=swift/extractor-pack` will then pick up the Swift extractor. You can also use
|
||||||
`--search-path=swift`, as the extractor pack is mentioned in `swift/.codeqlmanifest.json`.
|
`--search-path=swift`, as the extractor pack is mentioned in `swift/.codeqlmanifest.json`.
|
||||||
|
|
||||||
|
Notice you can run `bazel run :create-extractor-pack` if you already are in the `swift` directory.
|
||||||
|
|
||||||
|
## Code generation
|
||||||
|
|
||||||
|
Make sure to install the [pip requirements](./codegen/requirements.txt) via
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 -m pip install -r codegen/requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bazel run //swift/codegen
|
||||||
|
```
|
||||||
|
|
||||||
|
to update generated files. This can be shortened to
|
||||||
|
`bazel run codegen` if you are in the `swift` directory.
|
||||||
|
|||||||
4
swift/codegen/BUILD.bazel
Normal file
4
swift/codegen/BUILD.bazel
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
py_binary(
|
||||||
|
name = "codegen",
|
||||||
|
srcs = glob(["**/*.py"]),
|
||||||
|
)
|
||||||
8
swift/codegen/codegen.py
Executable file
8
swift/codegen/codegen.py
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
""" Driver script to run all checked in code generation """
|
||||||
|
|
||||||
|
from lib import generator
|
||||||
|
import dbschemegen
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
generator.run(dbschemegen.generate)
|
||||||
90
swift/codegen/dbschemegen.py
Executable file
90
swift/codegen/dbschemegen.py
Executable file
@@ -0,0 +1,90 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
import inflection
|
||||||
|
|
||||||
|
from lib import paths, schema, generator
|
||||||
|
from lib.dbscheme import *
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def dbtype(typename):
|
||||||
|
""" translate a type to a dbscheme counterpart, using `@lower_underscore` format for classes """
|
||||||
|
if typename[0].isupper():
|
||||||
|
return "@" + inflection.underscore(typename)
|
||||||
|
return typename
|
||||||
|
|
||||||
|
|
||||||
|
def cls_to_dbscheme(cls: schema.Class):
|
||||||
|
""" Yield all dbscheme entities needed to model class `cls` """
|
||||||
|
if cls.derived:
|
||||||
|
yield DbUnion(dbtype(cls.name), (dbtype(c) for c in cls.derived))
|
||||||
|
# output a table specific to a class only if it is a leaf class or it has 1-to-1 properties
|
||||||
|
# Leaf classes need a table to bind the `@` ids
|
||||||
|
# 1-to-1 properties are added to a class specific table
|
||||||
|
# in other cases, separate tables are used for the properties, and a class specific table is unneeded
|
||||||
|
if not cls.derived or any(f.is_single for f in cls.properties):
|
||||||
|
binding = not cls.derived
|
||||||
|
keyset = DbKeySet(["id"]) if cls.derived else None
|
||||||
|
yield DbTable(
|
||||||
|
keyset=keyset,
|
||||||
|
name=inflection.tableize(cls.name),
|
||||||
|
columns=[
|
||||||
|
DbColumn("id", type=dbtype(cls.name), binding=binding),
|
||||||
|
] + [
|
||||||
|
DbColumn(f.name, dbtype(f.type)) for f in cls.properties if f.is_single
|
||||||
|
]
|
||||||
|
)
|
||||||
|
# use property-specific tables for 1-to-many and 1-to-at-most-1 properties
|
||||||
|
for f in cls.properties:
|
||||||
|
if f.is_optional:
|
||||||
|
yield DbTable(
|
||||||
|
keyset=DbKeySet(["id"]),
|
||||||
|
name=inflection.tableize(f"{cls.name}_{f.name}"),
|
||||||
|
columns=[
|
||||||
|
DbColumn("id", type=dbtype(cls.name)),
|
||||||
|
DbColumn(f.name, dbtype(f.type)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
elif f.is_repeated:
|
||||||
|
yield DbTable(
|
||||||
|
keyset=DbKeySet(["id", "index"]),
|
||||||
|
name=inflection.tableize(f"{cls.name}_{f.name}"),
|
||||||
|
columns=[
|
||||||
|
DbColumn("id", type=dbtype(cls.name)),
|
||||||
|
DbColumn("index", type="int"),
|
||||||
|
DbColumn(inflection.singularize(f.name), dbtype(f.type)),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_declarations(data: schema.Schema):
|
||||||
|
return [d for cls in data.classes.values() for d in cls_to_dbscheme(cls)]
|
||||||
|
|
||||||
|
|
||||||
|
def get_includes(data: schema.Schema, include_dir: pathlib.Path):
|
||||||
|
includes = []
|
||||||
|
for inc in data.includes:
|
||||||
|
inc = include_dir / inc
|
||||||
|
with open(inc) as inclusion:
|
||||||
|
includes.append(DbSchemeInclude(src=inc.relative_to(paths.swift_dir), data=inclusion.read()))
|
||||||
|
return includes
|
||||||
|
|
||||||
|
|
||||||
|
def generate(opts, renderer):
|
||||||
|
input = opts.schema.resolve()
|
||||||
|
out = opts.dbscheme.resolve()
|
||||||
|
|
||||||
|
with open(input) as src:
|
||||||
|
data = schema.load(src)
|
||||||
|
|
||||||
|
dbscheme = DbScheme(src=input.relative_to(paths.swift_dir),
|
||||||
|
includes=get_includes(data, include_dir=input.parent),
|
||||||
|
declarations=get_declarations(data))
|
||||||
|
|
||||||
|
renderer.render(dbscheme, out)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
generator.run(generate, tags=["schema", "dbscheme"])
|
||||||
104
swift/codegen/lib/dbscheme.py
Normal file
104
swift/codegen/lib/dbscheme.py
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
""" dbscheme format representation """
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import ClassVar, List
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
dbscheme_keywords = {"case", "boolean", "int", "string", "type"}
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DbColumn:
|
||||||
|
schema_name: str
|
||||||
|
type: str
|
||||||
|
binding: bool = False
|
||||||
|
first: bool = False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
if self.schema_name in dbscheme_keywords:
|
||||||
|
return self.schema_name + "_"
|
||||||
|
return self.schema_name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lhstype(self):
|
||||||
|
if self.type[0] == "@":
|
||||||
|
return "unique int" if self.binding else "int"
|
||||||
|
return self.type
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rhstype(self):
|
||||||
|
if self.type[0] == "@" and self.binding:
|
||||||
|
return self.type
|
||||||
|
return self.type + " ref"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DbKeySetId:
|
||||||
|
id: str
|
||||||
|
first: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DbKeySet:
|
||||||
|
ids: List[DbKeySetId]
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
assert self.ids
|
||||||
|
self.ids = [DbKeySetId(x) for x in self.ids]
|
||||||
|
self.ids[0].first = True
|
||||||
|
|
||||||
|
|
||||||
|
class DbDecl:
|
||||||
|
is_table = False
|
||||||
|
is_union = False
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DbTable(DbDecl):
|
||||||
|
is_table: ClassVar = True
|
||||||
|
|
||||||
|
name: str
|
||||||
|
columns: List[DbColumn]
|
||||||
|
keyset: DbKeySet = None
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
if self.columns:
|
||||||
|
self.columns[0].first = True
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DbUnionCase:
|
||||||
|
type: str
|
||||||
|
first: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DbUnion(DbDecl):
|
||||||
|
is_union: ClassVar = True
|
||||||
|
|
||||||
|
lhs: str
|
||||||
|
rhs: List[DbUnionCase]
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
assert self.rhs
|
||||||
|
self.rhs = [DbUnionCase(x) for x in self.rhs]
|
||||||
|
self.rhs.sort(key=lambda c: c.type)
|
||||||
|
self.rhs[0].first = True
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DbSchemeInclude:
|
||||||
|
src: str
|
||||||
|
data: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DbScheme:
|
||||||
|
template: ClassVar = 'dbscheme'
|
||||||
|
|
||||||
|
src: str
|
||||||
|
includes: List[DbSchemeInclude]
|
||||||
|
declarations: List[DbDecl]
|
||||||
29
swift/codegen/lib/generator.py
Normal file
29
swift/codegen/lib/generator.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
""" generator script scaffolding """
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from . import options, render
|
||||||
|
|
||||||
|
|
||||||
|
def _parse(tags):
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
for opt in options.get(tags):
|
||||||
|
opt.add_to(parser)
|
||||||
|
ret = parser.parse_args()
|
||||||
|
log_level = logging.DEBUG if ret.verbose else logging.INFO
|
||||||
|
logging.basicConfig(format="{levelname} {message}", style='{', level=log_level)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def run(*generators, tags=None):
|
||||||
|
""" run generation functions in `generators`, parsing options tagged with `tags` (all if unspecified)
|
||||||
|
|
||||||
|
`generators` should be callables taking as input an option namespace and a `render.Renderer` instance
|
||||||
|
"""
|
||||||
|
opts = _parse(tags)
|
||||||
|
renderer = render.Renderer(dryrun=opts.check)
|
||||||
|
for g in generators:
|
||||||
|
g(opts, renderer)
|
||||||
|
sys.exit(1 if opts.check and renderer.done_something else 0)
|
||||||
48
swift/codegen/lib/options.py
Normal file
48
swift/codegen/lib/options.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
""" generator options, categorized by tags """
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import collections
|
||||||
|
import pathlib
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
from . import paths
|
||||||
|
|
||||||
|
|
||||||
|
def _init_options():
|
||||||
|
Option("--check", "-c", action="store_true")
|
||||||
|
Option("--verbose", "-v", action="store_true")
|
||||||
|
Option("--schema", tags=["schema"], type=pathlib.Path, default=paths.swift_dir / "codegen/schema.yml")
|
||||||
|
Option("--dbscheme", tags=["dbscheme"], type=pathlib.Path, default=paths.swift_dir / "ql/lib/swift.dbscheme")
|
||||||
|
|
||||||
|
|
||||||
|
_options = collections.defaultdict(list)
|
||||||
|
|
||||||
|
|
||||||
|
class Option:
|
||||||
|
def __init__(self, *args, tags=None, **kwargs):
|
||||||
|
tags = tags or []
|
||||||
|
self.args = args
|
||||||
|
self.kwargs = kwargs
|
||||||
|
if tags:
|
||||||
|
for t in tags:
|
||||||
|
_options[t].append(self)
|
||||||
|
else:
|
||||||
|
_options["*"].append(self)
|
||||||
|
|
||||||
|
def add_to(self, parser: argparse.ArgumentParser):
|
||||||
|
parser.add_argument(*self.args, **self.kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
_init_options()
|
||||||
|
|
||||||
|
|
||||||
|
def get(tags: Tuple[str]):
|
||||||
|
""" get options marked by `tags`
|
||||||
|
|
||||||
|
Return all options if tags is falsy. Options tagged by wildcard '*' are always returned
|
||||||
|
"""
|
||||||
|
if not tags:
|
||||||
|
return (o for tagged_opts in _options.values() for o in tagged_opts)
|
||||||
|
else:
|
||||||
|
# use specifically tagged options + those tagged with wildcard *
|
||||||
|
return (o for tag in ('*',) + tags for o in _options[tag])
|
||||||
17
swift/codegen/lib/paths.py
Normal file
17
swift/codegen/lib/paths.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
""" module providing useful filesystem paths """
|
||||||
|
|
||||||
|
import pathlib
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
try:
|
||||||
|
_workspace_dir = pathlib.Path(os.environ['BUILD_WORKSPACE_DIRECTORY']) # <- means we are using bazel run
|
||||||
|
swift_dir = _workspace_dir / 'swift'
|
||||||
|
lib_dir = swift_dir / 'codegen' / 'lib'
|
||||||
|
except KeyError:
|
||||||
|
_this_file = pathlib.Path(__file__).resolve()
|
||||||
|
swift_dir = _this_file.parents[2]
|
||||||
|
lib_dir = _this_file.parent
|
||||||
|
|
||||||
|
|
||||||
|
exe_file = pathlib.Path(sys.argv[0]).resolve()
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user