diff --git a/.github/workflows/csv-coverage-update.yml b/.github/workflows/csv-coverage-update.yml index 10834bdd36a..eb227ec844f 100644 --- a/.github/workflows/csv-coverage-update.yml +++ b/.github/workflows/csv-coverage-update.yml @@ -8,7 +8,7 @@ on: jobs: update: name: Update framework coverage report - if: github.event.repository.fork == false + if: github.repository == 'github/codeql' runs-on: ubuntu-latest steps: diff --git a/cpp/change-notes/2021-06-22-sql-tainted.md b/cpp/change-notes/2021-06-22-sql-tainted.md new file mode 100644 index 00000000000..004f96ce25b --- /dev/null +++ b/cpp/change-notes/2021-06-22-sql-tainted.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* The 'Uncontrolled data in SQL query' (cpp/sql-injection) query now supports the `libpqxx` library. \ No newline at end of file diff --git a/cpp/change-notes/2021-09-13-overflow-static.md b/cpp/change-notes/2021-09-13-overflow-static.md new file mode 100644 index 00000000000..5a9ef395815 --- /dev/null +++ b/cpp/change-notes/2021-09-13-overflow-static.md @@ -0,0 +1,4 @@ +lgtm,codescanning +* The `memberMayBeVarSize` predicate considers more fields to be variable size. + As a result, the "Static buffer overflow" query (cpp/static-buffer-overflow) + produces fewer false positives. diff --git a/cpp/ql/lib/semmle/code/cpp/File.qll b/cpp/ql/lib/semmle/code/cpp/File.qll index b2d933686d7..853b34ecfd9 100644 --- a/cpp/ql/lib/semmle/code/cpp/File.qll +++ b/cpp/ql/lib/semmle/code/cpp/File.qll @@ -171,7 +171,7 @@ class Container extends Locatable, @container { * To get the full path, use `getAbsolutePath`. */ class Folder extends Container, @folder { - override string getAbsolutePath() { folders(underlyingElement(this), result, _) } + override string getAbsolutePath() { folders(underlyingElement(this), result) } override Location getLocation() { result.getContainer() = this and @@ -190,7 +190,7 @@ class Folder extends Container, @folder { * DEPRECATED: use `getAbsolutePath` instead. * Gets the name of this folder. */ - deprecated string getName() { folders(underlyingElement(this), result, _) } + deprecated string getName() { folders(underlyingElement(this), result) } /** * DEPRECATED: use `getAbsolutePath` instead. @@ -208,17 +208,7 @@ class Folder extends Container, @folder { * DEPRECATED: use `getBaseName` instead. * Gets the last part of the folder name. */ - deprecated string getShortName() { - exists(string longnameRaw, string longname | - folders(underlyingElement(this), _, longnameRaw) and - longname = longnameRaw.replaceAll("\\", "/") - | - exists(int index | - result = longname.splitAt("/", index) and - not exists(longname.splitAt("/", index + 1)) - ) - ) - } + deprecated string getShortName() { result = this.getBaseName() } /** * DEPRECATED: use `getParentContainer` instead. @@ -242,7 +232,7 @@ class Folder extends Container, @folder { * `getStem` and `getExtension`. To get the full path, use `getAbsolutePath`. */ class File extends Container, @file { - override string getAbsolutePath() { files(underlyingElement(this), result, _, _, _) } + override string getAbsolutePath() { files(underlyingElement(this), result) } override string toString() { result = Container.super.toString() } @@ -336,7 +326,13 @@ class File extends Container, @file { * for example, for "file.tar.gz", this predicate will have the result * "tar.gz", while `getExtension` will have the result "gz". */ - string getExtensions() { files(underlyingElement(this), _, _, result, _) } + string getExtensions() { + exists(string name, int firstDotPos | + name = this.getBaseName() and + firstDotPos = min([name.indexOf("."), name.length() - 1]) and + result = name.suffix(firstDotPos + 1) + ) + } /** * Gets the short name of this file, that is, the prefix of its base name up @@ -351,7 +347,16 @@ class File extends Container, @file { * for example, for "file.tar.gz", this predicate will have the result * "file", while `getStem` will have the result "file.tar". */ - string getShortName() { files(underlyingElement(this), _, result, _, _) } + string getShortName() { + exists(string name, int firstDotPos | + name = this.getBaseName() and + firstDotPos = min([name.indexOf("."), name.length()]) and + result = name.prefix(firstDotPos) + ) + or + this.getAbsolutePath() = "" and + result = "" + } } /** diff --git a/cpp/ql/lib/semmle/code/cpp/commons/Buffer.qll b/cpp/ql/lib/semmle/code/cpp/commons/Buffer.qll index 88e6a48ff55..5778ee7dfb1 100644 --- a/cpp/ql/lib/semmle/code/cpp/commons/Buffer.qll +++ b/cpp/ql/lib/semmle/code/cpp/commons/Buffer.qll @@ -2,17 +2,18 @@ import cpp import semmle.code.cpp.dataflow.DataFlow /** - * Holds if `v` is a member variable of `c` that looks like it might be variable sized in practice. For - * example: + * Holds if `v` is a member variable of `c` that looks like it might be variable sized + * in practice. For example: * ``` * struct myStruct { // c * int amount; * char data[1]; // v * }; * ``` - * This requires that `v` is an array of size 0 or 1, and `v` is the last member of `c`. In addition, - * there must be at least one instance where a `c` pointer is allocated with additional space. For - * example, holds for `c` if it occurs as + * This requires that `v` is an array of size 0 or 1, and `v` is the last member of `c`. + * In addition, if the size of the structure is taken, there must be at least one instance + * where a `c` pointer is allocated with additional space. + * For example, holds for `c` if it occurs as * ``` * malloc(sizeof(c) + 100 * sizeof(char)) * ``` @@ -27,27 +28,25 @@ predicate memberMayBeVarSize(Class c, MemberVariable v) { i = max(int j | c.getCanonicalMember(j) instanceof Field | j) and v = c.getCanonicalMember(i) and // v is an array of size at most 1 - v.getUnspecifiedType().(ArrayType).getArraySize() <= 1 + v.getUnspecifiedType().(ArrayType).getArraySize() <= 1 and + not c instanceof Union ) and + // If the size is taken, then arithmetic is performed on the result at least once ( + // `sizeof(c)` is not taken + not exists(SizeofOperator so | + so.(SizeofTypeOperator).getTypeOperand().getUnspecifiedType() = c or + so.(SizeofExprOperator).getExprOperand().getUnspecifiedType() = c + ) + or + // or `sizeof(c)` is taken exists(SizeofOperator so | - // `sizeof(c)` is taken so.(SizeofTypeOperator).getTypeOperand().getUnspecifiedType() = c or so.(SizeofExprOperator).getExprOperand().getUnspecifiedType() = c | - // arithmetic is performed on the result + // and arithmetic is performed on the result so.getParent*() instanceof AddExpr ) - or - exists(AddressOfExpr aoe | - // `&(c.v)` is taken - aoe.getAddressable() = v - ) - or - exists(BuiltInOperationBuiltInOffsetOf oo | - // `offsetof(c, v)` using a builtin - oo.getAChild().(VariableAccess).getTarget() = v - ) ) } @@ -61,6 +60,10 @@ int getBufferSize(Expr bufferExpr, Element why) { result = bufferVar.getUnspecifiedType().(ArrayType).getSize() and why = bufferVar and not memberMayBeVarSize(_, bufferVar) and + not exists(Union bufferType | + bufferType.getAMemberVariable() = why and + bufferVar.getUnspecifiedType().(ArrayType).getSize() <= 1 + ) and not result = 0 // zero sized arrays are likely to have special usage, for example or // behaving a bit like a 'union' overlapping other fields. @@ -82,6 +85,13 @@ int getBufferSize(Expr bufferExpr, Element why) { parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and result = getBufferSize(parentPtr, _) + bufferVar.getType().getSize() - parentClass.getSize() ) + or + exists(Union bufferType | + bufferType.getAMemberVariable() = why and + why = bufferVar and + bufferVar.getUnspecifiedType().(ArrayType).getSize() <= 1 and + result = bufferType.getSize() + ) ) or // buffer is a fixed size dynamic allocation diff --git a/cpp/ql/lib/semmle/code/cpp/commons/NullTermination.qll b/cpp/ql/lib/semmle/code/cpp/commons/NullTermination.qll index 6cb366d46ee..ee072fb0ed3 100644 --- a/cpp/ql/lib/semmle/code/cpp/commons/NullTermination.qll +++ b/cpp/ql/lib/semmle/code/cpp/commons/NullTermination.qll @@ -93,6 +93,15 @@ predicate variableMustBeNullTerminated(VariableAccess va) { fc.getArgument(i) = va ) or + // String argument to a formatting function (such as `printf`) + exists(int n, FormatLiteral fl | + fc.(FormattingFunctionCall).getConversionArgument(n) = va and + fl = fc.(FormattingFunctionCall).getFormat() and + fl.getConversionType(n) instanceof PointerType and // `%s`, `%ws` etc + not fl.getConversionType(n) instanceof VoidPointerType and // exclude: `%p` + not fl.hasPrecision(n) // exclude: `%.*s` + ) + or // Call to a wrapper function that requires null termination // (not itself adding a null terminator) exists(Function wrapper, int i, Parameter p, VariableAccess use | diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 8597b5755f0..0c99a25ccc4 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -3639,9 +3643,10 @@ private module Subpaths { PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, apout) and + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, + unbindConf(arg.getConfiguration())) } /** @@ -3686,8 +3691,8 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | - arg.getASuccessor() = par and - arg.getASuccessor() = out and + pragma[only_bind_into](arg).getASuccessor() = par and + pragma[only_bind_into](arg).getASuccessor() = out and subpaths03(arg, p, ret, o, apout) and par.getNodeEx() = p and out.getNodeEx() = o and diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 8597b5755f0..0c99a25ccc4 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -3639,9 +3643,10 @@ private module Subpaths { PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, apout) and + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, + unbindConf(arg.getConfiguration())) } /** @@ -3686,8 +3691,8 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | - arg.getASuccessor() = par and - arg.getASuccessor() = out and + pragma[only_bind_into](arg).getASuccessor() = par and + pragma[only_bind_into](arg).getASuccessor() = out and subpaths03(arg, p, ret, o, apout) and par.getNodeEx() = p and out.getNodeEx() = o and diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 8597b5755f0..0c99a25ccc4 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -3639,9 +3643,10 @@ private module Subpaths { PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, apout) and + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, + unbindConf(arg.getConfiguration())) } /** @@ -3686,8 +3691,8 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | - arg.getASuccessor() = par and - arg.getASuccessor() = out and + pragma[only_bind_into](arg).getASuccessor() = par and + pragma[only_bind_into](arg).getASuccessor() = out and subpaths03(arg, p, ret, o, apout) and par.getNodeEx() = p and out.getNodeEx() = o and diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 8597b5755f0..0c99a25ccc4 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -3639,9 +3643,10 @@ private module Subpaths { PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, apout) and + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, + unbindConf(arg.getConfiguration())) } /** @@ -3686,8 +3691,8 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | - arg.getASuccessor() = par and - arg.getASuccessor() = out and + pragma[only_bind_into](arg).getASuccessor() = par and + pragma[only_bind_into](arg).getASuccessor() = out and subpaths03(arg, p, ret, o, apout) and par.getNodeEx() = p and out.getNodeEx() = o and diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll index 728f7b56c42..f588a25a176 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -786,13 +786,18 @@ private module Cached { } /** - * Holds if the call context `call` either improves virtual dispatch in - * `callable` or if it allows us to prune unreachable nodes in `callable`. + * Holds if the call context `call` improves virtual dispatch in `callable`. */ cached - predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + predicate recordDataFlowCallSiteDispatch(DataFlowCall call, DataFlowCallable callable) { reducedViableImplInCallContext(_, callable, call) - or + } + + /** + * Holds if the call context `call` allows us to prune unreachable nodes in `callable`. + */ + cached + predicate recordDataFlowCallSiteUnreachable(DataFlowCall call, DataFlowCallable callable) { exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call)) } @@ -846,6 +851,15 @@ private module Cached { TAccessPathFrontSome(AccessPathFront apf) } +/** + * Holds if the call context `call` either improves virtual dispatch in + * `callable` or if it allows us to prune unreachable nodes in `callable`. + */ +predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + recordDataFlowCallSiteDispatch(call, callable) or + recordDataFlowCallSiteUnreachable(call, callable) +} + /** * A `Node` at which a cast can occur such that the type should be checked. */ diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index 8597b5755f0..0c99a25ccc4 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -3639,9 +3643,10 @@ private module Subpaths { PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, apout) and + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, + unbindConf(arg.getConfiguration())) } /** @@ -3686,8 +3691,8 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | - arg.getASuccessor() = par and - arg.getASuccessor() = out and + pragma[only_bind_into](arg).getASuccessor() = par and + pragma[only_bind_into](arg).getASuccessor() = out and subpaths03(arg, p, ret, o, apout) and par.getNodeEx() = p and out.getNodeEx() = o and diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll index 49d11a7e3cc..b77bc6cebf0 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll @@ -550,6 +550,39 @@ module TaintedWithPath { ) } + /** + * Holds if there is flow from `arg` to `out` across a call that can by summarized by the flow + * from `par` to `ret` within it, in the graph of data flow path explanations. + */ + query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) { + DataFlow3::PathGraph::subpaths(arg.(WrapPathNode).inner(), par.(WrapPathNode).inner(), + ret.(WrapPathNode).inner(), out.(WrapPathNode).inner()) + or + // To avoid showing trivial-looking steps, we _replace_ the last node instead + // of adding an edge out of it. + exists(WrapPathNode sinkNode | + DataFlow3::PathGraph::subpaths(arg.(WrapPathNode).inner(), par.(WrapPathNode).inner(), + ret.(WrapPathNode).inner(), sinkNode.inner()) and + out.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode()) + ) + or + // Same for the first node + exists(WrapPathNode sourceNode | + DataFlow3::PathGraph::subpaths(sourceNode.inner(), par.(WrapPathNode).inner(), + ret.(WrapPathNode).inner(), out.(WrapPathNode).inner()) and + sourceNode.inner().getNode() = getNodeForExpr(arg.(InitialPathNode).inner()) + ) + or + // Finally, handle the case where the path goes directly from a source to a + // sink, meaning that they both need to be translated. + exists(WrapPathNode sinkNode, WrapPathNode sourceNode | + DataFlow3::PathGraph::subpaths(sourceNode.inner(), par.(WrapPathNode).inner(), + ret.(WrapPathNode).inner(), sinkNode.inner()) and + sourceNode.inner().getNode() = getNodeForExpr(arg.(InitialPathNode).inner()) and + out.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode()) + ) + } + /** Holds if `n` is a node in the graph of data flow path explanations. */ query predicate nodes(PathNode n, string key, string val) { key = "semmle.label" and val = n.toString() diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 8597b5755f0..0c99a25ccc4 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -3639,9 +3643,10 @@ private module Subpaths { PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, apout) and + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, + unbindConf(arg.getConfiguration())) } /** @@ -3686,8 +3691,8 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | - arg.getASuccessor() = par and - arg.getASuccessor() = out and + pragma[only_bind_into](arg).getASuccessor() = par and + pragma[only_bind_into](arg).getASuccessor() = out and subpaths03(arg, p, ret, o, apout) and par.getNodeEx() = p and out.getNodeEx() = o and diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 8597b5755f0..0c99a25ccc4 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -3639,9 +3643,10 @@ private module Subpaths { PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, apout) and + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, + unbindConf(arg.getConfiguration())) } /** @@ -3686,8 +3691,8 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | - arg.getASuccessor() = par and - arg.getASuccessor() = out and + pragma[only_bind_into](arg).getASuccessor() = par and + pragma[only_bind_into](arg).getASuccessor() = out and subpaths03(arg, p, ret, o, apout) and par.getNodeEx() = p and out.getNodeEx() = o and diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 8597b5755f0..0c99a25ccc4 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -3639,9 +3643,10 @@ private module Subpaths { PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, apout) and + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, + unbindConf(arg.getConfiguration())) } /** @@ -3686,8 +3691,8 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | - arg.getASuccessor() = par and - arg.getASuccessor() = out and + pragma[only_bind_into](arg).getASuccessor() = par and + pragma[only_bind_into](arg).getASuccessor() = out and subpaths03(arg, p, ret, o, apout) and par.getNodeEx() = p and out.getNodeEx() = o and diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 8597b5755f0..0c99a25ccc4 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -3639,9 +3643,10 @@ private module Subpaths { PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, apout) and + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, + unbindConf(arg.getConfiguration())) } /** @@ -3686,8 +3691,8 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | - arg.getASuccessor() = par and - arg.getASuccessor() = out and + pragma[only_bind_into](arg).getASuccessor() = par and + pragma[only_bind_into](arg).getASuccessor() = out and subpaths03(arg, p, ret, o, apout) and par.getNodeEx() = p and out.getNodeEx() = o and diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll index 728f7b56c42..f588a25a176 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll @@ -786,13 +786,18 @@ private module Cached { } /** - * Holds if the call context `call` either improves virtual dispatch in - * `callable` or if it allows us to prune unreachable nodes in `callable`. + * Holds if the call context `call` improves virtual dispatch in `callable`. */ cached - predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + predicate recordDataFlowCallSiteDispatch(DataFlowCall call, DataFlowCallable callable) { reducedViableImplInCallContext(_, callable, call) - or + } + + /** + * Holds if the call context `call` allows us to prune unreachable nodes in `callable`. + */ + cached + predicate recordDataFlowCallSiteUnreachable(DataFlowCall call, DataFlowCallable callable) { exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call)) } @@ -846,6 +851,15 @@ private module Cached { TAccessPathFrontSome(AccessPathFront apf) } +/** + * Holds if the call context `call` either improves virtual dispatch in + * `callable` or if it allows us to prune unreachable nodes in `callable`. + */ +predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + recordDataFlowCallSiteDispatch(call, callable) or + recordDataFlowCallSiteUnreachable(call, callable) +} + /** * A `Node` at which a cast can occur such that the type should be checked. */ diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 453838215ff..2fb3edad602 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -1856,12 +1856,12 @@ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { } /** - * Gets the address of the allocation this instruction is initializing. + * Gets the operand that represents the address of the allocation this instruction is initializing. */ final AddressOperand getAllocationAddressOperand() { result = getAnOperand() } /** - * Gets the operand for the allocation this instruction is initializing. + * Gets the address for the allocation this instruction is initializing. */ final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() } } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 453838215ff..2fb3edad602 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -1856,12 +1856,12 @@ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { } /** - * Gets the address of the allocation this instruction is initializing. + * Gets the operand that represents the address of the allocation this instruction is initializing. */ final AddressOperand getAllocationAddressOperand() { result = getAnOperand() } /** - * Gets the operand for the allocation this instruction is initializing. + * Gets the address for the allocation this instruction is initializing. */ final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() } } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 453838215ff..2fb3edad602 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -1856,12 +1856,12 @@ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { } /** - * Gets the address of the allocation this instruction is initializing. + * Gets the operand that represents the address of the allocation this instruction is initializing. */ final AddressOperand getAllocationAddressOperand() { result = getAnOperand() } /** - * Gets the operand for the allocation this instruction is initializing. + * Gets the address for the allocation this instruction is initializing. */ final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() } } diff --git a/cpp/ql/lib/semmle/code/cpp/models/Models.qll b/cpp/ql/lib/semmle/code/cpp/models/Models.qll index d5c7f50dde1..f6e40d140bd 100644 --- a/cpp/ql/lib/semmle/code/cpp/models/Models.qll +++ b/cpp/ql/lib/semmle/code/cpp/models/Models.qll @@ -33,3 +33,6 @@ private import implementations.Recv private import implementations.Accept private import implementations.Poll private import implementations.Select +private import implementations.MySql +private import implementations.SqLite3 +private import implementations.PostgreSql diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/MySql.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/MySql.qll new file mode 100644 index 00000000000..ca5d7020158 --- /dev/null +++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/MySql.qll @@ -0,0 +1,32 @@ +/** + * Provides implementation classes modeling the MySql C API. + * See `semmle.code.cpp.models.Models` for usage information. + */ + +private import semmle.code.cpp.models.interfaces.Sql +private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs + +/** + * The `mysql_query` family of functions from the MySQL C API. + */ +private class MySqlExecutionFunction extends SqlExecutionFunction { + MySqlExecutionFunction() { + this.hasName(["mysql_query", "mysql_real_query", "mysql_real_query_nonblocking"]) + } + + override predicate hasSqlArgument(FunctionInput input) { input.isParameterDeref(1) } +} + +/** + * The `mysql_real_escape_string` family of functions from the MySQL C API. + */ +private class MySqlBarrierFunction extends SqlBarrierFunction { + MySqlBarrierFunction() { + this.hasName(["mysql_real_escape_string", "mysql_real_escape_string_quote"]) + } + + override predicate barrierSqlArgument(FunctionInput input, FunctionOutput output) { + input.isParameterDeref(2) and + output.isParameterDeref(1) + } +} diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/PostgreSql.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/PostgreSql.qll new file mode 100644 index 00000000000..595805f176f --- /dev/null +++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/PostgreSql.qll @@ -0,0 +1,94 @@ +private import semmle.code.cpp.models.interfaces.Sql +private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs + +private predicate pqxxTransactionSqlArgument(string function, int arg) { + function = "exec" and arg = 0 + or + function = "exec0" and arg = 0 + or + function = "exec1" and arg = 0 + or + function = "exec_n" and arg = 1 + or + function = "exec_params" and arg = 0 + or + function = "exec_params0" and arg = 0 + or + function = "exec_params1" and arg = 0 + or + function = "exec_params_n" and arg = 1 + or + function = "query_value" and arg = 0 + or + function = "stream" and arg = 0 +} + +private predicate pqxxConnectionSqlArgument(string function, int arg) { + function = "prepare" and arg = 1 +} + +private predicate pqxxTransationClassNames(string className, string namespace) { + namespace = "pqxx" and + className in [ + "dbtransaction", "nontransaction", "basic_robusttransaction", "robusttransaction", + "subtransaction", "transaction", "basic_transaction", "transaction_base", "work" + ] +} + +private predicate pqxxConnectionClassNames(string className, string namespace) { + namespace = "pqxx" and + className in ["connection_base", "basic_connection", "connection"] +} + +private predicate pqxxEscapeArgument(string function, int arg) { + arg = 0 and + function in ["esc", "esc_raw", "quote", "quote_raw", "quote_name", "quote_table", "esc_like"] +} + +private class PostgreSqlExecutionFunction extends SqlExecutionFunction { + PostgreSqlExecutionFunction() { + exists(Class c | + this.getDeclaringType() = c and + // transaction exec and connection prepare variations + ( + pqxxTransationClassNames(c.getName(), c.getNamespace().getName()) and + pqxxTransactionSqlArgument(this.getName(), _) + or + pqxxConnectionSqlArgument(this.getName(), _) and + pqxxConnectionClassNames(c.getName(), c.getNamespace().getName()) + ) + ) + } + + override predicate hasSqlArgument(FunctionInput input) { + exists(int argIndex | + pqxxTransactionSqlArgument(this.getName(), argIndex) + or + pqxxConnectionSqlArgument(this.getName(), argIndex) + | + input.isParameterDeref(argIndex) + ) + } +} + +private class PostgreSqlBarrierFunction extends SqlBarrierFunction { + PostgreSqlBarrierFunction() { + exists(Class c | + this.getDeclaringType() = c and + // transaction and connection escape functions + ( + pqxxTransationClassNames(c.getName(), c.getNamespace().getName()) or + pqxxConnectionClassNames(c.getName(), c.getNamespace().getName()) + ) and + pqxxEscapeArgument(this.getName(), _) + ) + } + + override predicate barrierSqlArgument(FunctionInput input, FunctionOutput output) { + exists(int argIndex | + input.isParameterDeref(argIndex) and + output.isReturnValueDeref() and + pqxxEscapeArgument(this.getName(), argIndex) + ) + } +} diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/SqLite3.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/SqLite3.qll new file mode 100644 index 00000000000..d65df9a27ed --- /dev/null +++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/SqLite3.qll @@ -0,0 +1,21 @@ +/** + * Provides implementation classes modeling the SQLite C API. + * See `semmle.code.cpp.models.Models` for usage information. + */ + +private import semmle.code.cpp.models.interfaces.Sql +private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs + +/** + * The `sqlite3_exec` and `sqlite3_prepare` families of functions from the SQLite C API. + */ +private class SqLite3ExecutionFunction extends SqlExecutionFunction { + SqLite3ExecutionFunction() { + this.hasName([ + "sqlite3_exec", "sqlite3_prepare", "sqlite3_prepare_v2", "sqlite3_prepare_v3", + "sqlite3_prepare16", "sqlite3_prepare16_v2", "sqlite3_prepare16_v3" + ]) + } + + override predicate hasSqlArgument(FunctionInput input) { input.isParameterDeref(1) } +} diff --git a/cpp/ql/lib/semmle/code/cpp/models/interfaces/Sql.qll b/cpp/ql/lib/semmle/code/cpp/models/interfaces/Sql.qll new file mode 100644 index 00000000000..7d5111c2488 --- /dev/null +++ b/cpp/ql/lib/semmle/code/cpp/models/interfaces/Sql.qll @@ -0,0 +1,30 @@ +/** + * Provides abstract classes for modeling functions that execute and escape SQL query strings. + * To extend this QL library, create a QL class extending `SqlExecutionFunction` or `SqlEscapeFunction` + * with a characteristic predicate that selects the function or set of functions you are modeling. + * Within that class, override the predicates provided by the class to match the way a + * parameter flows into the function and, in the case of `SqlEscapeFunction`, out of the function. + */ + +private import cpp + +/** + * An abstract class that represents a function that executes an SQL query. + */ +abstract class SqlExecutionFunction extends Function { + /** + * Holds if `input` to this function represents SQL code to be executed. + */ + abstract predicate hasSqlArgument(FunctionInput input); +} + +/** + * An abstract class that represents a function that is a barrier to an SQL query string. + */ +abstract class SqlBarrierFunction extends Function { + /** + * Holds if the `output` is a barrier to the SQL input `input` such that is it safe to pass to + * an `SqlExecutionFunction`. + */ + abstract predicate barrierSqlArgument(FunctionInput input, FunctionOutput output); +} diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll index 8284ff6d78e..5ca9339ae01 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll @@ -1541,7 +1541,8 @@ private float getGuardedUpperBound(VariableAccess guardedAccess) { // that there is one predecessor, albeit somewhat conservative. exists(unique(BasicBlock b | b = def.(BasicBlock).getAPredecessor())) and guardedAccess = def.getAUse(v) and - result = max(float ub | upperBoundFromGuard(guard, guardVa, ub, branch)) + result = max(float ub | upperBoundFromGuard(guard, guardVa, ub, branch)) and + not convertedExprMightOverflow(guard.getAChild+()) ) } diff --git a/cpp/ql/lib/semmle/code/cpp/security/Security.qll b/cpp/ql/lib/semmle/code/cpp/security/Security.qll index d39c13a25a0..da808592b3e 100644 --- a/cpp/ql/lib/semmle/code/cpp/security/Security.qll +++ b/cpp/ql/lib/semmle/code/cpp/security/Security.qll @@ -7,6 +7,7 @@ import semmle.code.cpp.exprs.Expr import semmle.code.cpp.commons.Environment import semmle.code.cpp.security.SecurityOptions import semmle.code.cpp.models.interfaces.FlowSource +import semmle.code.cpp.models.interfaces.Sql /** * Extend this class to customize the security queries for @@ -34,13 +35,11 @@ class SecurityOptions extends string { * An argument to a function that is passed to a SQL server. */ predicate sqlArgument(string function, int arg) { - // MySQL C API - function = "mysql_query" and arg = 1 - or - function = "mysql_real_query" and arg = 1 - or - // SQLite3 C API - function = "sqlite3_exec" and arg = 1 + exists(FunctionInput input, SqlExecutionFunction sql | + sql.hasName(function) and + input.isParameterDeref(arg) and + sql.hasSqlArgument(input) + ) } /** diff --git a/cpp/ql/lib/semmlecode.cpp.dbscheme b/cpp/ql/lib/semmlecode.cpp.dbscheme index ddd31fd02e5..7806a11dd7a 100644 --- a/cpp/ql/lib/semmlecode.cpp.dbscheme +++ b/cpp/ql/lib/semmlecode.cpp.dbscheme @@ -310,23 +310,14 @@ diagnostics( int location: @location_default ref ); -/* - fromSource(0) = unknown, - fromSource(1) = from source, - fromSource(2) = from library -*/ files( unique int id: @file, - string name: string ref, - string simple: string ref, - string ext: string ref, - int fromSource: int ref + string name: string ref ); folders( unique int id: @folder, - string name: string ref, - string simple: string ref + string name: string ref ); @container = @folder | @file diff --git a/cpp/ql/lib/semmlecode.cpp.dbscheme.stats b/cpp/ql/lib/semmlecode.cpp.dbscheme.stats index 61a31212bfa..c9aaf043a7a 100644 --- a/cpp/ql/lib/semmlecode.cpp.dbscheme.stats +++ b/cpp/ql/lib/semmlecode.cpp.dbscheme.stats @@ -12875,18 +12875,6 @@ name 59320 - -simple -40580 - - -ext -97 - - -fromSource -10 - @@ -12906,54 +12894,6 @@ -id -simple - - -12 - - -1 -2 -59320 - - - - - - -id -ext - - -12 - - -1 -2 -59320 - - - - - - -id -fromSource - - -12 - - -1 -2 -59320 - - - - - - name id @@ -12969,406 +12909,6 @@ - -name -simple - - -12 - - -1 -2 -59320 - - - - - - -name -ext - - -12 - - -1 -2 -59320 - - - - - - -name -fromSource - - -12 - - -1 -2 -59320 - - - - - - -simple -id - - -12 - - -1 -2 -30814 - - -2 -3 -6123 - - -3 -7 -3197 - - -7 -42 -444 - - - - - - -simple -name - - -12 - - -1 -2 -30814 - - -2 -3 -6123 - - -3 -7 -3197 - - -7 -42 -444 - - - - - - -simple -ext - - -12 - - -1 -2 -36277 - - -2 -3 -3739 - - -3 -6 -563 - - - - - - -simple -fromSource - - -12 - - -1 -2 -40580 - - - - - - -ext -id - - -12 - - -1 -2 -10 - - -3 -4 -10 - - -15 -16 -10 - - -38 -39 -10 - - -80 -81 -10 - - -114 -115 -10 - - -441 -442 -10 - - -768 -769 -10 - - -4013 -4014 -10 - - - - - - -ext -name - - -12 - - -1 -2 -10 - - -3 -4 -10 - - -15 -16 -10 - - -38 -39 -10 - - -80 -81 -10 - - -114 -115 -10 - - -441 -442 -10 - - -768 -769 -10 - - -4013 -4014 -10 - - - - - - -ext -simple - - -12 - - -1 -2 -10 - - -3 -4 -10 - - -15 -16 -10 - - -38 -39 -10 - - -75 -76 -10 - - -112 -113 -10 - - -428 -429 -10 - - -688 -689 -10 - - -2838 -2839 -10 - - - - - - -ext -fromSource - - -12 - - -1 -2 -97 - - - - - - -fromSource -id - - -12 - - -5473 -5474 -10 - - - - - - -fromSource -name - - -12 - - -5473 -5474 -10 - - - - - - -fromSource -simple - - -12 - - -3744 -3745 -10 - - - - - - -fromSource -ext - - -12 - - -9 -10 -10 - - - - - @@ -13383,10 +12923,6 @@ name 10817 - -simple -3099 - @@ -13406,22 +12942,6 @@ -id -simple - - -12 - - -1 -2 -10817 - - - - - - name id @@ -13437,94 +12957,6 @@ - -name -simple - - -12 - - -1 -2 -10817 - - - - - - -simple -id - - -12 - - -1 -2 -1669 - - -2 -3 -661 - - -3 -4 -433 - - -4 -17 -238 - - -27 -121 -97 - - - - - - -simple -name - - -12 - - -1 -2 -1669 - - -2 -3 -661 - - -3 -4 -433 - - -4 -17 -238 - - -27 -121 -97 - - - - - diff --git a/cpp/ql/src/Metrics/Internal/DiagnosticsSumElapsedTimes.ql b/cpp/ql/src/Metrics/Internal/DiagnosticsSumElapsedTimes.ql new file mode 100644 index 00000000000..530811c0801 --- /dev/null +++ b/cpp/ql/src/Metrics/Internal/DiagnosticsSumElapsedTimes.ql @@ -0,0 +1,12 @@ +/** + * @name Sum of frontend and extractor time + * @description The sum of elapsed frontend time, and the sum of elapsed extractor time. + * This query is for internal use only and may change without notice. + * @kind table + * @id cpp/frontend-and-extractor-time + */ + +import cpp + +select sum(Compilation c, float seconds | compilation_time(c, _, 2, seconds) | seconds) as sum_frontend_elapsed_seconds, + sum(Compilation c, float seconds | compilation_time(c, _, 4, seconds) | seconds) as sum_extractor_elapsed_seconds diff --git a/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql b/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql index a3f935170d7..92c8b9a2bd5 100644 --- a/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql +++ b/cpp/ql/src/Security/CWE/CWE-089/SqlTainted.ql @@ -30,7 +30,15 @@ class Configuration extends TaintTrackingConfiguration { } override predicate isBarrier(Expr e) { - super.isBarrier(e) or e.getUnspecifiedType() instanceof IntegralType + super.isBarrier(e) + or + e.getUnspecifiedType() instanceof IntegralType + or + exists(SqlBarrierFunction sql, int arg, FunctionInput input | + e = sql.getACallToThisFunction().getArgument(arg) and + input.isParameterDeref(arg) and + sql.barrierSqlArgument(input, _) + ) } } diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-089/SqlPqxxTainted.cpp b/cpp/ql/src/experimental/Security/CWE/CWE-089/SqlPqxxTainted.cpp deleted file mode 100644 index 3b85835fff9..00000000000 --- a/cpp/ql/src/experimental/Security/CWE/CWE-089/SqlPqxxTainted.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include -#include - -int main(int argc, char ** argv) { - - if (argc != 2) { - throw std::runtime_error("Give me a string!"); - } - - pqxx::connection c; - pqxx::work w(c); - - // BAD - char *userName = argv[1]; - char query1[1000] = {0}; - sprintf(query1, "SELECT UID FROM USERS where name = \"%s\"", userName); - pqxx::row r = w.exec1(query1); - w.commit(); - std::cout << r[0].as() << std::endl; - - // GOOD - pqxx::result r2 = w.exec("SELECT " + w.quote(argv[1])); - w.commit(); - std::cout << r2[0][0].c_str() << std::endl; - - return 0; -} diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-089/SqlPqxxTainted.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-089/SqlPqxxTainted.qhelp deleted file mode 100644 index 1c01b3e4f3a..00000000000 --- a/cpp/ql/src/experimental/Security/CWE/CWE-089/SqlPqxxTainted.qhelp +++ /dev/null @@ -1,31 +0,0 @@ - - - -

The code passes user input as part of a SQL query without escaping special elements. -It generates a SQL query to Postgres using sprintf, -with the user-supplied data directly passed as an argument -to sprintf. This leaves the code vulnerable to attack by SQL Injection.

- -
- - -

Use a library routine to escape characters in the user-supplied -string before converting it to SQL. Use esc and quote pqxx library functions.

- -
- - - - - - -
  • MSDN Library: SQL Injection.
  • - - - - -
    -
    diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-089/SqlPqxxTainted.ql b/cpp/ql/src/experimental/Security/CWE/CWE-089/SqlPqxxTainted.ql deleted file mode 100644 index 8de55953b15..00000000000 --- a/cpp/ql/src/experimental/Security/CWE/CWE-089/SqlPqxxTainted.ql +++ /dev/null @@ -1,113 +0,0 @@ -/** - * @name Uncontrolled data in SQL query to Postgres - * @description Including user-supplied data in a SQL query to Postgres - * without neutralizing special elements can make code - * vulnerable to SQL Injection. - * @kind path-problem - * @problem.severity error - * @precision high - * @id cpp/sql-injection-via-pqxx - * @tags security - * external/cwe/cwe-089 - */ - -import cpp -import semmle.code.cpp.security.Security -import semmle.code.cpp.dataflow.TaintTracking -import DataFlow::PathGraph - -predicate pqxxTransationClassNames(string className, string namespace) { - namespace = "pqxx" and - className in [ - "dbtransaction", "nontransaction", "basic_robusttransaction", "robusttransaction", - "subtransaction", "transaction", "basic_transaction", "transaction_base", "work" - ] -} - -predicate pqxxConnectionClassNames(string className, string namespace) { - namespace = "pqxx" and - className in ["connection_base", "basic_connection", "connection"] -} - -predicate pqxxTransactionSqlArgument(string function, int arg) { - function = "exec" and arg = 0 - or - function = "exec0" and arg = 0 - or - function = "exec1" and arg = 0 - or - function = "exec_n" and arg = 1 - or - function = "exec_params" and arg = 0 - or - function = "exec_params0" and arg = 0 - or - function = "exec_params1" and arg = 0 - or - function = "exec_params_n" and arg = 1 - or - function = "query_value" and arg = 0 - or - function = "stream" and arg = 0 -} - -predicate pqxxConnectionSqlArgument(string function, int arg) { function = "prepare" and arg = 1 } - -Expr getPqxxSqlArgument() { - exists(FunctionCall fc, Expr e, int argIndex, UserType t | - // examples: 'work' for 'work.exec(...)'; '->' for 'tx->exec()'. - e = fc.getQualifier() and - // to find ConnectionHandle/TransationHandle and similar classes which override '->' operator behavior - // and return pointer to a connection/transation object - e.getType().refersTo(t) and - // transaction exec and connection prepare variations - ( - pqxxTransationClassNames(t.getName(), t.getNamespace().getName()) and - pqxxTransactionSqlArgument(fc.getTarget().getName(), argIndex) - or - pqxxConnectionClassNames(t.getName(), t.getNamespace().getName()) and - pqxxConnectionSqlArgument(fc.getTarget().getName(), argIndex) - ) and - result = fc.getArgument(argIndex) - ) -} - -predicate pqxxEscapeArgument(string function, int arg) { - arg = 0 and - function in ["esc", "esc_raw", "quote", "quote_raw", "quote_name", "quote_table", "esc_like"] -} - -predicate isEscapedPqxxArgument(Expr argExpr) { - exists(FunctionCall fc, Expr e, int argIndex, UserType t | - // examples: 'work' for 'work.exec(...)'; '->' for 'tx->exec()'. - e = fc.getQualifier() and - // to find ConnectionHandle/TransationHandle and similar classes which override '->' operator behavior - // and return pointer to a connection/transation object - e.getType().refersTo(t) and - // transaction and connection escape functions - ( - pqxxTransationClassNames(t.getName(), t.getNamespace().getName()) or - pqxxConnectionClassNames(t.getName(), t.getNamespace().getName()) - ) and - pqxxEscapeArgument(fc.getTarget().getName(), argIndex) and - // is escaped arg == argExpr - argExpr = fc.getArgument(argIndex) - ) -} - -class Configuration extends TaintTracking::Configuration { - Configuration() { this = "SqlPqxxTainted" } - - override predicate isSource(DataFlow::Node source) { isUserInput(source.asExpr(), _) } - - override predicate isSink(DataFlow::Node sink) { sink.asExpr() = getPqxxSqlArgument() } - - override predicate isSanitizer(DataFlow::Node node) { isEscapedPqxxArgument(node.asExpr()) } -} - -from DataFlow::PathNode source, DataFlow::PathNode sink, Configuration config, string taintCause -where - config.hasFlowPath(source, sink) and - isUserInput(source.getNode().asExpr(), taintCause) -select sink, source, sink, "This argument to a SQL query function is derived from $@", source, - "user input (" + taintCause + ")" diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-675/DoubleRelease.c b/cpp/ql/src/experimental/Security/CWE/CWE-675/DoubleRelease.c new file mode 100644 index 00000000000..22de8d4dde4 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-675/DoubleRelease.c @@ -0,0 +1,13 @@ +... + fs = socket(AF_UNIX, SOCK_STREAM, 0) +... + close(fs); + fs = -1; // GOOD +... + +... + fs = socket(AF_UNIX, SOCK_STREAM, 0) +... + close(fs); + if(fs) close(fs); // BAD +... diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-675/DoubleRelease.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-675/DoubleRelease.qhelp new file mode 100644 index 00000000000..2b590e025b8 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-675/DoubleRelease.qhelp @@ -0,0 +1,26 @@ + + + +

    Double release of the descriptor can lead to a crash of the program. Requires the attention of developers.

    + +
    + +

    We recommend that you exclude situations of possible double release.

    + +
    + +

    The following example demonstrates an erroneous and corrected use of descriptor deallocation.

    + + +
    + + +
  • + CERT C Coding Standard: + FIO46-C. Do not access a closed file. +
  • + +
    +
    diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-675/DoubleRelease.ql b/cpp/ql/src/experimental/Security/CWE/CWE-675/DoubleRelease.ql new file mode 100644 index 00000000000..474f00acc55 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-675/DoubleRelease.ql @@ -0,0 +1,142 @@ +/** + * @name Errors When Double Release + * @description Double release of the descriptor can lead to a crash of the program. + * @kind problem + * @id cpp/double-release + * @problem.severity warning + * @precision medium + * @tags security + * external/cwe/cwe-675 + * external/cwe/cwe-666 + */ + +import cpp +import semmle.code.cpp.commons.File +import semmle.code.cpp.valuenumbering.GlobalValueNumbering +import semmle.code.cpp.valuenumbering.HashCons + +/** + * A function call that potentially does not return (such as `exit`). + */ +class CallMayNotReturn extends FunctionCall { + CallMayNotReturn() { + // call that is known to not return + not exists(this.(ControlFlowNode).getASuccessor()) + or + // call to another function that may not return + exists(CallMayNotReturn exit | getTarget() = exit.getEnclosingFunction()) + or + exists(ThrowExpr tex | tex = this.(ControlFlowNode).getASuccessor()) + } +} + +/** Holds if there are no assignment expressions to the function argument. */ +pragma[inline] +predicate checkChangeVariable(FunctionCall fc0, ControlFlowNode fc1, ControlFlowNode fc2) { + not exists(Expr exptmp | + ( + exptmp = fc0.getArgument(0).(VariableAccess).getTarget().getAnAssignedValue() or + exptmp.(AddressOfExpr).getOperand() = + fc0.getArgument(0).(VariableAccess).getTarget().getAnAccess() + ) and + exptmp = fc1.getASuccessor*() and + exptmp = fc2.getAPredecessor*() + ) and + ( + ( + not fc0.getArgument(0) instanceof PointerFieldAccess and + not fc0.getArgument(0) instanceof ValueFieldAccess + or + fc0.getArgument(0).(VariableAccess).getQualifier() instanceof ThisExpr + ) + or + not exists(Expr exptmp | + ( + exptmp = + fc0.getArgument(0) + .(VariableAccess) + .getQualifier() + .(VariableAccess) + .getTarget() + .getAnAssignedValue() or + exptmp.(AddressOfExpr).getOperand() = + fc0.getArgument(0) + .(VariableAccess) + .getQualifier() + .(VariableAccess) + .getTarget() + .getAnAccess() + ) and + exptmp = fc1.getASuccessor*() and + exptmp = fc2.getAPredecessor*() + ) + ) +} + +/** Holds if the underlying expression is a call to the close function. Provided that the function parameter does not change after the call. */ +predicate closeReturn(FunctionCall fc) { + fcloseCall(fc, _) and + checkChangeVariable(fc, fc, fc.getEnclosingFunction()) +} + +/** Holds if the underlying expression is a call to the close function. Provided that the function parameter does not change before the call. */ +predicate closeWithoutChangeBefore(FunctionCall fc) { + fcloseCall(fc, _) and + checkChangeVariable(fc, fc.getEnclosingFunction().getEntryPoint(), fc) +} + +/** Holds, if a sequential call of the specified functions is possible, via a higher-level function call. */ +predicate callInOtherFunctions(FunctionCall fc, FunctionCall fc1) { + exists(FunctionCall fec1, FunctionCall fec2 | + fc.getEnclosingFunction() != fc1.getEnclosingFunction() and + fec1 = fc.getEnclosingFunction().getACallToThisFunction() and + fec2 = fc1.getEnclosingFunction().getACallToThisFunction() and + fec1.getASuccessor*() = fec2 and + checkChangeVariable(fc, fec1, fec2) + ) +} + +/** Holds if successive calls to close functions are possible. */ +predicate interDoubleCloseFunctions(FunctionCall fc, FunctionCall fc1) { + fcloseCall(fc, _) and + fcloseCall(fc1, _) and + fc != fc1 and + fc.getASuccessor*() = fc1 and + checkChangeVariable(fc, fc, fc1) +} + +/** Holds if the first arguments of the two functions are similar. */ +predicate similarArguments(FunctionCall fc, FunctionCall fc1) { + globalValueNumber(fc.getArgument(0)) = globalValueNumber(fc1.getArgument(0)) + or + fc.getArgument(0).(VariableAccess).getTarget() = fc1.getArgument(0).(VariableAccess).getTarget() and + ( + not fc.getArgument(0) instanceof PointerFieldAccess and + not fc.getArgument(0) instanceof ValueFieldAccess + or + fc.getArgument(0).(VariableAccess).getQualifier() instanceof ThisExpr + ) + or + fc.getArgument(0).(VariableAccess).getTarget() = fc1.getArgument(0).(VariableAccess).getTarget() and + ( + fc.getArgument(0) instanceof PointerFieldAccess or + fc.getArgument(0) instanceof ValueFieldAccess + ) and + hashCons(fc.getArgument(0)) = hashCons(fc1.getArgument(0)) +} + +from FunctionCall fc, FunctionCall fc1 +where + not exists(CallMayNotReturn fctmp | fctmp = fc.getASuccessor*()) and + not exists(IfStmt ifs | ifs.getCondition().getAChild*() = fc) and + ( + // detecting a repeated call situation within one function + closeReturn(fc) and + closeWithoutChangeBefore(fc1) and + callInOtherFunctions(fc, fc1) + or + // detection of repeated call in different functions + interDoubleCloseFunctions(fc, fc1) + ) and + similarArguments(fc, fc1) +select fc, "Second call to the $@ function is possible.", fc1, fc1.getTarget().getName() diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-787/UnsignedToSignedPointerArith.ql b/cpp/ql/src/experimental/Security/CWE/CWE-787/UnsignedToSignedPointerArith.ql new file mode 100644 index 00000000000..1fe82c9cc51 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-787/UnsignedToSignedPointerArith.ql @@ -0,0 +1,30 @@ +/** + * @name unsigned to signed used in pointer arithmetic + * @description finds unsigned to signed conversions used in pointer arithmetic, potentially causing an out-of-bound access + * @id cpp/sign-conversion-pointer-arithmetic + * @kind problem + * @problem.severity warning + * @tags reliability + * security + * external/cwe/cwe-787 + */ + +import cpp +import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.security.Overflow + +from FunctionCall call, Function f, Parameter p, DataFlow::Node sink, PointerArithmeticOperation pao +where + f = call.getTarget() and + p = f.getAParameter() and + p.getUnspecifiedType().(IntegralType).isSigned() and + call.getArgument(p.getIndex()).getUnspecifiedType().(IntegralType).isUnsigned() and + pao.getAnOperand() = sink.asExpr() and + not exists(Operation a | guardedLesser(a, sink.asExpr())) and + not exists(Operation b | guardedGreater(b, call.getArgument(p.getIndex()))) and + not call.getArgument(p.getIndex()).isConstant() and + DataFlow::localFlow(DataFlow::parameterNode(p), sink) and + p.getUnspecifiedType().getSize() < 8 +select call, + "This call: $@ passes an unsigned int to a function that requires a signed int: $@. And then used in pointer arithmetic: $@", + call, call.toString(), f, f.toString(), sink, sink.toString() diff --git a/cpp/ql/src/jsf/4.13 Functions/AV Rule 114.ql b/cpp/ql/src/jsf/4.13 Functions/AV Rule 114.ql index 0e021ca7575..ac5db25ea6b 100644 --- a/cpp/ql/src/jsf/4.13 Functions/AV Rule 114.ql +++ b/cpp/ql/src/jsf/4.13 Functions/AV Rule 114.ql @@ -63,6 +63,7 @@ where functionsMissingReturnStmt(f, blame) and reachable(blame) and not functionImperfectlyExtracted(f) and + not f.isFromUninstantiatedTemplate(_) and (blame = stmt or blame.(Expr).getEnclosingStmt() = stmt) and msg = "Function " + f.getName() + " should return a value of type " + f.getType().getName() + diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.expected b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.expected index bd08d2698a3..112b6cb0201 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.expected +++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.expected @@ -599,6 +599,10 @@ | test.c:675:7:675:7 | y | -2147483648 | | test.c:684:7:684:7 | x | -2147483648 | | test.c:689:7:689:7 | x | -2147483648 | +| test.c:696:8:696:8 | x | 2147483647 | +| test.c:696:12:696:12 | y | 256 | +| test.c:697:9:697:9 | x | 2147483647 | +| test.c:698:9:698:9 | y | 256 | | test.cpp:10:7:10:7 | b | -2147483648 | | test.cpp:11:5:11:5 | x | -2147483648 | | test.cpp:13:10:13:10 | x | -2147483648 | diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.c b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.c index c4a2afcb5a0..8c7978ac4aa 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.c +++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.c @@ -689,3 +689,12 @@ label: out(x); goto label; } + +void test_overflow() { + const int x = 2147483647; // 2^31-1 + const int y = 256; + if ((x + y) <= 512) { + out(x); + out(y); + } +} diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/upperBound.expected b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/upperBound.expected index d6cce638bc2..8772a763a4d 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/upperBound.expected +++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/upperBound.expected @@ -599,6 +599,10 @@ | test.c:675:7:675:7 | y | 2147483647 | | test.c:684:7:684:7 | x | 2147483647 | | test.c:689:7:689:7 | x | 15 | +| test.c:696:8:696:8 | x | 2147483647 | +| test.c:696:12:696:12 | y | 256 | +| test.c:697:9:697:9 | x | 2147483647 | +| test.c:698:9:698:9 | y | 256 | | test.cpp:10:7:10:7 | b | 2147483647 | | test.cpp:11:5:11:5 | x | 2147483647 | | test.cpp:13:10:13:10 | x | 2147483647 | diff --git a/cpp/ql/test/query-tests/Critical/OverflowStatic/OverflowStatic.expected b/cpp/ql/test/query-tests/Critical/OverflowStatic/OverflowStatic.expected index 01a2dfc38b3..9ecfb2303db 100644 --- a/cpp/ql/test/query-tests/Critical/OverflowStatic/OverflowStatic.expected +++ b/cpp/ql/test/query-tests/Critical/OverflowStatic/OverflowStatic.expected @@ -9,6 +9,10 @@ | test.c:15:9:15:13 | access to array | Potential buffer-overflow: 'xs' has size 5 but 'xs[6]' is accessed here. | | test.c:20:9:20:18 | access to array | Potential buffer-overflow: 'ys' has size 5 but 'ys[5]' is accessed here. | | test.c:21:9:21:18 | access to array | Potential buffer-overflow: 'ys' has size 5 but 'ys[6]' is accessed here. | +| test.c:47:3:47:18 | access to array | Potential buffer-overflow: 'ptr' has size 8 but 'ptr[8]' is accessed here. | +| test.c:54:3:54:26 | access to array | Potential buffer-overflow: 'ptr' has size 8 but 'ptr[8]' is accessed here. | +| test.c:61:3:61:18 | access to array | Potential buffer-overflow: 'ptr' has size 8 but 'ptr[8]' is accessed here. | +| test.c:72:3:72:11 | access to array | Potential buffer-overflow: 'buf' has size 1 but 'buf[1]' is accessed here. | | test.cpp:19:3:19:12 | access to array | Potential buffer-overflow: counter 'i' <= 3 but 'buffer1' has 3 elements. | | test.cpp:20:3:20:12 | access to array | Potential buffer-overflow: counter 'i' <= 3 but 'buffer2' has 3 elements. | | test.cpp:24:27:24:27 | 4 | Potential buffer-overflow: 'buffer1' has size 3 not 4. | diff --git a/cpp/ql/test/query-tests/Critical/OverflowStatic/test.c b/cpp/ql/test/query-tests/Critical/OverflowStatic/test.c index baa8999412c..4da951a3139 100644 --- a/cpp/ql/test/query-tests/Critical/OverflowStatic/test.c +++ b/cpp/ql/test/query-tests/Critical/OverflowStatic/test.c @@ -27,3 +27,47 @@ void f(void) { c = stru.zs[6]; // GOOD (zs is variable size) } +void* malloc(long unsigned int); +void test_buffer_sentinal() { + struct { char len; char buf[1]; } *b = malloc(10); // len(buf.buffer) effectively 8 + b->buf[0] = 0; // GOOD + b->buf[7] = 0; // GOOD + b->buf[8] = 0; // BAD [NOT DETECTED] +} + +union u { + unsigned long value; + char ptr[1]; +}; + +void union_test() { + union u u; + u.ptr[0] = 0; // GOOD + u.ptr[sizeof(u)-1] = 0; // GOOD + u.ptr[sizeof(u)] = 0; // BAD +} + +void test_struct_union() { + struct { union u u; } v; + v.u.ptr[0] = 0; // GOOD + v.u.ptr[sizeof(union u)-1] = 0; // GOOD + v.u.ptr[sizeof(union u)] = 0; // BAD +} + +void union_test2() { + union { char ptr[1]; unsigned long value; } u; + u.ptr[0] = 0; // GOOD + u.ptr[sizeof(u)-1] = 0; // GOOD + u.ptr[sizeof(u)] = 0; // BAD +} + +typedef struct { + char len; + char buf[1]; +} var_buf; + +void test_alloc() { + // Special case of taking sizeof without any addition or multiplications + var_buf *b = malloc(sizeof(var_buf)); + b->buf[1] = 0; // BAD +} diff --git a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/ImproperNullTermination/ImproperNullTermination.expected b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/ImproperNullTermination/ImproperNullTermination.expected index b8f5c71e8e2..c83205ef49f 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/ImproperNullTermination/ImproperNullTermination.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/ImproperNullTermination/ImproperNullTermination.expected @@ -23,3 +23,5 @@ | test.cpp:365:19:365:25 | buffer2 | Variable $@ may not be null terminated. | test.cpp:363:8:363:14 | buffer2 | buffer2 | | test.cpp:392:17:392:22 | buffer | Variable $@ may not be null terminated. | test.cpp:390:8:390:13 | buffer | buffer | | test.cpp:398:18:398:23 | buffer | Variable $@ may not be null terminated. | test.cpp:396:8:396:13 | buffer | buffer | +| test.cpp:444:10:444:15 | buffer | Variable $@ may not be null terminated. | test.cpp:442:8:442:13 | buffer | buffer | +| test.cpp:450:16:450:21 | buffer | Variable $@ may not be null terminated. | test.cpp:448:8:448:13 | buffer | buffer | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/ImproperNullTermination/test.cpp b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/ImproperNullTermination/test.cpp index 7fa4ef60093..45410c15ebf 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/ImproperNullTermination/test.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/ImproperNullTermination/test.cpp @@ -433,3 +433,36 @@ void test_read_fread(int read_src, FILE *s) strlen(buffer); // GOOD } } + +int printf(const char *format, ...); + +void test_printf(char *str) +{ + { + char buffer[1024]; + + printf(buffer, ""); // BAD + } + + { + char buffer[1024]; + + printf("%s", buffer); // BAD + } + + { + size_t len = strlen(str); + char *copied_str = (char *)malloc(len); + + memcpy(copied_str, str, len); + printf("%s", copied_str); // BAD [NOT DETECTED] + } + + { + size_t len = strlen(str); + char *copied_str = (char *)malloc(len + 1); + + memcpy(copied_str, str, len + 1); + printf("%s", copied_str); // GOOD + } +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-022/SAMATE/TaintedPath/CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-022/SAMATE/TaintedPath/CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp new file mode 100644 index 00000000000..876584c5117 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-022/SAMATE/TaintedPath/CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp @@ -0,0 +1,134 @@ +/** + * This test case is closely based on CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp + * from the SAMATE Juliet test suite. + */ + +#define NULL (0) + +typedef unsigned long size_t; +typedef size_t time_t; +time_t time(time_t *timer); + +typedef struct {} FILE; +extern FILE *stdin; +FILE *fopen(const char *filename, const char *mode); +int fclose(FILE *stream); +#define FILENAME_MAX (4096) + +typedef unsigned long size_t; +size_t strlen(const char *s); +char *strcat(char *s1, const char *s2); +char *fgets(char *s, int n, FILE *stream); + +int globalReturnsTrue() +{ + return 1; +} + +int globalReturnsFalse() +{ + return 0; +} + +void printLine(const char *str); + +#define BASEPATH "c:\\temp\\" +#define FOPEN fopen + +namespace CWE23_Relative_Path_Traversal__char_console_fopen_11 +{ + +void bad() +{ + char * data; + char dataBuffer[FILENAME_MAX] = BASEPATH; + data = dataBuffer; + if(globalReturnsTrue()) + { + { + /* Read input from the console */ + size_t dataLen = strlen(data); + /* if there is room in data, read into it from the console */ + if (FILENAME_MAX-dataLen > 1) + { + /* POTENTIAL FLAW: Read data from the console */ + if (fgets(data+dataLen, (int)(FILENAME_MAX-dataLen), stdin) != NULL) + { + /* The next few lines remove the carriage return from the string that is + * inserted by fgets() */ + dataLen = strlen(data); + if (dataLen > 0 && data[dataLen-1] == '\n') + { + data[dataLen-1] = '\0'; + } + } + else + { + printLine("fgets() failed"); + /* Restore NUL terminator if fgets fails */ + data[dataLen] = '\0'; + } + } + } + } + { + FILE *pFile = NULL; + /* POTENTIAL FLAW: Possibly opening a file without validating the file name or path */ + pFile = FOPEN(data, "wb+"); + if (pFile != NULL) + { + fclose(pFile); + } + } +} + +/* goodG2B1() - use goodsource and badsink by changing the globalReturnsTrue() to globalReturnsFalse() */ +static void goodG2B1() +{ + char * data; + char dataBuffer[FILENAME_MAX] = BASEPATH; + data = dataBuffer; + if(globalReturnsFalse()) + { + /* INCIDENTAL: CWE 561 Dead Code, the code below will never run */ + printLine("Benign, fixed string"); + } + else + { + /* FIX: Use a fixed file name */ + strcat(data, "file.txt"); + } + { + FILE *pFile = NULL; + /* POTENTIAL FLAW: Possibly opening a file without validating the file name or path */ + pFile = FOPEN(data, "wb+"); + if (pFile != NULL) + { + fclose(pFile); + } + } +} + +/* goodG2B2() - use goodsource and badsink by reversing the blocks in the if statement */ +static void goodG2B2() +{ + char * data; + char dataBuffer[FILENAME_MAX] = BASEPATH; + data = dataBuffer; + if(globalReturnsTrue()) + { + /* FIX: Use a fixed file name */ + strcat(data, "file.txt"); + } + { + FILE *pFile = NULL; + /* POTENTIAL FLAW: Possibly opening a file without validating the file name or path */ + pFile = FOPEN(data, "wb+"); + if (pFile != NULL) + { + fclose(pFile); + } + } +} + +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-022/SAMATE/TaintedPath/TaintedPath.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-022/SAMATE/TaintedPath/TaintedPath.expected new file mode 100644 index 00000000000..6271123d9d1 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-022/SAMATE/TaintedPath/TaintedPath.expected @@ -0,0 +1,18 @@ +edges +| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | (const char *)... | +| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | +| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | +| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | (const char *)... | +| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | +| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | +subpaths +nodes +| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | semmle.label | ... + ... | +| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | semmle.label | fgets output argument | +| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | (const char *)... | semmle.label | (const char *)... | +| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | (const char *)... | semmle.label | (const char *)... | +| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | semmle.label | data | +| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | semmle.label | data indirection | +| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | semmle.label | data indirection | +#select +| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | This argument to a file access function is derived from $@ and then passed to fopen(filename) | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | user input (fgets) | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-022/SAMATE/TaintedPath/TaintedPath.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-022/SAMATE/TaintedPath/TaintedPath.qlref new file mode 100644 index 00000000000..1677939387d --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-022/SAMATE/TaintedPath/TaintedPath.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-022/TaintedPath.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected index 7b513c574ad..cb8dfd321b3 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-022/semmle/tests/TaintedPath.expected @@ -5,6 +5,7 @@ edges | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName | | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName indirection | | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName indirection | +subpaths nodes | test.c:9:23:9:26 | argv | semmle.label | argv | | test.c:9:23:9:26 | argv | semmle.label | argv | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-078/SAMATE/ExecTainted/ExecTainted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-078/SAMATE/ExecTainted/ExecTainted.expected new file mode 100644 index 00000000000..6f011708465 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-078/SAMATE/ExecTainted/ExecTainted.expected @@ -0,0 +1 @@ +| tests.cpp:53:16:53:19 | data | This argument to an OS command is derived from $@ and then passed to system(string) | tests.cpp:33:34:33:39 | call to getenv | user input (getenv) | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-078/SAMATE/ExecTainted/ExecTainted.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-078/SAMATE/ExecTainted/ExecTainted.qlref new file mode 100644 index 00000000000..9fe2347270f --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-078/SAMATE/ExecTainted/ExecTainted.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-078/ExecTainted.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-078/SAMATE/ExecTainted/tests.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-078/SAMATE/ExecTainted/tests.cpp new file mode 100644 index 00000000000..80f8221d903 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-078/SAMATE/ExecTainted/tests.cpp @@ -0,0 +1,58 @@ +//semmle-extractor-options: --edg --target --edg win64 + +// A selection of tests from the SAMATE Juliet framework for rule CWE-78. + +// library types, functions etc +#define NULL (0) +typedef unsigned long size_t; +size_t strlen(const char *s); +char *strncat(char *s1, const char *s2, size_t n); +char *getenv(const char *name); +int system(const char *string); +void exit(int status); + +#define FULL_COMMAND "dir " +#define ENV_VARIABLE "ADD" +#define GETENV getenv +#define SYSTEM system + +void printLine(const char *str); + +// ---------- + +/* The static variable below is used to drive control flow in the source function */ +static int badStatic = 0; + +static char * badSource(char * data) +{ + if(badStatic) + { + { + /* Append input from an environment variable to data */ + size_t dataLen = strlen(data); + char * environment = GETENV(ENV_VARIABLE); + /* If there is data in the environment variable */ + if (environment != NULL) + { + /* POTENTIAL FLAW: Read data from an environment variable */ + strncat(data+dataLen, environment, 100-dataLen-1); + } + } + } + return data; +} + +void CWE78_OS_Command_Injection__char_environment_system_21_bad() +{ + char * data; + char data_buf[100] = FULL_COMMAND; + data = data_buf; + badStatic = 1; /* true */ + data = badSource(data); + /* POTENTIAL FLAW: Execute command in data possibly leading to command injection [NOT DETECTED] */ + if (SYSTEM(data) != 0) + { + printLine("command execution failed!"); + exit(1); + } +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected index d9fa0d7029f..ebf051ddd0b 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected @@ -24,6 +24,7 @@ edges | search.c:55:17:55:25 | raw_query indirection | search.c:14:24:14:28 | *query | | search.c:57:5:57:15 | raw_query | search.c:22:24:22:28 | query | | search.c:57:17:57:25 | raw_query indirection | search.c:22:24:22:28 | *query | +subpaths nodes | search.c:14:24:14:28 | *query | semmle.label | *query | | search.c:14:24:14:28 | query | semmle.label | query | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected index e267dd48bba..2b572375ce9 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/SqlTainted.expected @@ -5,6 +5,15 @@ edges | test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 | | test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 indirection | | test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 indirection | +| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | (const char *)... | +| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | (const char *)... | +| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array | +| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array | +| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array | +| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array | +| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array indirection | +| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array indirection | +subpaths nodes | test.c:15:20:15:23 | argv | semmle.label | argv | | test.c:15:20:15:23 | argv | semmle.label | argv | @@ -13,5 +22,15 @@ nodes | test.c:21:18:21:23 | query1 | semmle.label | query1 | | test.c:21:18:21:23 | query1 indirection | semmle.label | query1 indirection | | test.c:21:18:21:23 | query1 indirection | semmle.label | query1 indirection | +| test.cpp:43:27:43:30 | argv | semmle.label | argv | +| test.cpp:43:27:43:30 | argv | semmle.label | argv | +| test.cpp:43:27:43:33 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:43:27:43:33 | (const char *)... | semmle.label | (const char *)... | +| test.cpp:43:27:43:33 | access to array | semmle.label | access to array | +| test.cpp:43:27:43:33 | access to array | semmle.label | access to array | +| test.cpp:43:27:43:33 | access to array | semmle.label | access to array | +| test.cpp:43:27:43:33 | access to array indirection | semmle.label | access to array indirection | +| test.cpp:43:27:43:33 | access to array indirection | semmle.label | access to array indirection | #select | test.c:21:18:21:23 | query1 | test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg) | test.c:15:20:15:23 | argv | user input (argv) | +| test.cpp:43:27:43:33 | access to array | test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array | This argument to a SQL query function is derived from $@ and then passed to pqxx::work::exec1((unnamed parameter 0)) | test.cpp:43:27:43:30 | argv | user input (argv) | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.cpp new file mode 100644 index 00000000000..8bdf7dded23 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-089/SqlTainted/test.cpp @@ -0,0 +1,48 @@ +int sprintf(char* str, const char* format, ...); + +namespace std +{ + template struct char_traits; + + template class allocator { + public: + allocator() throw(); + }; + + template, class Allocator = allocator > + class basic_string { + public: + explicit basic_string(const Allocator& a = Allocator()); + basic_string(const charT* s, const Allocator& a = Allocator()); + + const charT* c_str() const; + }; + + typedef basic_string string; +} + +namespace pqxx { + struct connection {}; + + struct row {}; + struct result {}; + + struct work { + work(connection&); + + row exec1(const char*); + result exec(const std::string&); + std::string quote(const char*); + }; +} + +int main(int argc, char** argv) { + pqxx::connection c; + pqxx::work w(c); + + pqxx::row r = w.exec1(argv[1]); // BAD + + pqxx::result r2 = w.exec(w.quote(argv[1])); // GOOD + + return 0; +} \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-114/SAMATE/UncontrolledProcessOperation/UncontrolledProcessOperation.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-114/SAMATE/UncontrolledProcessOperation/UncontrolledProcessOperation.expected new file mode 100644 index 00000000000..11cca0cf50b --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-114/SAMATE/UncontrolledProcessOperation/UncontrolledProcessOperation.expected @@ -0,0 +1,31 @@ +edges +| test.cpp:37:73:37:76 | *data | test.cpp:43:32:43:35 | (LPCSTR)... | +| test.cpp:37:73:37:76 | *data | test.cpp:43:32:43:35 | data | +| test.cpp:37:73:37:76 | *data | test.cpp:43:32:43:35 | data indirection | +| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | (LPCSTR)... | +| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | data | +| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | data | +| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | data indirection | +| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:17:73:22 | data | +| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:17:73:22 | data | +| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data indirection | +| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data indirection | +| test.cpp:73:17:73:22 | data | test.cpp:37:73:37:76 | data | +| test.cpp:73:24:73:27 | data indirection | test.cpp:37:73:37:76 | *data | +subpaths +nodes +| test.cpp:37:73:37:76 | *data | semmle.label | *data | +| test.cpp:37:73:37:76 | data | semmle.label | data | +| test.cpp:43:32:43:35 | (LPCSTR)... | semmle.label | (LPCSTR)... | +| test.cpp:43:32:43:35 | (LPCSTR)... | semmle.label | (LPCSTR)... | +| test.cpp:43:32:43:35 | data | semmle.label | data | +| test.cpp:43:32:43:35 | data | semmle.label | data | +| test.cpp:43:32:43:35 | data | semmle.label | data | +| test.cpp:43:32:43:35 | data indirection | semmle.label | data indirection | +| test.cpp:43:32:43:35 | data indirection | semmle.label | data indirection | +| test.cpp:64:30:64:35 | call to getenv | semmle.label | call to getenv | +| test.cpp:64:30:64:35 | call to getenv | semmle.label | call to getenv | +| test.cpp:73:17:73:22 | data | semmle.label | data | +| test.cpp:73:24:73:27 | data indirection | semmle.label | data indirection | +#select +| test.cpp:43:32:43:35 | data | test.cpp:64:30:64:35 | call to getenv | test.cpp:43:32:43:35 | data | The value of this argument may come from $@ and is being passed to LoadLibraryA | test.cpp:64:30:64:35 | call to getenv | call to getenv | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-114/SAMATE/UncontrolledProcessOperation/UncontrolledProcessOperation.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-114/SAMATE/UncontrolledProcessOperation/UncontrolledProcessOperation.qlref new file mode 100644 index 00000000000..a9ca1db5199 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-114/SAMATE/UncontrolledProcessOperation/UncontrolledProcessOperation.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-114/UncontrolledProcessOperation.ql diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-114/SAMATE/UncontrolledProcessOperation/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-114/SAMATE/UncontrolledProcessOperation/test.cpp new file mode 100644 index 00000000000..299e0372d4a --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-114/SAMATE/UncontrolledProcessOperation/test.cpp @@ -0,0 +1,132 @@ +// Some SAMATE Juliet test cases for CWE-114. + +typedef unsigned long size_t; +typedef unsigned int BOOL; +typedef const char *LPCSTR; +typedef void *HMODULE; +#define NULL (0) + +size_t strlen(const char *s); +char *strncat(char *s1, const char *s2, size_t n); + +HMODULE LoadLibraryA(LPCSTR libname); +BOOL FreeLibrary(HMODULE hModule); + +char *getenv(const char *name); + +#define GETENV getenv +#define ENV_VARIABLE "ADD" + +void printLine(const char *msg); + +// --- CWE114_Process_Control__w32_char_environment_82 --- + +class CWE114_Process_Control__w32_char_environment_82_base +{ +public: + /* pure virtual function */ + virtual void action(char * data) = 0; +}; + +class CWE114_Process_Control__w32_char_environment_82_bad : public CWE114_Process_Control__w32_char_environment_82_base +{ +public: + void action(char * data); +}; + +void CWE114_Process_Control__w32_char_environment_82_bad::action(char * data) +{ + { + HMODULE hModule; + /* POTENTIAL FLAW: If the path to the library is not specified, an attacker may be able to + * replace his own file with the intended library */ + hModule = LoadLibraryA(data); + if (hModule != NULL) + { + FreeLibrary(hModule); + printLine("Library loaded and freed successfully"); + } + else + { + printLine("Unable to load library"); + } + } +} + +void bad() +{ + char * data; + char dataBuffer[100] = ""; + data = dataBuffer; + { + /* Append input from an environment variable to data */ + size_t dataLen = strlen(data); + char * environment = GETENV(ENV_VARIABLE); + /* If there is data in the environment variable */ + if (environment != NULL) + { + /* POTENTIAL FLAW: Read data from an environment variable */ + strncat(data+dataLen, environment, 100-dataLen-1); + } + } + CWE114_Process_Control__w32_char_environment_82_base* baseObject = new CWE114_Process_Control__w32_char_environment_82_bad; + baseObject->action(data); + delete baseObject; +} + +// --- CWE114_Process_Control__w32_char_console_33 --- + +typedef struct {} FILE; +char *fgets(char *s, int n, FILE *stream); +FILE *stdin; + +void CWE114_Process_Control__w32_char_console_33_bad() +{ + char * data; + char * &dataRef = data; + char dataBuffer[100] = ""; + data = dataBuffer; + { + /* Read input from the console */ + size_t dataLen = strlen(data); + /* if there is room in data, read into it from the console */ + if (100-dataLen > 1) + { + /* POTENTIAL FLAW: Read data from the console [NOT DETECTED] */ + if (fgets(data+dataLen, (int)(100-dataLen), stdin) != NULL) + { + /* The next few lines remove the carriage return from the string that is + * inserted by fgets() */ + dataLen = strlen(data); + if (dataLen > 0 && data[dataLen-1] == '\n') + { + data[dataLen-1] = '\0'; + } + } + else + { + printLine("fgets() failed"); + /* Restore NUL terminator if fgets fails */ + data[dataLen] = '\0'; + } + } + } + { + char * data = dataRef; + { + HMODULE hModule; + /* POTENTIAL FLAW: If the path to the library is not specified, an attacker may be able to + * replace his own file with the intended library */ + hModule = LoadLibraryA(data); + if (hModule != NULL) + { + FreeLibrary(hModule); + printLine("Library loaded and freed successfully"); + } + else + { + printLine("Unable to load library"); + } + } + } +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected index c610e346bb1..b9a0f7b3631 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-114/semmle/UncontrolledProcessOperation/UncontrolledProcessOperation.expected @@ -47,6 +47,7 @@ edges | test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | (const char *)... | | test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer | | test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer indirection | +subpaths nodes | test.cpp:24:30:24:36 | *command | semmle.label | *command | | test.cpp:24:30:24:36 | command | semmle.label | command | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/BadlyBoundedWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/BadlyBoundedWrite.expected new file mode 100644 index 00000000000..bd60a176ca9 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/BadlyBoundedWrite.expected @@ -0,0 +1,4 @@ +| tests.cpp:350:13:350:19 | call to strncat | This 'call to strncat' operation is limited to 100 bytes but the destination is only 50 bytes. | +| tests.cpp:452:9:452:15 | call to wcsncpy | This 'call to wcsncpy' operation is limited to 396 bytes but the destination is only 200 bytes. | +| tests.cpp:481:9:481:16 | call to swprintf | This 'call to swprintf' operation is limited to 400 bytes but the destination is only 200 bytes. | +| tests.cpp:630:13:630:20 | call to swprintf | This 'call to swprintf' operation is limited to 400 bytes but the destination is only 200 bytes. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/BadlyBoundedWrite.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/BadlyBoundedWrite.qlref new file mode 100644 index 00000000000..9636c74d0a8 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/BadlyBoundedWrite.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-120/BadlyBoundedWrite.ql \ No newline at end of file diff --git a/java/ql/test/library-tests/frameworks/guava/flow.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OffsetUseBeforeRangeCheck.expected similarity index 100% rename from java/ql/test/library-tests/frameworks/guava/flow.expected rename to cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OffsetUseBeforeRangeCheck.expected diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OffsetUseBeforeRangeCheck.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OffsetUseBeforeRangeCheck.qlref new file mode 100644 index 00000000000..d934901f174 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OffsetUseBeforeRangeCheck.qlref @@ -0,0 +1 @@ +Best Practices/Likely Errors/OffsetUseBeforeRangeCheck.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowBuffer.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowBuffer.expected new file mode 100644 index 00000000000..73f1b74db56 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowBuffer.expected @@ -0,0 +1,19 @@ +| tests.cpp:45:9:45:14 | call to memcpy | This 'memcpy' operation accesses 32 bytes but the $@ is only 16 bytes. | tests.cpp:32:10:32:18 | charFirst | destination buffer | +| tests.cpp:60:9:60:14 | call to memcpy | This 'memcpy' operation accesses 32 bytes but the $@ is only 16 bytes. | tests.cpp:32:10:32:18 | charFirst | destination buffer | +| tests.cpp:171:9:171:14 | call to memcpy | This 'memcpy' operation accesses 100 bytes but the $@ is only 50 bytes. | tests.cpp:164:20:164:25 | call to malloc | destination buffer | +| tests.cpp:172:9:172:19 | access to array | This array indexing operation accesses byte offset 99 but the $@ is only 50 bytes. | tests.cpp:164:20:164:25 | call to malloc | array | +| tests.cpp:192:9:192:14 | call to memcpy | This 'memcpy' operation accesses 100 bytes but the $@ is only 50 bytes. | tests.cpp:181:10:181:22 | dataBadBuffer | destination buffer | +| tests.cpp:192:9:192:14 | call to memcpy | This 'memcpy' operation accesses 100 bytes but the $@ is only 50 bytes. | tests.cpp:185:12:185:24 | dataBadBuffer | destination buffer | +| tests.cpp:193:9:193:19 | access to array | This array indexing operation accesses byte offset 99 but the $@ is only 50 bytes. | tests.cpp:181:10:181:22 | dataBadBuffer | array | +| tests.cpp:193:9:193:19 | access to array | This array indexing operation accesses byte offset 99 but the $@ is only 50 bytes. | tests.cpp:185:12:185:24 | dataBadBuffer | array | +| tests.cpp:212:9:212:14 | call to memcpy | This 'memcpy' operation accesses 100 bytes but the $@ is only 50 bytes. | tests.cpp:201:36:201:41 | call to alloca | destination buffer | +| tests.cpp:212:9:212:14 | call to memcpy | This 'memcpy' operation accesses 100 bytes but the $@ is only 50 bytes. | tests.cpp:205:12:205:24 | dataBadBuffer | destination buffer | +| tests.cpp:213:9:213:19 | access to array | This array indexing operation accesses byte offset 99 but the $@ is only 50 bytes. | tests.cpp:201:36:201:41 | call to alloca | array | +| tests.cpp:213:9:213:19 | access to array | This array indexing operation accesses byte offset 99 but the $@ is only 50 bytes. | tests.cpp:205:12:205:24 | dataBadBuffer | array | +| tests.cpp:237:9:237:19 | access to array | This array indexing operation accesses byte offset 99 but the $@ is only 50 bytes. | tests.cpp:221:36:221:41 | call to alloca | array | +| tests.cpp:237:9:237:19 | access to array | This array indexing operation accesses byte offset 99 but the $@ is only 50 bytes. | tests.cpp:225:12:225:24 | dataBadBuffer | array | +| tests.cpp:261:9:261:19 | access to array | This array indexing operation accesses byte offset 99 but the $@ is only 50 bytes. | tests.cpp:245:10:245:22 | dataBadBuffer | array | +| tests.cpp:261:9:261:19 | access to array | This array indexing operation accesses byte offset 99 but the $@ is only 50 bytes. | tests.cpp:249:12:249:24 | dataBadBuffer | array | +| tests.cpp:384:9:384:14 | call to memcpy | This 'memcpy' operation accesses 40 bytes but the $@ is only 10 bytes. | tests.cpp:380:19:380:24 | call to alloca | destination buffer | +| tests.cpp:434:9:434:19 | access to array | This array indexing operation accesses byte offset 399 but the $@ is only 200 bytes. | tests.cpp:422:12:422:26 | new[] | array | +| tests.cpp:453:9:453:19 | access to array | This array indexing operation accesses byte offset 399 but the $@ is only 200 bytes. | tests.cpp:445:12:445:26 | new[] | array | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowBuffer.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowBuffer.qlref new file mode 100644 index 00000000000..5c2bacec579 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowBuffer.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-119/OverflowBuffer.ql \ No newline at end of file diff --git a/python/ql/test/experimental/library-tests/frameworks/sqlalchemy/ConceptsTest.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowDestination.expected similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/sqlalchemy/ConceptsTest.expected rename to cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowDestination.expected diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowDestination.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowDestination.qlref new file mode 100644 index 00000000000..a4213e22fcd --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowDestination.qlref @@ -0,0 +1 @@ +Critical/OverflowDestination.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowStatic.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowStatic.expected new file mode 100644 index 00000000000..ab9263b8544 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowStatic.expected @@ -0,0 +1,2 @@ +| tests.cpp:45:51:45:72 | sizeof() | Potential buffer-overflow: 'charFirst' has size 16 not 32. | +| tests.cpp:60:52:60:74 | sizeof() | Potential buffer-overflow: 'charFirst' has size 16 not 32. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowStatic.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowStatic.qlref new file mode 100644 index 00000000000..9ff1c3b33dc --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverflowStatic.qlref @@ -0,0 +1 @@ +Critical/OverflowStatic.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverrunWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverrunWrite.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverrunWrite.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverrunWrite.qlref new file mode 100644 index 00000000000..f6c962c1a7b --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverrunWrite.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-120/OverrunWrite.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverrunWriteFloat.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverrunWriteFloat.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverrunWriteFloat.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverrunWriteFloat.qlref new file mode 100644 index 00000000000..757d1592e83 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/OverrunWriteFloat.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-120/OverrunWriteFloat.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/StrncpyFlippedArgs.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/StrncpyFlippedArgs.expected new file mode 100644 index 00000000000..778adb97718 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/StrncpyFlippedArgs.expected @@ -0,0 +1,3 @@ +| tests.cpp:290:13:290:19 | call to wcsncpy | Potentially unsafe call to wcsncpy; third argument should be size of destination. | +| tests.cpp:306:4:306:10 | call to wcsncpy | Potentially unsafe call to wcsncpy; third argument should be size of destination. | +| tests.cpp:452:9:452:15 | call to wcsncpy | Potentially unsafe call to wcsncpy; third argument should be size of destination. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/StrncpyFlippedArgs.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/StrncpyFlippedArgs.qlref new file mode 100644 index 00000000000..bf0bf1ea7d0 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/StrncpyFlippedArgs.qlref @@ -0,0 +1 @@ +Likely Bugs/Memory Management/StrncpyFlippedArgs.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/UnboundedWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/UnboundedWrite.expected new file mode 100644 index 00000000000..7cefb7cfafc --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/UnboundedWrite.expected @@ -0,0 +1,4 @@ +edges +subpaths +nodes +#select diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/UnboundedWrite.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/UnboundedWrite.qlref new file mode 100644 index 00000000000..767f2ea4db9 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/UnboundedWrite.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-120/UnboundedWrite.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/tests.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/tests.cpp new file mode 100644 index 00000000000..1c7f9ad60f5 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/tests.cpp @@ -0,0 +1,671 @@ +// A sample of tests from the SAMATE Juliet framework for rule CWE-119. + +// library types, functions etc +typedef unsigned long size_t; +void *malloc(size_t size); +void *alloca(size_t size); +void free(void *ptr); +#define ALLOCA alloca + +void *memcpy(void *s1, const void *s2, size_t n); +void *memset(void *s, int c, size_t n); +char *strcpy(char *s1, const char *s2); +size_t strlen(const char *s); + +void exit(int status); + +typedef unsigned int DWORD; +DWORD GetCurrentDirectoryA(DWORD bufferLength, char *buffer); +bool PathAppendA(char *path, const char *more); +#define MAX_PATH 4096 + +void printLine(const char *str); +void printSizeTLine(size_t val); +void printIntLine(int val); + +// ---------- + +#define SRC_STR "0123456789abcde0123" + +typedef struct _charVoid +{ + char charFirst[16]; + void * voidSecond; + void * voidThird; +} charVoid; + +void CWE121_Stack_Based_Buffer_Overflow__char_type_overrun_memcpy_01_bad() +{ + { + charVoid structCharVoid; + structCharVoid.voidSecond = (void *)SRC_STR; + /* Print the initial block pointed to by structCharVoid.voidSecond */ + printLine((char *)structCharVoid.voidSecond); + /* FLAW: Use the sizeof(structCharVoid) which will overwrite the pointer voidSecond */ + memcpy(structCharVoid.charFirst, SRC_STR, sizeof(structCharVoid)); + structCharVoid.charFirst[(sizeof(structCharVoid.charFirst)/sizeof(char))-1] = '\0'; /* null terminate the string */ + printLine((char *)structCharVoid.charFirst); + printLine((char *)structCharVoid.voidSecond); + } +} + +void CWE122_Heap_Based_Buffer_Overflow__char_type_overrun_memcpy_01_bad() +{ + { + charVoid * structCharVoid = (charVoid *)malloc(sizeof(charVoid)); + structCharVoid->voidSecond = (void *)SRC_STR; + /* Print the initial block pointed to by structCharVoid->voidSecond */ + printLine((char *)structCharVoid->voidSecond); + /* FLAW: Use the sizeof(*structCharVoid) which will overwrite the pointer y */ + memcpy(structCharVoid->charFirst, SRC_STR, sizeof(*structCharVoid)); + structCharVoid->charFirst[(sizeof(structCharVoid->charFirst)/sizeof(char))-1] = '\0'; /* null terminate the string */ + printLine((char *)structCharVoid->charFirst); + printLine((char *)structCharVoid->voidSecond); + free(structCharVoid); + } +} + +void CWE124_Buffer_Underwrite__char_alloca_cpy_01_bad() +{ + char * data; + char * dataBuffer = (char *)ALLOCA(100*sizeof(char)); + memset(dataBuffer, 'A', 100-1); + dataBuffer[100-1] = '\0'; + /* FLAW: Set data pointer to before the allocated memory buffer */ + data = dataBuffer - 8; + { + char source[100]; + memset(source, 'C', 100-1); /* fill with 'C's */ + source[100-1] = '\0'; /* null terminate */ + /* POTENTIAL FLAW: Possibly copying data to memory before the destination buffer */ + strcpy(data, source); // [NOT DETECTED] + printLine(data); + } +} + +void CWE126_Buffer_Overread__char_alloca_loop_01_bad() +{ + char * data; + char * dataBadBuffer = (char *)ALLOCA(50*sizeof(char)); + char * dataGoodBuffer = (char *)ALLOCA(100*sizeof(char)); + memset(dataBadBuffer, 'A', 50-1); /* fill with 'A's */ + dataBadBuffer[50-1] = '\0'; /* null terminate */ + memset(dataGoodBuffer, 'A', 100-1); /* fill with 'A's */ + dataGoodBuffer[100-1] = '\0'; /* null terminate */ + /* FLAW: Set data pointer to a small buffer */ + data = dataBadBuffer; + { + size_t i, destLen; + char dest[100]; + memset(dest, 'C', 100-1); + dest[100-1] = '\0'; /* null terminate */ + destLen = strlen(dest); + /* POTENTIAL FLAW: using length of the dest where data + * could be smaller than dest causing buffer overread */ + for (i = 0; i < destLen; i++) + { + dest[i] = data[i]; // [NOT DETECTED] + } + dest[100-1] = '\0'; + printLine(dest); + } +} + +void CWE127_Buffer_Underread__char_alloca_cpy_01_bad() +{ + char * data; + char * dataBuffer = (char *)ALLOCA(100*sizeof(char)); + memset(dataBuffer, 'A', 100-1); + dataBuffer[100-1] = '\0'; + /* FLAW: Set data pointer to before the allocated memory buffer */ + data = dataBuffer - 8; + { + char dest[100*2]; + memset(dest, 'C', 100*2-1); /* fill with 'C's */ + dest[100*2-1] = '\0'; /* null terminate */ + /* POTENTIAL FLAW: Possibly copy from a memory location located before the source buffer */ + strcpy(dest, data); // [NOT DETECTED] + printLine(dest); + } +} + +#define BAD_PATH_SIZE (MAX_PATH / 2) /* maintenance note: must be < MAX_PATH in order for 'bad' to be 'bad' */ + +void CWE785_Path_Manipulation_Function_Without_Max_Sized_Buffer__w32_01_bad() +{ + { + char path[BAD_PATH_SIZE]; + DWORD length; + length = GetCurrentDirectoryA(BAD_PATH_SIZE, path); + if (length == 0 || length >= BAD_PATH_SIZE) /* failure conditions for this API call */ + { + exit(1); + } + /* FLAW: PathAppend assumes the 'path' parameter is MAX_PATH */ + /* INCIDENTAL: CWE 121 stack based buffer overflow, which is intrinsic to + * this example identified on the CWE webpage */ + if (!PathAppendA(path, "AAAAAAAAAAAA")) // [NOT DETECTED] + { + exit(1); + } + printSizeTLine(strlen(path)); + printIntLine(BAD_PATH_SIZE); + printLine(path); + } +} + +#define NULL (0) + +void CWE122_Heap_Based_Buffer_Overflow__c_CWE805_char_memcpy_01_bad() +{ + char * data; + data = NULL; + /* FLAW: Allocate and point data to a small buffer that is smaller than the large buffer used in the sinks */ + data = (char *)malloc(50*sizeof(char)); + data[0] = '\0'; /* null terminate */ + { + char source[100]; + memset(source, 'C', 100-1); /* fill with 'C's */ + source[100-1] = '\0'; /* null terminate */ + /* POTENTIAL FLAW: Possible buffer overflow if source is larger than data */ + memcpy(data, source, 100*sizeof(char)); + data[100-1] = '\0'; /* Ensure the destination buffer is null terminated */ + printLine(data); + free(data); + } +} + +void CWE121_Stack_Based_Buffer_Overflow__CWE805_char_declare_memcpy_01_bad() +{ + char * data; + char dataBadBuffer[50]; + char dataGoodBuffer[100]; + /* FLAW: Set a pointer to a "small" buffer. This buffer will be used in the sinks as a destination + * buffer in various memory copying functions using a "large" source buffer. */ + data = dataBadBuffer; + data[0] = '\0'; /* null terminate */ + { + char source[100]; + memset(source, 'C', 100-1); /* fill with 'C's */ + source[100-1] = '\0'; /* null terminate */ + /* POTENTIAL FLAW: Possible buffer overflow if the size of data is less than the length of source */ + memcpy(data, source, 100*sizeof(char)); + data[100-1] = '\0'; /* Ensure the destination buffer is null terminated */ + printLine(data); + } +} + +void CWE121_Stack_Based_Buffer_Overflow__CWE805_char_alloca_memcpy_01_bad() +{ + char * data; + char * dataBadBuffer = (char *)ALLOCA(50*sizeof(char)); + char * dataGoodBuffer = (char *)ALLOCA(100*sizeof(char)); + /* FLAW: Set a pointer to a "small" buffer. This buffer will be used in the sinks as a destination + * buffer in various memory copying functions using a "large" source buffer. */ + data = dataBadBuffer; + data[0] = '\0'; /* null terminate */ + { + char source[100]; + memset(source, 'C', 100-1); /* fill with 'C's */ + source[100-1] = '\0'; /* null terminate */ + /* POTENTIAL FLAW: Possible buffer overflow if the size of data is less than the length of source */ + memcpy(data, source, 100*sizeof(char)); + data[100-1] = '\0'; /* Ensure the destination buffer is null terminated */ + printLine(data); + } +} + +void CWE121_Stack_Based_Buffer_Overflow__CWE805_char_alloca_loop_01_bad() +{ + char * data; + char * dataBadBuffer = (char *)ALLOCA(50*sizeof(char)); + char * dataGoodBuffer = (char *)ALLOCA(100*sizeof(char)); + /* FLAW: Set a pointer to a "small" buffer. This buffer will be used in the sinks as a destination + * buffer in various memory copying functions using a "large" source buffer. */ + data = dataBadBuffer; + data[0] = '\0'; /* null terminate */ + { + size_t i; + char source[100]; + memset(source, 'C', 100-1); /* fill with 'C's */ + source[100-1] = '\0'; /* null terminate */ + /* POTENTIAL FLAW: Possible buffer overflow if the size of data is less than the length of source */ + for (i = 0; i < 100; i++) + { + data[i] = source[i]; + } + data[100-1] = '\0'; /* Ensure the destination buffer is null terminated */ + printLine(data); + } +} + +void CWE121_Stack_Based_Buffer_Overflow__CWE805_char_declare_loop_01_bad() +{ + char * data; + char dataBadBuffer[50]; + char dataGoodBuffer[100]; + /* FLAW: Set a pointer to a "small" buffer. This buffer will be used in the sinks as a destination + * buffer in various memory copying functions using a "large" source buffer. */ + data = dataBadBuffer; + data[0] = '\0'; /* null terminate */ + { + size_t i; + char source[100]; + memset(source, 'C', 100-1); /* fill with 'C's */ + source[100-1] = '\0'; /* null terminate */ + /* POTENTIAL FLAW: Possible buffer overflow if the size of data is less than the length of source */ + for (i = 0; i < 100; i++) + { + data[i] = source[i]; + } + data[100-1] = '\0'; /* Ensure the destination buffer is null terminated */ + printLine(data); + } +} + +wchar_t *wcsncpy(wchar_t *destination, const wchar_t *source, size_t num); +size_t wcslen(const wchar_t *str); +char *strcat(char *destination, const char *source); +char *strncat(char *destination, const char *source, size_t num); + +void *memmove(void *destination, const void *source, size_t num); + +void printWLine(const wchar_t *line); + +/* MAINTENANCE NOTE: The length of this string should equal the 10 */ +#define SRC_STRING L"AAAAAAAAAA" + +namespace CWE122_Heap_Based_Buffer_Overflow__cpp_CWE193_wchar_t_ncpy_01 +{ + void bad() + { + wchar_t * data; + data = NULL; + /* FLAW: Did not leave space for a null terminator */ + data = new wchar_t[10]; + { + wchar_t source[10+1] = SRC_STRING; + /* Copy length + 1 to include NUL terminator from source */ + /* POTENTIAL FLAW: data may not have enough space to hold source */ + wcsncpy(data, source, wcslen(source) + 1); + printWLine(data); + delete [] data; + } + } + + static void goodG2B() + { + wchar_t * data; + data = NULL; + /* FIX: Allocate space for a null terminator */ + data = new wchar_t[10+1]; + { + wchar_t source[10+1] = SRC_STRING; + /* Copy length + 1 to include NUL terminator from source */ + /* POTENTIAL FLAW: data may not have enough space to hold source */ + wcsncpy(data, source, wcslen(source) + 1); // [FALSE POSITIVE RESULT] (debatable) + printWLine(data); + delete [] data; + } + } +} /* close namespace */ + +namespace CWE122_Heap_Based_Buffer_Overflow__cpp_CWE193_wchar_t_memmove_31 +{ + void bad() + { + wchar_t * data; + data = NULL; + /* FLAW: Did not leave space for a null terminator */ + data = new wchar_t[10]; + { + wchar_t * dataCopy = data; + wchar_t * data = dataCopy; + { + wchar_t source[10+1] = SRC_STRING; + /* Copy length + 1 to include NUL terminator from source */ + /* POTENTIAL FLAW: data may not have enough space to hold source */ + memmove(data, source, (wcslen(source) + 1) * sizeof(wchar_t)); // [NOT DETECTED] + printWLine(data); + delete [] data; + } + } + } +} /* close namespace */ + +namespace CWE122_Heap_Based_Buffer_Overflow__cpp_CWE805_char_ncat_01 +{ + void bad() + { + char * data; + data = NULL; + /* FLAW: Allocate using new[] and point data to a small buffer that is smaller than the large buffer used in the sinks */ + data = new char[50]; + data[0] = '\0'; /* null terminate */ + { + char source[100]; + memset(source, 'C', 100-1); /* fill with 'C's */ + source[100-1] = '\0'; /* null terminate */ + /* POTENTIAL FLAW: Possible buffer overflow if source is larger than sizeof(data)-strlen(data) */ + strncat(data, source, 100); + printLine(data); + delete [] data; + } + } +} /* close namespace */ + +void CWE122_Heap_Based_Buffer_Overflow__c_dest_char_cat_01_bad() +{ + char * data; + data = NULL; + /* FLAW: Allocate and point data to a small buffer that is smaller than the large buffer used in the sinks */ + data = (char *)malloc(50*sizeof(char)); + data[0] = '\0'; /* null terminate */ + { + char source[100]; + memset(source, 'C', 100-1); /* fill with 'C's */ + source[100-1] = '\0'; /* null terminate */ + /* POTENTIAL FLAW: Possible buffer overflow if source is larger than sizeof(data)-strlen(data) */ + strcat(data, source); // [NOT DETECTED] + printLine(data); + free(data); + } +} + +void CWE121_Stack_Based_Buffer_Overflow__CWE131_memcpy_01_bad() +{ + int * data; + data = NULL; + /* FLAW: Allocate memory without using sizeof(int) */ + data = (int *)ALLOCA(10); + { + int source[10] = {0}; + /* POTENTIAL FLAW: Possible buffer overflow if data was not allocated correctly in the source */ + memcpy(data, source, 10*sizeof(int)); + printIntLine(data[0]); + } +} + +typedef long long int64_t; +wchar_t *wmemset(wchar_t *dest, wchar_t c, size_t count); +void* calloc(size_t num, size_t size); + +void printLongLongLine(int64_t longLongIntNumber); +void printDoubleLine(double doubleNumber); + +void CWE122_Heap_Based_Buffer_Overflow__cpp_CWE805_int64_t_loop_01_bad() +{ + int64_t * data; + data = NULL; + /* FLAW: Allocate using new[] and point data to a small buffer that is smaller than the large buffer used in the sinks */ + data = new int64_t[50]; + { + int64_t source[100] = {0}; /* fill with 0's */ + { + size_t i; + /* POTENTIAL FLAW: Possible buffer overflow if data < 100 */ + for (i = 0; i < 100; i++) + { + data[i] = source[i]; // [NOT DETECTED] + } + printLongLongLine(data[0]); + delete [] data; + } + } +} + +void CWE122_Heap_Based_Buffer_Overflow__cpp_CWE805_wchar_t_loop_01_bad() +{ + wchar_t * data; + data = NULL; + /* FLAW: Allocate using new[] and point data to a small buffer that is smaller than the large buffer used in the sinks */ + data = new wchar_t[50]; + data[0] = L'\0'; /* null terminate */ + { + size_t i; + wchar_t source[100]; + wmemset(source, L'C', 100-1); /* fill with L'C's */ + source[100-1] = L'\0'; /* null terminate */ + /* POTENTIAL FLAW: Possible buffer overflow if source is larger than data */ + for (i = 0; i < 100; i++) + { + data[i] = source[i]; + } + data[100-1] = L'\0'; /* Ensure the destination buffer is null terminated */ + printWLine(data); + delete [] data; + } +} + +void CWE122_Heap_Based_Buffer_Overflow__cpp_CWE805_wchar_t_ncpy_01_bad() +{ + wchar_t * data; + data = NULL; + /* FLAW: Allocate using new[] and point data to a small buffer that is smaller than the large buffer used in the sinks */ + data = new wchar_t[50]; + data[0] = L'\0'; /* null terminate */ + { + wchar_t source[100]; + wmemset(source, L'C', 100-1); /* fill with L'C's */ + source[100-1] = L'\0'; /* null terminate */ + /* POTENTIAL FLAW: Possible buffer overflow if source is larger than data */ + wcsncpy(data, source, 100-1); + data[100-1] = L'\0'; /* Ensure the destination buffer is null terminated */ + printWLine(data); + delete [] data; + } +} + +#ifdef _WIN32 +int _snwprintf(wchar_t *buffer, size_t count, const wchar_t *format, ...); +#define SNPRINTF _snwprintf +#else +int snprintf(char *s, size_t n, const char *format, ...); +int swprintf(wchar_t *wcs, size_t maxlen, const wchar_t *format, ...); +//#define SNPRINTF snprintf --- original code; using snprintf appears to be a mistake in samate? +#define SNPRINTF swprintf +#endif + +void CWE122_Heap_Based_Buffer_Overflow__cpp_CWE805_wchar_t_snprintf_01_bad() +{ + wchar_t * data; + data = NULL; + /* FLAW: Allocate using new[] and point data to a small buffer that is smaller than the large buffer used in the sinks */ + data = new wchar_t[50]; + data[0] = L'\0'; /* null terminate */ + { + wchar_t source[100]; + wmemset(source, L'C', 100-1); /* fill with L'C's */ + source[100-1] = L'\0'; /* null terminate */ + /* POTENTIAL FLAW: Possible buffer overflow if source is larger than data */ + SNPRINTF(data, 100, L"%s", source); + printWLine(data); + delete [] data; + } +} + +/* classes used in some test cases as a custom type */ +class TwoIntsClass +{ + public: // Needed to access variables from label files + int intOne; + int intTwo; +}; + +class OneIntClass +{ + public: // Needed to access variables from label files + int intOne; +}; + +void *operator new(size_t size, void *ptr) throw(); // placement new (from #include ) + +void CWE122_Heap_Based_Buffer_Overflow__placement_new_01_bad() +{ + char * data; + char * dataBadBuffer = (char *)malloc(sizeof(OneIntClass)); + char * dataGoodBuffer = (char *)malloc(sizeof(TwoIntsClass)); + /* POTENTIAL FLAW: Initialize data to a buffer small than the sizeof(TwoIntsClass) */ + data = dataBadBuffer; + { + /* The Visual C++ compiler generates a warning if you initialize the class with (). + * This will cause the compile to default-initialize the object. + * See http://msdn.microsoft.com/en-us/library/wewb47ee%28v=VS.100%29.aspx + */ + /* POTENTIAL FLAW: data may not be large enough to hold a TwoIntsClass */ + TwoIntsClass * classTwo = new(data) TwoIntsClass; // [NOT DETECTED] + /* Initialize and make use of the class */ + classTwo->intOne = 5; + classTwo->intTwo = 10; /* POTENTIAL FLAW: If sizeof(data) < sizeof(TwoIntsClass) then this line will be a buffer overflow */ + printIntLine(classTwo->intOne); + /* skip printing classTwo->intTwo since that could be a buffer overread */ + free(data); + } +} + +void CWE122_Heap_Based_Buffer_Overflow__sizeof_double_01_bad() +{ + double * data; + /* Initialize data */ + data = NULL; + /* INCIDENTAL: CWE-467 (Use of sizeof() on a pointer type) */ + /* FLAW: Using sizeof the pointer and not the data type in malloc() */ + data = (double *)malloc(sizeof(data)); // [NOT DETECTED] + *data = 1.7E300; + /* POTENTIAL FLAW: Attempt to use data, which may not have enough memory allocated */ + printDoubleLine(*data); + free(data); +} + +int rand(void); +#define RAND32() ((rand()<<30) ^ (rand()<<15) ^ rand()) + +void CWE122_Heap_Based_Buffer_Overflow__c_CWE129_rand_01_bad() +{ + int data; + /* Initialize data */ + data = -1; + /* POTENTIAL FLAW: Set data to a random value */ + data = RAND32(); + { + int i; + int * buffer = (int *)malloc(10 * sizeof(int)); + /* initialize buffer */ + for (i = 0; i < 10; i++) + { + buffer[i] = 0; + } + /* POTENTIAL FLAW: Attempt to write to an index of the array that is above the upper bound + * This code does check to see if the array index is negative */ + if (data >= 0) + { + buffer[data] = 1; // [NOT DETECTED] + /* Print the array values */ + for(i = 0; i < 10; i++) + { + printIntLine(buffer[i]); + } + } + else + { + printLine("ERROR: Array index is negative."); + } + free(buffer); + } +} + +typedef struct FILE; +int fscanf(FILE *stream, const char *format, ...); +FILE *stdin; + +void CWE122_Heap_Based_Buffer_Overflow__c_CWE129_fscanf_01_bad() +{ + int data; + /* Initialize data */ + data = -1; + /* POTENTIAL FLAW: Read data from the console using fscanf() */ + fscanf(stdin, "%d", &data); + { + int i; + int * buffer = (int *)malloc(10 * sizeof(int)); + /* initialize buffer */ + for (i = 0; i < 10; i++) + { + buffer[i] = 0; + } + /* POTENTIAL FLAW: Attempt to write to an index of the array that is above the upper bound + * This code does check to see if the array index is negative */ + if (data >= 0) + { + buffer[data] = 1; // [NOT DETECTED] + /* Print the array values */ + for(i = 0; i < 10; i++) + { + printIntLine(buffer[i]); + } + } + else + { + printLine("ERROR: Array index is negative."); + } + free(buffer); + } +} + +void CWE122_Heap_Based_Buffer_Overflow__cpp_CWE805_wchar_t_snprintf_31_bad() +{ + wchar_t * data; + data = NULL; + /* FLAW: Allocate using new[] and point data to a small buffer that is smaller than the large buffer used in the sinks */ + data = new wchar_t[50]; + data[0] = L'\0'; /* null terminate */ + { + wchar_t * dataCopy = data; + wchar_t * data = dataCopy; + { + wchar_t source[100]; + wmemset(source, L'C', 100-1); /* fill with L'C's */ + source[100-1] = L'\0'; /* null terminate */ + /* POTENTIAL FLAW: Possible buffer overflow if source is larger than data */ + SNPRINTF(data, 100, L"%s", source); + printWLine(data); + delete [] data; + } + } +} + +int rand(void); + +int globalReturnsTrueOrFalse() +{ + return (rand() % 2); +} + +#define SRC_STRING "AAAAAAAAAA" + +void CWE121_Stack_Based_Buffer_Overflow__CWE193_char_declare_cpy_12_bad() +{ + char * data; + char dataBadBuffer[10]; + char dataGoodBuffer[10+1]; + if(globalReturnsTrueOrFalse()) + { + /* FLAW: Set a pointer to a buffer that does not leave room for a NULL terminator when performing + * string copies in the sinks */ + data = dataBadBuffer; + data[0] = '\0'; /* null terminate */ + } + else + { + /* FIX: Set a pointer to a buffer that leaves room for a NULL terminator when performing + * string copies in the sinks */ + data = dataGoodBuffer; + data[0] = '\0'; /* null terminate */ + } + { + char source[10+1] = SRC_STRING; + /* POTENTIAL FLAW: data may not have enough space to hold source */ // [NOT DETECTED] + strcpy(data, source); + printLine(data); + } +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowBuffer.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowBuffer.expected index 614716b470d..77751b66d4e 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowBuffer.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowBuffer.expected @@ -80,4 +80,4 @@ | var_size_struct.cpp:99:3:99:8 | call to memset | This 'memset' operation accesses 129 bytes but the $@ is only 128 bytes. | var_size_struct.cpp:92:8:92:10 | str | destination buffer | | var_size_struct.cpp:101:3:101:8 | call to memset | This 'memset' operation accesses 129 bytes but the $@ is only 128 bytes. | var_size_struct.cpp:92:8:92:10 | str | destination buffer | | var_size_struct.cpp:103:3:103:9 | call to strncpy | This 'strncpy' operation may access 129 bytes but the $@ is only 128 bytes. | var_size_struct.cpp:92:8:92:10 | str | destination buffer | -| var_size_struct.cpp:171:3:171:8 | call to memset | This 'memset' operation accesses 100 bytes but the $@ is only 1 byte. | var_size_struct.cpp:125:17:125:19 | arr | destination buffer | +| var_size_struct.cpp:169:3:169:8 | call to memset | This 'memset' operation accesses 100 bytes but the $@ is only 1 byte. | var_size_struct.cpp:125:17:125:19 | arr | destination buffer | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/UnboundedWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/UnboundedWrite.expected index 58e3dda0964..7cefb7cfafc 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/UnboundedWrite.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/UnboundedWrite.expected @@ -1,3 +1,4 @@ edges +subpaths nodes #select diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/var_size_struct.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/var_size_struct.cpp index 00b433c60ef..c006c35fe9b 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/var_size_struct.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/var_size_struct.cpp @@ -161,8 +161,6 @@ void useVarStruct34(varStruct5 *vs5) { varStruct5 *vs5b = (varStruct5 *)malloc(sizeof(*vs5)); varStruct6 *vs6 = (varStruct6 *)malloc(offsetof(varStruct6, arr) + 9); // establish varStruct6 as variable size varStruct7 *vs7 = (varStruct7 *)malloc(sizeForVarStruct7(9)); // establish varStruct7 as variable size - varStruct8 *vs8a = (varStruct8 *)malloc(sizeof(varStruct8) + 9); // establish varStruct8 as variable size - varStruct8 *vs8b = (varStruct8 *)malloc(sizeof(varStruct8)); varStruct9 *vs9 = (varStruct9 *)malloc(__builtin_offsetof(varStruct9, arr) + 9); // establish varStruct9 as variable size } diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected index 5255753b235..e98353732b9 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-120/semmle/tests/UnboundedWrite.expected @@ -49,6 +49,7 @@ edges | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array | | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array indirection | | tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array indirection | +subpaths nodes | tests.c:28:22:28:25 | argv | semmle.label | argv | | tests.c:28:22:28:25 | argv | semmle.label | argv | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-129/SAMATE/ImproperArrayIndexValidation/CWE122_Heap_Based_Buffer_Overflow__c_CWE129_fgets_01.c b/cpp/ql/test/query-tests/Security/CWE/CWE-129/SAMATE/ImproperArrayIndexValidation/CWE122_Heap_Based_Buffer_Overflow__c_CWE129_fgets_01.c new file mode 100644 index 00000000000..2092902b665 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-129/SAMATE/ImproperArrayIndexValidation/CWE122_Heap_Based_Buffer_Overflow__c_CWE129_fgets_01.c @@ -0,0 +1,65 @@ +// Snippet from a SAMATE Juliet test case for rule CWE-122 / CWE-129 +// CWE122_Heap_Based_Buffer_Overflow__c_CWE129_fgets_01.c + +typedef unsigned long size_t; +void *malloc(size_t size); +void free(void *ptr); +#define NULL (0) + +typedef struct {} FILE; +FILE *stdin; +char *fgets(char *s, int n, FILE *stream); + +int atoi(const char *nptr); + +void printLine(const char *str); +void printIntLine(int val); + +// --- + +#define CHAR_ARRAY_SIZE (64) + +void CWE122_Heap_Based_Buffer_Overflow__c_CWE129_fgets_01_bad() +{ + int data; + /* Initialize data */ + data = -1; + { + char inputBuffer[CHAR_ARRAY_SIZE] = ""; + /* POTENTIAL FLAW: Read data from the console using fgets() */ + if (fgets(inputBuffer, CHAR_ARRAY_SIZE, stdin) != NULL) + { + /* Convert to int */ + data = atoi(inputBuffer); + } + else + { + printLine("fgets() failed."); + } + } + { + int i; + int * buffer = (int *)malloc(10 * sizeof(int)); + /* initialize buffer */ + for (i = 0; i < 10; i++) + { + buffer[i] = 0; + } + /* POTENTIAL FLAW: Attempt to write to an index of the array that is above the upper bound + * This code does check to see if the array index is negative */ + if (data >= 0) + { + buffer[data] = 1; + /* Print the array values */ + for(i = 0; i < 10; i++) + { + printIntLine(buffer[i]); + } + } + else + { + printLine("ERROR: Array index is negative."); + } + free(buffer); + } +} \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-129/SAMATE/ImproperArrayIndexValidation/ImproperArrayIndexValidation.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-129/SAMATE/ImproperArrayIndexValidation/ImproperArrayIndexValidation.expected new file mode 100644 index 00000000000..008ff07b800 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-129/SAMATE/ImproperArrayIndexValidation/ImproperArrayIndexValidation.expected @@ -0,0 +1 @@ +| CWE122_Heap_Based_Buffer_Overflow__c_CWE129_fgets_01.c:52:20:52:23 | data | $@ flows to here and is used in an array indexing expression, potentially causing an invalid access. | CWE122_Heap_Based_Buffer_Overflow__c_CWE129_fgets_01.c:30:19:30:29 | inputBuffer | User-provided value | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-129/SAMATE/ImproperArrayIndexValidation/ImproperArrayIndexValidation.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-129/SAMATE/ImproperArrayIndexValidation/ImproperArrayIndexValidation.qlref new file mode 100644 index 00000000000..f1d46d8f8d6 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-129/SAMATE/ImproperArrayIndexValidation/ImproperArrayIndexValidation.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-129/ImproperArrayIndexValidation.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/SAMATE/UncontrolledFormatString.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/SAMATE/UncontrolledFormatString.expected new file mode 100644 index 00000000000..5bce7b8aa38 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/SAMATE/UncontrolledFormatString.expected @@ -0,0 +1,46 @@ +edges +| char_connect_socket_w32_vsnprintf_01_bad.c:94:46:94:69 | recv output argument | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | +| char_connect_socket_w32_vsnprintf_01_bad.c:94:46:94:69 | recv output argument | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | +| char_connect_socket_w32_vsnprintf_01_bad.c:94:46:94:69 | recv output argument | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data indirection | +| char_connect_socket_w32_vsnprintf_01_bad.c:94:55:94:68 | ... + ... | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | +| char_connect_socket_w32_vsnprintf_01_bad.c:94:55:94:68 | ... + ... | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | +| char_connect_socket_w32_vsnprintf_01_bad.c:94:55:94:68 | ... + ... | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data indirection | +| char_console_fprintf_01_bad.c:30:23:30:35 | ... + ... | char_console_fprintf_01_bad.c:49:21:49:24 | (const char *)... | +| char_console_fprintf_01_bad.c:30:23:30:35 | ... + ... | char_console_fprintf_01_bad.c:49:21:49:24 | data | +| char_console_fprintf_01_bad.c:30:23:30:35 | ... + ... | char_console_fprintf_01_bad.c:49:21:49:24 | data indirection | +| char_console_fprintf_01_bad.c:30:23:30:35 | fgets output argument | char_console_fprintf_01_bad.c:49:21:49:24 | (const char *)... | +| char_console_fprintf_01_bad.c:30:23:30:35 | fgets output argument | char_console_fprintf_01_bad.c:49:21:49:24 | data | +| char_console_fprintf_01_bad.c:30:23:30:35 | fgets output argument | char_console_fprintf_01_bad.c:49:21:49:24 | data indirection | +| char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | char_environment_fprintf_01_bad.c:36:21:36:24 | (const char *)... | +| char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | char_environment_fprintf_01_bad.c:36:21:36:24 | (const char *)... | +| char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | char_environment_fprintf_01_bad.c:36:21:36:24 | data | +| char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | char_environment_fprintf_01_bad.c:36:21:36:24 | data | +| char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | char_environment_fprintf_01_bad.c:36:21:36:24 | data indirection | +| char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | char_environment_fprintf_01_bad.c:36:21:36:24 | data indirection | +subpaths +nodes +| char_connect_socket_w32_vsnprintf_01_bad.c:94:46:94:69 | recv output argument | semmle.label | recv output argument | +| char_connect_socket_w32_vsnprintf_01_bad.c:94:55:94:68 | ... + ... | semmle.label | ... + ... | +| char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | semmle.label | data | +| char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | semmle.label | data | +| char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | semmle.label | data | +| char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data indirection | semmle.label | data indirection | +| char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data indirection | semmle.label | data indirection | +| char_console_fprintf_01_bad.c:30:23:30:35 | ... + ... | semmle.label | ... + ... | +| char_console_fprintf_01_bad.c:30:23:30:35 | fgets output argument | semmle.label | fgets output argument | +| char_console_fprintf_01_bad.c:49:21:49:24 | (const char *)... | semmle.label | (const char *)... | +| char_console_fprintf_01_bad.c:49:21:49:24 | (const char *)... | semmle.label | (const char *)... | +| char_console_fprintf_01_bad.c:49:21:49:24 | data | semmle.label | data | +| char_console_fprintf_01_bad.c:49:21:49:24 | data indirection | semmle.label | data indirection | +| char_console_fprintf_01_bad.c:49:21:49:24 | data indirection | semmle.label | data indirection | +| char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | semmle.label | call to getenv | +| char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | semmle.label | call to getenv | +| char_environment_fprintf_01_bad.c:36:21:36:24 | (const char *)... | semmle.label | (const char *)... | +| char_environment_fprintf_01_bad.c:36:21:36:24 | (const char *)... | semmle.label | (const char *)... | +| char_environment_fprintf_01_bad.c:36:21:36:24 | data | semmle.label | data | +| char_environment_fprintf_01_bad.c:36:21:36:24 | data indirection | semmle.label | data indirection | +| char_environment_fprintf_01_bad.c:36:21:36:24 | data indirection | semmle.label | data indirection | +#select +| char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | char_connect_socket_w32_vsnprintf_01_bad.c:94:55:94:68 | ... + ... | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | The value of this argument may come from $@ and is being used as a formatting argument to badVaSink(data), which calls vsnprintf(format) | char_connect_socket_w32_vsnprintf_01_bad.c:94:55:94:68 | ... + ... | recv | +| char_console_fprintf_01_bad.c:49:21:49:24 | data | char_console_fprintf_01_bad.c:30:23:30:35 | ... + ... | char_console_fprintf_01_bad.c:49:21:49:24 | data | The value of this argument may come from $@ and is being used as a formatting argument to fprintf(format) | char_console_fprintf_01_bad.c:30:23:30:35 | ... + ... | fgets | +| char_environment_fprintf_01_bad.c:36:21:36:24 | data | char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | char_environment_fprintf_01_bad.c:36:21:36:24 | data | The value of this argument may come from $@ and is being used as a formatting argument to fprintf(format) | char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | getenv | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/SAMATE/UncontrolledFormatString.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-134/SAMATE/UncontrolledFormatString.qlref new file mode 100644 index 00000000000..079e0c8a7c0 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/SAMATE/UncontrolledFormatString.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-134/UncontrolledFormatString.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/SAMATE/char_connect_socket_w32_vsnprintf_01_bad.c b/cpp/ql/test/query-tests/Security/CWE/CWE-134/SAMATE/char_connect_socket_w32_vsnprintf_01_bad.c new file mode 100644 index 00000000000..ccba3e54840 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/SAMATE/char_connect_socket_w32_vsnprintf_01_bad.c @@ -0,0 +1,126 @@ +// External test case from SAMATE's Juliet Test Suite for C/C++ +// (http://samate.nist.gov/SRD/testsuite.php) +// Associated with CWE-134: Uncontrolled format string. http://cwe.mitre.org/data/definitions/134.html +// This is a snippet with added declarations, not the entire test case. + +typedef unsigned long size_t; + +typedef void *va_list; +#define va_start(ap, parmN) +#define va_end(ap) +#define va_arg(ap, type) ((type)0) + +int vsnprintf(char *s, size_t n, const char *format, va_list arg); + +size_t strlen(const char *s); + +#define SOCKET int +#define INVALID_SOCKET (0) +#define SOCKET_ERROR (1) +#define AF_INET (2) +#define SOCK_STREAM (3) +#define IPPROTO_TCP (4) +#define IP_ADDRESS (5) +#define TCP_PORT (6) +typedef int in_addr_t; +struct in_addr { + in_addr_t s_addr; +}; +struct sockaddr_in { + int sin_family; + int sin_port; + struct in_addr sin_addr; +}; +in_addr_t inet_addr(const char *cp); + +#define IP_ADDRESS "0.0.0.0" + +void printLine(char *); + +static void badVaSink(char * data, ...) +{ + { + char dest[100] = ""; + va_list args; + va_start(args, data); + /* POTENTIAL FLAW: Do not specify the format allowing a possible format string vulnerability */ + vsnprintf(dest, 100-1, data, args); + va_end(args); + printLine(dest); + } +} + +void CWE134_Uncontrolled_Format_String__char_connect_socket_w32_vsnprintf_01_bad() +{ + char * data; + char dataBuffer[100] = ""; + data = dataBuffer; + { +#ifdef _WIN32 + WSADATA wsaData; + int wsaDataInit = 0; +#endif + int recvResult; + struct sockaddr_in service; + char *replace; + SOCKET connectSocket = INVALID_SOCKET; + size_t dataLen = strlen(data); + do + { +#ifdef _WIN32 + if (WSAStartup(MAKEWORD(2,2), &wsaData) != NO_ERROR) + { + break; + } + wsaDataInit = 1; +#endif + /* POTENTIAL FLAW: Read data using a connect socket */ + connectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (connectSocket == INVALID_SOCKET) + { + break; + } + memset(&service, 0, sizeof(service)); + service.sin_family = AF_INET; + service.sin_addr.s_addr = inet_addr(IP_ADDRESS); + service.sin_port = htons(TCP_PORT); + if (connect(connectSocket, (struct sockaddr*)&service, sizeof(service)) == SOCKET_ERROR) + { + break; + } + /* Abort on error or the connection was closed, make sure to recv one + * less char than is in the recv_buf in order to append a terminator */ + /* Abort on error or the connection was closed */ + recvResult = recv(connectSocket, (char *)(data + dataLen), sizeof(char) * (100 - dataLen - 1), 0); + if (recvResult == SOCKET_ERROR || recvResult == 0) + { + break; + } + /* Append null terminator */ + data[dataLen + recvResult / sizeof(char)] = '\0'; + /* Eliminate CRLF */ + replace = strchr(data, '\r'); + if (replace) + { + *replace = '\0'; + } + replace = strchr(data, '\n'); + if (replace) + { + *replace = '\0'; + } + } + while (0); + if (connectSocket != INVALID_SOCKET) + { + CLOSE_SOCKET(connectSocket); + } +#ifdef _WIN32 + if (wsaDataInit) + { + WSACleanup(); + } +#endif + } + badVaSink(data, data); +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/SAMATE/char_console_fprintf_01_bad.c b/cpp/ql/test/query-tests/Security/CWE/CWE-134/SAMATE/char_console_fprintf_01_bad.c new file mode 100644 index 00000000000..1af281b9f42 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/SAMATE/char_console_fprintf_01_bad.c @@ -0,0 +1,97 @@ +// External test case from SAMATE's Juliet Test Suite for C/C++ +// (http://samate.nist.gov/SRD/testsuite.php) +// Associated with CWE-134: Uncontrolled format string. http://cwe.mitre.org/data/definitions/134.html +// Examples amended to have all function declarations inlined. + +#define NULL 0 +typedef unsigned long size_t; +typedef struct {} FILE; +extern FILE * stdin; +extern FILE * stdout; +size_t strlen(const char *s); +char *fgets(char *s, int n, FILE *stream); +int fprintf(FILE *stream, const char *format, ...); +char *strcpy(char *s1, const char *s2); + +void printLine(char *); + +void CWE134_Uncontrolled_Format_String__char_console_fprintf_01_bad() +{ + char * data; + char data_buf[100] = ""; + data = data_buf; + { + /* Read input from the console */ + size_t data_len = strlen(data); + /* if there is room in data, read into it from the console */ + /* POTENTIAL FLAW: Read data from the console */ + if(100-data_len > 1) + { + if (fgets(data+data_len, (int)(100-data_len), stdin) != NULL) + { + /* The next 3 lines remove the carriage return from the string that is + * inserted by fgets() */ + data_len = strlen(data); + if (data_len > 0 && data[data_len-1] == '\n') + { + data[data_len-1] = '\0'; + } + } + else + { + printLine("fgets() failed"); + /* Restore NUL terminator if fgets fails */ + data[data_len] = '\0'; + } + } + } + /* POTENTIAL FLAW: Do not specify the format allowing a possible format string vulnerability */ + fprintf(stdout, data); +} + +/* goodG2B uses the GoodSource with the BadSink */ +static void goodG2B() +{ + char * data; + char data_buf[100] = ""; + data = data_buf; + /* FIX: Use a fixed string that does not contain a format specifier */ + strcpy(data, "fixedstringtest"); + /* POTENTIAL FLAW: Do not specify the format allowing a possible format string vulnerability */ + fprintf(stdout, data); +} + +/* goodB2G uses the BadSource with the GoodSink */ +static void goodB2G() +{ + char * data; + char data_buf[100] = ""; + data = data_buf; + { + /* Read input from the console */ + size_t data_len = strlen(data); + /* if there is room in data, read into it from the console */ + /* POTENTIAL FLAW: Read data from the console */ + if(100-data_len > 1) + { + if (fgets(data+data_len, (int)(100-data_len), stdin) != NULL) + { + /* The next 3 lines remove the carriage return from the string that is + * inserted by fgets() */ + data_len = strlen(data); + if (data_len > 0 && data[data_len-1] == '\n') + { + data[data_len-1] = '\0'; + } + } + else + { + printLine("fgets() failed"); + /* Restore NUL terminator if fgets fails */ + data[data_len] = '\0'; + } + } + } + /* FIX: Specify the format disallowing a format string vulnerability */ + fprintf(stdout, "%s\n", data); +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/SAMATE/char_environment_fprintf_01_bad.c b/cpp/ql/test/query-tests/Security/CWE/CWE-134/SAMATE/char_environment_fprintf_01_bad.c new file mode 100644 index 00000000000..f759a9d8e61 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/SAMATE/char_environment_fprintf_01_bad.c @@ -0,0 +1,70 @@ +// External test case from SAMATE's Juliet Test Suite for C/C++ +// (http://samate.nist.gov/SRD/testsuite.php) +// Associated with CWE-134: Uncontrolled format string. http://cwe.mitre.org/data/definitions/134.html +// Examples amended to have all function declarations inlined. + +#define NULL 0 +typedef struct {} FILE; +typedef unsigned long size_t; +extern FILE * stdout; +size_t strlen(const char *s); +char *getenv(const char *name); +char *strcpy(char *s1, const char *s2); +char *strncat(char *s1, const char *s2, size_t n); +int fprintf(FILE *stream, const char *format, ...); + +#define ENV_VARIABLE "ADD" +#define GETENV getenv + +void CWE134_Uncontrolled_Format_String__char_environment_fprintf_01_bad() +{ + char * data; + char data_buf[100] = ""; + data = data_buf; + { + /* Append input from an environment variable to data */ + size_t data_len = strlen(data); + char * environment = GETENV(ENV_VARIABLE); + /* If there is data in the environment variable */ + if (environment != NULL) + { + /* POTENTIAL FLAW: Read data from an environment variable */ + strncat(data+data_len, environment, 100-data_len-1); + } + } + /* POTENTIAL FLAW: Do not specify the format allowing a possible format string vulnerability */ + fprintf(stdout, data); +} + +/* goodG2B uses the GoodSource with the BadSink */ +static void goodG2B() +{ + char * data; + char data_buf[100] = ""; + data = data_buf; + /* FIX: Use a fixed string that does not contain a format specifier */ + strcpy(data, "fixedstringtest"); + /* POTENTIAL FLAW: Do not specify the format allowing a possible format string vulnerability */ + fprintf(stdout, data); +} + +/* goodB2G uses the BadSource with the GoodSink */ +static void goodB2G() +{ + char * data; + char data_buf[100] = ""; + data = data_buf; + { + /* Append input from an environment variable to data */ + size_t data_len = strlen(data); + char * environment = GETENV(ENV_VARIABLE); + /* If there is data in the environment variable */ + if (environment != NULL) + { + /* POTENTIAL FLAW: Read data from an environment variable */ + strncat(data+data_len, environment, 100-data_len-1); + } + } + /* FIX: Specify the format disallowing a format string vulnerability */ + fprintf(stdout, "%s\n", data); +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected index 16fa875d620..a5a17967f69 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/argv/argvLocal.expected @@ -247,6 +247,13 @@ edges | argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 | | argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 | | argvLocal.c:170:15:170:26 | i10 indirection | argvLocal.c:9:25:9:31 | *correct | +subpaths +| argvLocal.c:117:2:117:13 | i3 | argvLocal.c:9:25:9:31 | correct | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:117:15:117:16 | printWrapper output argument | +| argvLocal.c:117:15:117:16 | i3 indirection | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:117:15:117:16 | printWrapper output argument | +| argvLocal.c:122:2:122:13 | i4 | argvLocal.c:9:25:9:31 | correct | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:122:15:122:16 | printWrapper output argument | +| argvLocal.c:122:15:122:16 | i4 indirection | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:122:15:122:16 | printWrapper output argument | +| argvLocal.c:128:2:128:13 | i5 | argvLocal.c:9:25:9:31 | correct | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:128:15:128:16 | printWrapper output argument | +| argvLocal.c:128:15:128:16 | i5 indirection | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:128:15:128:16 | printWrapper output argument | nodes | argvLocal.c:9:25:9:31 | *correct | semmle.label | *correct | | argvLocal.c:9:25:9:31 | *correct | semmle.label | *correct | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected index ceaf0489ec6..0f78d29fd36 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/funcs/funcsLocal.expected @@ -51,6 +51,7 @@ edges | funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | (const char *)... | | funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | i6 | | funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | i6 indirection | +subpaths nodes | funcsLocal.c:16:8:16:9 | fread output argument | semmle.label | fread output argument | | funcsLocal.c:16:8:16:9 | i1 | semmle.label | i1 | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatString.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatString.expected index 58e3dda0964..7cefb7cfafc 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatString.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatString.expected @@ -1,3 +1,4 @@ edges +subpaths nodes #select diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected index f095153f39c..8d957ee499c 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/globalVars/UncontrolledFormatStringThroughGlobalVar.expected @@ -46,6 +46,7 @@ edges | globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | (const char *)... | | globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | copy2 | | globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | copy2 indirection | +subpaths nodes | globalVars.c:8:7:8:10 | copy | semmle.label | copy | | globalVars.c:9:7:9:11 | copy2 | semmle.label | copy2 | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/ifs/ifs.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/ifs/ifs.expected index 8c2c89035e2..2805eed6ad0 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/ifs/ifs.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/ifs/ifs.expected @@ -71,6 +71,7 @@ edges | ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 | | ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 indirection | | ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 indirection | +subpaths nodes | ifs.c:61:8:61:11 | argv | semmle.label | argv | | ifs.c:61:8:61:11 | argv | semmle.label | argv | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/ArithmeticTainted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/ArithmeticTainted.expected new file mode 100644 index 00000000000..690f5ed6550 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/ArithmeticTainted.expected @@ -0,0 +1,14 @@ +edges +| examples.cpp:63:26:63:30 | & ... | examples.cpp:66:11:66:14 | data | +| examples.cpp:63:26:63:30 | & ... | examples.cpp:66:11:66:14 | data | +| examples.cpp:63:26:63:30 | fscanf output argument | examples.cpp:66:11:66:14 | data | +| examples.cpp:63:26:63:30 | fscanf output argument | examples.cpp:66:11:66:14 | data | +subpaths +nodes +| examples.cpp:63:26:63:30 | & ... | semmle.label | & ... | +| examples.cpp:63:26:63:30 | fscanf output argument | semmle.label | fscanf output argument | +| examples.cpp:66:11:66:14 | data | semmle.label | data | +| examples.cpp:66:11:66:14 | data | semmle.label | data | +| examples.cpp:66:11:66:14 | data | semmle.label | data | +#select +| examples.cpp:66:11:66:14 | data | examples.cpp:63:26:63:30 | & ... | examples.cpp:66:11:66:14 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:63:26:63:30 | & ... | User-provided value | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/ArithmeticTainted.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/ArithmeticTainted.qlref new file mode 100644 index 00000000000..3939653db1c --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/ArithmeticTainted.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-190/ArithmeticTainted.ql diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/ArithmeticUncontrolled.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/ArithmeticUncontrolled.expected new file mode 100644 index 00000000000..c908f8789c4 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/ArithmeticUncontrolled.expected @@ -0,0 +1,78 @@ +edges +| examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data | +| examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data | +| examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data | +| examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data | +| examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data | +| examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data | +| examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data | +| examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data | +| examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data | +| examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data | +| examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data | +| examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data | +| examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data | +| examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data | +| examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data | +| examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data | +| examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data | +| examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data | +| examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data | +| examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data | +| examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data | +| examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data | +| examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data | +| examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data | +nodes +| examples.cpp:22:26:22:33 | (unsigned int)... | semmle.label | (unsigned int)... | +| examples.cpp:22:26:22:33 | (unsigned int)... | semmle.label | (unsigned int)... | +| examples.cpp:22:26:22:33 | (unsigned int)... | semmle.label | (unsigned int)... | +| examples.cpp:22:26:22:33 | (unsigned int)... | semmle.label | (unsigned int)... | +| examples.cpp:22:26:22:33 | (unsigned int)... | semmle.label | (unsigned int)... | +| examples.cpp:22:26:22:33 | (unsigned int)... | semmle.label | (unsigned int)... | +| examples.cpp:22:26:22:33 | call to rand | semmle.label | call to rand | +| examples.cpp:22:26:22:33 | call to rand | semmle.label | call to rand | +| examples.cpp:22:26:22:33 | call to rand | semmle.label | call to rand | +| examples.cpp:22:26:22:33 | call to rand | semmle.label | call to rand | +| examples.cpp:22:26:22:33 | call to rand | semmle.label | call to rand | +| examples.cpp:22:26:22:33 | call to rand | semmle.label | call to rand | +| examples.cpp:25:31:25:34 | data | semmle.label | data | +| examples.cpp:35:26:35:33 | (unsigned int)... | semmle.label | (unsigned int)... | +| examples.cpp:35:26:35:33 | (unsigned int)... | semmle.label | (unsigned int)... | +| examples.cpp:35:26:35:33 | (unsigned int)... | semmle.label | (unsigned int)... | +| examples.cpp:35:26:35:33 | (unsigned int)... | semmle.label | (unsigned int)... | +| examples.cpp:35:26:35:33 | (unsigned int)... | semmle.label | (unsigned int)... | +| examples.cpp:35:26:35:33 | (unsigned int)... | semmle.label | (unsigned int)... | +| examples.cpp:35:26:35:33 | call to rand | semmle.label | call to rand | +| examples.cpp:35:26:35:33 | call to rand | semmle.label | call to rand | +| examples.cpp:35:26:35:33 | call to rand | semmle.label | call to rand | +| examples.cpp:35:26:35:33 | call to rand | semmle.label | call to rand | +| examples.cpp:35:26:35:33 | call to rand | semmle.label | call to rand | +| examples.cpp:35:26:35:33 | call to rand | semmle.label | call to rand | +| examples.cpp:38:9:38:12 | data | semmle.label | data | +subpaths +#select +| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value | +| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value | +| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value | +| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value | +| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value | +| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value | +| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value | +| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value | +| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value | +| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value | +| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value | +| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value | +| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value | +| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value | +| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value | +| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value | +| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value | +| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value | +| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value | +| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value | +| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value | +| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value | +| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value | +| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/ArithmeticUncontrolled.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/ArithmeticUncontrolled.qlref new file mode 100644 index 00000000000..1fcafc3ca1c --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/ArithmeticUncontrolled.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-190/ArithmeticUncontrolled.ql diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/ArithmeticWithExtremeValues.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/ArithmeticWithExtremeValues.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/ArithmeticWithExtremeValues.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/ArithmeticWithExtremeValues.qlref new file mode 100644 index 00000000000..ab2c35ce59b --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/ArithmeticWithExtremeValues.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/IntegerOverflowTainted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/IntegerOverflowTainted.expected new file mode 100644 index 00000000000..9d1fa5388ff --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/IntegerOverflowTainted.expected @@ -0,0 +1 @@ +| examples.cpp:66:9:66:14 | -- ... | $@ flows to here and is used in an expression which might overflow negatively. | examples.cpp:63:26:63:30 | & ... | User-provided value | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/IntegerOverflowTainted.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/IntegerOverflowTainted.qlref new file mode 100644 index 00000000000..df42008c632 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/IntegerOverflowTainted.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-190/IntegerOverflowTainted.ql diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/examples.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/examples.cpp new file mode 100644 index 00000000000..b2cdbbe7133 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/SAMATE/examples.cpp @@ -0,0 +1,70 @@ +// Some SAMATE Juliet test cases for rule CWE-190. + +///// Library functions ////// + +typedef struct {} FILE; +extern FILE *stdin; +int fscanf(FILE *stream, const char *format, ...); +int rand(void); + +#define URAND31() (((unsigned)rand()<<30) ^ ((unsigned)rand()<<15) ^ rand()) +#define RAND32() ((int)(rand() & 1 ? URAND31() : -URAND31() - 1)) + +void printUnsignedLine(unsigned unsignedNumber); + +//// Test code ///// + +void CWE191_Integer_Underflow__unsigned_int_rand_sub_01_bad() +{ + unsigned int data; + data = 0; + /* POTENTIAL FLAW: Use a random value */ + data = (unsigned int)RAND32(); + { + /* POTENTIAL FLAW: Subtracting 1 from data could cause an underflow */ + unsigned int result = data - 1; + printUnsignedLine(result); + } +} + +void CWE191_Integer_Underflow__unsigned_int_rand_postdec_01_bad() +{ + unsigned int data; + data = 0; + /* POTENTIAL FLAW: Use a random value */ + data = (unsigned int)RAND32(); + { + /* POTENTIAL FLAW: Decrementing data could cause an underflow */ + data--; + unsigned int result = data; + printUnsignedLine(result); + } +} + +void CWE191_Integer_Underflow__unsigned_int_min_postdec_01_bad() +{ + unsigned int data; + data = 0; + /* POTENTIAL FLAW: Use the minimum size of the data type */ + data = 0; + { + /* POTENTIAL FLAW: Decrementing data could cause an underflow [NOT DETECTED] */ + data--; + unsigned int result = data; + printUnsignedLine(result); + } +} + +void CWE191_Integer_Underflow__unsigned_int_fscanf_predec_01_bad() +{ + unsigned int data; + data = 0; + /* POTENTIAL FLAW: Use a value input from the console */ + fscanf (stdin, "%u", &data); + { + /* POTENTIAL FLAW: Decrementing data could cause an underflow */ + --data; + unsigned int result = data; + printUnsignedLine(result); + } +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected index 694f46e1d26..7fe8651f89a 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected @@ -73,6 +73,7 @@ edges | test.cpp:305:18:305:21 | Chi | test.cpp:308:10:308:27 | ... * ... | | test.cpp:305:18:305:21 | Chi | test.cpp:308:10:308:27 | ... * ... | | test.cpp:305:18:305:21 | get_size output argument [[]] | test.cpp:305:18:305:21 | Chi | +subpaths nodes | test.cpp:40:21:40:24 | argv | semmle.label | argv | | test.cpp:40:21:40:24 | argv | semmle.label | argv | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected index e2fefe4a442..e0f72bffd44 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/ArithmeticTainted.expected @@ -23,6 +23,7 @@ edges | test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 | | test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 | | test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 | +subpaths nodes | test2.cpp:12:21:12:21 | v | semmle.label | v | | test2.cpp:14:11:14:11 | v | semmle.label | v | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-197/SAMATE/IntegerOverflowTainted/IntegerOverflowTainted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-197/SAMATE/IntegerOverflowTainted/IntegerOverflowTainted.expected new file mode 100644 index 00000000000..88b0b206cda --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-197/SAMATE/IntegerOverflowTainted/IntegerOverflowTainted.expected @@ -0,0 +1 @@ +| tests.cpp:38:31:38:34 | data | $@ flows to here and is used in an expression which might overflow. | tests.cpp:57:27:57:31 | & ... | User-provided value | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-197/SAMATE/IntegerOverflowTainted/IntegerOverflowTainted.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-197/SAMATE/IntegerOverflowTainted/IntegerOverflowTainted.qlref new file mode 100644 index 00000000000..72ed7d53685 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-197/SAMATE/IntegerOverflowTainted/IntegerOverflowTainted.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-190/IntegerOverflowTainted.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-197/SAMATE/IntegerOverflowTainted/tests.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-197/SAMATE/IntegerOverflowTainted/tests.cpp new file mode 100644 index 00000000000..79f9a79c97f --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-197/SAMATE/IntegerOverflowTainted/tests.cpp @@ -0,0 +1,74 @@ +//semmle-extractor-options: --edg --target --edg win64 + +// A selection of tests from the SAMATE Juliet framework for rule CWE-197. + +// library types, functions etc +typedef struct {} FILE; +int fscanf(FILE *stream, const char *format, ...); +#define CHAR_MAX (127) +FILE *stdin; + +void printHexCharLine(char charHex); + +// ---------- + +class CWE197_Numeric_Truncation_Error__short_fscanf_82_base +{ +public: + /* pure virtual function */ + virtual void action(short data) = 0; +}; + +class CWE197_Numeric_Truncation_Error__short_fscanf_82_bad : public CWE197_Numeric_Truncation_Error__short_fscanf_82_base +{ +public: + void action(short data); +}; + +class CWE197_Numeric_Truncation_Error__short_fscanf_82_goodG2B : public CWE197_Numeric_Truncation_Error__short_fscanf_82_base +{ +public: + void action(short data); +}; + +void CWE197_Numeric_Truncation_Error__short_fscanf_82_bad::action(short data) +{ + { + /* POTENTIAL FLAW: Convert data to a char, possibly causing a truncation error */ + char charData = (char)data; + printHexCharLine(charData); + } +} + +void CWE197_Numeric_Truncation_Error__short_fscanf_82_goodG2B::action(short data) +{ + { + char charData = (char)data; + printHexCharLine(charData); + } +} + +void bad() +{ + short data; + /* Initialize data */ + data = -1; + /* FLAW: Use a number input from the console using fscanf() */ + fscanf (stdin, "%hd", &data); + CWE197_Numeric_Truncation_Error__short_fscanf_82_base* baseObject = new CWE197_Numeric_Truncation_Error__short_fscanf_82_bad; + baseObject->action(data); + delete baseObject; +} + +/* goodG2B uses the GoodSource with the BadSink */ +static void goodG2B() +{ + short data; + /* Initialize data */ + data = -1; + /* FIX: Use a positive integer less than CHAR_MAX*/ + data = CHAR_MAX-5; + CWE197_Numeric_Truncation_Error__short_fscanf_82_base* baseObject = new CWE197_Numeric_Truncation_Error__short_fscanf_82_goodG2B; + baseObject->action(data); + delete baseObject; +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-290/semmle/AuthenticationBypass/AuthenticationBypass.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-290/semmle/AuthenticationBypass/AuthenticationBypass.expected index 1ad31c3f9f7..360ced04144 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-290/semmle/AuthenticationBypass/AuthenticationBypass.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-290/semmle/AuthenticationBypass/AuthenticationBypass.expected @@ -17,6 +17,7 @@ edges | test.cpp:38:25:38:42 | (const char *)... | test.cpp:42:14:42:20 | address | | test.cpp:38:25:38:42 | (const char *)... | test.cpp:42:14:42:20 | address | | test.cpp:38:25:38:42 | (const char *)... | test.cpp:42:14:42:20 | address indirection | +subpaths nodes | test.cpp:16:25:16:30 | call to getenv | semmle.label | call to getenv | | test.cpp:16:25:16:42 | (const char *)... | semmle.label | (const char *)... | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-311/semmle/tests/CleartextBufferWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-311/semmle/tests/CleartextBufferWrite.expected index e4f9bc918a4..400c49237ca 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-311/semmle/tests/CleartextBufferWrite.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-311/semmle/tests/CleartextBufferWrite.expected @@ -5,6 +5,7 @@ edges | test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input | | test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input indirection | | test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input indirection | +subpaths nodes | test.cpp:54:17:54:20 | argv | semmle.label | argv | | test.cpp:54:17:54:20 | argv | semmle.label | argv | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-497/SAMATE/ExposedSystemData.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-497/SAMATE/ExposedSystemData.expected new file mode 100644 index 00000000000..ffd6f77205e --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-497/SAMATE/ExposedSystemData.expected @@ -0,0 +1 @@ +| tests.c:70:9:70:15 | call to fprintf | This operation exposes system data from $@. | tests.c:54:13:54:22 | call to LogonUserA | call to LogonUserA | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-497/SAMATE/ExposedSystemData.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-497/SAMATE/ExposedSystemData.qlref new file mode 100644 index 00000000000..0c88835bf1f --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-497/SAMATE/ExposedSystemData.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-497/ExposedSystemData.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-497/SAMATE/OutputWrite.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-497/SAMATE/OutputWrite.expected new file mode 100644 index 00000000000..fe7e5b34c77 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-497/SAMATE/OutputWrite.expected @@ -0,0 +1,7 @@ +| tests.c:29:9:29:14 | call to printf | tests.c:29:16:29:21 | %s\n | +| tests.c:29:9:29:14 | call to printf | tests.c:29:24:29:27 | line | +| tests.c:43:13:43:21 | call to printLine | tests.c:43:23:43:38 | fgets() failed | +| tests.c:62:13:62:21 | call to printLine | tests.c:62:23:62:52 | User logged in successfully. | +| tests.c:67:13:67:21 | call to printLine | tests.c:67:23:67:40 | Unable to login. | +| tests.c:70:9:70:15 | call to fprintf | tests.c:70:25:70:67 | User attempted access with password: %s\n | +| tests.c:70:9:70:15 | call to fprintf | tests.c:70:70:70:77 | password | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-497/SAMATE/OutputWrite.ql b/cpp/ql/test/query-tests/Security/CWE/CWE-497/SAMATE/OutputWrite.ql new file mode 100644 index 00000000000..d9e67a944e9 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-497/SAMATE/OutputWrite.ql @@ -0,0 +1,4 @@ +import semmle.code.cpp.security.OutputWrite + +from OutputWrite ow +select ow, ow.getASource() diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-497/SAMATE/tests.c b/cpp/ql/test/query-tests/Security/CWE/CWE-497/SAMATE/tests.c new file mode 100644 index 00000000000..4b1df2a96e1 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-497/SAMATE/tests.c @@ -0,0 +1,72 @@ +// SAMATE Juliet test cases for rule CWE-497. + +// library functions etc +typedef struct {} FILE; + +// define stdout, stderr in a similar style to MinGW +FILE std_files[2]; +#define stdin (&std_files[0]) +#define stderr (&std_files[1]) + +typedef unsigned long size_t; +size_t strlen(const char *s); +int printf(const char *format, ...); +int fprintf(FILE *stream, const char *format, ...); +char *fgets(char *s, int n, FILE *stream); + +typedef struct {} *HANDLE; +int LogonUserA(const char *lpszUserName, const char *lpszDomain, const char *lpszPassword, int dwLogonType, int dwLogonProvider, HANDLE *phToken); +void CloseHandle(HANDLE h); + +#define NULL (0) +#define LOGON32_LOGON_NETWORK (1) +#define LOGON32_PROVIDER_DEFAULT (2) + +void printLine(const char * line) +{ + if(line != NULL) + { + printf("%s\n", line); + } +} + +void CWE535_Info_Exposure_Shell_Error__w32_char_01_bad() +{ + { + char password[100] = ""; + size_t passwordLen = 0; + HANDLE pHandle; + char * username = "User"; + char * domain = "Domain"; + if (fgets(password, 100, stdin) == NULL) + { + printLine("fgets() failed"); + /* Restore NUL terminator if fgets fails */ + password[0] = '\0'; + } + /* Remove the carriage return from the string that is inserted by fgets() */ + passwordLen = strlen(password); + if (passwordLen > 0) + { + password[passwordLen-1] = '\0'; + } + /* Use the password in LogonUser() to establish that it is "sensitive" */ + if (LogonUserA( + username, + domain, + password, + LOGON32_LOGON_NETWORK, + LOGON32_PROVIDER_DEFAULT, + &pHandle) != 0) + { + printLine("User logged in successfully."); + CloseHandle(pHandle); + } + else + { + printLine("Unable to login."); + } + /* FLAW: Write sensitive data to stderr */ + fprintf(stderr, "User attempted access with password: %s\n", password); + } +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-675/semmle/tests/DoubleRelease.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-675/semmle/tests/DoubleRelease.expected new file mode 100644 index 00000000000..8bed519ab4a --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-675/semmle/tests/DoubleRelease.expected @@ -0,0 +1,3 @@ +| test.cpp:20:3:20:8 | call to fclose | Second call to the $@ function is possible. | test.cpp:21:3:21:8 | call to fclose | fclose | +| test.cpp:31:3:31:8 | call to fclose | Second call to the $@ function is possible. | test.cpp:32:3:32:8 | call to fclose | fclose | +| test.cpp:38:3:38:8 | call to fclose | Second call to the $@ function is possible. | test.cpp:44:3:44:8 | call to fclose | fclose | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-675/semmle/tests/DoubleRelease.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-675/semmle/tests/DoubleRelease.qlref new file mode 100644 index 00000000000..3edd226abaa --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-675/semmle/tests/DoubleRelease.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-675/DoubleRelease.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-675/semmle/tests/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-675/semmle/tests/test.cpp new file mode 100644 index 00000000000..986a95b1ce9 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-675/semmle/tests/test.cpp @@ -0,0 +1,83 @@ +#define NULL (0) +typedef int FILE; +FILE *fopen(const char *filename, const char *mode); +int fclose(FILE *stream); +extern FILE * fe; +void test1() +{ + FILE *f; + + f = fopen("myFile.txt", "wt"); + fclose(f); // GOOD + f = NULL; +} + +void test2() +{ + FILE *f; + + f = fopen("myFile.txt", "wt"); + fclose(f); // BAD + fclose(f); +} + +void test3() +{ + FILE *f; + FILE *g; + + f = fopen("myFile.txt", "wt"); + g = f; + fclose(f); // BAD + fclose(g); +} + +int fGtest4_1() +{ + fe = fopen("myFile.txt", "wt"); + fclose(fe); // BAD + return -1; +} + +int fGtest4_2() +{ + fclose(fe); + return -1; +} + +void Gtest4() +{ + fGtest4_1(); + fGtest4_2(); +} + +int fGtest5_1() +{ + fe = fopen("myFile.txt", "wt"); + fclose(fe); // GOOD + fe = NULL; + return -1; +} + +int fGtest5_2() +{ + fclose(fe); + return -1; +} + +void Gtest5() +{ + fGtest5_1(); + fGtest5_2(); +} + +int main(int argc, char *argv[]) +{ + test1(); + test2(); + test3(); + + Gtest4(); + Gtest5(); + return 0; +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-676/SAMATE/DangerousUseOfCin/DangerousUseOfCin.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-676/SAMATE/DangerousUseOfCin/DangerousUseOfCin.expected new file mode 100644 index 00000000000..f5c0b85e28f --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-676/SAMATE/DangerousUseOfCin/DangerousUseOfCin.expected @@ -0,0 +1 @@ +| test.cpp:59:17:59:17 | call to operator>> | Use of 'cin' without specifying the length of the input may be dangerous. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-676/SAMATE/DangerousUseOfCin/DangerousUseOfCin.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-676/SAMATE/DangerousUseOfCin/DangerousUseOfCin.qlref new file mode 100644 index 00000000000..5a35bf81fd9 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-676/SAMATE/DangerousUseOfCin/DangerousUseOfCin.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-676/DangerousUseOfCin.ql diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-676/SAMATE/DangerousUseOfCin/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-676/SAMATE/DangerousUseOfCin/test.cpp new file mode 100644 index 00000000000..704c2a87b3f --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-676/SAMATE/DangerousUseOfCin/test.cpp @@ -0,0 +1,81 @@ +// SAMATE Juliet test case for rule DangerousUseOfCin.ql / CWE-676. + +// --- library types, functions etc --- + +typedef unsigned long size_t; + +namespace std +{ + // --- std::istream --- + + // std::char_traits + template class char_traits; + + typedef size_t streamsize; + + class ios_base { + public: + streamsize width(streamsize wide); + }; + + template > + class basic_ios : public ios_base { + public: + }; + + // std::basic_istream + template > + class basic_istream : virtual public basic_ios { + }; + + // operator>> std::basic_istream -> char* + template basic_istream& operator>>(basic_istream&, charT*); + + // std::istream + typedef basic_istream istream; + + // --- std::cin --- + + extern istream cin; +} + +void printLine(const char *str); + +// --- test cases --- + +using namespace std; + +#define CHAR_BUFFER_SIZE 10 + +void CWE676_Use_of_Potentially_Dangerous_Function__basic_17_bad() +{ + int j; + for(j = 0; j < 1; j++) + { + { + char charBuffer[CHAR_BUFFER_SIZE]; + /* FLAW: using cin in an inherently dangerous fashion */ + /* INCIDENTAL CWE120 Buffer Overflow since cin extraction is unbounded. */ + cin >> charBuffer; // BAD + charBuffer[CHAR_BUFFER_SIZE-1] = '\0'; + printLine(charBuffer); + } + } +} + +/* good1() changes the conditions on the for statements */ +static void CWE676_Use_of_Potentially_Dangerous_Function__basic_17_good1() +{ + int k; + for(k = 0; k < 1; k++) + { + { + char charBuffer[CHAR_BUFFER_SIZE]; + /* FIX: Use cin after specifying the length of the input */ + cin.width(CHAR_BUFFER_SIZE); + cin >> charBuffer; // GOOD + charBuffer[CHAR_BUFFER_SIZE-1] = '\0'; + printLine(charBuffer); + } + } +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/FileMayNotBeClosed.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/FileMayNotBeClosed.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/FileMayNotBeClosed.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/FileMayNotBeClosed.qlref new file mode 100644 index 00000000000..fd711c007f0 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/FileMayNotBeClosed.qlref @@ -0,0 +1 @@ +Critical/FileMayNotBeClosed.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/FileNeverClosed.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/FileNeverClosed.expected new file mode 100644 index 00000000000..c328cee7ec9 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/FileNeverClosed.expected @@ -0,0 +1,3 @@ +| tests.cpp:220:12:220:16 | call to fopen | The file is never closed | +| tests.cpp:252:12:252:15 | call to open | The file is never closed | +| tests.cpp:278:12:278:21 | call to CreateFile | The file is never closed | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/FileNeverClosed.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/FileNeverClosed.qlref new file mode 100644 index 00000000000..825ac26f500 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/FileNeverClosed.qlref @@ -0,0 +1 @@ +Critical/FileNeverClosed.ql diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/MemoryMayNotBeFreed.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/MemoryMayNotBeFreed.expected new file mode 100644 index 00000000000..11a19a071d0 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/MemoryMayNotBeFreed.expected @@ -0,0 +1,2 @@ +| tests.cpp:198:31:198:36 | call to malloc | The memory allocated here may not be released at $@. | tests.cpp:212:1:212:1 | return ... | this exit point | +| tests.cpp:325:5:325:68 | ... = ... | The memory allocated here may not be released at $@. | tests.cpp:333:1:333:1 | return ... | this exit point | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/MemoryMayNotBeFreed.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/MemoryMayNotBeFreed.qlref new file mode 100644 index 00000000000..33da8e296e2 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/MemoryMayNotBeFreed.qlref @@ -0,0 +1 @@ +Critical/MemoryMayNotBeFreed.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/MemoryNeverFreed.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/MemoryNeverFreed.expected new file mode 100644 index 00000000000..087186d9dc6 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/MemoryNeverFreed.expected @@ -0,0 +1,2 @@ +| tests.cpp:71:20:71:26 | new | This memory is never freed | +| tests.cpp:136:24:136:29 | call to malloc | This memory is never freed | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/MemoryNeverFreed.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/MemoryNeverFreed.qlref new file mode 100644 index 00000000000..2d1336a55eb --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/MemoryNeverFreed.qlref @@ -0,0 +1 @@ +Critical/MemoryNeverFreed.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/tests.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/tests.cpp new file mode 100644 index 00000000000..e7b889deb08 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-772/SAMATE/tests.cpp @@ -0,0 +1,333 @@ +// Sample of SAMATE Juliet tests for CWE-772. + +// --- library types, functions etc --- + +#define NULL (0) +typedef unsigned long size_t; + +void *malloc(size_t size); +void *realloc(void *ptr, size_t size); +void *alloca(size_t size); +#define ALLOCA alloca +void free(void *ptr); + +typedef struct {} FILE; +FILE *fopen(const char *filename, const char *mode); +int fclose(FILE *stream); + +char *strcpy(char *s1, const char *s2); + +void printLine(const char *str); +void printIntLine(int val); + +// --- open --- + +typedef unsigned int mode_t; +int open(const char *path, int oflags, mode_t mode); +#define OPEN open +int close(int fd); +#define CLOSE close + +#define O_RDWR (1) +#define O_CREAT (2) +#define S_IREAD (3) +#define S_IWRITE (4) + +// --- Windows --- + +typedef unsigned int HANDLE; +#define INVALID_HANDLE_VALUE (-1) +typedef const char *LPCTSTR; +typedef unsigned long DWORD; +typedef struct _SECURITY_ATTRIBUTES {} *LPSECURITY_ATTRIBUTES; +typedef bool BOOL; +HANDLE CreateFile( + LPCTSTR lpFileName, + DWORD dwDesiredAccess, + DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, + HANDLE hTemplateFile); +BOOL CloseHandle(HANDLE hObject); + +#define GENERIC_READ (1) +#define GENERIC_WRITE (2) +#define OPEN_ALWAYS (3) +#define FILE_ATTRIBUTE_NORMAL (4) + +// --- test cases --- + +namespace CWE401_Memory_Leak__new_int_17 +{ + void bad() + { + int i,j; + int * data; + data = NULL; + for(i = 0; i < 1; i++) + { + /* POTENTIAL FLAW: Allocate memory on the heap */ + data = new int; // BAD + /* Initialize and make use of data */ + *data = 5; + printIntLine(*data); + } + for(j = 0; j < 1; j++) + { + /* POTENTIAL FLAW: No deallocation */ + ; /* empty statement needed for some flow variants */ + } + } + + /* goodB2G() - use badsource and goodsink in the for statements */ + static void goodB2G() + { + int i,k; + int * data; + data = NULL; + for(i = 0; i < 1; i++) + { + /* POTENTIAL FLAW: Allocate memory on the heap */ + data = new int; // GOOD + /* Initialize and make use of data */ + *data = 5; + printIntLine(*data); + } + for(k = 0; k < 1; k++) + { + /* FIX: Deallocate memory */ + delete data; + } + } + + /* goodG2B() - use goodsource and badsink in the for statements */ + static void goodG2B() + { + int h,j; + int * data; + data = NULL; + for(h = 0; h < 1; h++) + { + /* FIX: Use memory allocated on the stack */ + int dataGoodBuffer; // GOOD + data = &dataGoodBuffer; + /* Initialize and make use of data */ + *data = 5; + printIntLine(*data); + } + for(j = 0; j < 1; j++) + { + /* POTENTIAL FLAW: No deallocation */ + ; /* empty statement needed for some flow variants */ + } + } +} /* close namespace */ + +void CWE401_Memory_Leak__char_malloc_32_bad() +{ + char * data; + char * *dataPtr1 = &data; + char * *dataPtr2 = &data; + data = NULL; + { + char * data = *dataPtr1; + /* POTENTIAL FLAW: Allocate memory on the heap */ + data = (char *)malloc(100*sizeof(char)); // BAD + /* Initialize and make use of data */ + strcpy(data, "A String"); + printLine(data); + *dataPtr1 = data; + } + { + char * data = *dataPtr2; + /* POTENTIAL FLAW: No deallocation */ + ; /* empty statement needed for some flow variants */ + } +} + +/* goodG2B() uses the GoodSource with the BadSink */ +static void CWE401_Memory_Leak__char_malloc_32_goodG2B() +{ + char * data; + char * *dataPtr1 = &data; + char * *dataPtr2 = &data; + data = NULL; + { + char * data = *dataPtr1; + /* FIX: Use memory allocated on the stack with ALLOCA */ + data = (char *)ALLOCA(100*sizeof(char)); // GOOD + /* Initialize and make use of data */ + strcpy(data, "A String"); + printLine(data); + *dataPtr1 = data; + } + { + char * data = *dataPtr2; + /* POTENTIAL FLAW: No deallocation */ + ; /* empty statement needed for some flow variants */ + } +} + +/* goodB2G() uses the BadSource with the GoodSink */ +static void CWE401_Memory_Leak__char_malloc_32_goodB2G() +{ + char * data; + char * *dataPtr1 = &data; + char * *dataPtr2 = &data; + data = NULL; + { + char * data = *dataPtr1; + /* POTENTIAL FLAW: Allocate memory on the heap */ + data = (char *)malloc(100*sizeof(char)); // GOOD + /* Initialize and make use of data */ + strcpy(data, "A String"); + printLine(data); + *dataPtr1 = data; + } + { + char * data = *dataPtr2; + /* FIX: Deallocate memory */ + free(data); + } +} + +void CWE401_Memory_Leak__malloc_realloc_char_01_bad() +{ + { + char * data = (char *)malloc(100*sizeof(char)); // BAD + /* Initialize and make use of data */ + strcpy(data, "A String"); + printLine(data); + /* FLAW: If realloc() fails, the initial memory block will not be freed() */ + data = (char *)realloc(data, (130000)*sizeof(char)); + if (data != NULL) + { + /* Reinitialize and make use of data */ + strcpy(data, "New String"); + printLine(data); + free(data); + } + } +} + +void CWE775_Missing_Release_of_File_Descriptor_or_Handle__fopen_no_close_17_bad() +{ + int j; + FILE * data; + data = NULL; + /* POTENTIAL FLAW: Open a file without closing it */ + data = fopen("BadSource_fopen.txt", "w+"); // BAD + for(j = 0; j < 1; j++) + { + /* FLAW: No attempt to close the file */ + ; /* empty statement needed for some flow variants */ + } +} + +/* goodB2G() - use the goodsink in the for statement */ +static void CWE775_Missing_Release_of_File_Descriptor_or_Handle__fopen_no_close_17_goodB2G() +{ + int k; + FILE * data; + data = NULL; + /* POTENTIAL FLAW: Open a file without closing it */ + data = fopen("BadSource_fopen.txt", "w+"); // GOOD + for(k = 0; k < 1; k++) + { + /* FIX: If the file is still opened, close it */ + if (data != NULL) + { + fclose(data); + } + } +} + +void CWE775_Missing_Release_of_File_Descriptor_or_Handle__open_no_close_01_bad() +{ + int data; + /* Initialize data */ + data = -1; + /* POTENTIAL FLAW: Open a file without closing it */ + data = OPEN("BadSource_open.txt", O_RDWR|O_CREAT, S_IREAD|S_IWRITE); // BAD + /* FLAW: No attempt to close the file */ + ; /* empty statement needed for some flow variants */ +} + +/* goodB2G() uses the BadSource with the GoodSink */ +static void CWE775_Missing_Release_of_File_Descriptor_or_Handle__open_no_close_01_goodB2G() +{ + int data; + /* Initialize data */ + data = -1; + /* POTENTIAL FLAW: Open a file without closing it */ + data = OPEN("BadSource_open.txt", O_RDWR|O_CREAT, S_IREAD|S_IWRITE); // GOOD + /* FIX: If the file is still opened, close it */ + if (data != -1) + { + CLOSE(data); + } +} + +void CWE775_Missing_Release_of_File_Descriptor_or_Handle__w32CreateFile_no_close_01_bad() +{ + HANDLE data; + /* Initialize data */ + data = INVALID_HANDLE_VALUE; + /* POTENTIAL FLAW: Open a file without closing it */ + data = CreateFile("BadSource_w32CreateFile.txt", // BAD + (GENERIC_WRITE|GENERIC_READ), + 0, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + /* FLAW: No attempt to close the file */ + ; /* empty statement needed for some flow variants */ +} + +/* goodB2G() uses the BadSource with the GoodSink */ +static void CWE775_Missing_Release_of_File_Descriptor_or_Handle__w32CreateFile_no_close_01_goodB2G() +{ + HANDLE data; + /* Initialize data */ + data = INVALID_HANDLE_VALUE; + /* POTENTIAL FLAW: Open a file without closing it */ + data = CreateFile("BadSource_w32CreateFile.txt", // GOOD + (GENERIC_WRITE|GENERIC_READ), + 0, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + /* FIX: If the file is still opened, close it */ + if (data != INVALID_HANDLE_VALUE) + { + CloseHandle(data); + } +} + +void exit(int status); + +typedef struct _twoIntsStruct +{ + int intOne; + int intTwo; +} twoIntsStruct; + +void printStructLine(const twoIntsStruct * structTwoIntsStruct); + +void CWE401_Memory_Leak__twoIntsStruct_realloc_01_bad() +{ + twoIntsStruct * data; + data = NULL; + /* POTENTIAL FLAW: Allocate memory on the heap */ + data = (twoIntsStruct *)realloc(data, 100*sizeof(twoIntsStruct)); + if (data == NULL) {exit(-1);} + /* Initialize and make use of data */ + data[0].intOne = 0; + data[0].intTwo = 0; + printStructLine(&data[0]); + /* POTENTIAL FLAW: No deallocation */ + ; /* empty statement needed for some flow variants */ +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-807/semmle/TaintedCondition/TaintedCondition.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-807/semmle/TaintedCondition/TaintedCondition.expected index e04a20830d0..1fdb1497922 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-807/semmle/TaintedCondition/TaintedCondition.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-807/semmle/TaintedCondition/TaintedCondition.expected @@ -7,6 +7,7 @@ edges | test.cpp:20:29:20:47 | (const char *)... | test.cpp:24:11:24:16 | call to strcmp | | test.cpp:20:29:20:47 | (const char *)... | test.cpp:41:10:41:38 | ! ... | | test.cpp:20:29:20:47 | (const char *)... | test.cpp:41:11:41:16 | call to strcmp | +subpaths nodes | test.cpp:20:29:20:34 | call to getenv | semmle.label | call to getenv | | test.cpp:20:29:20:47 | (const char *)... | semmle.label | (const char *)... | diff --git a/cpp/ql/test/query-tests/Security/CWE/README.md b/cpp/ql/test/query-tests/Security/CWE/README.md new file mode 100644 index 00000000000..465f0cb3b3f --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/README.md @@ -0,0 +1,5 @@ +# CWE specific security tests + +## Source from the Juliet Test Suite + +Some of the the files in these tests contain source code copied or derived from the public domain "Juliet Test Suite for C/C++" (provided by NIST / SAMATE Team at https://samate.nist.gov/SARD/testsuite.php). Such tests are typically in subdirectories named "SAMATE". diff --git a/cpp/upgrades/ddd31fd02e51ad270bc9e6712708e5a5b6881518/old.dbscheme b/cpp/upgrades/ddd31fd02e51ad270bc9e6712708e5a5b6881518/old.dbscheme new file mode 100644 index 00000000000..ddd31fd02e5 --- /dev/null +++ b/cpp/upgrades/ddd31fd02e51ad270bc9e6712708e5a5b6881518/old.dbscheme @@ -0,0 +1,2145 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +/** If `function` is a coroutine, then this gives the + std::experimental::resumable_traits instance associated with it, + and the variables representing the `handle` and `promise` for it. */ +coroutine( + unique int function: @function ref, + int traits: @type ref, + int handle: @variable ref, + int promise: @variable ref +); + +/** The `new` function used for allocating the coroutine state, if any. */ +coroutine_new( + unique int function: @function ref, + int new: @function ref +); + +/** The `delete` function used for deallocating the coroutine state, if any. */ +coroutine_delete( + unique int function: @function ref, + int delete: @function ref +); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + +member_function_this_type(unique int id: @function ref, int this_type: @type ref); + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref, + int enclosing : @element ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +/** + * An instance of the C++11 `decltype` operator. For example: + * ``` + * int a; + * decltype(1+a) b; + * ``` + * Here `expr` is `1+a`. + * + * Sometimes an additional pair of parentheses around the expression + * would change the semantics of this decltype, e.g. + * ``` + * struct A { double x; }; + * const A* a = new A(); + * decltype( a->x ); // type is double + * decltype((a->x)); // type is const double& + * ``` + * (Please consult the C++11 standard for more details). + * `parentheses_would_change_meaning` is `true` iff that is the case. + */ +#keyset[id, expr] +decltypes( + int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + unique string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + | @temp_init + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + | @co_await + | @co_yield + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +| 327 = @co_await +| 328 = @co_yield +| 329 = @temp_init +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +| 37 = @stmt_co_return +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/upgrades/ddd31fd02e51ad270bc9e6712708e5a5b6881518/semmlecode.cpp.dbscheme b/cpp/upgrades/ddd31fd02e51ad270bc9e6712708e5a5b6881518/semmlecode.cpp.dbscheme new file mode 100644 index 00000000000..7806a11dd7a --- /dev/null +++ b/cpp/upgrades/ddd31fd02e51ad270bc9e6712708e5a5b6881518/semmlecode.cpp.dbscheme @@ -0,0 +1,2136 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * gcc -c f1.c f2.c f3.c + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * gcc -c f1.c f2.c f3.c + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--mimic` + * 2 | `/usr/bin/gcc` + * 3 | `-c` + * 4 | f1.c + * 5 | f2.c + * 6 | f3.c + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * gcc -c f1.c f2.c f3.c + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.c + * 1 | f2.c + * 2 | f3.c + * + * Note that even if those files `#include` headers, those headers + * do not appear as rows. + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + + +/** + * External data, loaded from CSV files during snapshot creation. See + * [Tutorial: Incorporating external data](https://help.semmle.com/wiki/display/SD/Tutorial%3A+Incorporating+external+data) + * for more information. + */ +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +/** + * The date of the snapshot. + */ +snapshotDate(unique date snapshotDate : date ref); + +/** + * The source location of the snapshot. + */ +sourceLocationPrefix(string prefix : string ref); + +/** + * Data used by the 'duplicate code' detection. + */ +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'similar code' detection. + */ +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +@duplication_or_similarity = @duplication | @similarity + +/** + * Data used by the 'duplicate code' and 'similar code' detection. + */ +#keyset[id, offset] +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/** + * Information about packages that provide code used during compilation. + * The `id` is just a unique identifier. + * The `namespace` is typically the name of the package manager that + * provided the package (e.g. "dpkg" or "yum"). + * The `package_name` is the name of the package, and `version` is its + * version (as a string). + */ +external_packages( + unique int id: @external_package, + string namespace : string ref, + string package_name : string ref, + string version : string ref +); + +/** + * Holds if File `fileid` was provided by package `package`. + */ +header_to_external_package( + int fileid : @file ref, + int package : @external_package ref +); + +/* + * Version history + */ + +svnentries( + unique int id : @svnentry, + string revision : string ref, + string author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + string action : string ref +) + +svnentrymsg( + unique int id : @svnentry ref, + string message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/* + * C++ dbscheme + */ + +@location = @location_stmt | @location_expr | @location_default ; + +/** + * The location of an element that is not an expression or a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_default( + /** The location of an element that is not an expression or a statement. */ + unique int id: @location_default, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of a statement. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_stmt( + /** The location of a statement. */ + unique int id: @location_stmt, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** + * The location of an expression. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `file`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html). + */ +locations_expr( + /** The location of an expression. */ + unique int id: @location_expr, + int container: @container ref, + int startLine: int ref, + int startColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +/** An element for which line-count information is available. */ +@sourceline = @file | @function | @variable | @enumconstant | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +fileannotations( + int id: @file ref, + int kind: int ref, + string name: string ref, + string value: string ref +); + +inmacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +affectedbymacroexpansion( + int id: @element ref, + int inv: @macroinvocation ref +); + +/* + case @macroinvocations.kind of + 1 = macro expansion + | 2 = other macro reference + ; +*/ +macroinvocations( + unique int id: @macroinvocation, + int macro_id: @ppd_define ref, + int location: @location_default ref, + int kind: int ref +); + +macroparent( + unique int id: @macroinvocation ref, + int parent_id: @macroinvocation ref +); + +// a macroinvocation may be part of another location +// the way to find a constant expression that uses a macro +// is thus to find a constant expression that has a location +// to which a macro invocation is bound +macrolocationbind( + int id: @macroinvocation ref, + int location: @location ref +); + +#keyset[invocation, argument_index] +macro_argument_unexpanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +#keyset[invocation, argument_index] +macro_argument_expanded( + int invocation: @macroinvocation ref, + int argument_index: int ref, + string text: string ref +); + +/* + case @function.kind of + 1 = normal + | 2 = constructor + | 3 = destructor + | 4 = conversion + | 5 = operator + | 6 = builtin // GCC built-in functions, e.g. __builtin___memcpy_chk + ; +*/ +functions( + unique int id: @function, + string name: string ref, + int kind: int ref +); + +function_entry_point(int id: @function ref, unique int entry_point: @stmt ref); + +function_return_type(int id: @function ref, int return_type: @type ref); + +/** If `function` is a coroutine, then this gives the + std::experimental::resumable_traits instance associated with it, + and the variables representing the `handle` and `promise` for it. */ +coroutine( + unique int function: @function ref, + int traits: @type ref, + int handle: @variable ref, + int promise: @variable ref +); + +/** The `new` function used for allocating the coroutine state, if any. */ +coroutine_new( + unique int function: @function ref, + int new: @function ref +); + +/** The `delete` function used for deallocating the coroutine state, if any. */ +coroutine_delete( + unique int function: @function ref, + int delete: @function ref +); + +purefunctions(unique int id: @function ref); + +function_deleted(unique int id: @function ref); + +function_defaulted(unique int id: @function ref); + +member_function_this_type(unique int id: @function ref, int this_type: @type ref); + +#keyset[id, type_id] +fun_decls( + int id: @fun_decl, + int function: @function ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +fun_def(unique int id: @fun_decl ref); +fun_specialized(unique int id: @fun_decl ref); +fun_implicit(unique int id: @fun_decl ref); +fun_decl_specifiers( + int id: @fun_decl ref, + string name: string ref +) +#keyset[fun_decl, index] +fun_decl_throws( + int fun_decl: @fun_decl ref, + int index: int ref, + int type_id: @type ref +); +/* an empty throw specification is different from none */ +fun_decl_empty_throws(unique int fun_decl: @fun_decl ref); +fun_decl_noexcept( + int fun_decl: @fun_decl ref, + int constant: @expr ref +); +fun_decl_empty_noexcept(int fun_decl: @fun_decl ref); +fun_decl_typedef_type( + unique int fun_decl: @fun_decl ref, + int typedeftype_id: @usertype ref +); + +param_decl_bind( + unique int id: @var_decl ref, + int index: int ref, + int fun_decl: @fun_decl ref +); + +#keyset[id, type_id] +var_decls( + int id: @var_decl, + int variable: @variable ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); +var_def(unique int id: @var_decl ref); +var_decl_specifiers( + int id: @var_decl ref, + string name: string ref +) + +type_decls( + unique int id: @type_decl, + int type_id: @type ref, + int location: @location_default ref +); +type_def(unique int id: @type_decl ref); +type_decl_top( + unique int type_decl: @type_decl ref +); + +namespace_decls( + unique int id: @namespace_decl, + int namespace_id: @namespace ref, + int location: @location_default ref, + int bodylocation: @location_default ref +); + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref +); + +/** The element which contains the `using` declaration. */ +using_container( + int parent: @element ref, + int child: @using ref +); + +static_asserts( + unique int id: @static_assert, + int condition : @expr ref, + string message : string ref, + int location: @location_default ref, + int enclosing : @element ref +); + +// each function has an ordered list of parameters +#keyset[id, type_id] +#keyset[function, index, type_id] +params( + int id: @parameter, + int function: @functionorblock ref, + int index: int ref, + int type_id: @type ref +); + +overrides(int new: @function ref, int old: @function ref); + +#keyset[id, type_id] +membervariables( + int id: @membervariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +globalvariables( + int id: @globalvariable, + int type_id: @type ref, + string name: string ref +); + +#keyset[id, type_id] +localvariables( + int id: @localvariable, + int type_id: @type ref, + string name: string ref +); + +autoderivation( + unique int var: @variable ref, + int derivation_type: @type ref +); + +enumconstants( + unique int id: @enumconstant, + int parent: @usertype ref, + int index: int ref, + int type_id: @type ref, + string name: string ref, + int location: @location_default ref +); + +@variable = @localscopevariable | @globalvariable | @membervariable; + +@localscopevariable = @localvariable | @parameter; + +/* + Built-in types are the fundamental types, e.g., integral, floating, and void. + + case @builtintype.kind of + 1 = error + | 2 = unknown + | 3 = void + | 4 = boolean + | 5 = char + | 6 = unsigned_char + | 7 = signed_char + | 8 = short + | 9 = unsigned_short + | 10 = signed_short + | 11 = int + | 12 = unsigned_int + | 13 = signed_int + | 14 = long + | 15 = unsigned_long + | 16 = signed_long + | 17 = long_long + | 18 = unsigned_long_long + | 19 = signed_long_long + | 20 = __int8 // Microsoft-specific + | 21 = __int16 // Microsoft-specific + | 22 = __int32 // Microsoft-specific + | 23 = __int64 // Microsoft-specific + | 24 = float + | 25 = double + | 26 = long_double + | 27 = _Complex_float // C99-specific + | 28 = _Complex_double // C99-specific + | 29 = _Complex_long double // C99-specific + | 30 = _Imaginary_float // C99-specific + | 31 = _Imaginary_double // C99-specific + | 32 = _Imaginary_long_double // C99-specific + | 33 = wchar_t // Microsoft-specific + | 34 = decltype_nullptr // C++11 + | 35 = __int128 + | 36 = unsigned___int128 + | 37 = signed___int128 + | 38 = __float128 + | 39 = _Complex___float128 + | 40 = _Decimal32 + | 41 = _Decimal64 + | 42 = _Decimal128 + | 43 = char16_t + | 44 = char32_t + | 45 = _Float32 + | 46 = _Float32x + | 47 = _Float64 + | 48 = _Float64x + | 49 = _Float128 + | 50 = _Float128x + | 51 = char8_t + ; +*/ +builtintypes( + unique int id: @builtintype, + string name: string ref, + int kind: int ref, + int size: int ref, + int sign: int ref, + int alignment: int ref +); + +/* + Derived types are types that are directly derived from existing types and + point to, refer to, transform type data to return a new type. + + case @derivedtype.kind of + 1 = pointer + | 2 = reference + | 3 = type_with_specifiers + | 4 = array + | 5 = gnu_vector + | 6 = routineptr + | 7 = routinereference + | 8 = rvalue_reference // C++11 +// ... 9 type_conforming_to_protocols deprecated + | 10 = block + ; +*/ +derivedtypes( + unique int id: @derivedtype, + string name: string ref, + int kind: int ref, + int type_id: @type ref +); + +pointerishsize(unique int id: @derivedtype ref, + int size: int ref, + int alignment: int ref); + +arraysizes( + unique int id: @derivedtype ref, + int num_elements: int ref, + int bytesize: int ref, + int alignment: int ref +); + +typedefbase( + unique int id: @usertype ref, + int type_id: @type ref +); + +/** + * An instance of the C++11 `decltype` operator. For example: + * ``` + * int a; + * decltype(1+a) b; + * ``` + * Here `expr` is `1+a`. + * + * Sometimes an additional pair of parentheses around the expression + * would change the semantics of this decltype, e.g. + * ``` + * struct A { double x; }; + * const A* a = new A(); + * decltype( a->x ); // type is double + * decltype((a->x)); // type is const double& + * ``` + * (Please consult the C++11 standard for more details). + * `parentheses_would_change_meaning` is `true` iff that is the case. + */ +#keyset[id, expr] +decltypes( + int id: @decltype, + int expr: @expr ref, + int base_type: @type ref, + boolean parentheses_would_change_meaning: boolean ref +); + +/* + case @usertype.kind of + 1 = struct + | 2 = class + | 3 = union + | 4 = enum + | 5 = typedef // classic C: typedef typedef type name + | 6 = template + | 7 = template_parameter + | 8 = template_template_parameter + | 9 = proxy_class // a proxy class associated with a template parameter +// ... 10 objc_class deprecated +// ... 11 objc_protocol deprecated +// ... 12 objc_category deprecated + | 13 = scoped_enum + | 14 = using_alias // a using name = type style typedef + ; +*/ +usertypes( + unique int id: @usertype, + string name: string ref, + int kind: int ref +); + +usertypesize( + unique int id: @usertype ref, + int size: int ref, + int alignment: int ref +); + +usertype_final(unique int id: @usertype ref); + +usertype_uuid( + unique int id: @usertype ref, + unique string uuid: string ref +); + +mangled_name( + unique int id: @declaration ref, + int mangled_name : @mangledname +); + +is_pod_class(unique int id: @usertype ref); +is_standard_layout_class(unique int id: @usertype ref); + +is_complete(unique int id: @usertype ref); + +is_class_template(unique int id: @usertype ref); +class_instantiation( + int to: @usertype ref, + int from: @usertype ref +); +class_template_argument( + int type_id: @usertype ref, + int index: int ref, + int arg_type: @type ref +); +class_template_argument_value( + int type_id: @usertype ref, + int index: int ref, + int arg_value: @expr ref +); + +is_proxy_class_for( + unique int id: @usertype ref, + unique int templ_param_id: @usertype ref +); + +type_mentions( + unique int id: @type_mention, + int type_id: @type ref, + int location: @location ref, + // a_symbol_reference_kind from the EDG frontend. See symbol_ref.h there. + int kind: int ref +); + +is_function_template(unique int id: @function ref); +function_instantiation( + unique int to: @function ref, + int from: @function ref +); +function_template_argument( + int function_id: @function ref, + int index: int ref, + int arg_type: @type ref +); +function_template_argument_value( + int function_id: @function ref, + int index: int ref, + int arg_value: @expr ref +); + +is_variable_template(unique int id: @variable ref); +variable_instantiation( + unique int to: @variable ref, + int from: @variable ref +); +variable_template_argument( + int variable_id: @variable ref, + int index: int ref, + int arg_type: @type ref +); +variable_template_argument_value( + int variable_id: @variable ref, + int index: int ref, + int arg_value: @expr ref +); + +/* + Fixed point types + precision(1) = short, precision(2) = default, precision(3) = long + is_unsigned(1) = unsigned is_unsigned(2) = signed + is_fract_type(1) = declared with _Fract + saturating(1) = declared with _Sat +*/ +/* TODO +fixedpointtypes( + unique int id: @fixedpointtype, + int precision: int ref, + int is_unsigned: int ref, + int is_fract_type: int ref, + int saturating: int ref); +*/ + +routinetypes( + unique int id: @routinetype, + int return_type: @type ref +); + +routinetypeargs( + int routine: @routinetype ref, + int index: int ref, + int type_id: @type ref +); + +ptrtomembers( + unique int id: @ptrtomember, + int type_id: @type ref, + int class_id: @type ref +); + +/* + specifiers for types, functions, and variables + + "public", + "protected", + "private", + + "const", + "volatile", + "static", + + "pure", + "virtual", + "sealed", // Microsoft + "__interface", // Microsoft + "inline", + "explicit", + + "near", // near far extension + "far", // near far extension + "__ptr32", // Microsoft + "__ptr64", // Microsoft + "__sptr", // Microsoft + "__uptr", // Microsoft + "dllimport", // Microsoft + "dllexport", // Microsoft + "thread", // Microsoft + "naked", // Microsoft + "microsoft_inline", // Microsoft + "forceinline", // Microsoft + "selectany", // Microsoft + "nothrow", // Microsoft + "novtable", // Microsoft + "noreturn", // Microsoft + "noinline", // Microsoft + "noalias", // Microsoft + "restrict", // Microsoft +*/ + +specifiers( + unique int id: @specifier, + unique string str: string ref +); + +typespecifiers( + int type_id: @type ref, + int spec_id: @specifier ref +); + +funspecifiers( + int func_id: @function ref, + int spec_id: @specifier ref +); + +varspecifiers( + int var_id: @accessible ref, + int spec_id: @specifier ref +); + +attributes( + unique int id: @attribute, + int kind: int ref, + string name: string ref, + string name_space: string ref, + int location: @location_default ref +); + +case @attribute.kind of + 0 = @gnuattribute +| 1 = @stdattribute +| 2 = @declspec +| 3 = @msattribute +| 4 = @alignas +// ... 5 @objc_propertyattribute deprecated +; + +attribute_args( + unique int id: @attribute_arg, + int kind: int ref, + int attribute: @attribute ref, + int index: int ref, + int location: @location_default ref +); + +case @attribute_arg.kind of + 0 = @attribute_arg_empty +| 1 = @attribute_arg_token +| 2 = @attribute_arg_constant +| 3 = @attribute_arg_type +; + +attribute_arg_value( + unique int arg: @attribute_arg ref, + string value: string ref +); +attribute_arg_type( + unique int arg: @attribute_arg ref, + int type_id: @type ref +); +attribute_arg_name( + unique int arg: @attribute_arg ref, + string name: string ref +); + +typeattributes( + int type_id: @type ref, + int spec_id: @attribute ref +); + +funcattributes( + int func_id: @function ref, + int spec_id: @attribute ref +); + +varattributes( + int var_id: @accessible ref, + int spec_id: @attribute ref +); + +stmtattributes( + int stmt_id: @stmt ref, + int spec_id: @attribute ref +); + +@type = @builtintype + | @derivedtype + | @usertype + /* TODO | @fixedpointtype */ + | @routinetype + | @ptrtomember + | @decltype; + +unspecifiedtype( + unique int type_id: @type ref, + int unspecified_type_id: @type ref +); + +member( + int parent: @type ref, + int index: int ref, + int child: @member ref +); + +@enclosingfunction_child = @usertype | @variable | @namespace + +enclosingfunction( + unique int child: @enclosingfunction_child ref, + int parent: @function ref +); + +derivations( + unique int derivation: @derivation, + int sub: @type ref, + int index: int ref, + int super: @type ref, + int location: @location_default ref +); + +derspecifiers( + int der_id: @derivation ref, + int spec_id: @specifier ref +); + +/** + * Contains the byte offset of the base class subobject within the derived + * class. Only holds for non-virtual base classes, but see table + * `virtual_base_offsets` for offsets of virtual base class subobjects. + */ +direct_base_offsets( + unique int der_id: @derivation ref, + int offset: int ref +); + +/** + * Contains the byte offset of the virtual base class subobject for class + * `super` within a most-derived object of class `sub`. `super` can be either a + * direct or indirect base class. + */ +#keyset[sub, super] +virtual_base_offsets( + int sub: @usertype ref, + int super: @usertype ref, + int offset: int ref +); + +frienddecls( + unique int id: @frienddecl, + int type_id: @type ref, + int decl_id: @declaration ref, + int location: @location_default ref +); + +@declaredtype = @usertype ; + +@declaration = @function + | @declaredtype + | @variable + | @enumconstant + | @frienddecl; + +@member = @membervariable + | @function + | @declaredtype + | @enumconstant; + +@locatable = @diagnostic + | @declaration + | @ppd_include + | @ppd_define + | @macroinvocation + /*| @funcall*/ + | @xmllocatable + | @attribute + | @attribute_arg; + +@namedscope = @namespace | @usertype; + +@element = @locatable + | @file + | @folder + | @specifier + | @type + | @expr + | @namespace + | @initialiser + | @stmt + | @derivation + | @comment + | @preprocdirect + | @fun_decl + | @var_decl + | @type_decl + | @namespace_decl + | @using + | @namequalifier + | @specialnamequalifyingelement + | @static_assert + | @type_mention + | @lambdacapture; + +@exprparent = @element; + +comments( + unique int id: @comment, + string contents: string ref, + int location: @location_default ref +); + +commentbinding( + int id: @comment ref, + int element: @element ref +); + +exprconv( + int converted: @expr ref, + unique int conversion: @expr ref +); + +compgenerated(unique int id: @element ref); + +/** + * `destructor_call` destructs the `i`'th entity that should be + * destructed following `element`. Note that entities should be + * destructed in reverse construction order, so for a given `element` + * these should be called from highest to lowest `i`. + */ +#keyset[element, destructor_call] +#keyset[element, i] +synthetic_destructor_call( + int element: @element ref, + int i: int ref, + int destructor_call: @routineexpr ref +); + +namespaces( + unique int id: @namespace, + string name: string ref +); + +namespace_inline( + unique int id: @namespace ref +); + +namespacembrs( + int parentid: @namespace ref, + unique int memberid: @namespacembr ref +); + +@namespacembr = @declaration | @namespace; + +exprparents( + int expr_id: @expr ref, + int child_index: int ref, + int parent_id: @exprparent ref +); + +expr_isload(unique int expr_id: @expr ref); + +@cast = @c_style_cast + | @const_cast + | @dynamic_cast + | @reinterpret_cast + | @static_cast + ; + +/* +case @conversion.kind of + 0 = @simple_conversion // a numeric conversion, qualification conversion, or a reinterpret_cast +| 1 = @bool_conversion // conversion to 'bool' +| 2 = @base_class_conversion // a derived-to-base conversion +| 3 = @derived_class_conversion // a base-to-derived conversion +| 4 = @pm_base_class_conversion // a derived-to-base conversion of a pointer to member +| 5 = @pm_derived_class_conversion // a base-to-derived conversion of a pointer to member +| 6 = @glvalue_adjust // an adjustment of the type of a glvalue +| 7 = @prvalue_adjust // an adjustment of the type of a prvalue +; +*/ +/** + * Describes the semantics represented by a cast expression. This is largely + * independent of the source syntax of the cast, so it is separate from the + * regular expression kind. + */ +conversionkinds( + unique int expr_id: @cast ref, + int kind: int ref +); + +@conversion = @cast + | @array_to_pointer + | @parexpr + | @reference_to + | @ref_indirect + | @temp_init + ; + +/* +case @funbindexpr.kind of + 0 = @normal_call // a normal call +| 1 = @virtual_call // a virtual call +| 2 = @adl_call // a call whose target is only found by ADL +; +*/ +iscall(unique int caller: @funbindexpr ref, int kind: int ref); + +numtemplatearguments( + unique int expr_id: @expr ref, + int num: int ref +); + +specialnamequalifyingelements( + unique int id: @specialnamequalifyingelement, + unique string name: string ref +); + +@namequalifiableelement = @expr | @namequalifier; +@namequalifyingelement = @namespace + | @specialnamequalifyingelement + | @usertype; + +namequalifiers( + unique int id: @namequalifier, + unique int qualifiableelement: @namequalifiableelement ref, + int qualifyingelement: @namequalifyingelement ref, + int location: @location_default ref +); + +varbind( + int expr: @varbindexpr ref, + int var: @accessible ref +); + +funbind( + int expr: @funbindexpr ref, + int fun: @function ref +); + +@any_new_expr = @new_expr + | @new_array_expr; + +@new_or_delete_expr = @any_new_expr + | @delete_expr + | @delete_array_expr; + +@prefix_crement_expr = @preincrexpr | @predecrexpr; + +@postfix_crement_expr = @postincrexpr | @postdecrexpr; + +@increment_expr = @preincrexpr | @postincrexpr; + +@decrement_expr = @predecrexpr | @postdecrexpr; + +@crement_expr = @increment_expr | @decrement_expr; + +@un_arith_op_expr = @arithnegexpr + | @unaryplusexpr + | @conjugation + | @realpartexpr + | @imagpartexpr + | @crement_expr + ; + +@un_bitwise_op_expr = @complementexpr; + +@un_log_op_expr = @notexpr; + +@un_op_expr = @address_of + | @indirect + | @un_arith_op_expr + | @un_bitwise_op_expr + | @builtinaddressof + | @vec_fill + | @un_log_op_expr + | @co_await + | @co_yield + ; + +@bin_log_op_expr = @andlogicalexpr | @orlogicalexpr; + +@cmp_op_expr = @eq_op_expr | @rel_op_expr; + +@eq_op_expr = @eqexpr | @neexpr; + +@rel_op_expr = @gtexpr + | @ltexpr + | @geexpr + | @leexpr + | @spaceshipexpr + ; + +@bin_bitwise_op_expr = @lshiftexpr + | @rshiftexpr + | @andexpr + | @orexpr + | @xorexpr + ; + +@p_arith_op_expr = @paddexpr + | @psubexpr + | @pdiffexpr + ; + +@bin_arith_op_expr = @addexpr + | @subexpr + | @mulexpr + | @divexpr + | @remexpr + | @jmulexpr + | @jdivexpr + | @fjaddexpr + | @jfaddexpr + | @fjsubexpr + | @jfsubexpr + | @minexpr + | @maxexpr + | @p_arith_op_expr + ; + +@bin_op_expr = @bin_arith_op_expr + | @bin_bitwise_op_expr + | @cmp_op_expr + | @bin_log_op_expr + ; + +@op_expr = @un_op_expr + | @bin_op_expr + | @assign_expr + | @conditionalexpr + ; + +@assign_arith_expr = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + ; + +@assign_bitwise_expr = @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr + +@assign_expr = @assignexpr | @assign_op_expr + +/* + case @allocator.form of + 0 = plain + | 1 = alignment + ; +*/ + +/** + * The allocator function associated with a `new` or `new[]` expression. + * The `form` column specified whether the allocation call contains an alignment + * argument. + */ +expr_allocator( + unique int expr: @any_new_expr ref, + int func: @function ref, + int form: int ref +); + +/* + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 3 = size_and_alignment + ; +*/ + +/** + * The deallocator function associated with a `delete`, `delete[]`, `new`, or + * `new[]` expression. For a `new` or `new[]` expression, the deallocator is the + * one used to free memory if the initialization throws an exception. + * The `form` column specifies whether the deallocation call contains a size + * argument, and alignment argument, or both. + */ +expr_deallocator( + unique int expr: @new_or_delete_expr ref, + int func: @function ref, + int form: int ref +); + +/** + * Holds if the `@conditionalexpr` is of the two operand form + * `guard ? : false`. + */ +expr_cond_two_operand( + unique int cond: @conditionalexpr ref +); + +/** + * The guard of `@conditionalexpr` `guard ? true : false` + */ +expr_cond_guard( + unique int cond: @conditionalexpr ref, + int guard: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` holds. For the two operand form + * `guard ?: false` consider using `expr_cond_guard` instead. + */ +expr_cond_true( + unique int cond: @conditionalexpr ref, + int true: @expr ref +); + +/** + * The expression used when the guard of `@conditionalexpr` + * `guard ? true : false` does not hold. + */ +expr_cond_false( + unique int cond: @conditionalexpr ref, + int false: @expr ref +); + +/** A string representation of the value. */ +values( + unique int id: @value, + string str: string ref +); + +/** The actual text in the source code for the value, if any. */ +valuetext( + unique int id: @value ref, + string text: string ref +); + +valuebind( + int val: @value ref, + unique int expr: @expr ref +); + +fieldoffsets( + unique int id: @variable ref, + int byteoffset: int ref, + int bitoffset: int ref +); + +bitfield( + unique int id: @variable ref, + int bits: int ref, + int declared_bits: int ref +); + +/* TODO +memberprefix( + int member: @expr ref, + int prefix: @expr ref +); +*/ + +/* + kind(1) = mbrcallexpr + kind(2) = mbrptrcallexpr + kind(3) = mbrptrmbrcallexpr + kind(4) = ptrmbrptrmbrcallexpr + kind(5) = mbrreadexpr // x.y + kind(6) = mbrptrreadexpr // p->y + kind(7) = mbrptrmbrreadexpr // x.*pm + kind(8) = mbrptrmbrptrreadexpr // x->*pm + kind(9) = staticmbrreadexpr // static x.y + kind(10) = staticmbrptrreadexpr // static p->y +*/ +/* TODO +memberaccess( + int member: @expr ref, + int kind: int ref +); +*/ + +initialisers( + unique int init: @initialiser, + int var: @accessible ref, + unique int expr: @expr ref, + int location: @location_expr ref +); + +/** + * An ancestor for the expression, for cases in which we cannot + * otherwise find the expression's parent. + */ +expr_ancestor( + int exp: @expr ref, + int ancestor: @element ref +); + +exprs( + unique int id: @expr, + int kind: int ref, + int location: @location_expr ref +); + +/* + case @value.category of + 1 = prval + | 2 = xval + | 3 = lval + ; +*/ +expr_types( + int id: @expr ref, + int typeid: @type ref, + int value_category: int ref +); + +case @expr.kind of + 1 = @errorexpr +| 2 = @address_of // & AddressOfExpr +| 3 = @reference_to // ReferenceToExpr (implicit?) +| 4 = @indirect // * PointerDereferenceExpr +| 5 = @ref_indirect // ReferenceDereferenceExpr (implicit?) +// ... +| 8 = @array_to_pointer // (???) +| 9 = @vacuous_destructor_call // VacuousDestructorCall +// ... +| 11 = @assume // Microsoft +| 12 = @parexpr +| 13 = @arithnegexpr +| 14 = @unaryplusexpr +| 15 = @complementexpr +| 16 = @notexpr +| 17 = @conjugation // GNU ~ operator +| 18 = @realpartexpr // GNU __real +| 19 = @imagpartexpr // GNU __imag +| 20 = @postincrexpr +| 21 = @postdecrexpr +| 22 = @preincrexpr +| 23 = @predecrexpr +| 24 = @conditionalexpr +| 25 = @addexpr +| 26 = @subexpr +| 27 = @mulexpr +| 28 = @divexpr +| 29 = @remexpr +| 30 = @jmulexpr // C99 mul imaginary +| 31 = @jdivexpr // C99 div imaginary +| 32 = @fjaddexpr // C99 add real + imaginary +| 33 = @jfaddexpr // C99 add imaginary + real +| 34 = @fjsubexpr // C99 sub real - imaginary +| 35 = @jfsubexpr // C99 sub imaginary - real +| 36 = @paddexpr // pointer add (pointer + int or int + pointer) +| 37 = @psubexpr // pointer sub (pointer - integer) +| 38 = @pdiffexpr // difference between two pointers +| 39 = @lshiftexpr +| 40 = @rshiftexpr +| 41 = @andexpr +| 42 = @orexpr +| 43 = @xorexpr +| 44 = @eqexpr +| 45 = @neexpr +| 46 = @gtexpr +| 47 = @ltexpr +| 48 = @geexpr +| 49 = @leexpr +| 50 = @minexpr // GNU minimum +| 51 = @maxexpr // GNU maximum +| 52 = @assignexpr +| 53 = @assignaddexpr +| 54 = @assignsubexpr +| 55 = @assignmulexpr +| 56 = @assigndivexpr +| 57 = @assignremexpr +| 58 = @assignlshiftexpr +| 59 = @assignrshiftexpr +| 60 = @assignandexpr +| 61 = @assignorexpr +| 62 = @assignxorexpr +| 63 = @assignpaddexpr // assign pointer add +| 64 = @assignpsubexpr // assign pointer sub +| 65 = @andlogicalexpr +| 66 = @orlogicalexpr +| 67 = @commaexpr +| 68 = @subscriptexpr // access to member of an array, e.g., a[5] +// ... 69 @objc_subscriptexpr deprecated +// ... 70 @cmdaccess deprecated +// ... +| 73 = @virtfunptrexpr +| 74 = @callexpr +// ... 75 @msgexpr_normal deprecated +// ... 76 @msgexpr_super deprecated +// ... 77 @atselectorexpr deprecated +// ... 78 @atprotocolexpr deprecated +| 79 = @vastartexpr +| 80 = @vaargexpr +| 81 = @vaendexpr +| 82 = @vacopyexpr +// ... 83 @atencodeexpr deprecated +| 84 = @varaccess +| 85 = @thisaccess +// ... 86 @objc_box_expr deprecated +| 87 = @new_expr +| 88 = @delete_expr +| 89 = @throw_expr +| 90 = @condition_decl // a variable declared in a condition, e.g., if(int x = y > 2) +| 91 = @braced_init_list +| 92 = @type_id +| 93 = @runtime_sizeof +| 94 = @runtime_alignof +| 95 = @sizeof_pack +| 96 = @expr_stmt // GNU extension +| 97 = @routineexpr +| 98 = @type_operand // used to access a type in certain contexts (haven't found any examples yet....) +| 99 = @offsetofexpr // offsetof ::= type and field +| 100 = @hasassignexpr // __has_assign ::= type +| 101 = @hascopyexpr // __has_copy ::= type +| 102 = @hasnothrowassign // __has_nothrow_assign ::= type +| 103 = @hasnothrowconstr // __has_nothrow_constructor ::= type +| 104 = @hasnothrowcopy // __has_nothrow_copy ::= type +| 105 = @hastrivialassign // __has_trivial_assign ::= type +| 106 = @hastrivialconstr // __has_trivial_constructor ::= type +| 107 = @hastrivialcopy // __has_trivial_copy ::= type +| 108 = @hasuserdestr // __has_user_destructor ::= type +| 109 = @hasvirtualdestr // __has_virtual_destructor ::= type +| 110 = @isabstractexpr // __is_abstract ::= type +| 111 = @isbaseofexpr // __is_base_of ::= type type +| 112 = @isclassexpr // __is_class ::= type +| 113 = @isconvtoexpr // __is_convertible_to ::= type type +| 114 = @isemptyexpr // __is_empty ::= type +| 115 = @isenumexpr // __is_enum ::= type +| 116 = @ispodexpr // __is_pod ::= type +| 117 = @ispolyexpr // __is_polymorphic ::= type +| 118 = @isunionexpr // __is_union ::= type +| 119 = @typescompexpr // GNU __builtin_types_compatible ::= type type +| 120 = @intaddrexpr // EDG internal builtin, used to implement offsetof +// ... +| 122 = @hastrivialdestructor // __has_trivial_destructor ::= type +| 123 = @literal +| 124 = @uuidof +| 127 = @aggregateliteral +| 128 = @delete_array_expr +| 129 = @new_array_expr +// ... 130 @objc_array_literal deprecated +// ... 131 @objc_dictionary_literal deprecated +| 132 = @foldexpr +// ... +| 200 = @ctordirectinit +| 201 = @ctorvirtualinit +| 202 = @ctorfieldinit +| 203 = @ctordelegatinginit +| 204 = @dtordirectdestruct +| 205 = @dtorvirtualdestruct +| 206 = @dtorfielddestruct +// ... +| 210 = @static_cast +| 211 = @reinterpret_cast +| 212 = @const_cast +| 213 = @dynamic_cast +| 214 = @c_style_cast +| 215 = @lambdaexpr +| 216 = @param_ref +| 217 = @noopexpr +// ... +| 294 = @istriviallyconstructibleexpr +| 295 = @isdestructibleexpr +| 296 = @isnothrowdestructibleexpr +| 297 = @istriviallydestructibleexpr +| 298 = @istriviallyassignableexpr +| 299 = @isnothrowassignableexpr +| 300 = @istrivialexpr +| 301 = @isstandardlayoutexpr +| 302 = @istriviallycopyableexpr +| 303 = @isliteraltypeexpr +| 304 = @hastrivialmoveconstructorexpr +| 305 = @hastrivialmoveassignexpr +| 306 = @hasnothrowmoveassignexpr +| 307 = @isconstructibleexpr +| 308 = @isnothrowconstructibleexpr +| 309 = @hasfinalizerexpr +| 310 = @isdelegateexpr +| 311 = @isinterfaceclassexpr +| 312 = @isrefarrayexpr +| 313 = @isrefclassexpr +| 314 = @issealedexpr +| 315 = @issimplevalueclassexpr +| 316 = @isvalueclassexpr +| 317 = @isfinalexpr +| 319 = @noexceptexpr +| 320 = @builtinshufflevector +| 321 = @builtinchooseexpr +| 322 = @builtinaddressof +| 323 = @vec_fill +| 324 = @builtinconvertvector +| 325 = @builtincomplex +| 326 = @spaceshipexpr +| 327 = @co_await +| 328 = @co_yield +| 329 = @temp_init +; + +@var_args_expr = @vastartexpr + | @vaendexpr + | @vaargexpr + | @vacopyexpr + ; + +@builtin_op = @var_args_expr + | @noopexpr + | @offsetofexpr + | @intaddrexpr + | @hasassignexpr + | @hascopyexpr + | @hasnothrowassign + | @hasnothrowconstr + | @hasnothrowcopy + | @hastrivialassign + | @hastrivialconstr + | @hastrivialcopy + | @hastrivialdestructor + | @hasuserdestr + | @hasvirtualdestr + | @isabstractexpr + | @isbaseofexpr + | @isclassexpr + | @isconvtoexpr + | @isemptyexpr + | @isenumexpr + | @ispodexpr + | @ispolyexpr + | @isunionexpr + | @typescompexpr + | @builtinshufflevector + | @builtinconvertvector + | @builtinaddressof + | @istriviallyconstructibleexpr + | @isdestructibleexpr + | @isnothrowdestructibleexpr + | @istriviallydestructibleexpr + | @istriviallyassignableexpr + | @isnothrowassignableexpr + | @isstandardlayoutexpr + | @istriviallycopyableexpr + | @isliteraltypeexpr + | @hastrivialmoveconstructorexpr + | @hastrivialmoveassignexpr + | @hasnothrowmoveassignexpr + | @isconstructibleexpr + | @isnothrowconstructibleexpr + | @hasfinalizerexpr + | @isdelegateexpr + | @isinterfaceclassexpr + | @isrefarrayexpr + | @isrefclassexpr + | @issealedexpr + | @issimplevalueclassexpr + | @isvalueclassexpr + | @isfinalexpr + | @builtinchooseexpr + | @builtincomplex + ; + +new_allocated_type( + unique int expr: @new_expr ref, + int type_id: @type ref +); + +new_array_allocated_type( + unique int expr: @new_array_expr ref, + int type_id: @type ref +); + +/** + * The field being initialized by an initializer expression within an aggregate + * initializer for a class/struct/union. + */ +#keyset[aggregate, field] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. + */ +#keyset[aggregate, element_index] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref +); + +@ctorinit = @ctordirectinit + | @ctorvirtualinit + | @ctorfieldinit + | @ctordelegatinginit; +@dtordestruct = @dtordirectdestruct + | @dtorvirtualdestruct + | @dtorfielddestruct; + + +condition_decl_bind( + unique int expr: @condition_decl ref, + unique int decl: @declaration ref +); + +typeid_bind( + unique int expr: @type_id ref, + int type_id: @type ref +); + +uuidof_bind( + unique int expr: @uuidof ref, + int type_id: @type ref +); + +@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof; + +sizeof_bind( + unique int expr: @runtime_sizeof_or_alignof ref, + int type_id: @type ref +); + +code_block( + unique int block: @literal ref, + unique int routine: @function ref +); + +lambdas( + unique int expr: @lambdaexpr ref, + string default_capture: string ref, + boolean has_explicit_return_type: boolean ref +); + +lambda_capture( + unique int id: @lambdacapture, + int lambda: @lambdaexpr ref, + int index: int ref, + int field: @membervariable ref, + boolean captured_by_reference: boolean ref, + boolean is_implicit: boolean ref, + int location: @location_default ref +); + +@funbindexpr = @routineexpr + | @new_expr + | @delete_expr + | @delete_array_expr + | @ctordirectinit + | @ctorvirtualinit + | @ctordelegatinginit + | @dtordirectdestruct + | @dtorvirtualdestruct; + +@varbindexpr = @varaccess | @ctorfieldinit | @dtorfielddestruct; +@addressable = @function | @variable ; +@accessible = @addressable | @enumconstant ; + +@access = @varaccess | @routineexpr ; + +fold( + int expr: @foldexpr ref, + string operator: string ref, + boolean is_left_fold: boolean ref +); + +stmts( + unique int id: @stmt, + int kind: int ref, + int location: @location_stmt ref +); + +case @stmt.kind of + 1 = @stmt_expr +| 2 = @stmt_if +| 3 = @stmt_while +| 4 = @stmt_goto +| 5 = @stmt_label +| 6 = @stmt_return +| 7 = @stmt_block +| 8 = @stmt_end_test_while // do { ... } while ( ... ) +| 9 = @stmt_for +| 10 = @stmt_switch_case +| 11 = @stmt_switch +| 13 = @stmt_asm // "asm" statement or the body of an asm function +| 15 = @stmt_try_block +| 16 = @stmt_microsoft_try // Microsoft +| 17 = @stmt_decl +| 18 = @stmt_set_vla_size // C99 +| 19 = @stmt_vla_decl // C99 +| 25 = @stmt_assigned_goto // GNU +| 26 = @stmt_empty +| 27 = @stmt_continue +| 28 = @stmt_break +| 29 = @stmt_range_based_for // C++11 +// ... 30 @stmt_at_autoreleasepool_block deprecated +// ... 31 @stmt_objc_for_in deprecated +// ... 32 @stmt_at_synchronized deprecated +| 33 = @stmt_handler +// ... 34 @stmt_finally_end deprecated +| 35 = @stmt_constexpr_if +| 37 = @stmt_co_return +; + +type_vla( + int type_id: @type ref, + int decl: @stmt_vla_decl ref +); + +variable_vla( + int var: @variable ref, + int decl: @stmt_vla_decl ref +); + +if_then( + unique int if_stmt: @stmt_if ref, + int then_id: @stmt ref +); + +if_else( + unique int if_stmt: @stmt_if ref, + int else_id: @stmt ref +); + +constexpr_if_then( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int then_id: @stmt ref +); + +constexpr_if_else( + unique int constexpr_if_stmt: @stmt_constexpr_if ref, + int else_id: @stmt ref +); + +while_body( + unique int while_stmt: @stmt_while ref, + int body_id: @stmt ref +); + +do_body( + unique int do_stmt: @stmt_end_test_while ref, + int body_id: @stmt ref +); + +#keyset[switch_stmt, index] +switch_case( + int switch_stmt: @stmt_switch ref, + int index: int ref, + int case_id: @stmt_switch_case ref +); + +switch_body( + unique int switch_stmt: @stmt_switch ref, + int body_id: @stmt ref +); + +for_initialization( + unique int for_stmt: @stmt_for ref, + int init_id: @stmt ref +); + +for_condition( + unique int for_stmt: @stmt_for ref, + int condition_id: @expr ref +); + +for_update( + unique int for_stmt: @stmt_for ref, + int update_id: @expr ref +); + +for_body( + unique int for_stmt: @stmt_for ref, + int body_id: @stmt ref +); + +@stmtparent = @stmt | @expr_stmt ; +stmtparents( + unique int id: @stmt ref, + int index: int ref, + int parent: @stmtparent ref +); + +ishandler(unique int block: @stmt_block ref); + +@cfgnode = @stmt | @expr | @function | @initialiser ; + +stmt_decl_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl: @declaration ref +); + +stmt_decl_entry_bind( + int stmt: @stmt_decl ref, + int num: int ref, + int decl_entry: @element ref +); + +@functionorblock = @function | @stmt_block; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @functionorblock ref +); + +@jump = @stmt_goto | @stmt_break | @stmt_continue; + +@jumporlabel = @jump | @stmt_label | @literal; + +jumpinfo( + unique int id: @jumporlabel ref, + string str: string ref, + int target: @stmt ref +); + +preprocdirects( + unique int id: @preprocdirect, + int kind: int ref, + int location: @location_default ref +); +case @preprocdirect.kind of + 0 = @ppd_if +| 1 = @ppd_ifdef +| 2 = @ppd_ifndef +| 3 = @ppd_elif +| 4 = @ppd_else +| 5 = @ppd_endif +| 6 = @ppd_plain_include +| 7 = @ppd_define +| 8 = @ppd_undef +| 9 = @ppd_line +| 10 = @ppd_error +| 11 = @ppd_pragma +| 12 = @ppd_objc_import +| 13 = @ppd_include_next +| 18 = @ppd_warning +; + +@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next; + +@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif; + +preprocpair( + int begin : @ppd_branch ref, + int elseelifend : @preprocdirect ref +); + +preproctrue(int branch : @ppd_branch ref); +preprocfalse(int branch : @ppd_branch ref); + +preproctext( + unique int id: @preprocdirect ref, + string head: string ref, + string body: string ref +); + +includes( + unique int id: @ppd_include ref, + int included: @file ref +); + +link_targets( + unique int id: @link_target, + int binary: @file ref +); + +link_parent( + int element : @element ref, + int link_target : @link_target ref +); + +/* XML Files */ + +xmlEncoding(unique int id: @file ref, string encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters + | @xmlelement + | @xmlcomment + | @xmlattribute + | @xmldtd + | @file + | @xmlnamespace; diff --git a/cpp/upgrades/ddd31fd02e51ad270bc9e6712708e5a5b6881518/upgrade.properties b/cpp/upgrades/ddd31fd02e51ad270bc9e6712708e5a5b6881518/upgrade.properties new file mode 100644 index 00000000000..a0c4ba602a1 --- /dev/null +++ b/cpp/upgrades/ddd31fd02e51ad270bc9e6712708e5a5b6881518/upgrade.properties @@ -0,0 +1,4 @@ +description: Removed unused column from the `folders` and `files` relations +compatibility: full +files.rel: reorder files.rel (int id, string name, string simple, string ext, int fromSource) id name +folders.rel: reorder folders.rel (int id, string name, string simple) id name \ No newline at end of file diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs index 9fd505d5457..1cf1d6253a5 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs @@ -161,8 +161,11 @@ namespace Semmle.Autobuild.Shared pi.WorkingDirectory = workingDirectory; // Environment variables can only be used when not redirecting stdout - if (!redirectStandardOutput && environment is not null) - environment.ForEach(kvp => pi.Environment[kvp.Key] = kvp.Value); + if (!redirectStandardOutput) + { + if (environment is not null) + environment.ForEach(kvp => pi.Environment[kvp.Key] = kvp.Value); + } return pi; } diff --git a/csharp/change-notes/2021-09-09-service-stack-support.md b/csharp/change-notes/2021-09-09-service-stack-support.md new file mode 100644 index 00000000000..1be10e7aafb --- /dev/null +++ b/csharp/change-notes/2021-09-09-service-stack-support.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* added support for ServiceStack framework with support for SQL injection, XSS and external API calls diff --git a/csharp/documentation/library-coverage/coverage.csv b/csharp/documentation/library-coverage/coverage.csv index dbac4906d86..32137cb6d38 100644 --- a/csharp/documentation/library-coverage/coverage.csv +++ b/csharp/documentation/library-coverage/coverage.csv @@ -1,2 +1,6 @@ -package,sink,source,summary,sink:html,sink:xss,source:local,summary:taint -System,5,3,13,4,1,3,13 +package,sink,source,summary,sink:code,sink:html,sink:remote,sink:sql,sink:xss,source:local,summary:taint +Dapper,55,,,,,,55,,, +Microsoft.ApplicationBlocks.Data,28,,,,,,28,,, +MySql.Data.MySqlClient,48,,,,,,48,,, +ServiceStack,194,,7,27,,75,92,,,7 +System,28,3,13,,4,,23,1,3,13 diff --git a/csharp/documentation/library-coverage/coverage.rst b/csharp/documentation/library-coverage/coverage.rst index 568eadb4cc6..367e7a35bd2 100644 --- a/csharp/documentation/library-coverage/coverage.rst +++ b/csharp/documentation/library-coverage/coverage.rst @@ -7,6 +7,8 @@ C# framework & library support :widths: auto Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting` - System,"``System.*``, ``System``",3,13,5,5 - Totals,,3,13,5,5 + `ServiceStack `_,"``ServiceStack.*``, ``ServiceStack``",,7,194, + System,"``System.*``, ``System``",3,13,28,5 + Others,"``Dapper``, ``Microsoft.ApplicationBlocks.Data``, ``MySql.Data.MySqlClient``",,,131, + Totals,,3,20,353,5 diff --git a/csharp/documentation/library-coverage/frameworks.csv b/csharp/documentation/library-coverage/frameworks.csv index d0cc09b4e9c..6539f78b265 100644 --- a/csharp/documentation/library-coverage/frameworks.csv +++ b/csharp/documentation/library-coverage/frameworks.csv @@ -1,2 +1,3 @@ Framework name,URL,Namespace prefixes System,,System.* System +ServiceStack,https://servicestack.net/,ServiceStack.* ServiceStack diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs index c2fd6837e3e..85ced50fe7e 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs @@ -37,7 +37,7 @@ namespace Semmle.Extraction.CIL.Entities yield return parent; yield return Tuples.containerparent(parent, this); } - yield return Tuples.files(this, TransformedPath.Value, TransformedPath.NameWithoutExtension, TransformedPath.Extension); + yield return Tuples.files(this, TransformedPath.Value); } } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs index 9c3fbadcf20..e854127137d 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs @@ -28,7 +28,7 @@ namespace Semmle.Extraction.CIL.Entities yield return parentFolder; yield return Tuples.containerparent(parentFolder, this); } - yield return Tuples.folders(this, transformedPath.Value, transformedPath.NameWithoutExtension); + yield return Tuples.folders(this, transformedPath.Value); } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Tuples.cs b/csharp/extractor/Semmle.Extraction.CIL/Tuples.cs index c8ed3445c6f..d58647aba77 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Tuples.cs @@ -203,14 +203,14 @@ namespace Semmle.Extraction.CIL internal static Tuple containerparent(Folder parent, IFileOrFolder child) => new Tuple("containerparent", parent, child); - internal static Tuple files(File file, string fullName, string name, string extension) => - new Tuple("files", file, fullName, name, extension, 0); + internal static Tuple files(File file, string fullName) => + new Tuple("files", file, fullName); internal static Tuple file_extraction_mode(File file, int mode) => new Tuple("file_extraction_mode", file, mode); - internal static Tuple folders(Folder folder, string path, string name) => - new Tuple("folders", folder, path, name); + internal static Tuple folders(Folder folder, string path) => + new Tuple("folders", folder, path); internal static Tuple locations_default(PdbSourceLocation label, File file, int startLine, int startCol, int endLine, int endCol) => new Tuple("locations_default", label, file, startLine, startCol, endLine, endCol); diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs b/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs index e8a42b3f5a0..047a8ddb8ae 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs @@ -1,3 +1,7 @@ +using System; +using System.Text.RegularExpressions; +using System.Collections.Generic; + namespace Semmle.Extraction.CSharp { /// @@ -9,6 +13,31 @@ namespace Semmle.Extraction.CSharp { Extractor.SetInvariantCulture(); + Console.WriteLine($"Semmle.Extraction.CSharp.Driver: called with {string.Join(", ", args)}"); + + if (args.Length > 0 && args[0] == "--dotnetexec") + { + var compilerRegEx = new Regex(@"csc\.exe|mcs\.exe|csc\.dll", RegexOptions.Compiled); + var cil = args.Length > 1 && args[1] == "--cil"; + for (var i = cil ? 2 : 1; i < args.Length; i++) + { + if (compilerRegEx.IsMatch(args[i])) + { + var argsList = new List(); + if (cil) + argsList.Add("--cil"); + argsList.Add("--compiler"); + argsList.Add(args[i]); + if (i + 1 < args.Length) + argsList.AddRange(args[(i + 1)..]); + return (int)Extractor.Run(argsList.ToArray()); + } + } + + Console.WriteLine($"Semmle.Extraction.CSharp.Driver: not a compiler invocation"); + return 0; + } + return (int)Extractor.Run(args); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/File.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/File.cs index f22edb158aa..fae77b033ad 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/File.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/File.cs @@ -17,7 +17,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void Populate(TextWriter trapFile) { - trapFile.files(this, TransformedPath.Value, TransformedPath.NameWithoutExtension, TransformedPath.Extension); + trapFile.files(this, TransformedPath.Value); if (TransformedPath.ParentDirectory is PathTransformer.ITransformedPath dir) trapFile.containerparent(Extraction.Entities.Folder.Create(Context, dir), this); diff --git a/csharp/extractor/Semmle.Extraction/Entities/Folder.cs b/csharp/extractor/Semmle.Extraction/Entities/Folder.cs index 2826ab49ed1..465d545d983 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Folder.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/Folder.cs @@ -8,7 +8,7 @@ namespace Semmle.Extraction.Entities public override void Populate(TextWriter trapFile) { - trapFile.folders(this, Symbol.Value, Symbol.NameWithoutExtension); + trapFile.folders(this, Symbol.Value); if (Symbol.ParentDirectory is PathTransformer.ITransformedPath parent) trapFile.containerparent(Create(Context, parent), this); } diff --git a/csharp/extractor/Semmle.Extraction/Entities/GeneratedFile.cs b/csharp/extractor/Semmle.Extraction/Entities/GeneratedFile.cs index 7c0e5df7be9..b4a771f53db 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/GeneratedFile.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/GeneratedFile.cs @@ -10,7 +10,7 @@ namespace Semmle.Extraction.Entities public override void Populate(TextWriter trapFile) { - trapFile.files(this, "", "", ""); + trapFile.files(this, ""); } public override void WriteId(EscapingTextWriter trapFile) diff --git a/csharp/extractor/Semmle.Extraction/Tuples.cs b/csharp/extractor/Semmle.Extraction/Tuples.cs index 49c14df7643..2cff4bfbdf1 100644 --- a/csharp/extractor/Semmle.Extraction/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction/Tuples.cs @@ -18,14 +18,14 @@ namespace Semmle.Extraction trapFile.WriteTuple("extractor_messages", error, (int)severity, origin, errorMessage, entityText, location, stackTrace); } - public static void files(this System.IO.TextWriter trapFile, File file, string fullName, string name, string extension) + public static void files(this System.IO.TextWriter trapFile, File file, string fullName) { - trapFile.WriteTuple("files", file, fullName, name, extension, 0); + trapFile.WriteTuple("files", file, fullName); } - internal static void folders(this System.IO.TextWriter trapFile, Folder folder, string path, string name) + internal static void folders(this System.IO.TextWriter trapFile, Folder folder, string path) { - trapFile.WriteTuple("folders", folder, path, name); + trapFile.WriteTuple("folders", folder, path); } public static void locations_default(this System.IO.TextWriter trapFile, SourceLocation label, Entities.File file, int startLine, int startCol, int endLine, int endCol) diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml index b760898bf7c..43ea66c228e 100644 --- a/csharp/ql/lib/qlpack.yml +++ b/csharp/ql/lib/qlpack.yml @@ -1,7 +1,6 @@ name: codeql/csharp-all version: 0.0.2 dbscheme: semmlecode.csharp.dbscheme -suites: codeql-suites extractor: csharp library: true dependencies: diff --git a/csharp/ql/lib/semmle/code/csharp/File.qll b/csharp/ql/lib/semmle/code/csharp/File.qll index d8b23bb61f4..8ee61b29085 100644 --- a/csharp/ql/lib/semmle/code/csharp/File.qll +++ b/csharp/ql/lib/semmle/code/csharp/File.qll @@ -171,14 +171,14 @@ class Container extends @container { /** A folder. */ class Folder extends Container, @folder { - override string getAbsolutePath() { folders(this, result, _) } + override string getAbsolutePath() { folders(this, result) } override string getURL() { result = "folder://" + getAbsolutePath() } } /** A file. */ class File extends Container, @file { - override string getAbsolutePath() { files(this, result, _, _, _) } + override string getAbsolutePath() { files(this, result) } /** Gets the number of lines in this file. */ int getNumberOfLines() { numlines(this, result, _, _) } @@ -192,7 +192,7 @@ class File extends Container, @file { override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } /** Holds if this file contains source code. */ - predicate fromSource() { files(this, _, _, "cs", _) } + predicate fromSource() { this.getExtension() = "cs" } /** Holds if this file is a library. */ predicate fromLibrary() { diff --git a/csharp/ql/lib/semmle/code/csharp/Unification.qll b/csharp/ql/lib/semmle/code/csharp/Unification.qll index 73f739a1f7b..173feedb695 100644 --- a/csharp/ql/lib/semmle/code/csharp/Unification.qll +++ b/csharp/ql/lib/semmle/code/csharp/Unification.qll @@ -17,7 +17,7 @@ module Gvn { string getNameNested(Type t) { if not t instanceof NestedType or t.(NestedType).getDeclaringType() instanceof GenericType then result = t.getName() - else result = getNameNested(t.(NestedType).getDeclaringType()) + "." + t.getName() + else result = getNameNested(t.(NestedType).getDeclaringType()) + "+" + t.getName() } /** @@ -326,79 +326,53 @@ module Gvn { getTypeArgument(k, t, i) = TTypeParameterGvnType() } - /** - * Hold if (non-type-parameters) `arg1` and `arg2` are unifiable, and both are - * the `i`th type argument of a compound type of kind `k`. - */ - pragma[nomagic] - private predicate unifiableNonTypeParameterTypeArguments( - CompoundTypeKind k, GvnTypeArgument arg1, GvnTypeArgument arg2, int i - ) { - exists(int j | - arg1 = getNonTypeParameterTypeArgument(k, _, i) and - arg2 = getNonTypeParameterTypeArgument(k, _, j) and - i <= j and - j <= i - | - arg1 = arg2 - or - unifiable(arg1, arg2) - ) - } - /** * Hold if `arg1` and `arg2` are unifiable, and both are the `i`th type argument * of a compound type of kind `k`. + * + * `subsumes` indicates whether `arg1` in fact subsumes `arg2`. */ pragma[nomagic] private predicate unifiableTypeArguments( - CompoundTypeKind k, GvnTypeArgument arg1, GvnTypeArgument arg2, int i + CompoundTypeKind k, GvnTypeArgument arg1, GvnTypeArgument arg2, int i, boolean subsumes ) { - unifiableNonTypeParameterTypeArguments(k, arg1, arg2, i) - or - exists(int j | - arg1 = TTypeParameterGvnType() and - typeArgumentIsTypeParameter(k, _, i) and - arg2 = getTypeArgument(k, _, j) and - i <= j and - j <= i + arg1 = getNonTypeParameterTypeArgument(k, _, pragma[only_bind_into](i)) and + arg2 = getNonTypeParameterTypeArgument(k, _, pragma[only_bind_into](i)) and + ( + arg1 = arg2 and + subsumes = true + or + unifiable(arg1, arg2, subsumes) ) or - exists(int j | - arg1 = getTypeArgument(k, _, i) and - typeArgumentIsTypeParameter(k, _, j) and - arg2 = TTypeParameterGvnType() and - i <= j and - j <= i - ) + arg1 = TTypeParameterGvnType() and + typeArgumentIsTypeParameter(k, _, pragma[only_bind_into](i)) and + arg2 = getTypeArgument(k, _, pragma[only_bind_into](i)) and + subsumes = true + or + arg1 = getNonTypeParameterTypeArgument(k, _, pragma[only_bind_into](i)) and + typeArgumentIsTypeParameter(k, _, pragma[only_bind_into](i)) and + arg2 = TTypeParameterGvnType() and + subsumes = false } pragma[nomagic] private predicate unifiableSingle0( - CompoundTypeKind k, ConstructedGvnType t2, GvnTypeArgument arg1, GvnTypeArgument arg2 + CompoundTypeKind k, ConstructedGvnType t2, GvnTypeArgument arg1, GvnTypeArgument arg2, + boolean subsumes ) { - unifiableTypeArguments(k, arg1, arg2, 0) and + unifiableTypeArguments(k, arg1, arg2, 0, subsumes) and arg2 = getTypeArgument(k, t2, 0) and k.getNumberOfTypeParameters() = 1 } - /** - * Holds if the type arguments of types `t1` and `t2` are unifiable, `t1` - * and `t2` are of the same kind, and the number of type arguments is 1. - */ - private predicate unifiableSingle(ConstructedGvnType t1, ConstructedGvnType t2) { - exists(CompoundTypeKind k, GvnTypeArgument arg1, GvnTypeArgument arg2 | - unifiableSingle0(k, t2, arg1, arg2) and - arg1 = getTypeArgument(k, t1, 0) - ) - } - pragma[nomagic] private predicate unifiableMultiple01Aux0( - CompoundTypeKind k, ConstructedGvnType t2, GvnTypeArgument arg10, GvnTypeArgument arg21 + CompoundTypeKind k, ConstructedGvnType t2, GvnTypeArgument arg10, GvnTypeArgument arg21, + boolean subsumes ) { exists(GvnTypeArgument arg20 | - unifiableTypeArguments(k, arg10, arg20, 0) and + unifiableTypeArguments(k, arg10, arg20, 0, subsumes) and arg20 = getTypeArgument(k, t2, 0) and arg21 = getTypeArgument(k, t2, 1) ) @@ -406,43 +380,24 @@ module Gvn { pragma[nomagic] private predicate unifiableMultiple01Aux1( - CompoundTypeKind k, ConstructedGvnType t1, GvnTypeArgument arg10, GvnTypeArgument arg21 + CompoundTypeKind k, ConstructedGvnType t1, GvnTypeArgument arg10, GvnTypeArgument arg21, + boolean subsumes ) { exists(GvnTypeArgument arg11 | - unifiableTypeArguments(k, arg11, arg21, 1) and + unifiableTypeArguments(k, arg11, arg21, 1, subsumes) and arg10 = getTypeArgument(k, t1, 0) and arg11 = getTypeArgument(k, t1, 1) ) } - /** - * Holds if the first two type arguments of types `t1` and `t2` are unifiable, - * and both `t1` and `t2` are of kind `k`. - */ - private predicate unifiableMultiple01( - CompoundTypeKind k, ConstructedGvnType t1, ConstructedGvnType t2 - ) { - exists(GvnTypeArgument arg10, GvnTypeArgument arg21 | - unifiableMultiple01Aux0(k, t2, arg10, arg21) and - unifiableMultiple01Aux1(k, t1, arg10, arg21) - ) - } - pragma[nomagic] private predicate unifiableMultiple2Aux( - CompoundTypeKind k, ConstructedGvnType t2, int i, GvnTypeArgument arg1, GvnTypeArgument arg2 + CompoundTypeKind k, ConstructedGvnType t2, int i, GvnTypeArgument arg1, boolean subsumes ) { - unifiableTypeArguments(k, arg1, arg2, i) and - arg2 = getTypeArgument(k, t2, i) and - i >= 2 - } - - private predicate unifiableMultiple2( - CompoundTypeKind k, ConstructedGvnType t1, ConstructedGvnType t2, int i - ) { - exists(GvnTypeArgument arg1, GvnTypeArgument arg2 | - unifiableMultiple2Aux(k, t2, i, arg1, arg2) and - arg1 = getTypeArgument(k, t1, i) + exists(GvnTypeArgument arg2 | + unifiableTypeArguments(k, arg1, arg2, i, subsumes) and + arg2 = getTypeArgument(k, t2, i) and + i >= 2 ) } @@ -452,43 +407,33 @@ module Gvn { */ pragma[nomagic] private predicate unifiableMultiple( - CompoundTypeKind k, ConstructedGvnType t1, ConstructedGvnType t2, int i + CompoundTypeKind k, ConstructedGvnType t1, ConstructedGvnType t2, int i, boolean subsumes ) { - unifiableMultiple01(k, t1, t2) and i = 1 + exists(GvnTypeArgument arg10, GvnTypeArgument arg21, boolean subsumes1, boolean subsumes2 | + unifiableMultiple01Aux0(k, t2, arg10, arg21, subsumes1) and + unifiableMultiple01Aux1(k, t1, arg10, arg21, subsumes2) and + subsumes = subsumes1.booleanAnd(subsumes2) + ) and + i = 1 or - unifiableMultiple(k, t1, t2, i - 1) and - unifiableMultiple2(k, t1, t2, i) - } - - private newtype TTypePath = - TTypePathNil() or - TTypePathCons(int head, TTypePath tail) { exists(getTypeAtCons(_, head, tail)) } - - /** - * Gets the GVN inside GVN `t`, by following the path `path`, if any. - */ - private GvnType getTypeAt(GvnType t, TTypePath path) { - path = TTypePathNil() and - result = t - or - exists(ConstructedGvnTypeList l, int head, TTypePath tail | - t = TConstructedGvnType(l) and - path = TTypePathCons(head, tail) and - result = getTypeAtCons(l, head, tail) + exists(GvnTypeArgument arg1, boolean subsumes1, boolean subsumes2 | + unifiableMultiple(k, t1, t2, i - 1, subsumes1) and + unifiableMultiple2Aux(k, t2, i, arg1, subsumes2) and + arg1 = getTypeArgument(k, t1, i) and + subsumes = subsumes1.booleanAnd(subsumes2) ) } - private GvnType getTypeAtCons(ConstructedGvnTypeList l, int head, TTypePath tail) { - result = getTypeAt(l.getArg(head), tail) - } - - /** - * Gets the leaf GVN inside GVN `t`, by following the path `path`, if any. - */ - pragma[noinline] - private GvnType getLeafTypeAt(GvnType t, TTypePath path) { - result = getTypeAt(t, path) and - not result instanceof ConstructedGvnType + pragma[nomagic] + private predicate unifiable(ConstructedGvnType t1, ConstructedGvnType t2, boolean subsumes) { + exists(CompoundTypeKind k, GvnTypeArgument arg1, GvnTypeArgument arg2 | + unifiableSingle0(k, t2, arg1, arg2, subsumes) and + arg1 = getTypeArgument(k, t1, 0) + ) + or + exists(CompoundTypeKind k | + unifiableMultiple(k, t1, t2, k.getNumberOfTypeParameters() - 1, subsumes) + ) } cached @@ -540,33 +485,20 @@ module Gvn { } /** - * Holds if GVNs `t1` and `t2` can be unified. That is, is it possible to + * Holds if GVNs `t1` and `t2` can be unified. That is, it is possible to * replace all type parameters in `t1` and `t2` with some GVNs (possibly * type parameters themselves) to make the two substituted terms equal. */ cached - predicate unifiable(ConstructedGvnType t1, ConstructedGvnType t2) { - unifiableSingle(t1, t2) - or - exists(CompoundTypeKind k | unifiableMultiple(k, t1, t2, k.getNumberOfTypeParameters() - 1)) - } + predicate unifiable(ConstructedGvnType t1, ConstructedGvnType t2) { unifiable(t1, t2, _) } /** - * Holds if GVN `t1` subsumes GVN `t2`. That is, is it possible to replace all + * Holds if GVN `t1` subsumes GVN `t2`. That is, it is possible to replace all * type parameters in `t1` with some GVNs (possibly type parameters themselves) * to make the two substituted terms equal. */ cached - predicate subsumes(ConstructedGvnType t1, ConstructedGvnType t2) { - unifiable(t1, t2) and // subsumption implies unification - forall(TTypePath path, GvnType leaf1 | leaf1 = getLeafTypeAt(t1, path) | - exists(GvnType child2 | child2 = getTypeAt(t2, path) | - leaf1 = TTypeParameterGvnType() - or - leaf1 = child2 - ) - ) - } + predicate subsumes(ConstructedGvnType t1, ConstructedGvnType t2) { unifiable(t1, t2, true) } } import Cached diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll index f36e00403c1..c7140238213 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll @@ -88,6 +88,9 @@ private module Frameworks { private import semmle.code.csharp.security.dataflow.flowsinks.Html private import semmle.code.csharp.frameworks.System private import semmle.code.csharp.security.dataflow.XSSSinks + private import semmle.code.csharp.frameworks.ServiceStack + private import semmle.code.csharp.frameworks.Sql + private import semmle.code.csharp.frameworks.EntityFramework } /** diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 8597b5755f0..0c99a25ccc4 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -3639,9 +3643,10 @@ private module Subpaths { PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, apout) and + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, + unbindConf(arg.getConfiguration())) } /** @@ -3686,8 +3691,8 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | - arg.getASuccessor() = par and - arg.getASuccessor() = out and + pragma[only_bind_into](arg).getASuccessor() = par and + pragma[only_bind_into](arg).getASuccessor() = out and subpaths03(arg, p, ret, o, apout) and par.getNodeEx() = p and out.getNodeEx() = o and diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 8597b5755f0..0c99a25ccc4 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -3639,9 +3643,10 @@ private module Subpaths { PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, apout) and + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, + unbindConf(arg.getConfiguration())) } /** @@ -3686,8 +3691,8 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | - arg.getASuccessor() = par and - arg.getASuccessor() = out and + pragma[only_bind_into](arg).getASuccessor() = par and + pragma[only_bind_into](arg).getASuccessor() = out and subpaths03(arg, p, ret, o, apout) and par.getNodeEx() = p and out.getNodeEx() = o and diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 8597b5755f0..0c99a25ccc4 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -3639,9 +3643,10 @@ private module Subpaths { PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, apout) and + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, + unbindConf(arg.getConfiguration())) } /** @@ -3686,8 +3691,8 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | - arg.getASuccessor() = par and - arg.getASuccessor() = out and + pragma[only_bind_into](arg).getASuccessor() = par and + pragma[only_bind_into](arg).getASuccessor() = out and subpaths03(arg, p, ret, o, apout) and par.getNodeEx() = p and out.getNodeEx() = o and diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 8597b5755f0..0c99a25ccc4 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -3639,9 +3643,10 @@ private module Subpaths { PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, apout) and + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, + unbindConf(arg.getConfiguration())) } /** @@ -3686,8 +3691,8 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | - arg.getASuccessor() = par and - arg.getASuccessor() = out and + pragma[only_bind_into](arg).getASuccessor() = par and + pragma[only_bind_into](arg).getASuccessor() = out and subpaths03(arg, p, ret, o, apout) and par.getNodeEx() = p and out.getNodeEx() = o and diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 8597b5755f0..0c99a25ccc4 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -3639,9 +3643,10 @@ private module Subpaths { PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, apout) and + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, + unbindConf(arg.getConfiguration())) } /** @@ -3686,8 +3691,8 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | - arg.getASuccessor() = par and - arg.getASuccessor() = out and + pragma[only_bind_into](arg).getASuccessor() = par and + pragma[only_bind_into](arg).getASuccessor() = out and subpaths03(arg, p, ret, o, apout) and par.getNodeEx() = p and out.getNodeEx() = o and diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll index 728f7b56c42..f588a25a176 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -786,13 +786,18 @@ private module Cached { } /** - * Holds if the call context `call` either improves virtual dispatch in - * `callable` or if it allows us to prune unreachable nodes in `callable`. + * Holds if the call context `call` improves virtual dispatch in `callable`. */ cached - predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + predicate recordDataFlowCallSiteDispatch(DataFlowCall call, DataFlowCallable callable) { reducedViableImplInCallContext(_, callable, call) - or + } + + /** + * Holds if the call context `call` allows us to prune unreachable nodes in `callable`. + */ + cached + predicate recordDataFlowCallSiteUnreachable(DataFlowCall call, DataFlowCallable callable) { exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call)) } @@ -846,6 +851,15 @@ private module Cached { TAccessPathFrontSome(AccessPathFront apf) } +/** + * Holds if the call context `call` either improves virtual dispatch in + * `callable` or if it allows us to prune unreachable nodes in `callable`. + */ +predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + recordDataFlowCallSiteDispatch(call, callable) or + recordDataFlowCallSiteUnreachable(call, callable) +} + /** * A `Node` at which a cast can occur such that the type should be checked. */ diff --git a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll index 80066392c1c..d0b4ef45ce8 100644 --- a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll +++ b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll @@ -508,7 +508,7 @@ private module Internal { override RuntimeCallable getADynamicTarget() { result = getAViableInherited() or - result = getAViableOverrider() and strictcount(getAViableOverrider()) < 1000 + result = getAViableOverrider() or // Simple case: target method cannot be overridden result = getAStaticTarget() and diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/EntityFramework.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/EntityFramework.qll index 29939efccdb..36882d3b12e 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/EntityFramework.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/EntityFramework.qll @@ -9,6 +9,7 @@ private import semmle.code.csharp.frameworks.system.data.Entity private import semmle.code.csharp.frameworks.system.collections.Generic private import semmle.code.csharp.frameworks.Sql private import semmle.code.csharp.dataflow.FlowSummary +private import semmle.code.csharp.dataflow.ExternalFlow private import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate /** @@ -234,26 +235,29 @@ module EntityFramework { override Expr getSql() { result = this.getArgumentForParameter(sqlParam) } } - /** A call to `System.Data.Entity.DbSet.SqlQuery`. */ - class SystemDataEntityDbSetSqlExpr extends SqlExpr, MethodCall { - SystemDataEntityDbSetSqlExpr() { - this.getTarget() = any(SystemDataEntity::DbSet dbSet).getSqlQueryMethod() + /** The sink method `System.Data.Entity.DbSet.SqlQuery`. */ + private class SystemDataEntityDbSetSqlQuerySinkModelCsv extends SinkModelCsv { + override predicate row(string row) { + row = + ["System.Data.Entity;DbSet;false;SqlQuery;(System.String,System.Object[]);;Argument[0];sql"] } - - override Expr getSql() { result = this.getArgumentForName("sql") } } - /** A call to a method in `System.Data.Entity.Database` that executes SQL. */ - class SystemDataEntityDatabaseSqlExpr extends SqlExpr, MethodCall { - SystemDataEntityDatabaseSqlExpr() { - exists(SystemDataEntity::Database db | - this.getTarget() = db.getSqlQueryMethod() or - this.getTarget() = db.getExecuteSqlCommandMethod() or - this.getTarget() = db.getExecuteSqlCommandAsyncMethod() - ) + /** A sink method in `System.Data.Entity.Database` that executes SQL. */ + private class SystemDataEntityDatabaseSinkModelCsv extends SinkModelCsv { + override predicate row(string row) { + row = + [ + "System.Data.Entity;Database;false;SqlQuery;(System.Type,System.String,System.Object[]);;Argument[1];sql", + "System.Data.Entity;Database;false;SqlQuery<>;(System.String,System.Object[]);;Argument[0];sql", + "System.Data.Entity;Database;false;ExecuteSqlCommand;(System.String,System.Object[]);;Argument[0];sql", + "System.Data.Entity;Database;false;ExecuteSqlCommand;(System.Data.Entity.TransactionalBehavior,System.String,System.Object[]);;Argument[1];sql", + "System.Data.Entity;Database;false;ExecuteSqlCommandAsync;(System.Data.Entity.TransactionalBehavior,System.String,System.Threading.CancellationToken,System.Object[]);;Argument[1];sql", + "System.Data.Entity;Database;false;ExecuteSqlCommandAsync;(System.String,System.Threading.CancellationToken,System.Object[]);;Argument[0];sql", + "System.Data.Entity;Database;false;ExecuteSqlCommandAsync;(System.String,System.Object[]);;Argument[0];sql", + "System.Data.Entity;Database;false;ExecuteSqlCommandAsync;(System.Data.Entity.TransactionalBehavior,System.String,System.Object[]);;Argument[1];sql" + ] } - - override Expr getSql() { result = this.getArgumentForName("sql") } } /** Holds if `t` is compatible with a DB column type. */ diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/ServiceStack.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/ServiceStack.qll new file mode 100644 index 00000000000..6604597d9bc --- /dev/null +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/ServiceStack.qll @@ -0,0 +1,321 @@ +/** + * General modelling of ServiceStack framework including separate modules for: + * - flow sources + * - SQLi sinks + * - XSS sinks + */ + +import csharp +private import semmle.code.csharp.dataflow.ExternalFlow + +/** A class representing a Service */ +private class ServiceClass extends Class { + ServiceClass() { + this.getBaseClass+().hasQualifiedName("ServiceStack", "Service") or + this.getABaseType*().getABaseInterface().hasQualifiedName("ServiceStack", "IService") + } + + /** Get a method that handles incoming requests */ + Method getARequestMethod() { + exists(string name | + result = this.getAMethod(name) and + name.regexpMatch("(Get|Post|Put|Delete|Any|Option|Head|Patch)(Async|Json|Xml|Jsv|Csv|Html|Protobuf|Msgpack|Wire)?") + ) + } +} + +/** Top-level Request DTO types */ +private class RequestDTO extends Class { + RequestDTO() { + this.getABaseType*().getABaseInterface().hasQualifiedName("ServiceStack", "IReturn") + } +} + +/** Flow sources for the ServiceStack framework */ +module Sources { + private import semmle.code.csharp.security.dataflow.flowsources.Remote + + /** + * Remote flow sources for ServiceStack. Parameters of well-known `request` methods. + */ + private class ServiceStackSource extends RemoteFlowSource { + ServiceStackSource() { + exists(ServiceClass service | + service.getARequestMethod().getAParameter() = this.asParameter() + ) + } + + override string getSourceType() { result = "ServiceStack request parameter" } + } +} + +private class ServiceStackRemoteSinkModelCsv extends SinkModelCsv { + override predicate row(string row) { + row = + [ + // IRestClient + "ServiceStack;IRestClient;true;Send<>;(System.String,System.String,System.Object);;Argument[2];remote", + "ServiceStack;IRestClient;true;Patch<>;(System.String,System.Object);;Argument[1];remote", + "ServiceStack;IRestClient;true;Post<>;(System.String,System.Object);;Argument[1];remote", + "ServiceStack;IRestClient;true;Put<>;(System.String,System.Object);;Argument[1];remote", + // IRestClientSync + "ServiceStack;IRestClientSync;true;CustomMethod;(System.String,ServiceStack.IReturnVoid);;Argument[1];remote", + "ServiceStack;IRestClientSync;true;CustomMethod<>;(System.String,System.Object);;Argument[1];remote", + "ServiceStack;IRestClientSync;true;CustomMethod<>;(System.String,ServiceStack.IReturn);;Argument[1];remote", + "ServiceStack;IRestClientSync;true;Delete;(ServiceStack.IReturnVoid);;Argument[0];remote", + "ServiceStack;IRestClientSync;true;Delete<>;(System.Object);;Argument[0];remote", + "ServiceStack;IRestClientSync;true;Delete<>;(ServiceStack.IReturn);;Argument[0];remote", + "ServiceStack;IRestClientSync;true;Get;(ServiceStack.IReturnVoid);;Argument[0];remote", + "ServiceStack;IRestClientSync;true;Get<>;(System.Object);;Argument[0];remote", + "ServiceStack;IRestClientSync;true;Get<>;(ServiceStack.IReturn);;Argument[0];remote", + "ServiceStack;IRestClientSync;true;Patch;(ServiceStack.IReturnVoid);;Argument[0];remote", + "ServiceStack;IRestClientSync;true;Patch<>;(System.Object);;Argument[0];remote", + "ServiceStack;IRestClientSync;true;Patch<>;(ServiceStack.IReturn);;Argument[0];remote", + "ServiceStack;IRestClientSync;true;Post;(ServiceStack.IReturnVoid);;Argument[0];remote", + "ServiceStack;IRestClientSync;true;Post<>;(System.Object);;Argument[0];remote", + "ServiceStack;IRestClientSync;true;Post<>;(ServiceStack.IReturn);;Argument[0];remote", + "ServiceStack;IRestClientSync;true;Put;(ServiceStack.IReturnVoid);;Argument[0];remote", + "ServiceStack;IRestClientSync;true;Put<>;(System.Object);;Argument[0];remote", + "ServiceStack;IRestClientSync;true;Put<>;(ServiceStack.IReturn);;Argument[0];remote", + // IRestGateway + "ServiceStack;IRestGateway;true;Delete<>;(ServiceStack.IReturn);;Argument[0];remote", + "ServiceStack;IRestGateway;true;Get<>;(ServiceStack.IReturn);;Argument[0];remote", + "ServiceStack;IRestGateway;true;Post<>;(ServiceStack.IReturn);;Argument[0];remote", + "ServiceStack;IRestGateway;true;Put<>;(ServiceStack.IReturn);;Argument[0];remote", + "ServiceStack;IRestGateway;true;Send<>;(ServiceStack.IReturn);;Argument[0];remote", + // IOneWayClient + "ServiceStack;IOneWayClient;true;SendAllOneWay;(System.Collections.Generic.IEnumerable);;Element of Argument[1];remote", + "ServiceStack;IOneWayClient;true;SendOneWay;(System.String,System.Object);;Argument[1];remote", + "ServiceStack;IOneWayClient;true;SendOneWay;(System.Object);;Argument[0];remote", + // IServiceGateway + "ServiceStack;IServiceGateway;true;Publish;(System.Object);;Argument[0];remote", + "ServiceStack;IServiceGateway;true;PublishAll;(System.Collections.Generic.IEnumerable);;Element of Argument[0];remote", + "ServiceStack;IServiceGateway;true;Send<>;(System.Object);;Argument[0];remote", + "ServiceStack;IServiceGateway;true;SendAll<>;(System.Collections.Generic.IEnumerable);;Element of Argument[0];remote", + // IRestClientAsync + "ServiceStack;IRestClientAsync;true;CustomMethodAsync;(System.String,ServiceStack.IReturnVoid,System.Threading.CancellationToken);;Argument[1];remote", + "ServiceStack;IRestClientAsync;true;CustomMethodAsync<>;(System.String,System.Object,System.Threading.CancellationToken);;Argument[1];remote", + "ServiceStack;IRestClientAsync;true;CustomMethodAsync<>;(System.String,ServiceStack.IReturn,System.Threading.CancellationToken);;Argument[1];remote", + "ServiceStack;IRestClientAsync;true;DeleteAsync;(ServiceStack.IReturnVoid,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IRestClientAsync;true;DeleteAsync<>;(System.Object,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IRestClientAsync;true;DeleteAsync<>;(ServiceStack.IReturn,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IRestClientAsync;true;GetAsync;(ServiceStack.IReturnVoid,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IRestClientAsync;true;GetAsync<>;(System.Object,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IRestClientAsync;true;GetAsync<>;(ServiceStack.IReturn,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IRestClientAsync;true;PatchAsync;(ServiceStack.IReturnVoid,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IRestClientAsync;true;PatchAsync<>;(System.Object,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IRestClientAsync;true;PatchAsync<>;(ServiceStack.IReturn,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IRestClientAsync;true;PostAsync;(ServiceStack.IReturnVoid,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IRestClientAsync;true;PostAsync<>;(System.Object,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IRestClientAsync;true;PostAsync<>;(ServiceStack.IReturn,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IRestClientAsync;true;PutAsync;(ServiceStack.IReturnVoid,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IRestClientAsync;true;PutAsync<>;(System.Object,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IRestClientAsync;true;PutAsync<>;(ServiceStack.IReturn,System.Threading.CancellationToken);;Argument[0];remote", + // IRestGatewayAsync + "ServiceStack;IRestGatewayAsync;true;DeleteAsync<>;(ServiceStack.IReturn,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IRestGatewayAsync;true;GetAsync<>;(ServiceStack.IReturn,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IRestGatewayAsync;true;PostAsync<>;(ServiceStack.IReturn,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IRestGatewayAsync;true;PutAsync<>;(ServiceStack.IReturn,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IRestGatewayAsync;true;SendAsync<>;(ServiceStack.IReturn,System.Threading.CancellationToken);;Argument[0];remote", + // IServiceGatewayAsync + "ServiceStack;IServiceGatewayAsync;true;PublishAsync;(System.Object,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IServiceGatewayAsync;true;PublishAllAsync;(System.Collections.Generic.IEnumerable,System.Threading.CancellationToken);;Element of Argument[0];remote", + "ServiceStack;IServiceGatewayAsync;true;SendAsync<>;(System.Object,System.Threading.CancellationToken);;Argument[0];remote", + "ServiceStack;IServiceGatewayAsync;true;SendAllAsync<>;(System.Collections.Generic.IEnumerable,System.Threading.CancellationToken);;Element of Argument[0];remote", + // ServiceClientBase + "ServiceStack;ServiceClientBase;true;Publish<>;(T);;Argument[0];remote", + "ServiceStack;ServiceClientBase;true;Publish<>;(ServiceStack.Messaging.IMessage);;Argument[0];remote", + "ServiceStack;ServiceClientBase;true;Delete;(System.Object);;Argument[0];remote", + "ServiceStack;ServiceClientBase;true;Get;(System.Object);;Argument[0];remote", + "ServiceStack;ServiceClientBase;true;Patch;(System.Object);;Argument[0];remote", + "ServiceStack;ServiceClientBase;true;Post;(System.Object);;Argument[0];remote", + "ServiceStack;ServiceClientBase;true;Put;(System.Object);;Argument[0];remote", + "ServiceStack;ServiceClientBase;true;Head;(System.Object);;Argument[0];remote", + "ServiceStack;ServiceClientBase;true;Head;(ServiceStack.IReturn);;Argument[0];remote", + "ServiceStack;ServiceClientBase;true;CustomMethod;(System.String,System.String,System.Object);;Argument[2];remote", + "ServiceStack;ServiceClientBase;true;CustomMethod<>;(System.String,System.String,System.Object);;Argument[2];remote", + "ServiceStack;ServiceClientBase;true;CustomMethodAsync<>;(System.String,System.String,System.Object,System.Threading.CancellationToken);;Argument[2];remote", + "ServiceStack;ServiceClientBase;true;DownloadBytes;(System.String,System.String,System.Object);;Argument[2];remote", + "ServiceStack;ServiceClientBase;true;DownloadBytesAsync;(System.String,System.String,System.Object);;Argument[2];remote" + ] + } +} + +private class ServiceStackSqlSinkModelCsv extends SinkModelCsv { + override predicate row(string row) { + row = + [ + // SqlExpression + "ServiceStack.OrmLite;SqlExpression<>;true;UnsafeAnd;(System.String,System.Object[]);;Argument[0];sql", + "ServiceStack.OrmLite;SqlExpression<>;true;UnsafeFrom;(System.String);;Argument[0];sql", + "ServiceStack.OrmLite;SqlExpression<>;true;UnsafeGroupBy;(System.String);;Argument[0];sql", + "ServiceStack.OrmLite;SqlExpression<>;true;UnsafeHaving;(System.String,System.Object[]);;Argument[0];sql", + "ServiceStack.OrmLite;SqlExpression<>;true;UnsafeOr;(System.String,System.Object[]);;Argument[0];sql", + "ServiceStack.OrmLite;SqlExpression<>;true;UnsafeOrderBy;(System.String);;Argument[0];sql", + "ServiceStack.OrmLite;SqlExpression<>;true;UnsafeSelect;(System.String,System.Boolean);;Argument[0];sql", + "ServiceStack.OrmLite;SqlExpression<>;true;UnsafeSelect;(System.String);;Argument[0];sql", + "ServiceStack.OrmLite;SqlExpression<>;true;UnsafeWhere;(System.String,System.Object[]);;Argument[0];sql", + // IUntypedSqlExpression + "ServiceStack.OrmLite;IUntypedSqlExpression;true;UnsafeAnd;(System.String,System.Object[]);;Argument[0];sql", + "ServiceStack.OrmLite;IUntypedSqlExpression;true;UnsafeFrom;(System.String);;Argument[0];sql", + "ServiceStack.OrmLite;IUntypedSqlExpression;true;UnsafeOr;(System.String,System.Object[]);;Argument[0];sql", + "ServiceStack.OrmLite;IUntypedSqlExpression;true;UnsafeSelect;(System.String);;Argument[0];sql", + "ServiceStack.OrmLite;IUntypedSqlExpression;true;UnsafeWhere;(System.String,System.Object[]);;Argument[0];sql", + // OrmLiteReadApi + "ServiceStack.OrmLite;OrmLiteReadApi;false;ExecuteNonQuery;(System.Data.IDbConnection,System.String);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;ExecuteNonQuery;(System.Data.IDbConnection,System.String,System.Object);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;ExecuteNonQuery;(System.Data.IDbConnection,System.String,System.Action);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;ExecuteNonQuery;(System.Data.IDbConnection,System.String,System.Collections.Generic.Dictionary);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;Exists<>;(System.Data.IDbConnection,System.String,System.Object);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;Dictionary<,>;(System.Data.IDbConnection,System.String,System.Object);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;Lookup<,>;(System.Data.IDbConnection,System.String,System.Object);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;Lookup<,>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;KeyValuePairs;(System.Data.IDbConnection,System.String,System.System.Object);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;Scalar<>;(System.Data.IDbConnection,System.String,System.Object);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;Scalar<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;Select<>;(System.Data.IDbConnection,System.Type,System.String,System.Object);;Argument[2];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;Select<>;(System.Data.IDbConnection,System.String);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;Select<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.Dictionary);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;Select<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;Select<>;(System.Data.IDbConnection,System.String,System.Object);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;SelectLazy<>;(System.Data.IDbConnection,System.String,System.Object);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;SelectNonDefaults<>;(System.Data.IDbConnection,System.String,T);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;Single<>;(System.Data.IDbConnection,System.String,System.Object);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;Single<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;SqlColumn<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.Dictionary);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;SqlColumn<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;SqlColumn<>;(System.Data.IDbConnection,System.String,System.Object);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;SqlList<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.Dictionary);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;SqlList<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;SqlList<>;(System.Data.IDbConnection,System.String,System.Object);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;SqlList<>;(System.Data.IDbConnection,System.String,System.Action);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;SqlScalar<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.Dictionary);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;SqlScalar<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;SqlScalar<>;(System.Data.IDbConnection,System.String,System.Object);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;Column<>;(System.Data.IDbConnection,System.String,System.Object);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;Column<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;ColumnDistinct<>;(System.Data.IDbConnection,System.String,System.Object);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;ColumnDistinct<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;ColumnLazy<>;(System.Data.IDbConnection,System.String,System.Object);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApi;false;ColumnLazy<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable);;Argument[1];sql", + // OrmLiteReadExpressionsApi + "ServiceStack.OrmLite;OrmLiteReadExpressionsApi;false;RowCount;(System.Data.IDbConnection,System.String,System.Object);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadExpressionsApi;false;RowCount;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable);;Argument[1];sql", + // OrmLiteReadExpressionsApiAsync + "ServiceStack.OrmLite;OrmLiteReadExpressionsApiAsync;false;RowCountAsync;(System.Data.IDbConnection,System.String,System.Object,System.Threading.CancellationToken);;Argument[1];sql", + // OrmLiteReadApiAsync + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;ColumnAsync<>;(System.Data.IDbConnection,System.String,System.Object,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;ColumnAsync<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;ColumnDistinctAsync<>;(System.Data.IDbConnection,System.String,System.Object,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;ColumnDistinctAsync<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;DictionaryAsync<,>;(System.Data.IDbConnection,System.String,System.Object,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;ExecuteNonQueryAsync;(System.Data.IDbConnection,System.String,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;ExecuteNonQueryAsync;(System.Data.IDbConnection,System.String,System.Object,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;ExecuteNonQueryAsync;(System.Data.IDbConnection,System.String,System.Collections.Generic.Dictionary,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;ExistsAsync<>;(System.Data.IDbConnection,System.String,System.Object,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;KeyValuePairsAsync<,>;(System.Data.IDbConnection,System.String,System.Object,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;KeyValuePairsAsync<,>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;LookupAsync<,>;(System.Data.IDbConnection,System.String,System.Object,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;LookupAsync<,>;(System.Data.IDbCommand,System.String,System.Collections.Generic.IEnumerable,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;LookupAsync<,>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;ScalarAsync<>;(System.Data.IDbConnection,System.String,System.Object,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;ScalarAsync<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;SelectAsync<>;(System.Data.IDbConnection,System.Type,System.String,System.Object,System.Threading.CancellationToken);;Argument[2];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;SelectAsync<>;(System.Data.IDbConnection,System.String,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;SelectAsync<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.Dictionary,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;SelectAsync<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;SelectAsync<>;(System.Data.IDbConnection,System.String,System.Object,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;SelectNonDefaultsAsync<>;(System.Data.IDbConnection,System.String,T,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;SingleAsync<>;(System.Data.IDbConnection,System.String,System.Object,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;SingleAsync<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;SqlColumnAsync<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.Dictionary,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;SqlColumnAsync<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;SqlColumnAsync<>;(System.Data.IDbConnection,System.String,System.Object,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;SqlListAsync<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.Dictionary,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;SqlListAsync<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;SqlListAsync<>;(System.Data.IDbConnection,System.String,System.Object,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;SqlListAsync<>;(System.Data.IDbConnection,System.String,System.Action,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;SqlScalarAsync<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.Dictionary,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;SqlScalarAsync<>;(System.Data.IDbConnection,System.String,System.Collections.Generic.IEnumerable,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteReadApiAsync;false;SqlScalarAsync<>;(System.Data.IDbConnection,System.String,System.Object,System.Threading.CancellationToken);;Argument[1];sql", + // Write API + "ServiceStack.OrmLite;OrmLiteWriteApi;false;ExecuteSql;(System.Data.IDbConnection,System.String);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteWriteApi;false;ExecuteSql;(System.Data.IDbConnection,System.String,System.Object);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteWriteApi;false;ExecuteSql;(System.Data.IDbConnection,System.String,System.Collections.Generic.Dictionary);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteWriteApiAsync;false;ExecuteSqlAsync;(System.Data.IDbConnection,System.String,System.Threading.CancellationToken);;Argument[1];sql", + "ServiceStack.OrmLite;OrmLiteWriteApiAsync;false;ExecuteSqlAsync;(System.Data.IDbConnection,System.String,System.Object,System.Threading.CancellationToken);;Argument[1];sql" + ] + } +} + +private class ServiceStackCodeInjectionSinkModelCsv extends SinkModelCsv { + override predicate row(string row) { + row = + [ + // Redis API + "ServiceStack.Redis;IRedisClient;true;Custom;(System.Object[]);;Argument[0];code", + "ServiceStack.Redis;IRedisClient;true;ExecCachedLua;(System.String,System.Func);;Argument[0];code", + "ServiceStack.Redis;IRedisClient;true;ExecLua;(System.String,System.String[],System.String[]);;Argument[0];code", + "ServiceStack.Redis;IRedisClient;true;ExecLua;(System.String,System.String[]);;Argument[0];code", + "ServiceStack.Redis;IRedisClient;true;ExecLuaAsInt;(System.String,System.String[],System.String[]);;Argument[0];code", + "ServiceStack.Redis;IRedisClient;true;ExecLuaAsInt;(System.String,System.String[]);;Argument[0];code", + "ServiceStack.Redis;IRedisClient;true;ExecLuaAsList;(System.String,System.String[],System.String[]);;Argument[0];code", + "ServiceStack.Redis;IRedisClient;true;ExecLuaAsList;(System.String,System.String[]);;Argument[0];code", + "ServiceStack.Redis;IRedisClient;true;ExecLuaAsString;(System.String,System.String[],System.String[]);;Argument[0];code", + "ServiceStack.Redis;IRedisClient;true;ExecLuaAsString;(System.String,System.String[]);;Argument[0];code", + "ServiceStack.Redis;IRedisClient;true;LoadLuaScript;(System.String);;Argument[0];code", + // IRedisClientAsync + "ServiceStack.Redis;IRedisClientAsync;true;CustomAsync;(System.Object[]);;Argument[0];code", + "ServiceStack.Redis;IRedisClientAsync;true;CustomAsync;(System.Object[],System.Threading.CancellationToken);;Element of Argument[0];code", + "ServiceStack.Redis;IRedisClientAsync;true;ExecCachedLuaAsync;(System.String,System.Func>,System.Threading.CancellationToken);;Argument[0];code", + "ServiceStack.Redis;IRedisClientAsync;true;ExecLuaAsync;(System.String,System.String[],System.String[],System.Threading.CancellationToken);;Argument[0];code", + "ServiceStack.Redis;IRedisClientAsync;true;ExecLuaAsync;(System.String,System.String[],System.Threading.CancellationToken);;Argument[0];code", + "ServiceStack.Redis;IRedisClientAsync;true;ExecLuaAsync;(System.String,System.String[]);;Argument[0];code", + "ServiceStack.Redis;IRedisClientAsync;true;ExecLuaAsIntAsync;(System.String,System.String[],System.String[],System.Threading.CancellationToken);;Argument[0];code", + "ServiceStack.Redis;IRedisClientAsync;true;ExecLuaAsIntAsync;(System.String,System.String[],System.Threading.CancellationToken);;Argument[0];code", + "ServiceStack.Redis;IRedisClientAsync;true;ExecLuaAsIntAsync;(System.String,System.String[]);;Argument[0];code", + "ServiceStack.Redis;IRedisClientAsync;true;ExecLuaAsStringAsync;(System.String,System.String[],System.String[],System.Threading.CancellationToken);;Argument[0];code", + "ServiceStack.Redis;IRedisClientAsync;true;ExecLuaAsStringAsync;(System.String,System.String[],System.Threading.CancellationToken);;Argument[0];code", + "ServiceStack.Redis;IRedisClientAsync;true;ExecLuaAsStringAsync;(System.String,System.String[]);;Argument[0];code", + "ServiceStack.Redis;IRedisClientAsync;true;ExecLuaAsListAsync;(System.String,System.String[],System.String[],System.Threading.CancellationToken);;Argument[0];code", + "ServiceStack.Redis;IRedisClientAsync;true;ExecLuaAsListAsync;(System.String,System.String[],System.Threading.CancellationToken);;Argument[0];code", + "ServiceStack.Redis;IRedisClientAsync;true;ExecLuaAsListAsync;(System.String,System.String[]);;Argument[0];code", + "ServiceStack.Redis;IRedisClientAsync;true;LoadLuaScriptAsync;(System.String,System.Threading.CancellationToken);;Argument[0];code" + ] + } +} + +private class ServiceStackXssSummaryModelCsv extends SummaryModelCsv { + override predicate row(string row) { + row = + [ + "ServiceStack;HttpResult;false;HttpResult;(System.String,System.String);;Argument[0];ReturnValue;taint", + "ServiceStack;HttpResult;false;HttpResult;(System.Object,System.String,System.Net.HttpStatusCode);;Argument[0];ReturnValue;taint", + "ServiceStack;HttpResult;false;HttpResult;(System.Object,System.String);;Argument[0];ReturnValue;taint", + "ServiceStack;HttpResult;false;HttpResult;(System.Object,System.Net.HttpStatusCode);;Argument[0];ReturnValue;taint", + "ServiceStack;HttpResult;false;HttpResult;(System.Object);;Argument[0];ReturnValue;taint", + "ServiceStack;HttpResult;false;HttpResult;(System.IO.Stream,System.String);;Argument[0];ReturnValue;taint", + "ServiceStack;HttpResult;false;HttpResult;(System.Byte[],System.String);;Argument[0];ReturnValue;taint" + ] + } +} + +/** XSS support for ServiceStack framework */ +module XSS { + private import semmle.code.csharp.security.dataflow.XSSSinks + + /** XSS sinks for ServiceStack */ + class XssSink extends Sink { + XssSink() { + exists(ServiceClass service, Method m, Expr e | + service.getARequestMethod() = m and + this.asExpr() = e and + m.canReturn(e) and + ( + e.getType() instanceof StringType or + e.getType().hasQualifiedName("ServiceStack", "HttpResult") + ) + ) + } + } +} diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/Sql.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/Sql.qll index 1a727030bea..78975527af6 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/Sql.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/Sql.qll @@ -7,6 +7,7 @@ private import semmle.code.csharp.frameworks.EntityFramework private import semmle.code.csharp.frameworks.NHibernate private import semmle.code.csharp.frameworks.Dapper private import semmle.code.csharp.dataflow.DataFlow4 +private import semmle.code.csharp.dataflow.ExternalFlow /** An expression containing a SQL command. */ abstract class SqlExpr extends Expr { @@ -28,71 +29,236 @@ class CommandTextAssignmentSqlExpr extends SqlExpr, AssignExpr { override Expr getSql() { result = this.getRValue() } } -/** A construction of an `IDbCommand` object. */ +/** A construction of an unknown `IDbCommand` object. */ class IDbCommandConstructionSqlExpr extends SqlExpr, ObjectCreation { IDbCommandConstructionSqlExpr() { exists(InstanceConstructor ic | ic = this.getTarget() | ic.getDeclaringType().getABaseType*() instanceof SystemDataIDbCommandInterface and - ic.getParameter(0).getType() instanceof StringType + ic.getParameter(0).getType() instanceof StringType and + not ic.getDeclaringType() + .hasQualifiedName([ + // Known sealed classes: + "System.Data.SqlClient.SqlCommand", "System.Data.Odbc.OdbcCommand", + "System.Data.OleDb.OleDbCommand", "System.Data.EntityClient.EntityCommand" + ]) ) } override Expr getSql() { result = this.getArgument(0) } } +/** A construction of a known `IDbCommand` object. */ +private class IDbCommandConstructionSinkModelCsv extends SinkModelCsv { + override predicate row(string row) { + row = + [ + // SqlCommand + "System.Data.SqlClient;SqlCommand;false;SqlCommand;(System.String);;Argument[0];sql", + "System.Data.SqlClient;SqlCommand;false;SqlCommand;(System.String,System.Data.SqlClient.SqlConnection);;Argument[0];sql", + "System.Data.SqlClient;SqlCommand;false;SqlCommand;(System.String,System.Data.SqlClient.SqlConnection,System.Data.SqlClient.SqlTransaction);;Argument[0];sql", + // OdbcCommand + "System.Data.Odbc;OdbcCommand;false;OdbcCommand;(System.String);;Argument[0];sql", + "System.Data.Odbc;OdbcCommand;false;OdbcCommand;(System.String,System.Data.Odbc.OdbcConnection);;Argument[0];sql", + "System.Data.Odbc;OdbcCommand;false;OdbcCommand;(System.String,System.Data.Odbc.OdbcConnection,System.Data.Odbc.OdbcTransaction);;Argument[0];sql", + // OleDbCommand + "System.Data.OleDb;OleDbCommand;false;OleDbCommand;(System.String);;Argument[0];sql", + "System.Data.OleDb;OleDbCommand;false;OleDbCommand;(System.String,System.Data.OleDb.OleDbConnection);;Argument[0];sql", + "System.Data.OleDb;OleDbCommand;false;OleDbCommand;(System.String,System.Data.OleDb.OleDbConnection,System.Data.OleDb.OleDbTransaction);;Argument[0];sql", + // EntityCommand + "System.Data.EntityClient;EntityCommand;false;EntityCommand;(System.String);;Argument[0];sql", + "System.Data.EntityClient;EntityCommand;false;EntityCommand;(System.String,System.Data.EntityClient.EntityConnection);;Argument[0];sql", + "System.Data.EntityClient;EntityCommand;false;EntityCommand;(System.String,System.Data.EntityClient.EntityConnection,System.Data.EntityClient.EntityTransaction);;Argument[0];sql" + ] + } +} + /** A construction of an `SqlDataAdapter` object. */ -class SqlDataAdapterConstructionSqlExpr extends SqlExpr, ObjectCreation { - SqlDataAdapterConstructionSqlExpr() { - exists(InstanceConstructor ic | - ic = this.getTarget() and - ic.getDeclaringType() instanceof SystemDataSqlClientSqlDataAdapterClass and - ic.getParameter(0).getType() instanceof StringType - ) +private class SqlDataAdapterConstructionSinkModelCsv extends SinkModelCsv { + override predicate row(string row) { + row = + [ + "System.Data.SqlClient;SqlDataAdapter;false;SqlDataAdapter;(System.String,System.String);;Argument[0];sql", + "System.Data.SqlClient;SqlDataAdapter;false;SqlDataAdapter;(System.String,System.Data.SqlClient.SqlConnection);;Argument[0];sql" + ] } - - override Expr getSql() { result = this.getArgument(0) } } /** A `MySql.Data.MySqlClient.MySqlHelper` method. */ -class MySqlHelperMethodCallSqlExpr extends SqlExpr, MethodCall { - MySqlHelperMethodCallSqlExpr() { - this.getQualifier().getType().(Class).hasQualifiedName("MySql.Data.MySqlClient", "MySqlHelper") - } - - override Expr getSql() { - exists(int i | - result = getArgument(i) and - this.getTarget().getParameter(i).hasName("commandText") and - this.getTarget().getParameter(i).getType() instanceof StringType - ) +private class MySqlHelperMethodCallSinkModelCsv extends SinkModelCsv { + override predicate row(string row) { + row = + [ + // ExecuteDataRow/Async + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteDataRow;(System.String,System.String,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteDataRowAsync;(System.String,System.String,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteDataRowAsync;(System.String,System.String,System.Threading.CancellationToken,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + // ExecuteDataset + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteDataset;(System.String,System.String);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteDataset;(System.String,System.String,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteDataset;(MySql.Data.MySqlClient.MySqlConnection,System.String);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteDataset;(MySql.Data.MySqlClient.MySqlConnection,System.String,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + // ExecuteDatasetAsync + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteDatasetAsync;(System.String,System.String);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteDatasetAsync;(System.String,System.String,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteDatasetAsync;(System.String,System.String,System.Threading.CancellationToken);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteDatasetAsync;(System.String,System.String,System.Threading.CancellationToken,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteDatasetAsync;(MySql.Data.MySqlClient.MySqlConnection,System.String);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteDatasetAsync;(MySql.Data.MySqlClient.MySqlConnection,System.String,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteDatasetAsync;(MySql.Data.MySqlClient.MySqlConnection,System.String,System.Threading.CancellationToken);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteDatasetAsync;(MySql.Data.MySqlClient.MySqlConnection,System.String,System.Threading.CancellationToken,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + // ExecuteNonQuery + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteNonQuery;(System.String,System.String,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteNonQuery;(MySql.Data.MySqlClient.MySqlConnection,System.String,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + // ExecuteNonQueryAsync + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteNonQueryAsync;(System.String,System.String,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteNonQueryAsync;(System.String,System.String,System.Threading.CancellationToken,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteNonQueryAsync;(MySql.Data.MySqlClient.MySqlConnection,System.String,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteNonQueryAsync;(MySql.Data.MySqlClient.MySqlConnection,System.String,System.Threading.CancellationToken,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + // ExecuteReader + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteReader;(System.String,System.String);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteReader;(System.String,System.String,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteReader;(MySql.Data.MySqlClient.MySqlConnection,System.String);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteReader;(MySql.Data.MySqlClient.MySqlConnection,System.String,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + // ExecuteReaderAsync + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteReaderAsync;(System.String,System.String);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteReaderAsync;(System.String,System.String,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteReaderAsync;(System.String,System.String,System.Threading.CancellationToken);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteReaderAsync;(System.String,System.String,System.Threading.CancellationToken,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteReaderAsync;(MySql.Data.MySqlClient.MySqlConnection,System.String);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteReaderAsync;(MySql.Data.MySqlClient.MySqlConnection,System.String,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteReaderAsync;(MySql.Data.MySqlClient.MySqlConnection,System.String,System.Threading.CancellationToken);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteReaderAsync;(MySql.Data.MySqlClient.MySqlConnection,System.String,System.Threading.CancellationToken,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + // ExecuteScalar + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteScalar;(System.String,System.String);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteScalar;(System.String,System.String,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteScalar;(MySql.Data.MySqlClient.MySqlConnection,System.String);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteScalar;(MySql.Data.MySqlClient.MySqlConnection,System.String,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + // ExecuteScalarAsync + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteScalarAsync;(System.String,System.String);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteScalarAsync;(System.String,System.String,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteScalarAsync;(System.String,System.String,System.Threading.CancellationToken);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteScalarAsync;(System.String,System.String,System.Threading.CancellationToken,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteScalarAsync;(MySql.Data.MySqlClient.MySqlConnection,System.String);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteScalarAsync;(MySql.Data.MySqlClient.MySqlConnection,System.String,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteScalarAsync;(MySql.Data.MySqlClient.MySqlConnection,System.String,System.Threading.CancellationToken);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;ExecuteScalarAsync;(MySql.Data.MySqlClient.MySqlConnection,System.String,System.Threading.CancellationToken,MySql.Data.MySqlClient.MySqlParameter[]);;Argument[1];sql", + // UpdateDataset/Async + "MySql.Data.MySqlClient;MySqlHelper;false;UpdateDataset;(System.String,System.String,System.Data.DataSet,System.String);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;UpdateDatasetAsync;(System.String,System.String,System.Data.DataSet,System.String);;Argument[1];sql", + "MySql.Data.MySqlClient;MySqlHelper;false;UpdateDatasetAsync;(System.String,System.String,System.Data.DataSet,System.String,System.Threading.CancellationToken);;Argument[1];sql" + ] } } /** A `Microsoft.ApplicationBlocks.Data.SqlHelper` method. */ -class MicrosoftSqlHelperMethodCallSqlExpr extends SqlExpr, MethodCall { - MicrosoftSqlHelperMethodCallSqlExpr() { - this.getQualifier() - .getType() - .(Class) - .hasQualifiedName("Microsoft.ApplicationBlocks.Data", "SqlHelper") - } - - override Expr getSql() { - exists(int i | - result = getArgument(i) and - this.getTarget().getParameter(i).hasName("commandText") and - this.getTarget().getParameter(i).getType() instanceof StringType - ) +private class MicrosoftSqlHelperSinkModelCsv extends SinkModelCsv { + override predicate row(string row) { + row = + [ + // ExecuteNonQuery + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteNonQuery;(System.String,System.Data.CommandType,System.String);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteNonQuery;(System.String,System.Data.CommandType,System.String,System.Data.SqlClient.SqlParameter[]);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteNonQuery;(System.Data.SqlClient.SqlConnection,System.Data.CommandType,System.String);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteNonQuery;(System.Data.SqlClient.SqlConnection,System.Data.CommandType,System.String,System.Data.SqlClient.SqlParameter[]);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteNonQuery;(System.Data.SqlClient.SqlTransaction,System.Data.CommandType,System.String);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteNonQuery;(System.Data.SqlClient.SqlTransaction,System.Data.CommandType,System.String,System.Data.SqlClient.SqlParameter[]);;Argument[2];sql", + // ExecuteDataset + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteDataset;(System.String,System.Data.CommandType,System.String);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteDataset;(System.String,System.Data.CommandType,System.String,System.Data.SqlClient.SqlParameter[]);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteDataset;(System.Data.SqlClient.SqlConnection,System.Data.CommandType,System.String);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteDataset;(System.Data.SqlClient.SqlConnection,System.Data.CommandType,System.String,System.Data.SqlClient.SqlParameter[]);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteDataset;(System.Data.SqlClient.SqlTransaction,System.Data.CommandType,System.String);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteDataset;(System.Data.SqlClient.SqlTransaction,System.Data.CommandType,System.String,System.Data.SqlClient.SqlParameter[]);;Argument[2];sql", + // ExecuteReader + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteReader;(System.String,System.Data.CommandType,System.String);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteReader;(System.String,System.Data.CommandType,System.String,System.Data.SqlClient.SqlParameter[]);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteReader;(System.Data.SqlClient.SqlConnection,System.Data.CommandType,System.String);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteReader;(System.Data.SqlClient.SqlConnection,System.Data.CommandType,System.String,System.Data.SqlClient.SqlParameter[]);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteReader;(System.Data.SqlClient.SqlTransaction,System.Data.CommandType,System.String);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteReader;(System.Data.SqlClient.SqlTransaction,System.Data.CommandType,System.String,System.Data.SqlClient.SqlParameter[]);;Argument[2];sql", + // ExecuteScalar + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteScalar;(System.String,System.Data.CommandType,System.String);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteScalar;(System.String,System.Data.CommandType,System.String,System.Data.SqlClient.SqlParameter[]);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteScalar;(System.Data.SqlClient.SqlConnection,System.Data.CommandType,System.String);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteScalar;(System.Data.SqlClient.SqlConnection,System.Data.CommandType,System.String,System.Data.SqlClient.SqlParameter[]);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteScalar;(System.Data.SqlClient.SqlTransaction,System.Data.CommandType,System.String);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteScalar;(System.Data.SqlClient.SqlTransaction,System.Data.CommandType,System.String,System.Data.SqlClient.SqlParameter[]);;Argument[2];sql", + // ExecuteXmlReader + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteXmlReader;(System.Data.SqlClient.SqlConnection,System.Data.CommandType,System.String);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteXmlReader;(System.Data.SqlClient.SqlConnection,System.Data.CommandType,System.String,System.Data.SqlClient.SqlParameter[]);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteXmlReader;(System.Data.SqlClient.SqlTransaction,System.Data.CommandType,System.String);;Argument[2];sql", + "Microsoft.ApplicationBlocks.Data;SqlHelper;false;ExecuteXmlReader;(System.Data.SqlClient.SqlTransaction,System.Data.CommandType,System.String,System.Data.SqlClient.SqlParameter[]);;Argument[2];sql" + ] } } /** A `Dapper.SqlMapper` method that is taking a SQL string argument. */ -class DapperSqlMethodCallSqlExpr extends SqlExpr, MethodCall { - DapperSqlMethodCallSqlExpr() { - this.getTarget() = any(Dapper::SqlMapperClass c).getAQueryMethod() +private class DapperSqlMapperSinkModelCsv extends SinkModelCsv { + override predicate row(string row) { + row = + [ + // Execute* + "Dapper;SqlMapper;false;Execute;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;ExecuteAsync;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;ExecuteScalar;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;ExecuteScalarAsync;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;ExecuteScalar<>;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;ExecuteScalarAsync<>;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;ExecuteReader;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;ExecuteReaderAsync;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;ExecuteReaderAsync;(System.Data.DbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + // Query* + "Dapper;SqlMapper;false;Query;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Boolean,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QueryAsync;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;Query<>;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Boolean,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QueryAsync<>;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QueryMultiple;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QueryMultipleAsync;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QueryFirst;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QueryFirstAsync;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QueryFirst<>;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QueryFirstAsync<>;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QueryFirstOrDefault;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QueryFirstOrDefaultAsync;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QueryFirstOrDefault<>;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QueryFirstOrDefaultAsync<>;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QuerySingle;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QuerySingleAsync;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QuerySingle<>;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QuerySingleAsync<>;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QuerySingleOrDefault;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QuerySingleOrDefaultAsync;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QuerySingleOrDefault<>;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QuerySingleOrDefaultAsync<>;(System.Data.IDbConnection,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[1];sql", + // Query* with System.Type parameter + "Dapper;SqlMapper;false;Query;(System.Data.IDbConnection,System.Type,System.String,System.Object,System.Data.IDbTransaction,System.Boolean,System.Nullable,System.Nullable);;Argument[2];sql", + "Dapper;SqlMapper;false;QueryAsync;(System.Data.IDbConnection,System.Type,System.String,System.Object,System.Data.IDbTransaction,System.Boolean,System.Nullable,System.Nullable);;Argument[2];sql", + "Dapper;SqlMapper;false;QueryFirst;(System.Data.IDbConnection,System.Type,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[2];sql", + "Dapper;SqlMapper;false;QueryFirstAsync;(System.Data.IDbConnection,System.Type,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[2];sql", + "Dapper;SqlMapper;false;QueryFirstOrDefault;(System.Data.IDbConnection,System.Type,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[2];sql", + "Dapper;SqlMapper;false;QueryFirstOrDefaultAsync;(System.Data.IDbConnection,System.Type,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[2];sql", + "Dapper;SqlMapper;false;QuerySingle;(System.Data.IDbConnection,System.Type,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[2];sql", + "Dapper;SqlMapper;false;QuerySingleAsync;(System.Data.IDbConnection,System.Type,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[2];sql", + "Dapper;SqlMapper;false;QuerySingleOrDefault;(System.Data.IDbConnection,System.Type,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[2];sql", + "Dapper;SqlMapper;false;QuerySingleOrDefaultAsync;(System.Data.IDbConnection,System.Type,System.String,System.Object,System.Data.IDbTransaction,System.Nullable,System.Nullable);;Argument[2];sql", + // Query with multiple type parameters + "Dapper;SqlMapper;false;Query<,,>;(System.Data.IDbConnection,System.String,System.Func,System.Object,System.Data.IDbTransaction,System.Boolean,System.String,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QueryAsync<,,>;(System.Data.IDbConnection,System.String,System.Func,System.Object,System.Data.IDbTransaction,System.Boolean,System.String,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;Query<,,,>;(System.Data.IDbConnection,System.String,System.Func,System.Object,System.Data.IDbTransaction,System.Boolean,System.String,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QueryAsync<,,,>;(System.Data.IDbConnection,System.String,System.Func,System.Object,System.Data.IDbTransaction,System.Boolean,System.String,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;Query<,,,,>;(System.Data.IDbConnection,System.String,System.Func,System.Object,System.Data.IDbTransaction,System.Boolean,System.String,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QueryAsync<,,,,>;(System.Data.IDbConnection,System.String,System.Func,System.Object,System.Data.IDbTransaction,System.Boolean,System.String,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;Query<,,,,,>;(System.Data.IDbConnection,System.String,System.Func,System.Object,System.Data.IDbTransaction,System.Boolean,System.String,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QueryAsync<,,,,,>;(System.Data.IDbConnection,System.String,System.Func,System.Object,System.Data.IDbTransaction,System.Boolean,System.String,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;Query<,,,,,,>;(System.Data.IDbConnection,System.String,System.Func,System.Object,System.Data.IDbTransaction,System.Boolean,System.String,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QueryAsync<,,,,,,>;(System.Data.IDbConnection,System.String,System.Func,System.Object,System.Data.IDbTransaction,System.Boolean,System.String,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;Query<,,,,,,,>;(System.Data.IDbConnection,System.String,System.Func,System.Object,System.Data.IDbTransaction,System.Boolean,System.String,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QueryAsync<,,,,,,,>;(System.Data.IDbConnection,System.String,System.Func,System.Object,System.Data.IDbTransaction,System.Boolean,System.String,System.Nullable,System.Nullable);;Argument[1];sql", + // Query with System.Type[] parameter + "Dapper;SqlMapper;false;Query<>;(System.Data.IDbConnection,System.String,System.Type[],System.Func,System.Object,System.Data.IDbTransaction,System.Boolean,System.String,System.Nullable,System.Nullable);;Argument[1];sql", + "Dapper;SqlMapper;false;QueryAsync<>;(System.Data.IDbConnection,System.String,System.Type[],System.Func,System.Object,System.Data.IDbTransaction,System.Boolean,System.String,System.Nullable,System.Nullable);;Argument[1];sql" + ] } - - override Expr getSql() { result = this.getArgumentForName("sql") } } /** A `Dapper.CommandDefinition` creation that is taking a SQL string argument and is passed to a `Dapper.SqlMapper` method. */ diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/CodeInjectionQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/CodeInjectionQuery.qll index 39254fe6072..758fbf50b16 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/CodeInjectionQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/CodeInjectionQuery.qll @@ -7,6 +7,7 @@ private import semmle.code.csharp.security.dataflow.flowsources.Remote private import semmle.code.csharp.security.dataflow.flowsources.Local private import semmle.code.csharp.frameworks.system.codedom.Compiler private import semmle.code.csharp.security.Sanitizers +private import semmle.code.csharp.dataflow.ExternalFlow /** * A data flow source for user input treated as code vulnerabilities. @@ -79,3 +80,8 @@ class RoslynCSharpScriptSink extends Sink { ) } } + +/** Code injection sinks defined through CSV models. */ +private class ExternalCodeInjectionExprSink extends Sink { + ExternalCodeInjectionExprSink() { sinkNode(this, "code") } +} diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/SqlInjectionQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/SqlInjectionQuery.qll index 37b2d7fd7c3..f4184a391b9 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/SqlInjectionQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/SqlInjectionQuery.qll @@ -7,6 +7,7 @@ private import semmle.code.csharp.security.dataflow.flowsources.Remote private import semmle.code.csharp.security.dataflow.flowsources.Local private import semmle.code.csharp.frameworks.Sql private import semmle.code.csharp.security.Sanitizers +private import semmle.code.csharp.dataflow.ExternalFlow /** * A source specific to SQL injection vulnerabilities. @@ -51,6 +52,11 @@ class SqlInjectionExprSink extends Sink { SqlInjectionExprSink() { exists(SqlExpr s | this.getExpr() = s.getSql()) } } +/** SQL sinks defined through CSV models. */ +private class ExternalSqlInjectionExprSink extends Sink { + ExternalSqlInjectionExprSink() { sinkNode(this, "sql") } +} + private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { } private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { } diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSQuery.qll index 055726a7bc3..a216ce5e9d2 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSQuery.qll @@ -62,6 +62,16 @@ module PathGraph { key = "semmle.label" and val = n.(XssAspNode).toString() } + + /** + * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through + * a subpath between `par` and `ret` with the connecting edges `arg -> par` and + * `ret -> out` is summarized as the edge `arg -> out`. + */ + query predicate subpaths(XssNode arg, XssNode par, XssNode ret, XssNode out) { + DataFlow2::PathGraph::subpaths(arg.asDataFlowNode(), par.asDataFlowNode(), ret.asDataFlowNode(), + out.asDataFlowNode()) + } } private newtype TXssNode = diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSSinks.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSSinks.qll index 3d3858d974a..4be005be4de 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSSinks.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSSinks.qll @@ -10,6 +10,7 @@ private import semmle.code.csharp.frameworks.system.web.UI private import semmle.code.csharp.security.dataflow.flowsinks.Html private import semmle.code.csharp.security.dataflow.flowsinks.Remote private import semmle.code.csharp.dataflow.ExternalFlow +private import semmle.code.csharp.frameworks.ServiceStack::XSS /** * A data flow sink for cross-site scripting (XSS) vulnerabilities. diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll index 25a50f3733c..673473eb49b 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll @@ -6,6 +6,7 @@ import csharp private import Remote private import semmle.code.csharp.commons.Loggers private import semmle.code.csharp.frameworks.system.Web +private import semmle.code.csharp.dataflow.ExternalFlow /** * An external location sink. @@ -16,6 +17,10 @@ private import semmle.code.csharp.frameworks.system.Web */ abstract class ExternalLocationSink extends DataFlow::ExprNode { } +private class ExternalModelSink extends ExternalLocationSink { + ExternalModelSink() { sinkNode(this, "remote") } +} + /** * An argument to a call to a method on a logger class. */ diff --git a/csharp/ql/lib/semmlecode.csharp.dbscheme b/csharp/ql/lib/semmlecode.csharp.dbscheme index 0f562410898..73b4f980116 100644 --- a/csharp/ql/lib/semmlecode.csharp.dbscheme +++ b/csharp/ql/lib/semmlecode.csharp.dbscheme @@ -276,22 +276,13 @@ assemblies( string name: string ref, string version: string ref); -/* - fromSource(0) = unknown, - fromSource(1) = from source, - fromSource(2) = from library -*/ files( unique int id: @file, - string name: string ref, - string simple: string ref, - string ext: string ref, - int fromSource: int ref); + string name: string ref); folders( unique int id: @folder, - string name: string ref, - string simple: string ref); + string name: string ref); @container = @folder | @file ; diff --git a/csharp/ql/lib/semmlecode.csharp.dbscheme.stats b/csharp/ql/lib/semmlecode.csharp.dbscheme.stats index f1fbd130ff8..a192af2bce3 100644 --- a/csharp/ql/lib/semmlecode.csharp.dbscheme.stats +++ b/csharp/ql/lib/semmlecode.csharp.dbscheme.stats @@ -11522,18 +11522,6 @@ name 47336 - -simple -26591 - - -ext -43 - - -fromSource -4 - @@ -11553,54 +11541,6 @@ -id -simple - - -12 - - -1 -2 -47336 - - - - - - -id -ext - - -12 - - -1 -2 -47336 - - - - - - -id -fromSource - - -12 - - -1 -2 -47336 - - - - - - name id @@ -11616,376 +11556,6 @@ - -name -simple - - -12 - - -1 -2 -47336 - - - - - - -name -ext - - -12 - - -1 -2 -47336 - - - - - - -name -fromSource - - -12 - - -1 -2 -47336 - - - - - - -simple -id - - -12 - - -1 -2 -24857 - - -2 -154 -1734 - - - - - - -simple -name - - -12 - - -1 -2 -24857 - - -2 -154 -1734 - - - - - - -simple -ext - - -12 - - -1 -2 -25597 - - -2 -5 -994 - - - - - - -simple -fromSource - - -12 - - -1 -2 -26591 - - - - - - -ext -id - - -12 - - -1 -2 -4 - - -2 -3 -4 - - -6 -7 -4 - - -166 -167 -4 - - -173 -174 -4 - - -861 -862 -4 - - -995 -996 -4 - - -2875 -2876 -4 - - -4635 -4636 -4 - - - - - - -ext -name - - -12 - - -1 -2 -4 - - -2 -3 -4 - - -6 -7 -4 - - -166 -167 -4 - - -173 -174 -4 - - -861 -862 -4 - - -995 -996 -4 - - -2875 -2876 -4 - - -4635 -4636 -4 - - - - - - -ext -simple - - -12 - - -1 -2 -4 - - -2 -3 -9 - - -166 -167 -4 - - -169 -170 -4 - - -214 -215 -4 - - -650 -651 -4 - - -790 -791 -4 - - -3818 -3819 -4 - - - - - - -ext -fromSource - - -12 - - -1 -2 -43 - - - - - - -fromSource -id - - -12 - - -9714 -9715 -4 - - - - - - -fromSource -name - - -12 - - -9714 -9715 -4 - - - - - - -fromSource -simple - - -12 - - -5457 -5458 -4 - - - - - - -fromSource -ext - - -12 - - -9 -10 -4 - - - - - @@ -12000,10 +11570,6 @@ name 15622 - -simple -2777 - @@ -12023,22 +11589,6 @@ -id -simple - - -12 - - -1 -2 -17839 - - - - - - name id @@ -12054,99 +11604,6 @@ - -name -simple - - -12 - - -1 -2 -13405 - - -2 -3 -2217 - - - - - - -simple -id - - -12 - - -1 -2 -1637 - - -2 -3 -540 - - -3 -4 -209 - - -4 -10 -209 - - -10 -383 -180 - - - - - - -simple -name - - -12 - - -1 -2 -1637 - - -2 -3 -540 - - -3 -4 -209 - - -4 -10 -209 - - -10 -383 -180 - - - - - diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll index 453838215ff..2fb3edad602 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll @@ -1856,12 +1856,12 @@ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { } /** - * Gets the address of the allocation this instruction is initializing. + * Gets the operand that represents the address of the allocation this instruction is initializing. */ final AddressOperand getAllocationAddressOperand() { result = getAnOperand() } /** - * Gets the operand for the allocation this instruction is initializing. + * Gets the address for the allocation this instruction is initializing. */ final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() } } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll index 453838215ff..2fb3edad602 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll @@ -1856,12 +1856,12 @@ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { } /** - * Gets the address of the allocation this instruction is initializing. + * Gets the operand that represents the address of the allocation this instruction is initializing. */ final AddressOperand getAllocationAddressOperand() { result = getAnOperand() } /** - * Gets the operand for the allocation this instruction is initializing. + * Gets the address for the allocation this instruction is initializing. */ final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() } } diff --git a/csharp/ql/test/library-tests/dataflow/types/Types.expected b/csharp/ql/test/library-tests/dataflow/types/Types.expected index c0b3bf14bbc..52591455b1e 100644 --- a/csharp/ql/test/library-tests/dataflow/types/Types.expected +++ b/csharp/ql/test/library-tests/dataflow/types/Types.expected @@ -32,21 +32,21 @@ edges | Types.cs:74:9:74:9 | access to local variable d : D | Types.cs:16:30:16:30 | this : D | | Types.cs:77:22:77:22 | a : C | Types.cs:79:18:79:25 | SSA def(b) : C | | Types.cs:79:18:79:25 | SSA def(b) : C | Types.cs:80:18:80:18 | access to local variable b | -| Types.cs:90:22:90:22 | e : Types.E.E2 | Types.cs:92:26:92:26 | access to parameter e : Types.E.E2 | -| Types.cs:92:13:92:16 | [post] this access [field Field] : Types.E.E2 | Types.cs:93:13:93:16 | this access [field Field] : Types.E.E2 | -| Types.cs:92:26:92:26 | access to parameter e : Types.E.E2 | Types.cs:92:13:92:16 | [post] this access [field Field] : Types.E.E2 | -| Types.cs:93:13:93:16 | this access [field Field] : Types.E.E2 | Types.cs:113:34:113:34 | this [field Field] : Types.E.E2 | -| Types.cs:110:25:110:32 | object creation of type E2 : Types.E.E2 | Types.cs:90:22:90:22 | e : Types.E.E2 | -| Types.cs:113:34:113:34 | this [field Field] : Types.E.E2 | Types.cs:115:22:115:25 | this access [field Field] : Types.E.E2 | -| Types.cs:115:22:115:25 | this access [field Field] : Types.E.E2 | Types.cs:115:22:115:31 | access to field Field | +| Types.cs:90:22:90:22 | e : Types+E.E2 | Types.cs:92:26:92:26 | access to parameter e : Types+E.E2 | +| Types.cs:92:13:92:16 | [post] this access [field Field] : Types+E.E2 | Types.cs:93:13:93:16 | this access [field Field] : Types+E.E2 | +| Types.cs:92:26:92:26 | access to parameter e : Types+E.E2 | Types.cs:92:13:92:16 | [post] this access [field Field] : Types+E.E2 | +| Types.cs:93:13:93:16 | this access [field Field] : Types+E.E2 | Types.cs:113:34:113:34 | this [field Field] : Types+E.E2 | +| Types.cs:110:25:110:32 | object creation of type E2 : Types+E.E2 | Types.cs:90:22:90:22 | e : Types+E.E2 | +| Types.cs:113:34:113:34 | this [field Field] : Types+E.E2 | Types.cs:115:22:115:25 | this access [field Field] : Types+E.E2 | +| Types.cs:115:22:115:25 | this access [field Field] : Types+E.E2 | Types.cs:115:22:115:31 | access to field Field | | Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:122:30:122:30 | access to local variable a : A | -| Types.cs:121:26:121:33 | object creation of type E2 : Types.E.E2 | Types.cs:123:30:123:31 | access to local variable e2 : Types.E.E2 | +| Types.cs:121:26:121:33 | object creation of type E2 : Types+E.E2 | Types.cs:123:30:123:31 | access to local variable e2 : Types+E.E2 | | Types.cs:122:30:122:30 | access to local variable a : A | Types.cs:122:22:122:31 | call to method Through | | Types.cs:122:30:122:30 | access to local variable a : A | Types.cs:130:34:130:34 | x : A | -| Types.cs:123:30:123:31 | access to local variable e2 : Types.E.E2 | Types.cs:123:22:123:32 | call to method Through | -| Types.cs:123:30:123:31 | access to local variable e2 : Types.E.E2 | Types.cs:130:34:130:34 | x : Types.E.E2 | +| Types.cs:123:30:123:31 | access to local variable e2 : Types+E.E2 | Types.cs:123:22:123:32 | call to method Through | +| Types.cs:123:30:123:31 | access to local variable e2 : Types+E.E2 | Types.cs:130:34:130:34 | x : Types+E.E2 | | Types.cs:130:34:130:34 | x : A | Types.cs:130:40:130:40 | access to parameter x : A | -| Types.cs:130:34:130:34 | x : Types.E.E2 | Types.cs:130:40:130:40 | access to parameter x : Types.E.E2 | +| Types.cs:130:34:130:34 | x : Types+E.E2 | Types.cs:130:40:130:40 | access to parameter x : Types+E.E2 | | Types.cs:138:21:138:25 | this [field Field] : Object | Types.cs:138:32:138:35 | this access [field Field] : Object | | Types.cs:138:32:138:35 | this access [field Field] : Object | Types.cs:153:30:153:30 | this [field Field] : Object | | Types.cs:144:13:144:13 | [post] access to parameter c [field Field] : Object | Types.cs:145:13:145:13 | access to parameter c [field Field] : Object | @@ -97,24 +97,24 @@ nodes | Types.cs:77:22:77:22 | a : C | semmle.label | a : C | | Types.cs:79:18:79:25 | SSA def(b) : C | semmle.label | SSA def(b) : C | | Types.cs:80:18:80:18 | access to local variable b | semmle.label | access to local variable b | -| Types.cs:90:22:90:22 | e : Types.E.E2 | semmle.label | e : Types.E.E2 | -| Types.cs:92:13:92:16 | [post] this access [field Field] : Types.E.E2 | semmle.label | [post] this access [field Field] : Types.E.E2 | -| Types.cs:92:26:92:26 | access to parameter e : Types.E.E2 | semmle.label | access to parameter e : Types.E.E2 | -| Types.cs:93:13:93:16 | this access [field Field] : Types.E.E2 | semmle.label | this access [field Field] : Types.E.E2 | -| Types.cs:110:25:110:32 | object creation of type E2 : Types.E.E2 | semmle.label | object creation of type E2 : Types.E.E2 | -| Types.cs:113:34:113:34 | this [field Field] : Types.E.E2 | semmle.label | this [field Field] : Types.E.E2 | -| Types.cs:115:22:115:25 | this access [field Field] : Types.E.E2 | semmle.label | this access [field Field] : Types.E.E2 | +| Types.cs:90:22:90:22 | e : Types+E.E2 | semmle.label | e : Types+E.E2 | +| Types.cs:92:13:92:16 | [post] this access [field Field] : Types+E.E2 | semmle.label | [post] this access [field Field] : Types+E.E2 | +| Types.cs:92:26:92:26 | access to parameter e : Types+E.E2 | semmle.label | access to parameter e : Types+E.E2 | +| Types.cs:93:13:93:16 | this access [field Field] : Types+E.E2 | semmle.label | this access [field Field] : Types+E.E2 | +| Types.cs:110:25:110:32 | object creation of type E2 : Types+E.E2 | semmle.label | object creation of type E2 : Types+E.E2 | +| Types.cs:113:34:113:34 | this [field Field] : Types+E.E2 | semmle.label | this [field Field] : Types+E.E2 | +| Types.cs:115:22:115:25 | this access [field Field] : Types+E.E2 | semmle.label | this access [field Field] : Types+E.E2 | | Types.cs:115:22:115:31 | access to field Field | semmle.label | access to field Field | | Types.cs:120:25:120:31 | object creation of type A : A | semmle.label | object creation of type A : A | -| Types.cs:121:26:121:33 | object creation of type E2 : Types.E.E2 | semmle.label | object creation of type E2 : Types.E.E2 | +| Types.cs:121:26:121:33 | object creation of type E2 : Types+E.E2 | semmle.label | object creation of type E2 : Types+E.E2 | | Types.cs:122:22:122:31 | call to method Through | semmle.label | call to method Through | | Types.cs:122:30:122:30 | access to local variable a : A | semmle.label | access to local variable a : A | | Types.cs:123:22:123:32 | call to method Through | semmle.label | call to method Through | -| Types.cs:123:30:123:31 | access to local variable e2 : Types.E.E2 | semmle.label | access to local variable e2 : Types.E.E2 | +| Types.cs:123:30:123:31 | access to local variable e2 : Types+E.E2 | semmle.label | access to local variable e2 : Types+E.E2 | | Types.cs:130:34:130:34 | x : A | semmle.label | x : A | -| Types.cs:130:34:130:34 | x : Types.E.E2 | semmle.label | x : Types.E.E2 | +| Types.cs:130:34:130:34 | x : Types+E.E2 | semmle.label | x : Types+E.E2 | | Types.cs:130:40:130:40 | access to parameter x : A | semmle.label | access to parameter x : A | -| Types.cs:130:40:130:40 | access to parameter x : Types.E.E2 | semmle.label | access to parameter x : Types.E.E2 | +| Types.cs:130:40:130:40 | access to parameter x : Types+E.E2 | semmle.label | access to parameter x : Types+E.E2 | | Types.cs:138:21:138:25 | this [field Field] : Object | semmle.label | this [field Field] : Object | | Types.cs:138:32:138:35 | this access [field Field] : Object | semmle.label | this access [field Field] : Object | | Types.cs:144:13:144:13 | [post] access to parameter c [field Field] : Object | semmle.label | [post] access to parameter c [field Field] : Object | @@ -125,7 +125,7 @@ nodes | Types.cs:153:42:153:51 | access to field Field | semmle.label | access to field Field | subpaths | Types.cs:122:30:122:30 | access to local variable a : A | Types.cs:130:34:130:34 | x : A | Types.cs:130:40:130:40 | access to parameter x : A | Types.cs:122:22:122:31 | call to method Through : A | -| Types.cs:123:30:123:31 | access to local variable e2 : Types.E.E2 | Types.cs:130:34:130:34 | x : Types.E.E2 | Types.cs:130:40:130:40 | access to parameter x : Types.E.E2 | Types.cs:123:22:123:32 | call to method Through : Types.E.E2 | +| Types.cs:123:30:123:31 | access to local variable e2 : Types+E.E2 | Types.cs:130:34:130:34 | x : Types+E.E2 | Types.cs:130:40:130:40 | access to parameter x : Types+E.E2 | Types.cs:123:22:123:32 | call to method Through : Types+E.E2 | #select | Types.cs:23:12:23:18 | object creation of type C : C | Types.cs:23:12:23:18 | object creation of type C : C | Types.cs:50:18:50:18 | access to local variable c | $@ | Types.cs:50:18:50:18 | access to local variable c | access to local variable c | | Types.cs:25:12:25:18 | object creation of type C : C | Types.cs:25:12:25:18 | object creation of type C : C | Types.cs:63:33:63:36 | (...) ... | $@ | Types.cs:63:33:63:36 | (...) ... | (...) ... | @@ -141,7 +141,7 @@ subpaths | Types.cs:39:12:39:18 | object creation of type D : D | Types.cs:39:12:39:18 | object creation of type D : D | Types.cs:69:52:69:52 | access to parameter x | $@ | Types.cs:69:52:69:52 | access to parameter x | access to parameter x | | Types.cs:40:12:40:18 | object creation of type D : D | Types.cs:40:12:40:18 | object creation of type D : D | Types.cs:16:42:16:45 | this access | $@ | Types.cs:16:42:16:45 | this access | this access | | Types.cs:43:20:43:23 | null : null | Types.cs:43:20:43:23 | null : null | Types.cs:44:14:44:14 | access to local variable o | $@ | Types.cs:44:14:44:14 | access to local variable o | access to local variable o | -| Types.cs:110:25:110:32 | object creation of type E2 : Types.E.E2 | Types.cs:110:25:110:32 | object creation of type E2 : Types.E.E2 | Types.cs:115:22:115:31 | access to field Field | $@ | Types.cs:115:22:115:31 | access to field Field | access to field Field | +| Types.cs:110:25:110:32 | object creation of type E2 : Types+E.E2 | Types.cs:110:25:110:32 | object creation of type E2 : Types+E.E2 | Types.cs:115:22:115:31 | access to field Field | $@ | Types.cs:115:22:115:31 | access to field Field | access to field Field | | Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:120:25:120:31 | object creation of type A : A | Types.cs:122:22:122:31 | call to method Through | $@ | Types.cs:122:22:122:31 | call to method Through | call to method Through | -| Types.cs:121:26:121:33 | object creation of type E2 : Types.E.E2 | Types.cs:121:26:121:33 | object creation of type E2 : Types.E.E2 | Types.cs:123:22:123:32 | call to method Through | $@ | Types.cs:123:22:123:32 | call to method Through | call to method Through | +| Types.cs:121:26:121:33 | object creation of type E2 : Types+E.E2 | Types.cs:121:26:121:33 | object creation of type E2 : Types+E.E2 | Types.cs:123:22:123:32 | call to method Through | $@ | Types.cs:123:22:123:32 | call to method Through | call to method Through | | Types.cs:144:23:144:34 | object creation of type Object : Object | Types.cs:144:23:144:34 | object creation of type Object : Object | Types.cs:153:42:153:51 | access to field Field | $@ | Types.cs:153:42:153:51 | access to field Field | access to field Field | diff --git a/csharp/ql/test/library-tests/frameworks/ServiceStack/SinksExternal.cs b/csharp/ql/test/library-tests/frameworks/ServiceStack/SinksExternal.cs new file mode 100644 index 00000000000..65e77d237c9 --- /dev/null +++ b/csharp/ql/test/library-tests/frameworks/ServiceStack/SinksExternal.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using System.Linq; +using ServiceStack; +using System.Threading.Tasks; +using System; +using Microsoft.Extensions.ObjectPool; +using System.IO; + +namespace ServiceStackTest +{ + public class ResponseDto { } + public class ReqDto1 : IReturn { } + + public class ReqDto2 : IReturnVoid { } + + public class C + { + public async Task M() + { + var client = new JsonServiceClient(""); + + client.DeserializeFromStream(new MemoryStream()); // not a sink + + client.Get(new ReqDto1()); + client.Get(new ReqDto2()); + client.Get("relativeOrAbsoluteUrl"); // not a sink + client.Get(new object()); + client.Get("relativeOrAbsoluteUrl"); // not a sink + client.Get(new object()); + + await client.GetAsync("relativeOrAbsoluteUrl"); // not a sink + await client.GetAsync(new object()); + await client.GetAsync(new ReqDto1()); + await client.GetAsync(new ReqDto2()); + + + client.CustomMethod("GET", new ReqDto2()); + client.CustomMethod("GET", "relativeOrAbsoluteUrl", new ReqDto1()); + client.CustomMethod("GET", new ReqDto1()); + client.CustomMethod("GET", new object()); + client.CustomMethod("GET", "relativeOrAbsoluteUrl", new object()); + client.CustomMethod("GET", (IReturnVoid)null); + await client.CustomMethodAsync("GET", new ReqDto2()); + await client.CustomMethodAsync("GET", "relativeOrAbsoluteUrl", new ReqDto1()); + await client.CustomMethodAsync("GET", new ReqDto1()); + await client.CustomMethodAsync("GET", new object()); + + client.DownloadBytes("GET", "requestUri", new object()); + await client.DownloadBytesAsync("GET", "relativeOrAbsoluteUrl", new object()); + + client.Head(new object()); + client.Patch(new object()); + client.Post(new object()); + client.Put(new object()); + + client.Send(new object()); + client.Publish(new ReqDto1()); + client.SendOneWay(new object()); + } + } +} diff --git a/csharp/ql/test/library-tests/frameworks/ServiceStack/SinksInjection.cs b/csharp/ql/test/library-tests/frameworks/ServiceStack/SinksInjection.cs new file mode 100644 index 00000000000..19c8f14a582 --- /dev/null +++ b/csharp/ql/test/library-tests/frameworks/ServiceStack/SinksInjection.cs @@ -0,0 +1,74 @@ +using System.Collections.Generic; +using System.Linq; +using ServiceStack; +using System.Threading.Tasks; +using System; +using Microsoft.AspNetCore.Components.Forms; +using ServiceStack.OrmLite; + +namespace ServiceStackTest +{ + public class Table + { + public int Column { get; set; } + } + + public class Sql + { + public static async Task M() + { + ServiceStack.OrmLite.SqlExpression expr = null; + + expr = expr.Select(t => t.Column); // ok + + expr = expr + .UnsafeAnd("SQL") + .UnsafeFrom("SQL") + .UnsafeGroupBy("SQL") + .UnsafeHaving("SQL") + .UnsafeOr("SQL") + .UnsafeOrderBy("SQL") + .UnsafeSelect("SQL") + .UnsafeWhere("SQL"); + + var untyped = expr.GetUntypedSqlExpression(); + + untyped + .UnsafeAnd("SQL") + .UnsafeFrom("SQL") + .UnsafeOr("SQL") + .UnsafeSelect("SQL") + .UnsafeWhere("SQL") + .Where("SQL"); // safe + + System.Data.IDbConnection conn = null; + + var row = conn.SingleById
    (1); // ok + + var rows = conn.Select
    (typeof(Table), "SQL", null); + rows = await conn.SelectAsync
    (typeof(Table), "SQL", null); + + var count = conn.RowCount("SQL"); + count = await conn.RowCountAsync("SQL"); + + conn.ExecuteSql("SQL", null); + await conn.ExecuteSqlAsync("SQL", null); + } + + public static async Task Redis() + { + ServiceStack.Redis.IRedisClient client = null; + + client.SetValue("key", "value"); // ok + + var s = client.LoadLuaScript("script"); + client.ExecLua("script", new[] { "" }, new[] { "" }); + client.ExecLuaSha("SHA", new[] { "" }, new[] { "" }); // ok + client.Custom("command", "arg"); // false negative, params sinks doesn't work + + ServiceStack.Redis.IRedisClientAsync asyncClient = null; + s = await asyncClient.LoadLuaScriptAsync("script"); + asyncClient.ExecLuaAsync("script", new[] { "" }, new[] { "" }); + } + } +} diff --git a/csharp/ql/test/library-tests/frameworks/ServiceStack/SinksXss.cs b/csharp/ql/test/library-tests/frameworks/ServiceStack/SinksXss.cs new file mode 100644 index 00000000000..df3bbd155de --- /dev/null +++ b/csharp/ql/test/library-tests/frameworks/ServiceStack/SinksXss.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using System.Linq; +using ServiceStack; +using System.Threading.Tasks; +using System; + +namespace ServiceStackTest +{ + public class XssServices : Service + { + public object Get(Request1 request) + { + return ""); + } + + // GOOD: use the method `writeText` that performs escaping appropriate for the markup language being rendered. + public void encodeBegin2(FacesContext facesContext, UIComponent component) throws IOException + { + super.encodeBegin(facesContext, component); + + Map requestParameters = facesContext.getExternalContext().getRequestParameterMap(); + String windowId = requestParameters.get("window_id"); + + ResponseWriter writer = facesContext.getResponseWriter(); + writer.write(""); + } + + public void testAllSources(FacesContext facesContext) throws IOException + { + ExternalContext ec = facesContext.getExternalContext(); + ResponseWriter writer = facesContext.getResponseWriter(); + writer.write(ec.getRequestParameterMap().keySet().iterator().next()); // $xss + writer.write(ec.getRequestParameterNames().next()); // $xss + writer.write(ec.getRequestParameterValuesMap().get("someKey")[0]); // $xss + writer.write(ec.getRequestParameterValuesMap().keySet().iterator().next()); // $xss + writer.write(ec.getRequestPathInfo()); // $xss + writer.write(((Cookie)ec.getRequestCookieMap().get("someKey")).getName()); // $xss + writer.write(ec.getRequestHeaderMap().get("someKey")); // $xss + writer.write(ec.getRequestHeaderValuesMap().get("someKey")[0]); // $xss + } +} diff --git a/java/ql/test/query-tests/security/CWE-079/semmle/tests/SpringXSS.java b/java/ql/test/query-tests/security/CWE-079/semmle/tests/SpringXSS.java index 744fe853b67..49ea5165fd4 100644 --- a/java/ql/test/query-tests/security/CWE-079/semmle/tests/SpringXSS.java +++ b/java/ql/test/query-tests/security/CWE-079/semmle/tests/SpringXSS.java @@ -28,11 +28,11 @@ public class SpringXSS { } else { if(chainDirectly) { - return builder.contentType(MediaType.APPLICATION_JSON).body(userControlled); // $SPURIOUS: xss + return builder.contentType(MediaType.APPLICATION_JSON).body(userControlled); } else { ResponseEntity.BodyBuilder builder2 = builder.contentType(MediaType.APPLICATION_JSON); - return builder2.body(userControlled); // $SPURIOUS: xss + return builder2.body(userControlled); } } @@ -60,7 +60,7 @@ public class SpringXSS { @GetMapping(value = "/xyz", produces = MediaType.TEXT_HTML_VALUE) public static ResponseEntity methodContentTypeUnsafe(String userControlled) { - return ResponseEntity.ok(userControlled); // $MISSING: xss + return ResponseEntity.ok(userControlled); // $xss } @GetMapping(value = "/xyz", produces = "text/html") @@ -75,7 +75,7 @@ public class SpringXSS { @GetMapping(value = "/xyz", produces = MediaType.APPLICATION_JSON_VALUE) public static ResponseEntity methodContentTypeSafeOverriddenWithUnsafe(String userControlled) { - return ResponseEntity.ok().contentType(MediaType.TEXT_HTML).body(userControlled); // $MISSING: xss + return ResponseEntity.ok().contentType(MediaType.TEXT_HTML).body(userControlled); // $xss } @GetMapping(value = "/xyz", produces = MediaType.TEXT_HTML_VALUE) @@ -105,12 +105,12 @@ public class SpringXSS { private static class ClassContentTypeSafe { @GetMapping(value = "/abc") public ResponseEntity test(String userControlled) { - return ResponseEntity.ok(userControlled); // $SPURIOUS: xss + return ResponseEntity.ok(userControlled); } @GetMapping(value = "/abc") public String testDirectReturn(String userControlled) { - return userControlled; // $SPURIOUS: xss + return userControlled; } @GetMapping(value = "/xyz", produces = {"text/html"}) @@ -139,12 +139,12 @@ public class SpringXSS { @GetMapping(value = "/xyz", produces = {"application/json"}) public ResponseEntity overridesWithSafe(String userControlled) { - return ResponseEntity.ok(userControlled); // $SPURIOUS: xss + return ResponseEntity.ok(userControlled); } @GetMapping(value = "/abc") public ResponseEntity overridesWithSafe2(String userControlled) { - return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(userControlled); // $SPURIOUS: xss + return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(userControlled); } } diff --git a/java/ql/test/query-tests/security/CWE-079/semmle/tests/options b/java/ql/test/query-tests/security/CWE-079/semmle/tests/options index 719c5e3dd57..22487fb2daf 100644 --- a/java/ql/test/query-tests/security/CWE-079/semmle/tests/options +++ b/java/ql/test/query-tests/security/CWE-079/semmle/tests/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/servlet-api-2.4:${testdir}/../../../../../stubs/javax-ws-rs-api-2.1.1/:${testdir}/../../../../../stubs/springframework-5.3.8 +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/servlet-api-2.4:${testdir}/../../../../../stubs/javax-ws-rs-api-2.1.1/:${testdir}/../../../../../stubs/springframework-5.3.8:${testdir}/../../../../../stubs/javax-faces-2.3/ diff --git a/java/ql/test/query-tests/security/CWE-094/SpelInjectionTest.expected b/java/ql/test/query-tests/security/CWE-094/SpelInjectionTest.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/SpelInjection.java b/java/ql/test/query-tests/security/CWE-094/SpelInjectionTest.java similarity index 76% rename from java/ql/test/experimental/query-tests/security/CWE-094/SpelInjection.java rename to java/ql/test/query-tests/security/CWE-094/SpelInjectionTest.java index 9eeb552ef34..d10bcfa6686 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-094/SpelInjection.java +++ b/java/ql/test/query-tests/security/CWE-094/SpelInjectionTest.java @@ -3,11 +3,12 @@ import java.io.InputStream; import java.net.Socket; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpression; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.SimpleEvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext; -public class SpelInjection { +public class SpelInjectionTest { private static final ExpressionParser PARSER = new SpelExpressionParser(); @@ -20,7 +21,18 @@ public class SpelInjection { ExpressionParser parser = new SpelExpressionParser(); Expression expression = parser.parseExpression(input); - expression.getValue(); + expression.getValue(); // $hasSpelInjection + } + + public void testGetValueWithParseRaw(Socket socket) throws IOException { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + SpelExpressionParser parser = new SpelExpressionParser(); + SpelExpression expression = parser.parseRaw(input); + expression.getValue(); // $hasSpelInjection } public void testGetValueWithChainedCalls(Socket socket) throws IOException { @@ -31,7 +43,7 @@ public class SpelInjection { String input = new String(bytes, 0, n); Expression expression = new SpelExpressionParser().parseExpression(input); - expression.getValue(); + expression.getValue(); // $hasSpelInjection } public void testSetValueWithRootObject(Socket socket) throws IOException { @@ -45,7 +57,7 @@ public class SpelInjection { Object root = new Object(); Object value = new Object(); - expression.setValue(root, value); + expression.setValue(root, value); // $hasSpelInjection } public void testGetValueWithStaticParser(Socket socket) throws IOException { @@ -56,7 +68,7 @@ public class SpelInjection { String input = new String(bytes, 0, n); Expression expression = PARSER.parseExpression(input); - expression.getValue(); + expression.getValue(); // $hasSpelInjection } public void testGetValueType(Socket socket) throws IOException { @@ -67,7 +79,7 @@ public class SpelInjection { String input = new String(bytes, 0, n); Expression expression = PARSER.parseExpression(input); - expression.getValueType(); + expression.getValueType(); // $hasSpelInjection } public void testWithStandardEvaluationContext(Socket socket) throws IOException { @@ -80,7 +92,7 @@ public class SpelInjection { Expression expression = PARSER.parseExpression(input); StandardEvaluationContext context = new StandardEvaluationContext(); - expression.getValue(context); + expression.getValue(context); // $hasSpelInjection } public void testWithSimpleEvaluationContext(Socket socket) throws IOException { @@ -93,8 +105,7 @@ public class SpelInjection { Expression expression = PARSER.parseExpression(input); SimpleEvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build(); - // the expression is evaluated in a limited context - expression.getValue(context); + expression.getValue(context); // Safe - the expression is evaluated in a limited context } } diff --git a/java/ql/test/query-tests/security/CWE-094/SpelInjectionTest.ql b/java/ql/test/query-tests/security/CWE-094/SpelInjectionTest.ql new file mode 100644 index 00000000000..1da99aa3de8 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-094/SpelInjectionTest.ql @@ -0,0 +1,22 @@ +import java +import semmle.code.java.dataflow.TaintTracking +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.security.SpelInjectionQuery +import TestUtilities.InlineExpectationsTest + +class HasSpelInjectionTest extends InlineExpectationsTest { + HasSpelInjectionTest() { this = "HasSpelInjectionTest" } + + override string getARelevantTag() { result = "hasSpelInjection" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "hasSpelInjection" and + exists(DataFlow::Node src, DataFlow::Node sink, SpelInjectionConfig conf | + conf.hasFlow(src, sink) + | + sink.getLocation() = location and + element = sink.toString() and + value = "" + ) + } +} diff --git a/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.expected b/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.expected index b393af42f71..19ab13ed803 100644 --- a/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.expected +++ b/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.expected @@ -4,5 +4,5 @@ nodes | Test.java:42:33:42:37 | "RC2" | semmle.label | "RC2" | subpaths #select -| Test.java:19:20:19:50 | getInstance(...) | Test.java:19:45:19:49 | "DES" | Test.java:19:45:19:49 | "DES" | Cryptographic algorithm $@ is weak and should not be used. | Test.java:19:45:19:49 | "DES" | "DES" | -| Test.java:42:14:42:38 | getInstance(...) | Test.java:42:33:42:37 | "RC2" | Test.java:42:33:42:37 | "RC2" | Cryptographic algorithm $@ is weak and should not be used. | Test.java:42:33:42:37 | "RC2" | "RC2" | +| Test.java:19:20:19:50 | getInstance(...) | Test.java:19:45:19:49 | "DES" | Test.java:19:45:19:49 | "DES" | Cryptographic algorithm $@ is weak and should not be used. | Test.java:19:45:19:49 | "DES" | DES | +| Test.java:42:14:42:38 | getInstance(...) | Test.java:42:33:42:37 | "RC2" | Test.java:42:33:42:37 | "RC2" | Cryptographic algorithm $@ is weak and should not be used. | Test.java:42:33:42:37 | "RC2" | RC2 | diff --git a/java/ql/test/query-tests/security/CWE-327/semmle/tests/MaybeBrokenCryptoAlgorithm.expected b/java/ql/test/query-tests/security/CWE-327/semmle/tests/MaybeBrokenCryptoAlgorithm.expected index c046f507430..f61954d848a 100644 --- a/java/ql/test/query-tests/security/CWE-327/semmle/tests/MaybeBrokenCryptoAlgorithm.expected +++ b/java/ql/test/query-tests/security/CWE-327/semmle/tests/MaybeBrokenCryptoAlgorithm.expected @@ -3,4 +3,4 @@ nodes | Test.java:34:48:34:52 | "foo" | semmle.label | "foo" | subpaths #select -| Test.java:34:21:34:53 | new SecretKeySpec(...) | Test.java:34:48:34:52 | "foo" | Test.java:34:48:34:52 | "foo" | Cryptographic algorithm $@ may not be secure, consider using a different algorithm. | Test.java:34:48:34:52 | "foo" | "foo" | +| Test.java:34:21:34:53 | new SecretKeySpec(...) | Test.java:34:48:34:52 | "foo" | Test.java:34:48:34:52 | "foo" | Cryptographic algorithm $@ may not be secure, consider using a different algorithm. | Test.java:34:48:34:52 | "foo" | foo | diff --git a/java/ql/test/query-tests/security/CWE-502/FlexjsonServlet.java b/java/ql/test/query-tests/security/CWE-502/FlexjsonServlet.java new file mode 100644 index 00000000000..c7e5c1ce587 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-502/FlexjsonServlet.java @@ -0,0 +1,126 @@ +import java.io.IOException; +import java.io.Reader; + +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import flexjson.JSONDeserializer; +import flexjson.factories.ExistingObjectFactory; + +import com.example.User; +import com.thirdparty.Person; + +public class FlexjsonServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + // GOOD: a final class type is specified + public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + JSONDeserializer deserializer = new JSONDeserializer<>(); + User user = deserializer.deserialize(req.getReader(), User.class); + } + + @Override + // GOOD: a non-null class type is specified which is not the generic `Object` type + public void doHead(HttpServletRequest req, HttpServletResponse resp) throws IOException { + JSONDeserializer deserializer = new JSONDeserializer(); + Person person = deserializer.deserialize(req.getReader(), Person.class); + } + + @Override + // BAD: allow class name to be controlled by remote source + public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { + JSONDeserializer deserializer = new JSONDeserializer<>(); + User user = (User) deserializer.deserialize(req.getReader()); // $unsafeDeserialization + + } + + @Override + // BAD: allow class name to be controlled by remote source + public void doTrace(HttpServletRequest req, HttpServletResponse resp) throws IOException { + JSONDeserializer deserializer = new JSONDeserializer<>(); + User user = (User) deserializer.deserialize(req.getReader()); // $unsafeDeserialization + + } + + @Override + // BAD: specify overly generic class type + public void doPut(HttpServletRequest req, HttpServletResponse resp) throws IOException { + JSONDeserializer deserializer = new JSONDeserializer(); + User user = (User) deserializer.deserialize(req.getReader(), Object.class); // $unsafeDeserialization + } + + private Person fromJsonToPerson(String json) { + return new JSONDeserializer().use(null, Person.class).deserialize(json); + } + + // GOOD: Specify the class to deserialize with `use` + public void doPut2(HttpServletRequest req, HttpServletResponse resp) throws IOException { + String json = req.getParameter("json"); + Person person = fromJsonToPerson(json); + } + + // BAD: Specify a concrete class type to `use` with `ObjectFactory` + public void doPut3(HttpServletRequest req, HttpServletResponse resp) throws IOException { + String json = req.getParameter("json"); + Person person = new JSONDeserializer().use(Person.class, new ExistingObjectFactory(new Person())).deserialize(json); // $unsafeDeserialization + } + + // GOOD: Specify a null path to `use` with a concrete class type + public void doPut4(HttpServletRequest req, HttpServletResponse resp) throws IOException { + String json = req.getParameter("json"); + Person person = new JSONDeserializer().use(null, Person.class).deserialize(json); + } + + // BAD: Specify a non-null json path to `use` with a concrete class type + public void doPut5(HttpServletRequest req, HttpServletResponse resp) throws IOException { + String json = req.getParameter("json"); + Person person = new JSONDeserializer().use("abc", Person.class).deserialize(json); // $unsafeDeserialization + } + + // GOOD: Specify a null json path to `use` with `ObjectFactory` + public void doPut6(HttpServletRequest req, HttpServletResponse resp) throws IOException { + String json = req.getParameter("json"); + Person person = new JSONDeserializer().use(new ExistingObjectFactory(new Person()), "abc", null).deserialize(json); + } + + // GOOD: Specify a concrete class type to deserialize with `ObjectFactory` + public void doPut7(HttpServletRequest req, HttpServletResponse resp) throws IOException { + String json = req.getParameter("json"); + Person person = new JSONDeserializer().deserialize(json, new ExistingObjectFactory(new Person())); + } + + // GOOD: Specify the class type to deserialize into + public void doPut8(HttpServletRequest req, HttpServletResponse resp) throws IOException { + String json = req.getParameter("json"); + Person person = new JSONDeserializer().deserializeInto(json, new Person()); + } + + // GOOD: Specify a null json path to `use` with a concrete class type, interwoven with irrelevant use directives + public void doPut9(HttpServletRequest req, HttpServletResponse resp) throws IOException { + String json = req.getParameter("json"); + Person person = new JSONDeserializer().use(Person.class, null).use(null, Person.class).use(String.class, null).deserialize(json); + } + + // GOOD: Specify a null json path to `use` with a concrete class type, interwoven with irrelevant use directives, without using fluent method chaining + public void doPut10(HttpServletRequest req, HttpServletResponse resp) throws IOException { + String json = req.getParameter("json"); + JSONDeserializer deserializer = new JSONDeserializer(); + deserializer.use(Person.class, null); + deserializer.use(null, Person.class); + deserializer.use(String.class, null); + Person person = deserializer.deserialize(json); + } + + // BAD: Specify a non-null json path to `use` with a concrete class type, interwoven with irrelevant use directives, without using fluent method chaining + public void doPut11(HttpServletRequest req, HttpServletResponse resp) throws IOException { + String json = req.getParameter("json"); + JSONDeserializer deserializer = new JSONDeserializer(); + deserializer.use(Person.class, null); + deserializer.use("someKey", Person.class); + deserializer.use(String.class, null); + Person person = deserializer.deserialize(json); // $unsafeDeserialization + } +} diff --git a/java/ql/test/query-tests/security/CWE-502/options b/java/ql/test/query-tests/security/CWE-502/options index 79476eded38..cdd0375684e 100644 --- a/java/ql/test/query-tests/security/CWE-502/options +++ b/java/ql/test/query-tests/security/CWE-502/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/snakeyaml-1.21:${testdir}/../../../stubs/xstream-1.4.10:${testdir}/../../../stubs/kryo-4.0.2:${testdir}/../../../stubs/jsr311-api-1.1.1:${testdir}/../../../stubs/fastjson-1.2.74:${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/jyaml-1.3:${testdir}/../../../stubs/json-io-4.10.0:${testdir}/../../../stubs/yamlbeans-1.09:${testdir}/../../../stubs/hessian-4.0.38:${testdir}/../../../stubs/castor-1.4.1:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/jackson-core-2.12:${testdir}/../../../stubs/jabsorb-1.3.2:${testdir}/../../../stubs/json-java-20210307:${testdir}/../../../stubs/joddjson-6.0.3 +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/snakeyaml-1.21:${testdir}/../../../stubs/xstream-1.4.10:${testdir}/../../../stubs/kryo-4.0.2:${testdir}/../../../stubs/jsr311-api-1.1.1:${testdir}/../../../stubs/fastjson-1.2.74:${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/jyaml-1.3:${testdir}/../../../stubs/json-io-4.10.0:${testdir}/../../../stubs/yamlbeans-1.09:${testdir}/../../../stubs/hessian-4.0.38:${testdir}/../../../stubs/castor-1.4.1:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/jackson-core-2.12:${testdir}/../../../stubs/jabsorb-1.3.2:${testdir}/../../../stubs/json-java-20210307:${testdir}/../../../stubs/joddjson-6.0.3:${testdir}/../../../stubs/flexjson-2.1 diff --git a/java/ql/test/query-tests/security/CWE-522/InsecureBasicAuthTest.expected b/java/ql/test/query-tests/security/CWE-522/InsecureBasicAuthTest.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/ql/test/query-tests/security/CWE-522/InsecureBasicAuthTest.java b/java/ql/test/query-tests/security/CWE-522/InsecureBasicAuthTest.java new file mode 100644 index 00000000000..2098dd4139c --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-522/InsecureBasicAuthTest.java @@ -0,0 +1,253 @@ +import org.apache.http.RequestLine; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.message.BasicHttpRequest; +import org.apache.http.message.BasicRequestLine; + +import java.net.URI; +import java.net.URL; +import java.net.HttpURLConnection; +import java.net.URLConnection; +import java.util.Base64; +import javax.net.ssl.HttpsURLConnection; + +public class InsecureBasicAuthTest { + /** + * Test basic authentication with Apache HTTP POST request using string constructor. + */ + public void testApacheHttpRequest(String username, String password) { + String host = "www.example.com"; + String authString = username + ":" + password; + byte[] authEncBytes = Base64.getEncoder().encode(authString.getBytes()); + String authStringEnc = new String(authEncBytes); + { + HttpRequestBase post = new HttpPost("http://" + host + "/rest/getuser.do?uid=abcdx"); + post.setHeader("Accept", "application/json"); + post.setHeader("Content-type", "application/json"); + post.addHeader("Authorization", "Basic " + authStringEnc); // $hasInsecureBasicAuth + } + { + HttpRequestBase post = new HttpPost("https://" + host + "/rest/getuser.do?uid=abcdx"); + post.setHeader("Accept", "application/json"); + post.setHeader("Content-type", "application/json"); + post.addHeader("Authorization", "Basic " + authStringEnc); // Safe + } + } + + /** + * Test basic authentication with Apache HTTP GET request. + */ + public void testApacheHttpRequest2(String url) throws java.io.IOException { + { + String urlStr = "http://www.example.com:8000/payment/retrieve"; + HttpGet get = new HttpGet(urlStr); + get.setHeader("Accept", "application/json"); + get.setHeader("Authorization", // $hasInsecureBasicAuth + "Basic " + new String(Base64.getEncoder().encode("admin:test".getBytes()))); + } + { + String urlStr = "https://www.example.com:8000/payment/retrieve"; + HttpGet get = new HttpGet(urlStr); + get.setHeader("Accept", "application/json"); + get.setHeader("Authorization", // Safe + "Basic " + new String(Base64.getEncoder().encode("admin:test".getBytes()))); + } + } + + /** + * Test basic authentication with Apache HTTP POST request using URI create method. + */ + public void testApacheHttpRequest3(String username, String password) { + String authString = username + ":" + password; + byte[] authEncBytes = Base64.getEncoder().encode(authString.getBytes()); + String authStringEnc = new String(authEncBytes); + { + String uriStr = "http://www.example.com/rest/getuser.do?uid=abcdx"; + HttpRequestBase post = new HttpPost(URI.create(uriStr)); + post.setHeader("Accept", "application/json"); + post.setHeader("Content-type", "application/json"); + post.addHeader("Authorization", "Basic " + authStringEnc); // $hasInsecureBasicAuth + } + { + String uriStr = "https://www.example.com/rest/getuser.do?uid=abcdx"; + HttpRequestBase post = new HttpPost(URI.create(uriStr)); + post.setHeader("Accept", "application/json"); + post.setHeader("Content-type", "application/json"); + post.addHeader("Authorization", "Basic " + authStringEnc); // Safe + } + } + + /** + * Test basic authentication with Apache HTTP POST request using the URI constructor with one + * argument. + */ + public void testApacheHttpRequest4(String username, String password) throws Exception { + String authString = username + ":" + password; + byte[] authEncBytes = Base64.getEncoder().encode(authString.getBytes()); + String authStringEnc = new String(authEncBytes); + { + String uriStr = "http://www.example.com/rest/getuser.do?uid=abcdx"; + URI uri = new URI(uriStr); + HttpRequestBase post = new HttpPost(uri); + post.setHeader("Accept", "application/json"); + post.setHeader("Content-type", "application/json"); + post.addHeader("Authorization", "Basic " + authStringEnc); // $hasInsecureBasicAuth + } + { + String uriStr = "https://www.example.com/rest/getuser.do?uid=abcdx"; + URI uri = new URI(uriStr); + HttpRequestBase post = new HttpPost(uri); + post.setHeader("Accept", "application/json"); + post.setHeader("Content-type", "application/json"); + post.addHeader("Authorization", "Basic " + authStringEnc); // Safe + } + } + + /** + * Test basic authentication with Apache HTTP POST request using a URI constructor with multiple + * arguments. + */ + public void testApacheHttpRequest5(String username, String password) throws Exception { + String authString = username + ":" + password; + byte[] authEncBytes = Base64.getEncoder().encode(authString.getBytes()); + String authStringEnc = new String(authEncBytes); + { + HttpRequestBase post = + new HttpPost(new URI("http", "www.example.com", "/test", "abc=123", null)); + post.setHeader("Accept", "application/json"); + post.setHeader("Content-type", "application/json"); + post.addHeader("Authorization", "Basic " + authStringEnc); // $hasInsecureBasicAuth + } + { + HttpRequestBase post = + new HttpPost(new URI("https", "www.example.com", "/test", "abc=123", null)); + post.setHeader("Accept", "application/json"); + post.setHeader("Content-type", "application/json"); + post.addHeader("Authorization", "Basic " + authStringEnc); // Safe + } + } + + /** + * Test basic authentication with Apache HTTP `BasicHttpRequest` using string constructor. + */ + public void testApacheHttpRequest6(String username, String password) { + String authString = username + ":" + password; + byte[] authEncBytes = Base64.getEncoder().encode(authString.getBytes()); + String authStringEnc = new String(authEncBytes); + { + String uriStr = "http://www.example.com/rest/getuser.do?uid=abcdx"; + BasicHttpRequest post = new BasicHttpRequest("POST", uriStr); + post.setHeader("Accept", "application/json"); + post.setHeader("Content-type", "application/json"); + post.addHeader("Authorization", "Basic " + authStringEnc); // $hasInsecureBasicAuth + } + { + String uriStr = "https://www.example.com/rest/getuser.do?uid=abcdx"; + BasicHttpRequest post = new BasicHttpRequest("POST", uriStr); + post.setHeader("Accept", "application/json"); + post.setHeader("Content-type", "application/json"); + post.addHeader("Authorization", "Basic " + authStringEnc); // Safe + } + } + + /** + * Test basic authentication with Apache HTTP `BasicHttpRequest` using `RequestLine`. + */ + public void testApacheHttpRequest7(String username, String password) { + String authString = username + ":" + password; + byte[] authEncBytes = Base64.getEncoder().encode(authString.getBytes()); + String authStringEnc = new String(authEncBytes); + { + String uriStr = "http://www.example.com/rest/getuser.do?uid=abcdx"; + RequestLine requestLine = new BasicRequestLine("POST", uriStr, null); + BasicHttpRequest post = new BasicHttpRequest(requestLine); + post.setHeader("Accept", "application/json"); + post.setHeader("Content-type", "application/json"); + post.addHeader("Authorization", "Basic " + authStringEnc); // $hasInsecureBasicAuth + } + { + String uriStr = "https://www.example.com/rest/getuser.do?uid=abcdx"; + RequestLine requestLine = new BasicRequestLine("POST", uriStr, null); + BasicHttpRequest post = new BasicHttpRequest(requestLine); + post.setHeader("Accept", "application/json"); + post.setHeader("Content-type", "application/json"); + post.addHeader("Authorization", "Basic " + authStringEnc); // Safe + } + } + + /** + * Test basic authentication with Java HTTP URL connection using the `URL(String spec)` + * constructor. + */ + public void testHttpUrlConnection(String username, String password) throws Exception { + String authString = username + ":" + password; + String encoding = Base64.getEncoder().encodeToString(authString.getBytes("UTF-8")); + { + String urlStr = "http://www.example.com/rest/getuser.do?uid=abcdx"; + URL url = new URL(urlStr); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + conn.setDoOutput(true); + conn.setRequestProperty("Authorization", "Basic " + encoding); // $hasInsecureBasicAuth + } + { + String urlStr = "https://www.example.com/rest/getuser.do?uid=abcdx"; + URL url = new URL(urlStr); + HttpURLConnection conn = (HttpsURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + conn.setDoOutput(true); + conn.setRequestProperty("Authorization", "Basic " + encoding); // Safe + } + } + + /** + * Test basic authentication with Java HTTP URL connection using the `URL(String protocol, + * String host, String file)` constructor. + */ + public void testHttpUrlConnection2(String username, String password) throws Exception { + String authString = username + ":" + password; + String encoding = Base64.getEncoder().encodeToString(authString.getBytes("UTF-8")); + String host = "www.example.com"; + String path = "/rest/getuser.do?uid=abcdx"; + { + String protocol = "http"; + URL url = new URL(protocol, host, path); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + conn.setDoOutput(true); + conn.setRequestProperty("Authorization", "Basic " + encoding); // $hasInsecureBasicAuth + } + { + String protocol = "https"; + URL url = new URL(protocol, host, path); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + conn.setDoOutput(true); + conn.setRequestProperty("Authorization", "Basic " + encoding); // Safe + } + } + + /** + * Test basic authentication with Java HTTP URL connection using a constructor with private URL. + */ + public void testHttpUrlConnection3(String username, String password) throws Exception { + String host = "LOCALHOST"; + String authString = username + ":" + password; + String encoding = Base64.getEncoder().encodeToString(authString.getBytes("UTF-8")); + { + HttpURLConnection conn = (HttpURLConnection) new URL( + "http://" + (((host + "/rest/getuser.do") + "?uid=abcdx"))).openConnection(); + conn.setRequestMethod("POST"); + conn.setDoOutput(true); + conn.setRequestProperty("Authorization", "Basic " + encoding); // Safe + } + { + HttpURLConnection conn = (HttpURLConnection) new URL( + "https://" + (((host + "/rest/getuser.do") + "?uid=abcdx"))).openConnection(); + conn.setRequestMethod("POST"); + conn.setDoOutput(true); + conn.setRequestProperty("Authorization", "Basic " + encoding); // Safe + } + } +} diff --git a/java/ql/test/query-tests/security/CWE-522/InsecureBasicAuthTest.ql b/java/ql/test/query-tests/security/CWE-522/InsecureBasicAuthTest.ql new file mode 100644 index 00000000000..53064d42bd5 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-522/InsecureBasicAuthTest.ql @@ -0,0 +1,20 @@ +import java +import semmle.code.java.security.InsecureBasicAuthQuery +import TestUtilities.InlineExpectationsTest + +class HasInsecureBasicAuthTest extends InlineExpectationsTest { + HasInsecureBasicAuthTest() { this = "HasInsecureBasicAuthTest" } + + override string getARelevantTag() { result = "hasInsecureBasicAuth" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "hasInsecureBasicAuth" and + exists(DataFlow::Node src, DataFlow::Node sink, BasicAuthFlowConfig conf | + conf.hasFlow(src, sink) + | + sink.getLocation() = location and + element = sink.toString() and + value = "" + ) + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-522/options b/java/ql/test/query-tests/security/CWE-522/options similarity index 68% rename from java/ql/test/experimental/query-tests/security/CWE-522/options rename to java/ql/test/query-tests/security/CWE-522/options index 7eaf4cb235f..2e6054aac45 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-522/options +++ b/java/ql/test/query-tests/security/CWE-522/options @@ -1 +1 @@ -// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/apache-http-4.4.13 +// semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/apache-http-4.4.13 diff --git a/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypass.expected b/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypass.expected deleted file mode 100644 index 1275f03033a..00000000000 --- a/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypass.expected +++ /dev/null @@ -1,25 +0,0 @@ -edges -| Test.java:17:26:17:38 | args : String[] | Test.java:25:6:25:21 | ... == ... | -| Test.java:31:6:31:27 | getValue(...) : String | Test.java:31:6:31:43 | equals(...) | -| Test.java:36:6:36:27 | getValue(...) : String | Test.java:36:6:36:36 | ... == ... | -| Test.java:81:6:81:27 | getValue(...) : String | Test.java:81:6:81:36 | ... == ... | -| Test.java:91:6:91:27 | getValue(...) : String | Test.java:91:6:91:36 | ... == ... | -nodes -| Test.java:17:26:17:38 | args : String[] | semmle.label | args : String[] | -| Test.java:25:6:25:21 | ... == ... | semmle.label | ... == ... | -| Test.java:31:6:31:27 | getValue(...) : String | semmle.label | getValue(...) : String | -| Test.java:31:6:31:43 | equals(...) | semmle.label | equals(...) | -| Test.java:36:6:36:27 | getValue(...) : String | semmle.label | getValue(...) : String | -| Test.java:36:6:36:36 | ... == ... | semmle.label | ... == ... | -| Test.java:81:6:81:27 | getValue(...) : String | semmle.label | getValue(...) : String | -| Test.java:81:6:81:36 | ... == ... | semmle.label | ... == ... | -| Test.java:91:6:91:27 | getValue(...) : String | semmle.label | getValue(...) : String | -| Test.java:91:6:91:36 | ... == ... | semmle.label | ... == ... | -subpaths -#select -| Test.java:26:4:26:24 | login(...) | Test.java:17:26:17:38 | args : String[] | Test.java:25:6:25:21 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:25:6:25:21 | ... == ... | this condition | Test.java:17:26:17:38 | args | user input | -| Test.java:32:4:32:24 | login(...) | Test.java:31:6:31:27 | getValue(...) : String | Test.java:31:6:31:43 | equals(...) | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:31:6:31:43 | equals(...) | this condition | Test.java:31:6:31:27 | getValue(...) | user input | -| Test.java:37:4:37:24 | login(...) | Test.java:36:6:36:27 | getValue(...) : String | Test.java:36:6:36:36 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:36:6:36:36 | ... == ... | this condition | Test.java:36:6:36:27 | getValue(...) | user input | -| Test.java:39:4:39:30 | reCheckAuth(...) | Test.java:36:6:36:27 | getValue(...) : String | Test.java:36:6:36:36 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:36:6:36:36 | ... == ... | this condition | Test.java:36:6:36:27 | getValue(...) | user input | -| Test.java:82:4:82:24 | login(...) | Test.java:81:6:81:27 | getValue(...) : String | Test.java:81:6:81:36 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:81:6:81:36 | ... == ... | this condition | Test.java:81:6:81:27 | getValue(...) | user input | -| Test.java:92:4:92:24 | login(...) | Test.java:91:6:91:27 | getValue(...) : String | Test.java:91:6:91:36 | ... == ... | Sensitive method may not be executed depending on $@, which flows from $@. | Test.java:91:6:91:36 | ... == ... | this condition | Test.java:91:6:91:27 | getValue(...) | user input | diff --git a/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypass.qlref b/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypass.qlref deleted file mode 100644 index 82d29b30b17..00000000000 --- a/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypass.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/CWE/CWE-807/ConditionalBypass.ql \ No newline at end of file diff --git a/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypassTest.expected b/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypassTest.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/ql/test/query-tests/security/CWE-807/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypassTest.java similarity index 52% rename from java/ql/test/query-tests/security/CWE-807/semmle/tests/Test.java rename to java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypassTest.java index 5d9b8db623c..51dd5379005 100644 --- a/java/ql/test/query-tests/security/CWE-807/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypassTest.java @@ -2,58 +2,45 @@ // http://cwe.mitre.org/data/definitions/807.html package test.cwe807.semmle.tests; - - - import java.net.InetAddress; import java.net.Inet4Address; import java.net.UnknownHostException; import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; import org.apache.shiro.SecurityUtils; import org.apache.shiro.subject.Subject; -class Test { - public static void main(String[] args) throws UnknownHostException { - String user = args[0]; - String password = args[1]; - - String isAdmin = args[3]; - +class ConditionalBypassTest { + public static void main(HttpServletRequest request) throws Exception { + String user = request.getParameter("user"); + String password = request.getParameter("password"); + + String isAdmin = request.getParameter("isAdmin"); + // BAD: login is only executed if isAdmin is false, but isAdmin // is controlled by the user - if(isAdmin=="false") + if (isAdmin == "false") // $ hasConditionalBypassTest login(user, password); - + Cookie adminCookie = getCookies()[0]; // BAD: login is only executed if the cookie value is false, but the cookie // is controlled by the user - if(adminCookie.getValue().equals("false")) + if (adminCookie.getValue().equals("false")) // $ hasConditionalBypassTest login(user, password); - - // FALSE POSITIVES: both methods are conditionally executed, but they probably + + // GOOD: both methods are conditionally executed, but they probably // both perform the security-critical action - if(adminCookie.getValue()=="false") { + if (adminCookie.getValue() == "false") { // Safe login(user, password); } else { reCheckAuth(user, password); } - + // FALSE NEGATIVE: we have no way of telling that the skipped method is sensitive - if(adminCookie.getValue()=="false") + if (adminCookie.getValue() == "false") // $ MISSING: $ hasConditionalBypassTest doReallyImportantSecurityWork(); - - // Apache Shiro permissions system - String whatDoTheyWantToDo = args[4]; - Subject subject = SecurityUtils.getSubject(); - // BAD: permissions decision made using tainted data - if(subject.isPermitted("domain:sublevel:" + whatDoTheyWantToDo)) - doIt(); - - // GOOD: use fixed checks - if(subject.isPermitted("domain:sublevel:whatTheMethodDoes")) - doIt(); - + InetAddress local = InetAddress.getLocalHost(); // GOOD: reverse DNS on localhost is fine if (local.getCanonicalHostName().equals("localhost")) { @@ -63,68 +50,129 @@ class Test { login(user, password); } } - + public static void test(String user, String password) { Cookie adminCookie = getCookies()[0]; // GOOD: login always happens - if(adminCookie.getValue()=="false") + if (adminCookie.getValue() == "false") login(user, password); else { - // do something else login(user, password); } } - + public static void test2(String user, String password) { Cookie adminCookie = getCookies()[0]; // BAD: login may happen once or twice - if(adminCookie.getValue()=="false") + if (adminCookie.getValue() == "false") // $ hasConditionalBypassTest login(user, password); else { // do something else + doIt(); } login(user, password); } - + public static void test3(String user, String password) { Cookie adminCookie = getCookies()[0]; - if(adminCookie.getValue()=="false") + // BAD: login may not happen + if (adminCookie.getValue() == "false") // $ hasConditionalBypassTest login(user, password); else { // do something else - // BAD: login may not happen - return; + doIt(); } + return; } - + public static void test4(String user, String password) { Cookie adminCookie = getCookies()[0]; // GOOD: login always happens - if(adminCookie.getValue()=="false") { + if (adminCookie.getValue() == "false") { login(user, password); return; } - + // do other things login(user, password); return; } - + + public static void test5(String user, String password) throws Exception { + Cookie adminCookie = getCookies()[0]; + // GOOD: exit with Exception if condition is not met + if (adminCookie.getValue() == "false") { + throw new Exception(); + } + + login(user, password); + } + + public static void test6(String user, String password) { + Cookie adminCookie = getCookies()[0]; + // GOOD: exit with return if condition is not met + if (adminCookie.getValue() == "false") { + return; + } + + login(user, password); + } + + public static void test7(String user, String password) { + Cookie adminCookie = getCookies()[0]; + // BAD: login is bypasseable + if (adminCookie.getValue() == "false") { // $ hasConditionalBypassTest + login(user, password); + return; + } else { + doIt(); + } + } + + public static void test8(String user, String password) { + Cookie adminCookie = getCookies()[0]; + { + // BAD: login may not happen + if (adminCookie.getValue() == "false") // $ hasConditionalBypassTest + authorize(user, password); + else { + // do something else + doIt(); + } + } + { + // obtainAuthor is not sensitive, so this is safe + if (adminCookie.getValue() == "false") + obtainAuthor(); + else { + doIt(); + } + } + } + public static void login(String user, String password) { // login } - + public static void reCheckAuth(String user, String password) { // login } - + + public static void authorize(String user, String password) { + // login + } + + public static String obtainAuthor() { + return ""; + } + public static Cookie[] getCookies() { // get cookies from a servlet return new Cookie[0]; } - + public static void doIt() {} - + public static void doReallyImportantSecurityWork() { // login, authenticate, everything } diff --git a/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypassTest.ql b/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypassTest.ql new file mode 100644 index 00000000000..8fc8fe9b9af --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypassTest.ql @@ -0,0 +1,20 @@ +import java +import semmle.code.java.security.ConditionalBypassQuery +import TestUtilities.InlineExpectationsTest + +class ConditionalBypassTest extends InlineExpectationsTest { + ConditionalBypassTest() { this = "ConditionalBypassTest" } + + override string getARelevantTag() { result = "hasConditionalBypassTest" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "hasConditionalBypassTest" and + exists(DataFlow::Node src, DataFlow::Node sink, ConditionalBypassFlowConfig conf | + conf.hasFlow(src, sink) + | + sink.getLocation() = location and + element = sink.toString() and + value = "" + ) + } +} diff --git a/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheck.expected b/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheck.expected index 72c161165c4..10622bf7d90 100644 --- a/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheck.expected +++ b/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheck.expected @@ -1,8 +1,8 @@ edges -| Test.java:17:26:17:38 | args : String[] | Test.java:50:26:50:64 | ... + ... | +| TaintedPermissionsCheckTest.java:12:19:12:48 | getParameter(...) : String | TaintedPermissionsCheckTest.java:15:27:15:53 | ... + ... | nodes -| Test.java:17:26:17:38 | args : String[] | semmle.label | args : String[] | -| Test.java:50:26:50:64 | ... + ... | semmle.label | ... + ... | +| TaintedPermissionsCheckTest.java:12:19:12:48 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| TaintedPermissionsCheckTest.java:15:27:15:53 | ... + ... | semmle.label | ... + ... | subpaths #select -| Test.java:50:6:50:65 | isPermitted(...) | Test.java:17:26:17:38 | args : String[] | Test.java:50:26:50:64 | ... + ... | Permissions check uses user-controlled $@. | Test.java:17:26:17:38 | args | data | +| TaintedPermissionsCheckTest.java:15:7:15:54 | isPermitted(...) | TaintedPermissionsCheckTest.java:12:19:12:48 | getParameter(...) : String | TaintedPermissionsCheckTest.java:15:27:15:53 | ... + ... | Permissions check uses user-controlled $@. | TaintedPermissionsCheckTest.java:12:19:12:48 | getParameter(...) | data | diff --git a/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheckTest.java b/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheckTest.java new file mode 100644 index 00000000000..622538b7e35 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-807/semmle/tests/TaintedPermissionsCheckTest.java @@ -0,0 +1,25 @@ +// Test case for CWE-807 (Reliance on Untrusted Inputs in a Security Decision) +// http://cwe.mitre.org/data/definitions/807.html +package test.cwe807.semmle.tests; + +import javax.servlet.http.HttpServletRequest; +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.subject.Subject; + +class TaintedPermissionsCheckTest { + public static void main(HttpServletRequest request) throws Exception { + // Apache Shiro permissions system + String action = request.getParameter("action"); + Subject subject = SecurityUtils.getSubject(); + // BAD: permissions decision made using tainted data + if (subject.isPermitted("domain:sublevel:" + action)) + doIt(); + + // GOOD: use fixed checks + if (subject.isPermitted("domain:sublevel:whatTheMethodDoes")) + doIt(); + } + + public static void doIt() {} + +} diff --git a/java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/Configuration.java b/java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/Configuration.java similarity index 100% rename from java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/Configuration.java rename to java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/Configuration.java diff --git a/java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/lib/SourceResolver.java b/java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/lib/SourceResolver.java similarity index 100% rename from java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/lib/SourceResolver.java rename to java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/lib/SourceResolver.java diff --git a/java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/om/NotationSet.java b/java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/om/NotationSet.java similarity index 100% rename from java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/om/NotationSet.java rename to java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/om/NotationSet.java diff --git a/java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/AbstractXsltTransformer.java b/java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/AbstractXsltTransformer.java similarity index 100% rename from java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/AbstractXsltTransformer.java rename to java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/AbstractXsltTransformer.java diff --git a/java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/Destination.java b/java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/Destination.java similarity index 100% rename from java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/Destination.java rename to java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/Destination.java diff --git a/java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/Processor.java b/java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/Processor.java similarity index 100% rename from java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/Processor.java rename to java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/Processor.java diff --git a/java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/QName.java b/java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/QName.java similarity index 100% rename from java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/QName.java rename to java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/QName.java diff --git a/java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/SaxonApiException.java b/java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/SaxonApiException.java similarity index 100% rename from java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/SaxonApiException.java rename to java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/SaxonApiException.java diff --git a/java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/SaxonApiUncheckedException.java b/java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/SaxonApiUncheckedException.java similarity index 100% rename from java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/SaxonApiUncheckedException.java rename to java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/SaxonApiUncheckedException.java diff --git a/java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XdmItem.java b/java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XdmItem.java similarity index 100% rename from java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XdmItem.java rename to java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XdmItem.java diff --git a/java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XdmValue.java b/java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XdmValue.java similarity index 100% rename from java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XdmValue.java rename to java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XdmValue.java diff --git a/java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/Xslt30Transformer.java b/java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/Xslt30Transformer.java similarity index 100% rename from java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/Xslt30Transformer.java rename to java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/Xslt30Transformer.java diff --git a/java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltCompiler.java b/java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltCompiler.java similarity index 100% rename from java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltCompiler.java rename to java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltCompiler.java diff --git a/java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltExecutable.java b/java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltExecutable.java similarity index 100% rename from java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltExecutable.java rename to java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltExecutable.java diff --git a/java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltPackage.java b/java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltPackage.java similarity index 100% rename from java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltPackage.java rename to java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltPackage.java diff --git a/java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltTransformer.java b/java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltTransformer.java similarity index 100% rename from java/ql/test/experimental/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltTransformer.java rename to java/ql/test/stubs/Saxon-HE-9.9.1-7/net/sf/saxon/s9api/XsltTransformer.java diff --git a/java/ql/test/stubs/apache-commons-digester3-3.2/org/apache/commons/digester3/Digester.java b/java/ql/test/stubs/apache-commons-digester3-3.2/org/apache/commons/digester3/Digester.java new file mode 100644 index 00000000000..546aecbe521 --- /dev/null +++ b/java/ql/test/stubs/apache-commons-digester3-3.2/org/apache/commons/digester3/Digester.java @@ -0,0 +1,50 @@ +package org.apache.commons.digester3; + +import java.io.File; +import org.xml.sax.InputSource; +import java.io.Reader; +import java.net.URL; +import java.io.InputStream; +import java.io.IOException; +import org.xml.sax.SAXException; +import javax.xml.parsers.SAXParser; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; +import javax.xml.parsers.ParserConfigurationException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; + +public class Digester extends DefaultHandler { + + public Digester() { } + + public Digester(SAXParser parser) { } + + public Digester(XMLReader reader) { } + + public T parse(InputStream input) throws IOException, SAXException { + return null; + } + + public T parse(File file) throws IOException, SAXException { + return null; + } + + public T parse(InputSource input) throws IOException, SAXException { + return null; + } + + public T parse(Reader reader) throws IOException, SAXException { + return null; + } + + public T parse(String uri) throws IOException, SAXException { + return null; + } + + public T parse(URL url) throws IOException, SAXException { + return null; + } + + public void setFeature(String feature, boolean value) throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException { } +} \ No newline at end of file diff --git a/java/ql/test/stubs/dom4j-2.1.1/org/dom4j/DocumentException.java b/java/ql/test/stubs/dom4j-2.1.1/org/dom4j/DocumentException.java new file mode 100644 index 00000000000..2afcfe6e3cd --- /dev/null +++ b/java/ql/test/stubs/dom4j-2.1.1/org/dom4j/DocumentException.java @@ -0,0 +1,24 @@ +package org.dom4j; + +public class DocumentException extends Exception { + public DocumentException() { + } + + public DocumentException(String message) { + super(message); + } + + public DocumentException(String message, Throwable cause) { + super(message, cause); + } + + public DocumentException(Throwable cause) { + super(cause); + } + + /** @deprecated */ + @Deprecated + public Throwable getNestedException() { + return null; + } +} diff --git a/java/ql/test/stubs/dom4j-2.1.1/org/dom4j/DocumentHelper.java b/java/ql/test/stubs/dom4j-2.1.1/org/dom4j/DocumentHelper.java index 669dbfa9e9b..65254265774 100644 --- a/java/ql/test/stubs/dom4j-2.1.1/org/dom4j/DocumentHelper.java +++ b/java/ql/test/stubs/dom4j-2.1.1/org/dom4j/DocumentHelper.java @@ -69,6 +69,9 @@ public final class DocumentHelper { return null; } + public static Document parseText(String text) throws DocumentException { + return null; + } } /* diff --git a/java/ql/test/stubs/flexjson-2.1/flexjson/JSONDeserializer.java b/java/ql/test/stubs/flexjson-2.1/flexjson/JSONDeserializer.java new file mode 100644 index 00000000000..f165b51bd49 --- /dev/null +++ b/java/ql/test/stubs/flexjson-2.1/flexjson/JSONDeserializer.java @@ -0,0 +1,121 @@ +package flexjson; + +import java.io.Reader; + +public class JSONDeserializer { + + public JSONDeserializer() { + } + + /** + * Deserialize the given json formatted input into a Java object. + * + * @param input a json formatted string. + * @return an Java instance deserialized from the json input. + */ + public T deserialize( String input ) { + return null; + } + + /** + * Same as {@link #deserialize(String)}, but uses an instance of + * java.io.Reader as json input. + * + * @param input the stream where the json input is coming from. + * @return an Java instance deserialized from the java.io.Reader's input. + */ + public T deserialize( Reader input ) { + return null; + } + + /** + * Deserialize the given json input, and use the given Class as + * the type of the initial object to deserialize into. This object + * must implement a no-arg constructor. + * + * @param input a json formatted string. + * @param root a Class used to create the initial object. + * @return the object created from the given json input. + */ + public T deserialize( String input, Class root ) { + return null; + } + + /** + * Same as {@link #deserialize(java.io.Reader, Class)}, but uses an instance of + * java.io.Reader as json input. + * + * @param input the stream where the json input is coming from. + * @param root a Class used to create the initial object. + * @return an Java instance deserialized from the java.io.Reader's input. + */ + public T deserialize( Reader input, Class root ) { + return null; + } + + /** + * Deserialize the given json input, and use the given ObjectFactory to + * create the initial object to deserialize into. + * + * @param input a json formatted string. + * @param factory an ObjectFactory used to create the initial object. + * @return the object created from the given json input. + */ + public T deserialize( String input, ObjectFactory factory ) { + return null; + } + + /** + * Same as {@link #deserialize(String, ObjectFactory)}, but uses an instance of + * java.io.Reader as json input. + * + * @param input the stream where the json input is coming from. + * @param factory an ObjectFactory used to create the initial object. + * @return an Java instance deserialized from the java.io.Reader's input. + */ + public T deserialize( Reader input, ObjectFactory factory ) { + return null; + } + + /** + * Deserialize the given input into the existing object target. + * Values in the json input will overwrite values in the + * target object. This means if a value is included in json + * a new object will be created and set into the existing object. + * + * @param input a json formatted string. + * @param target an instance to set values into from the json string. + * @return will return a reference to target. + */ + public T deserializeInto( String input, T target ) { + return null; + } + + /** + * Same as {@link #deserializeInto(String, Object)}, but uses an instance of + * java.io.Reader as json input. + * + * @param input the stream where the json input is coming from. + * @param target an instance to set values into from the json string. + * @return will return a reference to target. + */ + public T deserializeInto( Reader input, T target ) { + return null; + } + + public JSONDeserializer use( String path, Class clazz ) { + return null; + } + + public JSONDeserializer use( Class clazz, ObjectFactory factory ) { + return null; + } + + public JSONDeserializer use( String path, ObjectFactory factory ) { + return null; + } + + public JSONDeserializer use(ObjectFactory factory, String... paths) { + return null; + } +} diff --git a/java/ql/test/stubs/flexjson-2.1/flexjson/ObjectBinder.java b/java/ql/test/stubs/flexjson-2.1/flexjson/ObjectBinder.java new file mode 100644 index 00000000000..efb648971dc --- /dev/null +++ b/java/ql/test/stubs/flexjson-2.1/flexjson/ObjectBinder.java @@ -0,0 +1,40 @@ +package flexjson; + +import java.lang.reflect.Type; + +import java.util.Map; +import java.util.Collection; + +public class ObjectBinder { + + public ObjectBinder() { + } + + public ObjectBinder use(Class clazz, ObjectFactory factory) { + return null; + } + + public Object bind( Object input ) { + return null; + } + + public Object bind( Object source, Object target ) { + return null; + } + + public Object bind( Object input, Type targetType ) { + return null; + } + + public > T bindIntoCollection(Collection value, T target, Type targetType) { + return null; + } + + public Object bindIntoMap(Map input, Map result, Type keyType, Type valueType) { + return null; + } + + public Object bindIntoObject(Map jsonOwner, Object target, Type targetType) { + return null; + } +} diff --git a/java/ql/test/stubs/flexjson-2.1/flexjson/ObjectFactory.java b/java/ql/test/stubs/flexjson-2.1/flexjson/ObjectFactory.java new file mode 100644 index 00000000000..87989d29947 --- /dev/null +++ b/java/ql/test/stubs/flexjson-2.1/flexjson/ObjectFactory.java @@ -0,0 +1,26 @@ +package flexjson; + +import java.lang.reflect.Type; + +/** + * ObjectFactory allows you to instantiate specific types of objects on path or class types. This interface allows + * you to override the default rules. + */ +public interface ObjectFactory { + /** + * This method is called by the deserializer to construct and bind an object. At the end of this method + * the object should be fully constructed. {@link flexjson.ObjectBinder} can be used to bind values into + * the object according to default rules. For simple implementations you won't need to use this, but + * for more complex or generic objects reusing methods like {@link flexjson.ObjectBinder#bind(Object, java.lang.reflect.Type)} + * and {@link flexjson.ObjectBinder#bindIntoCollection(java.util.Collection, java.util.Collection, java.lang.reflect.Type)}. + * + * @param context the object binding context to keep track of where we are in the object graph + * and used for binding into objects. + * @param value This is the value from the json object at the current path. + * @param targetType This is the type pulled from the object introspector. Used for Collections and generic types. + * @param targetClass concrete class pulled from the configuration of the deserializer. + * + * @return the fully bound object. At the end of this method the object should be fully constructed. + */ + public Object instantiate(ObjectBinder context, Object value, Type targetType, Class targetClass); +} diff --git a/java/ql/test/stubs/flexjson-2.1/flexjson/factories/ExistingObjectFactory.java b/java/ql/test/stubs/flexjson-2.1/flexjson/factories/ExistingObjectFactory.java new file mode 100644 index 00000000000..eab94681557 --- /dev/null +++ b/java/ql/test/stubs/flexjson-2.1/flexjson/factories/ExistingObjectFactory.java @@ -0,0 +1,17 @@ +package flexjson.factories; + +import flexjson.ObjectBinder; +import flexjson.ObjectFactory; + +import java.lang.reflect.Type; + +public class ExistingObjectFactory implements ObjectFactory { + + public ExistingObjectFactory(Object source) { + } + + @Override + public Object instantiate(ObjectBinder context, Object value, Type targetType, Class targetClass) { + return null; + } +} \ No newline at end of file diff --git a/java/ql/test/stubs/google-android-9.0.0/android/net/Uri.java b/java/ql/test/stubs/google-android-9.0.0/android/net/Uri.java index d5352f0f7ea..2b63354b8f2 100644 --- a/java/ql/test/stubs/google-android-9.0.0/android/net/Uri.java +++ b/java/ql/test/stubs/google-android-9.0.0/android/net/Uri.java @@ -541,4 +541,152 @@ public abstract class Uri implements Parcelable, Comparable { public boolean isPathPrefixMatch(Uri prefix) { return false; } + + public Builder buildUpon() { return null; } + + /** + * Helper class for building or manipulating URI references. Not safe for + * concurrent use. + * + *

    An absolute hierarchical URI reference follows the pattern: + * {@code ://?#} + * + *

    Relative URI references (which are always hierarchical) follow one + * of two patterns: {@code ?#} + * or {@code //?#} + * + *

    An opaque URI follows this pattern: + * {@code :#} + * + *

    Use {@link Uri#buildUpon()} to obtain a builder representing an existing URI. + */ + public static final class Builder { + /** + * Constructs a new Builder. + */ + public Builder() {} + /** + * Sets the scheme. + * + * @param scheme name or {@code null} if this is a relative Uri + */ + public Builder scheme(String scheme) { + return null; + } + /** + * Encodes and sets the given opaque scheme-specific-part. + * + * @param opaquePart decoded opaque part + */ + public Builder opaquePart(String opaquePart) { + return null; + } + /** + * Sets the previously encoded opaque scheme-specific-part. + * + * @param opaquePart encoded opaque part + */ + public Builder encodedOpaquePart(String opaquePart) { + return null; + } + /** + * Encodes and sets the authority. + */ + public Builder authority(String authority) { + return null; + } + /** + * Sets the previously encoded authority. + */ + public Builder encodedAuthority(String authority) { + return null; + } + /** + * Sets the path. Leaves '/' characters intact but encodes others as + * necessary. + * + *

    If the path is not null and doesn't start with a '/', and if + * you specify a scheme and/or authority, the builder will prepend the + * given path with a '/'. + */ + public Builder path(String path) { + return null; + } + /** + * Sets the previously encoded path. + * + *

    If the path is not null and doesn't start with a '/', and if + * you specify a scheme and/or authority, the builder will prepend the + * given path with a '/'. + */ + public Builder encodedPath(String path) { + return null; + } + /** + * Encodes the given segment and appends it to the path. + */ + public Builder appendPath(String newSegment) { + return null; + } + /** + * Appends the given segment to the path. + */ + public Builder appendEncodedPath(String newSegment) { + return null; + } + /** + * Encodes and sets the query. + */ + public Builder query(String query) { + return null; + } + /** + * Sets the previously encoded query. + */ + public Builder encodedQuery(String query) { + return null; + } + /** + * Encodes and sets the fragment. + */ + public Builder fragment(String fragment) { + return null; + } + /** + * Sets the previously encoded fragment. + */ + public Builder encodedFragment(String fragment) { + return null; + } + /** + * Encodes the key and value and then appends the parameter to the + * query string. + * + * @param key which will be encoded + * @param value which will be encoded + */ + public Builder appendQueryParameter(String key, String value) { + return null; + } + /** + * Clears the the previously set query. + */ + public Builder clearQuery() { + return null; + } + /** + * Constructs a Uri with the current attributes. + * + * @throws UnsupportedOperationException if the URI is opaque and the + * scheme is null + */ + public Uri build() { + return null; + } + @Override + public String toString() { + return null; + } + } + } diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/base/Converter.java b/java/ql/test/stubs/guava-30.0/com/google/common/base/Converter.java index d4e59f3ff91..4d2a445ccf8 100644 --- a/java/ql/test/stubs/guava-30.0/com/google/common/base/Converter.java +++ b/java/ql/test/stubs/guava-30.0/com/google/common/base/Converter.java @@ -1,55 +1,20 @@ -/* - * Copyright (C) 2008 The Guava Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ +// Generated automatically from com.google.common.base.Converter for testing purposes package com.google.common.base; -import org.checkerframework.checker.nullness.qual.Nullable; -public abstract class Converter implements Function { - public final @Nullable B convert(@Nullable A a) { - return null; - } - - public Iterable convertAll(final Iterable fromIterable) { - return null; - } - - public Converter reverse() { - return null; - } - - public final Converter andThen(Converter secondConverter) { - return null; - } - - @Override - public final @Nullable B apply(@Nullable A a) { - return null; - } - - @Override - public boolean equals(@Nullable Object object) { - return false; - } - - public static Converter from( - Function forwardFunction, - Function backwardFunction) { - return null; - } - - public static Converter identity() { - return null; - } +import com.google.common.base.Function; +abstract public class Converter implements Function +{ + protected Converter(){} + protected abstract A doBackward(B p0); + protected abstract B doForward(A p0); + public Converter reverse(){ return null; } + public Iterable convertAll(Iterable p0){ return null; } + public boolean equals(Object p0){ return false; } + public final Converter andThen(Converter p0){ return null; } + public final B apply(A p0){ return null; } + public final B convert(A p0){ return null; } + public static Converter from(Function p0, Function p1){ return null; } + public static Converter identity(){ return null; } } diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/base/Equivalence.java b/java/ql/test/stubs/guava-30.0/com/google/common/base/Equivalence.java new file mode 100644 index 00000000000..f3fe531bf93 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/base/Equivalence.java @@ -0,0 +1,32 @@ +// Generated automatically from com.google.common.base.Equivalence for testing purposes + +package com.google.common.base; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import java.io.Serializable; +import java.util.function.BiPredicate; + +abstract public class Equivalence implements BiPredicate +{ + protected Equivalence(){} + protected abstract boolean doEquivalent(T p0, T p1); + protected abstract int doHash(T p0); + public final Equivalence onResultOf(Function p0){ return null; } + public final Equivalence.Wrapper wrap(S p0){ return null; } + public final Equivalence> pairwise(){ return null; } + public final Predicate equivalentTo(T p0){ return null; } + public final boolean equivalent(T p0, T p1){ return false; } + public final boolean test(T p0, T p1){ return false; } + public final int hash(T p0){ return 0; } + public static Equivalence equals(){ return null; } + public static Equivalence identity(){ return null; } + static public class Wrapper implements Serializable + { + protected Wrapper() {} + public String toString(){ return null; } + public T get(){ return null; } + public boolean equals(Object p0){ return false; } + public int hashCode(){ return 0; } + } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/base/Optional.java b/java/ql/test/stubs/guava-30.0/com/google/common/base/Optional.java index 3f39995651a..7228faa03ab 100644 --- a/java/ql/test/stubs/guava-30.0/com/google/common/base/Optional.java +++ b/java/ql/test/stubs/guava-30.0/com/google/common/base/Optional.java @@ -1,77 +1,31 @@ -/* - * Copyright (C) 2011 The Guava Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ +// Generated automatically from com.google.common.base.Optional for testing purposes, and manually adjusted. package com.google.common.base; + +import com.google.common.base.Function; +import com.google.common.base.Supplier; import java.io.Serializable; import java.util.Set; -import org.checkerframework.checker.nullness.qual.Nullable; - -public abstract class Optional implements Serializable { - public static Optional absent() { - return null; - } - - public static Optional of(T reference) { - return null; - } - - public static Optional fromNullable(@Nullable T nullableReference) { - return null; - } - - public static @Nullable Optional fromJavaUtil( - java.util.@Nullable Optional javaUtilOptional) { - return null; - } - - public static java.util.@Nullable Optional toJavaUtil( - @Nullable Optional googleOptional) { - return null; - } - - public java.util.Optional toJavaUtil() { - return null; - } - - public abstract boolean isPresent(); - - public abstract T get(); - - public abstract T or(T defaultValue); - - public abstract Optional or(Optional secondChoice); - - public abstract T or(Supplier supplier); - - public abstract @Nullable T orNull(); - - public abstract Set asSet(); - - public abstract Optional transform(Function function); - - @Override - public abstract boolean equals(@Nullable Object object); - - @Override - public abstract int hashCode(); - - @Override - public abstract String toString(); - - public static Iterable presentInstances( - final Iterable> optionals) { - return null; - } +abstract public class Optional implements Serializable +{ + Optional(){} + public java.util.Optional toJavaUtil(){ return null; } + public abstract Optional transform(Function p0); + public abstract Optional or(Optional p0); + public abstract Set asSet(); + public abstract String toString(); + public abstract T get(); + public abstract T or(Supplier p0); + public abstract T or(T p0); + public abstract T orNull(); + public abstract boolean equals(Object p0); + public abstract boolean isPresent(); + public abstract int hashCode(); + public static Iterable presentInstances(Iterable> p0){ return null; } + public static Optional absent(){ return null; } + public static Optional fromJavaUtil(java.util.Optional p0){ return null; } + public static Optional fromNullable(T p0){ return null; } + public static Optional of(T p0){ return null; } + public static java.util.Optional toJavaUtil(Optional p0){ return null; } } diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractListMultimap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractListMultimap.java new file mode 100644 index 00000000000..673bf12660a --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractListMultimap.java @@ -0,0 +1,21 @@ +// Generated automatically from com.google.common.collect.AbstractListMultimap for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.AbstractMapBasedMultimap; +import com.google.common.collect.ListMultimap; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +abstract class AbstractListMultimap extends AbstractMapBasedMultimap implements ListMultimap +{ + protected AbstractListMultimap() {} + protected AbstractListMultimap(Map> p0){} + public List get(K p0){ return null; } + public List removeAll(Object p0){ return null; } + public List replaceValues(K p0, Iterable p1){ return null; } + public Map> asMap(){ return null; } + public boolean equals(Object p0){ return false; } + public boolean put(K p0, V p1){ return false; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractMapBasedMultimap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractMapBasedMultimap.java new file mode 100644 index 00000000000..81883754e6a --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractMapBasedMultimap.java @@ -0,0 +1,28 @@ +// Generated automatically from com.google.common.collect.AbstractMapBasedMultimap for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.AbstractMultimap; +import java.io.Serializable; +import java.util.AbstractCollection; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Spliterator; +import java.util.function.BiConsumer; + +abstract class AbstractMapBasedMultimap extends AbstractMultimap implements Serializable +{ + protected AbstractMapBasedMultimap() {} + protected AbstractMapBasedMultimap(Map> p0){} + public Collection> entries(){ return null; } + public Collection get(K p0){ return null; } + public Collection removeAll(Object p0){ return null; } + public Collection replaceValues(K p0, Iterable p1){ return null; } + public Collection values(){ return null; } + public boolean containsKey(Object p0){ return false; } + public boolean put(K p0, V p1){ return false; } + public int size(){ return 0; } + public void clear(){} + public void forEach(BiConsumer p0){} +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractMapBasedMultiset.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractMapBasedMultiset.java new file mode 100644 index 00000000000..85f575c0d00 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractMapBasedMultiset.java @@ -0,0 +1,27 @@ +// Generated automatically from com.google.common.collect.AbstractMapBasedMultiset for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.AbstractMultiset; +import com.google.common.collect.Count; +import com.google.common.collect.Multiset; +import java.io.Serializable; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.function.ObjIntConsumer; + +abstract class AbstractMapBasedMultiset extends AbstractMultiset implements Serializable +{ + protected AbstractMapBasedMultiset() {} + protected AbstractMapBasedMultiset(Map p0){} + public Iterator iterator(){ return null; } + public Set> entrySet(){ return null; } + public int add(E p0, int p1){ return 0; } + public int count(Object p0){ return 0; } + public int remove(Object p0, int p1){ return 0; } + public int setCount(E p0, int p1){ return 0; } + public int size(){ return 0; } + public void clear(){} + public void forEachEntry(ObjIntConsumer p0){} +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractMultiset.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractMultiset.java new file mode 100644 index 00000000000..1403d74287b --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractMultiset.java @@ -0,0 +1,29 @@ +// Generated automatically from com.google.common.collect.AbstractMultiset for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.Multiset; +import java.util.AbstractCollection; +import java.util.Collection; +import java.util.Set; + +abstract class AbstractMultiset extends AbstractCollection implements Multiset +{ + public Set elementSet(){ return null; } + public Set> entrySet(){ return null; } + public abstract void clear(); + public boolean contains(Object p0){ return false; } + public boolean isEmpty(){ return false; } + public boolean setCount(E p0, int p1, int p2){ return false; } + public final String toString(){ return null; } + public final boolean add(E p0){ return false; } + public final boolean addAll(Collection p0){ return false; } + public final boolean equals(Object p0){ return false; } + public final boolean remove(Object p0){ return false; } + public final boolean removeAll(Collection p0){ return false; } + public final boolean retainAll(Collection p0){ return false; } + public final int hashCode(){ return 0; } + public int add(E p0, int p1){ return 0; } + public int remove(Object p0, int p1){ return 0; } + public int setCount(E p0, int p1){ return 0; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractSetMultimap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractSetMultimap.java new file mode 100644 index 00000000000..58a869e4061 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractSetMultimap.java @@ -0,0 +1,22 @@ +// Generated automatically from com.google.common.collect.AbstractSetMultimap for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.AbstractMapBasedMultimap; +import com.google.common.collect.SetMultimap; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +abstract class AbstractSetMultimap extends AbstractMapBasedMultimap implements SetMultimap +{ + protected AbstractSetMultimap() {} + protected AbstractSetMultimap(Map> p0){} + public Map> asMap(){ return null; } + public Set> entries(){ return null; } + public Set get(K p0){ return null; } + public Set removeAll(Object p0){ return null; } + public Set replaceValues(K p0, Iterable p1){ return null; } + public boolean equals(Object p0){ return false; } + public boolean put(K p0, V p1){ return false; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractSortedKeySortedSetMultimap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractSortedKeySortedSetMultimap.java new file mode 100644 index 00000000000..99e7dae3f3c --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractSortedKeySortedSetMultimap.java @@ -0,0 +1,15 @@ +// Generated automatically from com.google.common.collect.AbstractSortedKeySortedSetMultimap for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.AbstractSortedSetMultimap; +import java.util.Collection; +import java.util.SortedMap; +import java.util.SortedSet; + +abstract class AbstractSortedKeySortedSetMultimap extends AbstractSortedSetMultimap +{ + protected AbstractSortedKeySortedSetMultimap() {} + public SortedMap> asMap(){ return null; } + public SortedSet keySet(){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractSortedMultiset.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractSortedMultiset.java new file mode 100644 index 00000000000..4b9b54003d6 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractSortedMultiset.java @@ -0,0 +1,22 @@ +// Generated automatically from com.google.common.collect.AbstractSortedMultiset for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.AbstractMultiset; +import com.google.common.collect.BoundType; +import com.google.common.collect.Multiset; +import com.google.common.collect.SortedMultiset; +import java.util.Comparator; +import java.util.NavigableSet; + +abstract class AbstractSortedMultiset extends AbstractMultiset implements SortedMultiset +{ + public Comparator comparator(){ return null; } + public Multiset.Entry firstEntry(){ return null; } + public Multiset.Entry lastEntry(){ return null; } + public Multiset.Entry pollFirstEntry(){ return null; } + public Multiset.Entry pollLastEntry(){ return null; } + public NavigableSet elementSet(){ return null; } + public SortedMultiset descendingMultiset(){ return null; } + public SortedMultiset subMultiset(E p0, BoundType p1, E p2, BoundType p3){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractSortedSetMultimap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractSortedSetMultimap.java new file mode 100644 index 00000000000..00d6491a2ca --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractSortedSetMultimap.java @@ -0,0 +1,20 @@ +// Generated automatically from com.google.common.collect.AbstractSortedSetMultimap for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.AbstractSetMultimap; +import com.google.common.collect.SortedSetMultimap; +import java.util.Collection; +import java.util.Map; +import java.util.SortedSet; + +abstract class AbstractSortedSetMultimap extends AbstractSetMultimap implements SortedSetMultimap +{ + protected AbstractSortedSetMultimap() {} + protected AbstractSortedSetMultimap(Map> p0){} + public Collection values(){ return null; } + public Map> asMap(){ return null; } + public SortedSet get(K p0){ return null; } + public SortedSet removeAll(Object p0){ return null; } + public SortedSet replaceValues(K p0, Iterable p1){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractTable.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractTable.java index 9003783bab9..64ca3131671 100644 --- a/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractTable.java +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/AbstractTable.java @@ -1,90 +1,28 @@ -/* - * Copyright (C) 2013 The Guava Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ +// Generated automatically from com.google.common.collect.AbstractTable for testing purposes package com.google.common.collect; +import com.google.common.collect.Table; import java.util.Collection; -import java.util.Map; import java.util.Set; -abstract class AbstractTable implements Table { - @Override - public boolean containsRow(Object rowKey) { - return false; - } - - @Override - public boolean containsColumn(Object columnKey) { - return false; - } - - @Override - public Set rowKeySet() { - return null; - } - - @Override - public Set columnKeySet() { - return null; - } - - @Override - public boolean containsValue(Object value) { - return false; - } - - @Override - public boolean contains(Object rowKey, Object columnKey) { - return false; - } - - @Override - public V get(Object rowKey, Object columnKey) { - return null; - } - - @Override - public boolean isEmpty() { - return false; - } - - @Override - public void clear() { - } - - @Override - public V remove(Object rowKey, Object columnKey) { - return null; - } - - @Override - public V put(R rowKey, C columnKey, V value) { - return null; - } - - @Override - public void putAll(Table table) { - } - - @Override - public Set> cellSet() { - return null; - } - - @Override - public Collection values() { - return null; - } - +abstract class AbstractTable implements Table +{ + public Collection values(){ return null; } + public Set columnKeySet(){ return null; } + public Set rowKeySet(){ return null; } + public Set> cellSet(){ return null; } + public String toString(){ return null; } + public V get(Object p0, Object p1){ return null; } + public V put(R p0, C p1, V p2){ return null; } + public V remove(Object p0, Object p1){ return null; } + public boolean contains(Object p0, Object p1){ return false; } + public boolean containsColumn(Object p0){ return false; } + public boolean containsRow(Object p0){ return false; } + public boolean containsValue(Object p0){ return false; } + public boolean equals(Object p0){ return false; } + public boolean isEmpty(){ return false; } + public int hashCode(){ return 0; } + public void clear(){} + public void putAll(Table p0){} } diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ArrayListMultimap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ArrayListMultimap.java new file mode 100644 index 00000000000..3e985271163 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ArrayListMultimap.java @@ -0,0 +1,15 @@ +// Generated automatically from com.google.common.collect.ArrayListMultimap for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.ArrayListMultimapGwtSerializationDependencies; +import com.google.common.collect.Multimap; + +public class ArrayListMultimap extends ArrayListMultimapGwtSerializationDependencies +{ + protected ArrayListMultimap() {} + public static ArrayListMultimap create(){ return null; } + public static ArrayListMultimap create(Multimap p0){ return null; } + public static ArrayListMultimap create(int p0, int p1){ return null; } + public void trimToSize(){} +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ArrayListMultimapGwtSerializationDependencies.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ArrayListMultimapGwtSerializationDependencies.java new file mode 100644 index 00000000000..9cb4c8f0c51 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ArrayListMultimapGwtSerializationDependencies.java @@ -0,0 +1,10 @@ +// Generated automatically from com.google.common.collect.ArrayListMultimapGwtSerializationDependencies for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.AbstractListMultimap; + +abstract class ArrayListMultimapGwtSerializationDependencies extends AbstractListMultimap +{ + protected ArrayListMultimapGwtSerializationDependencies() {} +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ArrayTable.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ArrayTable.java new file mode 100644 index 00000000000..32543b5bc6a --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ArrayTable.java @@ -0,0 +1,45 @@ +// Generated automatically from com.google.common.collect.ArrayTable for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.AbstractTable; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Table; +import java.io.Serializable; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +public class ArrayTable extends AbstractTable implements Serializable +{ + protected ArrayTable() {} + public Collection values(){ return null; } + public ImmutableList columnKeyList(){ return null; } + public ImmutableList rowKeyList(){ return null; } + public ImmutableSet columnKeySet(){ return null; } + public ImmutableSet rowKeySet(){ return null; } + public Map> columnMap(){ return null; } + public Map row(R p0){ return null; } + public Map> rowMap(){ return null; } + public Map column(C p0){ return null; } + public Set> cellSet(){ return null; } + public V at(int p0, int p1){ return null; } + public V erase(Object p0, Object p1){ return null; } + public V get(Object p0, Object p1){ return null; } + public V put(R p0, C p1, V p2){ return null; } + public V remove(Object p0, Object p1){ return null; } + public V set(int p0, int p1, V p2){ return null; } + public V[][] toArray(Class p0){ return null; } + public boolean contains(Object p0, Object p1){ return false; } + public boolean containsColumn(Object p0){ return false; } + public boolean containsRow(Object p0){ return false; } + public boolean containsValue(Object p0){ return false; } + public boolean isEmpty(){ return false; } + public int size(){ return 0; } + public static ArrayTable create(Iterable p0, Iterable p1){ return null; } + public static ArrayTable create(Table p0){ return null; } + public void clear(){} + public void eraseAll(){} + public void putAll(Table p0){} +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/BiMap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/BiMap.java new file mode 100644 index 00000000000..00e7a90086b --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/BiMap.java @@ -0,0 +1,15 @@ +// Generated automatically from com.google.common.collect.BiMap for testing purposes + +package com.google.common.collect; + +import java.util.Map; +import java.util.Set; + +public interface BiMap extends Map +{ + BiMap inverse(); + Set values(); + V forcePut(K p0, V p1); + V put(K p0, V p1); + void putAll(Map p0); +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/BoundType.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/BoundType.java new file mode 100644 index 00000000000..dda52f260dd --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/BoundType.java @@ -0,0 +1,10 @@ +// Generated automatically from com.google.common.collect.BoundType for testing purposes + +package com.google.common.collect; + + +public enum BoundType +{ + CLOSED, OPEN; + private BoundType() {} +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ClassToInstanceMap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ClassToInstanceMap.java new file mode 100644 index 00000000000..53dca6fb602 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ClassToInstanceMap.java @@ -0,0 +1,11 @@ +// Generated automatically from com.google.common.collect.ClassToInstanceMap for testing purposes + +package com.google.common.collect; + +import java.util.Map; + +public interface ClassToInstanceMap extends Map, B> +{ + T getInstance(Class p0); + T putInstance(Class p0, T p1); +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/Collections2.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Collections2.java new file mode 100644 index 00000000000..12b85b66058 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Collections2.java @@ -0,0 +1,19 @@ +// Generated automatically from com.google.common.collect.Collections2 for testing purposes + +package com.google.common.collect; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; + +public class Collections2 +{ + protected Collections2() {} + public static > Collection> orderedPermutations(Iterable p0){ return null; } + public static Collection filter(Collection p0, Predicate p1){ return null; } + public static Collection> orderedPermutations(Iterable p0, Comparator p1){ return null; } + public static Collection> permutations(Collection p0){ return null; } + public static Collection transform(Collection p0, Function p1){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ConcurrentHashMultiset.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ConcurrentHashMultiset.java new file mode 100644 index 00000000000..8eeff3c5792 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ConcurrentHashMultiset.java @@ -0,0 +1,32 @@ +// Generated automatically from com.google.common.collect.ConcurrentHashMultiset for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.AbstractMultiset; +import com.google.common.collect.Multiset; +import java.io.Serializable; +import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; + +public class ConcurrentHashMultiset extends AbstractMultiset implements Serializable +{ + protected ConcurrentHashMultiset() {} + public T[] toArray(T[] p0){ return null; } + public Iterator iterator(){ return null; } + public Object[] toArray(){ return null; } + public Set> createEntrySet(){ return null; } + public boolean isEmpty(){ return false; } + public boolean removeExactly(Object p0, int p1){ return false; } + public boolean setCount(E p0, int p1, int p2){ return false; } + public int add(E p0, int p1){ return 0; } + public int count(Object p0){ return 0; } + public int remove(Object p0, int p1){ return 0; } + public int setCount(E p0, int p1){ return 0; } + public int size(){ return 0; } + public static ConcurrentHashMultiset create(){ return null; } + public static ConcurrentHashMultiset create(ConcurrentMap p0){ return null; } + public static ConcurrentHashMultiset create(Iterable p0){ return null; } + public void clear(){} +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/Count.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Count.java new file mode 100644 index 00000000000..a49c1849e0a --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Count.java @@ -0,0 +1,18 @@ +// Generated automatically from com.google.common.collect.Count for testing purposes + +package com.google.common.collect; + +import java.io.Serializable; + +class Count implements Serializable +{ + protected Count() {} + public String toString(){ return null; } + public boolean equals(Object p0){ return false; } + public int addAndGet(int p0){ return 0; } + public int get(){ return 0; } + public int getAndSet(int p0){ return 0; } + public int hashCode(){ return 0; } + public void add(int p0){} + public void set(int p0){} +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/Cut.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Cut.java new file mode 100644 index 00000000000..ae1d3e14bc7 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Cut.java @@ -0,0 +1,13 @@ +// Generated automatically from com.google.common.collect.Cut for testing purposes + +package com.google.common.collect; + +import java.io.Serializable; + +abstract class Cut implements Comparable>, Serializable +{ + protected Cut() {} + public abstract int hashCode(); + public boolean equals(Object p0){ return false; } + public int compareTo(Cut p0){ return 0; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/DiscreteDomain.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/DiscreteDomain.java new file mode 100644 index 00000000000..6eb3681e382 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/DiscreteDomain.java @@ -0,0 +1,18 @@ +// Generated automatically from com.google.common.collect.DiscreteDomain for testing purposes + +package com.google.common.collect; + +import java.math.BigInteger; + +abstract public class DiscreteDomain +{ + protected DiscreteDomain(){} + public C maxValue(){ return null; } + public C minValue(){ return null; } + public abstract C next(C p0); + public abstract C previous(C p0); + public abstract long distance(C p0, C p1); + public static DiscreteDomain bigIntegers(){ return null; } + public static DiscreteDomain integers(){ return null; } + public static DiscreteDomain longs(){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ForwardingMap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ForwardingMap.java new file mode 100644 index 00000000000..bcb15cec45e --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ForwardingMap.java @@ -0,0 +1,37 @@ +// Generated automatically from com.google.common.collect.ForwardingMap for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.ForwardingObject; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +abstract public class ForwardingMap extends ForwardingObject implements Map +{ + protected ForwardingMap(){} + protected String standardToString(){ return null; } + protected V standardRemove(Object p0){ return null; } + protected abstract Map delegate(); + protected boolean standardContainsKey(Object p0){ return false; } + protected boolean standardContainsValue(Object p0){ return false; } + protected boolean standardEquals(Object p0){ return false; } + protected boolean standardIsEmpty(){ return false; } + protected int standardHashCode(){ return 0; } + protected void standardClear(){} + protected void standardPutAll(Map p0){} + public Collection values(){ return null; } + public Set keySet(){ return null; } + public Set> entrySet(){ return null; } + public V get(Object p0){ return null; } + public V put(K p0, V p1){ return null; } + public V remove(Object p0){ return null; } + public boolean containsKey(Object p0){ return false; } + public boolean containsValue(Object p0){ return false; } + public boolean equals(Object p0){ return false; } + public boolean isEmpty(){ return false; } + public int hashCode(){ return 0; } + public int size(){ return 0; } + public void clear(){} + public void putAll(Map p0){} +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ForwardingObject.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ForwardingObject.java new file mode 100644 index 00000000000..54cf8f64689 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ForwardingObject.java @@ -0,0 +1,11 @@ +// Generated automatically from com.google.common.collect.ForwardingObject for testing purposes + +package com.google.common.collect; + + +abstract public class ForwardingObject +{ + protected ForwardingObject(){} + protected abstract Object delegate(); + public String toString(){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/GeneralRange.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/GeneralRange.java new file mode 100644 index 00000000000..acf8f6bc9c9 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/GeneralRange.java @@ -0,0 +1,34 @@ +// Generated automatically from com.google.common.collect.GeneralRange for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.BoundType; +import com.google.common.collect.Range; +import java.io.Serializable; +import java.util.Comparator; + +class GeneralRange implements Serializable +{ + protected GeneralRange() {} + BoundType getLowerBoundType(){ return null; } + BoundType getUpperBoundType(){ return null; } + Comparator comparator(){ return null; } + GeneralRange intersect(GeneralRange p0){ return null; } + GeneralRange reverse(){ return null; } + T getLowerEndpoint(){ return null; } + T getUpperEndpoint(){ return null; } + boolean contains(T p0){ return false; } + boolean hasLowerBound(){ return false; } + boolean hasUpperBound(){ return false; } + boolean isEmpty(){ return false; } + boolean tooHigh(T p0){ return false; } + boolean tooLow(T p0){ return false; } + public String toString(){ return null; } + public boolean equals(Object p0){ return false; } + public int hashCode(){ return 0; } + static GeneralRange from(Range p0){ return null; } + static GeneralRange all(Comparator p0){ return null; } + static GeneralRange downTo(Comparator p0, T p1, BoundType p2){ return null; } + static GeneralRange range(Comparator p0, T p1, BoundType p2, T p3, BoundType p4){ return null; } + static GeneralRange upTo(Comparator p0, T p1, BoundType p2){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/HashBasedTable.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/HashBasedTable.java new file mode 100644 index 00000000000..6284328c191 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/HashBasedTable.java @@ -0,0 +1,24 @@ +// Generated automatically from com.google.common.collect.HashBasedTable for testing purposes + +package com.google.common.collect; + +import com.google.common.base.Supplier; +import com.google.common.collect.StandardTable; +import com.google.common.collect.Table; +import java.io.Serializable; +import java.util.Map; + +public class HashBasedTable extends StandardTable +{ + protected HashBasedTable() {} + public V get(Object p0, Object p1){ return null; } + public V remove(Object p0, Object p1){ return null; } + public boolean contains(Object p0, Object p1){ return false; } + public boolean containsColumn(Object p0){ return false; } + public boolean containsRow(Object p0){ return false; } + public boolean containsValue(Object p0){ return false; } + public boolean equals(Object p0){ return false; } + public static HashBasedTable create(){ return null; } + public static HashBasedTable create(Table p0){ return null; } + public static HashBasedTable create(int p0, int p1){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/HashBiMap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/HashBiMap.java new file mode 100644 index 00000000000..ec5fd73b93f --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/HashBiMap.java @@ -0,0 +1,32 @@ +// Generated automatically from com.google.common.collect.HashBiMap for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.BiMap; +import com.google.common.collect.Maps; +import java.io.Serializable; +import java.util.Map; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; + +public class HashBiMap extends Maps.IteratorBasedAbstractMap implements BiMap, Serializable +{ + protected HashBiMap() {} + public BiMap inverse(){ return null; } + public Set keySet(){ return null; } + public Set values(){ return null; } + public V forcePut(K p0, V p1){ return null; } + public V get(Object p0){ return null; } + public V put(K p0, V p1){ return null; } + public V remove(Object p0){ return null; } + public boolean containsKey(Object p0){ return false; } + public boolean containsValue(Object p0){ return false; } + public int size(){ return 0; } + public static HashBiMap create(){ return null; } + public static HashBiMap create(Map p0){ return null; } + public static HashBiMap create(int p0){ return null; } + public void clear(){} + public void forEach(BiConsumer p0){} + public void replaceAll(BiFunction p0){} +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/HashMultimap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/HashMultimap.java new file mode 100644 index 00000000000..69ff1caa89f --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/HashMultimap.java @@ -0,0 +1,14 @@ +// Generated automatically from com.google.common.collect.HashMultimap for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.HashMultimapGwtSerializationDependencies; +import com.google.common.collect.Multimap; + +public class HashMultimap extends HashMultimapGwtSerializationDependencies +{ + protected HashMultimap() {} + public static HashMultimap create(){ return null; } + public static HashMultimap create(Multimap p0){ return null; } + public static HashMultimap create(int p0, int p1){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/HashMultimapGwtSerializationDependencies.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/HashMultimapGwtSerializationDependencies.java new file mode 100644 index 00000000000..9ff6310fa70 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/HashMultimapGwtSerializationDependencies.java @@ -0,0 +1,10 @@ +// Generated automatically from com.google.common.collect.HashMultimapGwtSerializationDependencies for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.AbstractSetMultimap; + +abstract class HashMultimapGwtSerializationDependencies extends AbstractSetMultimap +{ + protected HashMultimapGwtSerializationDependencies() {} +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/HashMultiset.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/HashMultiset.java new file mode 100644 index 00000000000..38d026f45fc --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/HashMultiset.java @@ -0,0 +1,13 @@ +// Generated automatically from com.google.common.collect.HashMultiset for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.AbstractMapBasedMultiset; + +public class HashMultiset extends AbstractMapBasedMultiset +{ + protected HashMultiset() {} + public static HashMultiset create(){ return null; } + public static HashMultiset create(Iterable p0){ return null; } + public static HashMultiset create(int p0){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableBiMap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableBiMap.java new file mode 100644 index 00000000000..b573c4aad0c --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableBiMap.java @@ -0,0 +1,40 @@ +// Generated automatically from com.google.common.collect.ImmutableBiMap for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.BiMap; +import com.google.common.collect.ImmutableBiMapFauxverideShim; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import java.util.Comparator; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collector; + +abstract public class ImmutableBiMap extends ImmutableBiMapFauxverideShim implements BiMap +{ + public ImmutableSet values(){ return null; } + public abstract ImmutableBiMap inverse(); + public final V forcePut(K p0, V p1){ return null; } + public static ImmutableBiMap.Builder builder(){ return null; } + public static ImmutableBiMap.Builder builderWithExpectedSize(int p0){ return null; } + public static ImmutableBiMap copyOf(Iterable> p0){ return null; } + public static ImmutableBiMap copyOf(Map p0){ return null; } + public static ImmutableBiMap of(){ return null; } + public static ImmutableBiMap of(K p0, V p1){ return null; } + public static ImmutableBiMap of(K p0, V p1, K p2, V p3){ return null; } + public static ImmutableBiMap of(K p0, V p1, K p2, V p3, K p4, V p5){ return null; } + public static ImmutableBiMap of(K p0, V p1, K p2, V p3, K p4, V p5, K p6, V p7){ return null; } + public static ImmutableBiMap of(K p0, V p1, K p2, V p3, K p4, V p5, K p6, V p7, K p8, V p9){ return null; } + public static Collector> toImmutableBiMap(Function p0, Function p1){ return null; } + static public class Builder extends ImmutableMap.Builder + { + public Builder(){} + public ImmutableBiMap.Builder orderEntriesByValue(Comparator p0){ return null; } + public ImmutableBiMap.Builder put(K p0, V p1){ return null; } + public ImmutableBiMap.Builder put(Map.Entry p0){ return null; } + public ImmutableBiMap.Builder putAll(Iterable> p0){ return null; } + public ImmutableBiMap.Builder putAll(Map p0){ return null; } + public ImmutableBiMap build(){ return null; } + } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableBiMapFauxverideShim.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableBiMapFauxverideShim.java new file mode 100644 index 00000000000..d55d3be8d28 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableBiMapFauxverideShim.java @@ -0,0 +1,14 @@ +// Generated automatically from com.google.common.collect.ImmutableBiMapFauxverideShim for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.ImmutableMap; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.stream.Collector; + +abstract class ImmutableBiMapFauxverideShim extends ImmutableMap +{ + public static Collector> toImmutableMap(Function p0, Function p1){ return null; } + public static Collector> toImmutableMap(Function p0, Function p1, BinaryOperator p2){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableClassToInstanceMap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableClassToInstanceMap.java new file mode 100644 index 00000000000..2fd624f570a --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableClassToInstanceMap.java @@ -0,0 +1,27 @@ +// Generated automatically from com.google.common.collect.ImmutableClassToInstanceMap for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.ClassToInstanceMap; +import com.google.common.collect.ForwardingMap; +import java.io.Serializable; +import java.util.Map; + +public class ImmutableClassToInstanceMap extends ForwardingMap, B> implements ClassToInstanceMap, Serializable +{ + protected ImmutableClassToInstanceMap() {} + protected Map, B> delegate(){ return null; } + public T getInstance(Class p0){ return null; } + public T putInstance(Class p0, T p1){ return null; } + public static ImmutableClassToInstanceMap copyOf(Map, ? extends S> p0){ return null; } + public static ImmutableClassToInstanceMap of(Class p0, T p1){ return null; } + public static ImmutableClassToInstanceMap.Builder builder(){ return null; } + public static ImmutableClassToInstanceMap of(){ return null; } + static public class Builder + { + public ImmutableClassToInstanceMap.Builder put(Class p0, T p1){ return null; } + public ImmutableClassToInstanceMap.Builder putAll(Map, ? extends T> p0){ return null; } + public Builder(){} + public ImmutableClassToInstanceMap build(){ return null; } + } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableListMultimap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableListMultimap.java new file mode 100644 index 00000000000..b8df07aa844 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableListMultimap.java @@ -0,0 +1,46 @@ +// Generated automatically from com.google.common.collect.ImmutableListMultimap for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ListMultimap; +import com.google.common.collect.Multimap; +import java.util.Comparator; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collector; +import java.util.stream.Stream; + +public class ImmutableListMultimap extends ImmutableMultimap implements ListMultimap +{ + protected ImmutableListMultimap() {} + public ImmutableList get(K p0){ return null; } + public ImmutableListMultimap inverse(){ return null; } + public final ImmutableList removeAll(Object p0){ return null; } + public final ImmutableList replaceValues(K p0, Iterable p1){ return null; } + public static ImmutableListMultimap.Builder builder(){ return null; } + public static ImmutableListMultimap copyOf(Iterable> p0){ return null; } + public static ImmutableListMultimap copyOf(Multimap p0){ return null; } + public static ImmutableListMultimap of(){ return null; } + public static ImmutableListMultimap of(K p0, V p1){ return null; } + public static ImmutableListMultimap of(K p0, V p1, K p2, V p3){ return null; } + public static ImmutableListMultimap of(K p0, V p1, K p2, V p3, K p4, V p5){ return null; } + public static ImmutableListMultimap of(K p0, V p1, K p2, V p3, K p4, V p5, K p6, V p7){ return null; } + public static ImmutableListMultimap of(K p0, V p1, K p2, V p3, K p4, V p5, K p6, V p7, K p8, V p9){ return null; } + public static Collector> flatteningToImmutableListMultimap(Function p0, Function> p1){ return null; } + public static Collector> toImmutableListMultimap(Function p0, Function p1){ return null; } + static public class Builder extends ImmutableMultimap.Builder + { + public Builder(){} + public ImmutableListMultimap.Builder orderKeysBy(Comparator p0){ return null; } + public ImmutableListMultimap.Builder orderValuesBy(Comparator p0){ return null; } + public ImmutableListMultimap.Builder put(K p0, V p1){ return null; } + public ImmutableListMultimap.Builder put(Map.Entry p0){ return null; } + public ImmutableListMultimap.Builder putAll(Iterable> p0){ return null; } + public ImmutableListMultimap.Builder putAll(K p0, Iterable p1){ return null; } + public ImmutableListMultimap.Builder putAll(K p0, V... p1){ return null; } + public ImmutableListMultimap.Builder putAll(Multimap p0){ return null; } + public ImmutableListMultimap build(){ return null; } + } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedMap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedMap.java index dc3bfd49083..a88c9d79376 100644 --- a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedMap.java +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedMap.java @@ -1,105 +1,79 @@ -/* - * Copyright (C) 2009 The Guava Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Generated automatically from com.google.common.collect.ImmutableSortedMap for testing purposes package com.google.common.collect; +import com.google.common.collect.ImmutableCollection; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSortedMapFauxverideShim; +import com.google.common.collect.ImmutableSortedSet; import java.util.Comparator; import java.util.Map; +import java.util.NavigableMap; import java.util.SortedMap; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.stream.Collector; -public final class ImmutableSortedMap extends ImmutableMap{ - - public static ImmutableSortedMap of() { - return null; - } - - public static , V> ImmutableSortedMap of(K k1, V v1) { - return null; - } - - public static , V> ImmutableSortedMap of( - K k1, V v1, K k2, V v2) { - return null; - } - - public static , V> ImmutableSortedMap of( - K k1, V v1, K k2, V v2, K k3, V v3) { - return null; - } - - public static , V> ImmutableSortedMap of( - K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { - return null; - } - - public static , V> ImmutableSortedMap of( - K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { - return null; - } - - public static ImmutableSortedMap copyOf(Map map) { - return null; - } - - public static ImmutableSortedMap copyOf( - Map map, Comparator comparator) { - return null; - } - - public static ImmutableSortedMap copyOf( - Iterable> entries) { - return null; - } - - public static ImmutableSortedMap copyOf( - Iterable> entries, - Comparator comparator) { - return null; - } - - public static ImmutableSortedMap copyOfSorted(SortedMap map) { - return null; - } - - @Override - public V get(Object key) { - return null; - } - - @Override - public int size() { - return 0; - } - - public static , V> Builder naturalOrder() { - return null; - } - - public static Builder orderedBy(Comparator comparator) { - return null; - } - - public static , V> Builder reverseOrder() { - return null; - } - - public static class Builder extends ImmutableMap.Builder { - public Builder(Comparator comparator) { +public class ImmutableSortedMap extends ImmutableSortedMapFauxverideShim implements NavigableMap +{ + protected ImmutableSortedMap() {} + public Comparator comparator(){ return null; } + public ImmutableCollection values(){ return null; } + public ImmutableSet> entrySet(){ return null; } + public ImmutableSortedMap descendingMap(){ return null; } + public ImmutableSortedMap headMap(K p0){ return null; } + public ImmutableSortedMap headMap(K p0, boolean p1){ return null; } + public ImmutableSortedMap subMap(K p0, K p1){ return null; } + public ImmutableSortedMap subMap(K p0, boolean p1, K p2, boolean p3){ return null; } + public ImmutableSortedMap tailMap(K p0){ return null; } + public ImmutableSortedMap tailMap(K p0, boolean p1){ return null; } + public ImmutableSortedSet descendingKeySet(){ return null; } + public ImmutableSortedSet keySet(){ return null; } + public ImmutableSortedSet navigableKeySet(){ return null; } + public K ceilingKey(K p0){ return null; } + public K firstKey(){ return null; } + public K floorKey(K p0){ return null; } + public K higherKey(K p0){ return null; } + public K lastKey(){ return null; } + public K lowerKey(K p0){ return null; } + public Map.Entry ceilingEntry(K p0){ return null; } + public Map.Entry firstEntry(){ return null; } + public Map.Entry floorEntry(K p0){ return null; } + public Map.Entry higherEntry(K p0){ return null; } + public Map.Entry lastEntry(){ return null; } + public Map.Entry lowerEntry(K p0){ return null; } + public V get(Object p0){ return null; } + public final Map.Entry pollFirstEntry(){ return null; } + public final Map.Entry pollLastEntry(){ return null; } + public int size(){ return 0; } + public static , V> ImmutableSortedMap.Builder naturalOrder(){ return null; } + public static , V> ImmutableSortedMap.Builder reverseOrder(){ return null; } + public static , V> ImmutableSortedMap of(K p0, V p1){ return null; } + public static , V> ImmutableSortedMap of(K p0, V p1, K p2, V p3){ return null; } + public static , V> ImmutableSortedMap of(K p0, V p1, K p2, V p3, K p4, V p5){ return null; } + public static , V> ImmutableSortedMap of(K p0, V p1, K p2, V p3, K p4, V p5, K p6, V p7){ return null; } + public static , V> ImmutableSortedMap of(K p0, V p1, K p2, V p3, K p4, V p5, K p6, V p7, K p8, V p9){ return null; } + public static ImmutableSortedMap.Builder orderedBy(Comparator p0){ return null; } + public static ImmutableSortedMap copyOf(Iterable> p0){ return null; } + public static ImmutableSortedMap copyOf(Iterable> p0, Comparator p1){ return null; } + public static ImmutableSortedMap copyOf(Map p0){ return null; } + public static ImmutableSortedMap copyOf(Map p0, Comparator p1){ return null; } + public static ImmutableSortedMap copyOfSorted(SortedMap p0){ return null; } + public static ImmutableSortedMap of(){ return null; } + public static Collector> toImmutableSortedMap(Comparator p0, Function p1, Function p2){ return null; } + public static Collector> toImmutableSortedMap(Comparator p0, Function p1, Function p2, BinaryOperator p3){ return null; } + public void forEach(BiConsumer p0){} + static public class Builder extends ImmutableMap.Builder + { + protected Builder() {} + public Builder(Comparator p0){} + public ImmutableSortedMap.Builder put(K p0, V p1){ return null; } + public ImmutableSortedMap.Builder put(Map.Entry p0){ return null; } + public ImmutableSortedMap.Builder putAll(Iterable> p0){ return null; } + public ImmutableSortedMap.Builder putAll(Map p0){ return null; } + public ImmutableSortedMap build(){ return null; } + public final ImmutableSortedMap.Builder orderEntriesByValue(Comparator p0){ return null; } } - - } - } diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedMapFauxverideShim.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedMapFauxverideShim.java new file mode 100644 index 00000000000..c09533487b1 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedMapFauxverideShim.java @@ -0,0 +1,22 @@ +// Generated automatically from com.google.common.collect.ImmutableSortedMapFauxverideShim for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSortedMap; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.stream.Collector; + +abstract class ImmutableSortedMapFauxverideShim extends ImmutableMap +{ + public static ImmutableSortedMap.Builder builder(){ return null; } + public static ImmutableSortedMap.Builder builderWithExpectedSize(int p0){ return null; } + public static ImmutableSortedMap of(K p0, V p1){ return null; } + public static ImmutableSortedMap of(K p0, V p1, K p2, V p3){ return null; } + public static ImmutableSortedMap of(K p0, V p1, K p2, V p3, K p4, V p5){ return null; } + public static ImmutableSortedMap of(K p0, V p1, K p2, V p3, K p4, V p5, K p6, V p7){ return null; } + public static ImmutableSortedMap of(K p0, V p1, K p2, V p3, K p4, V p5, K p6, V p7, K p8, V p9){ return null; } + public static Collector> toImmutableMap(Function p0, Function p1){ return null; } + public static Collector> toImmutableMap(Function p0, Function p1, BinaryOperator p2){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedMultiset.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedMultiset.java new file mode 100644 index 00000000000..fc068de4215 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedMultiset.java @@ -0,0 +1,57 @@ +// Generated automatically from com.google.common.collect.ImmutableSortedMultiset for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.BoundType; +import com.google.common.collect.ImmutableMultiset; +import com.google.common.collect.ImmutableSortedMultisetFauxverideShim; +import com.google.common.collect.ImmutableSortedSet; +import com.google.common.collect.Multiset; +import com.google.common.collect.SortedMultiset; +import java.util.Comparator; +import java.util.Iterator; +import java.util.function.Function; +import java.util.function.ToIntFunction; +import java.util.stream.Collector; + +abstract public class ImmutableSortedMultiset extends ImmutableSortedMultisetFauxverideShim implements SortedMultiset +{ + public ImmutableSortedMultiset descendingMultiset(){ return null; } + public ImmutableSortedMultiset subMultiset(E p0, BoundType p1, E p2, BoundType p3){ return null; } + public abstract ImmutableSortedMultiset headMultiset(E p0, BoundType p1); + public abstract ImmutableSortedMultiset tailMultiset(E p0, BoundType p1); + public abstract ImmutableSortedSet elementSet(); + public final Comparator comparator(){ return null; } + public final Multiset.Entry pollFirstEntry(){ return null; } + public final Multiset.Entry pollLastEntry(){ return null; } + public static > ImmutableSortedMultiset.Builder naturalOrder(){ return null; } + public static > ImmutableSortedMultiset.Builder reverseOrder(){ return null; } + public static > ImmutableSortedMultiset copyOf(E[] p0){ return null; } + public static > ImmutableSortedMultiset of(E p0){ return null; } + public static > ImmutableSortedMultiset of(E p0, E p1){ return null; } + public static > ImmutableSortedMultiset of(E p0, E p1, E p2){ return null; } + public static > ImmutableSortedMultiset of(E p0, E p1, E p2, E p3){ return null; } + public static > ImmutableSortedMultiset of(E p0, E p1, E p2, E p3, E p4){ return null; } + public static > ImmutableSortedMultiset of(E p0, E p1, E p2, E p3, E p4, E p5, E... p6){ return null; } + public static Collector> toImmutableSortedMultiset(Comparator p0){ return null; } + public static ImmutableSortedMultiset.Builder orderedBy(Comparator p0){ return null; } + public static ImmutableSortedMultiset copyOf(Comparator p0, Iterable p1){ return null; } + public static ImmutableSortedMultiset copyOf(Comparator p0, Iterator p1){ return null; } + public static ImmutableSortedMultiset copyOf(Iterable p0){ return null; } + public static ImmutableSortedMultiset copyOf(Iterator p0){ return null; } + public static ImmutableSortedMultiset copyOfSorted(SortedMultiset p0){ return null; } + public static ImmutableSortedMultiset of(){ return null; } + public static Collector> toImmutableSortedMultiset(Comparator p0, Function p1, ToIntFunction p2){ return null; } + static public class Builder extends ImmutableMultiset.Builder + { + protected Builder() {} + public Builder(Comparator p0){} + public ImmutableSortedMultiset.Builder add(E p0){ return null; } + public ImmutableSortedMultiset.Builder add(E... p0){ return null; } + public ImmutableSortedMultiset.Builder addAll(Iterable p0){ return null; } + public ImmutableSortedMultiset.Builder addAll(Iterator p0){ return null; } + public ImmutableSortedMultiset.Builder addCopies(E p0, int p1){ return null; } + public ImmutableSortedMultiset.Builder setCount(E p0, int p1){ return null; } + public ImmutableSortedMultiset build(){ return null; } + } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedMultisetFauxverideShim.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedMultisetFauxverideShim.java new file mode 100644 index 00000000000..85af2f484d6 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedMultisetFauxverideShim.java @@ -0,0 +1,23 @@ +// Generated automatically from com.google.common.collect.ImmutableSortedMultisetFauxverideShim for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.ImmutableMultiset; +import com.google.common.collect.ImmutableSortedMultiset; +import java.util.function.Function; +import java.util.function.ToIntFunction; +import java.util.stream.Collector; + +abstract class ImmutableSortedMultisetFauxverideShim extends ImmutableMultiset +{ + public static Collector> toImmutableMultiset(){ return null; } + public static ImmutableSortedMultiset.Builder builder(){ return null; } + public static ImmutableSortedMultiset copyOf(E[] p0){ return null; } + public static ImmutableSortedMultiset of(E p0){ return null; } + public static ImmutableSortedMultiset of(E p0, E p1){ return null; } + public static ImmutableSortedMultiset of(E p0, E p1, E p2){ return null; } + public static ImmutableSortedMultiset of(E p0, E p1, E p2, E p3){ return null; } + public static ImmutableSortedMultiset of(E p0, E p1, E p2, E p3, E p4){ return null; } + public static ImmutableSortedMultiset of(E p0, E p1, E p2, E p3, E p4, E p5, E... p6){ return null; } + public static Collector> toImmutableMultiset(Function p0, ToIntFunction p1){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedSet.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedSet.java index fb22c85b5ef..92cfc939d96 100644 --- a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedSet.java +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedSet.java @@ -1,111 +1,68 @@ -/* - * Copyright (C) 2008 The Guava Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Generated automatically from com.google.common.collect.ImmutableSortedSet for testing purposes package com.google.common.collect; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSortedSetFauxverideShim; +import com.google.common.collect.SortedIterable; +import com.google.common.collect.UnmodifiableIterator; import java.util.Collection; import java.util.Comparator; import java.util.Iterator; import java.util.NavigableSet; import java.util.SortedSet; +import java.util.Spliterator; +import java.util.stream.Collector; -public abstract class ImmutableSortedSet extends ImmutableSet - implements NavigableSet { - - public static ImmutableSortedSet of() { - return null; - } - - public static > ImmutableSortedSet of(E element) { - return null; - } - - public static > ImmutableSortedSet of(E e1, E e2) { - return null; - } - - public static > ImmutableSortedSet of(E e1, E e2, E e3) { - return null; - } - - public static > ImmutableSortedSet of(E e1, E e2, E e3, E e4) { - return null; - } - - public static > ImmutableSortedSet of( - E e1, E e2, E e3, E e4, E e5) { - return null; - } - - public static > ImmutableSortedSet of( - E e1, E e2, E e3, E e4, E e5, E e6, E... remaining) { - return null; - } - - public static > ImmutableSortedSet copyOf(E[] elements) { - return null; - } - - public static ImmutableSortedSet copyOf(Iterable elements) { - return null; - } - - public static ImmutableSortedSet copyOf(Collection elements) { - return null; - } - - public static ImmutableSortedSet copyOf(Iterator elements) { - return null; - } - - public static ImmutableSortedSet copyOf( - Comparator comparator, Iterator elements) { - return null; - } - - public static ImmutableSortedSet copyOf( - Comparator comparator, Iterable elements) { - return null; - } - - public static ImmutableSortedSet copyOf( - Comparator comparator, Collection elements) { - return null; - } - - public static ImmutableSortedSet copyOfSorted(SortedSet sortedSet) { - return null; - } - - public static Builder orderedBy(Comparator comparator) { - return null; - } - - public static > Builder reverseOrder() { - return null; - } - - public static > Builder naturalOrder() { - return null; - } - - public static final class Builder extends ImmutableSet.Builder { - public Builder(Comparator comparator) { +abstract public class ImmutableSortedSet extends ImmutableSortedSetFauxverideShim implements NavigableSet, SortedIterable +{ + protected ImmutableSortedSet() {} + public Comparator comparator(){ return null; } + public E ceiling(E p0){ return null; } + public E first(){ return null; } + public E floor(E p0){ return null; } + public E higher(E p0){ return null; } + public E last(){ return null; } + public E lower(E p0){ return null; } + public ImmutableSortedSet descendingSet(){ return null; } + public ImmutableSortedSet headSet(E p0){ return null; } + public ImmutableSortedSet headSet(E p0, boolean p1){ return null; } + public ImmutableSortedSet subSet(E p0, E p1){ return null; } + public ImmutableSortedSet subSet(E p0, boolean p1, E p2, boolean p3){ return null; } + public ImmutableSortedSet tailSet(E p0){ return null; } + public ImmutableSortedSet tailSet(E p0, boolean p1){ return null; } + public Spliterator spliterator(){ return null; } + public abstract UnmodifiableIterator descendingIterator(); + public abstract UnmodifiableIterator iterator(); + public final E pollFirst(){ return null; } + public final E pollLast(){ return null; } + public static > ImmutableSortedSet.Builder naturalOrder(){ return null; } + public static > ImmutableSortedSet.Builder reverseOrder(){ return null; } + public static > ImmutableSortedSet copyOf(E[] p0){ return null; } + public static > ImmutableSortedSet of(E p0){ return null; } + public static > ImmutableSortedSet of(E p0, E p1){ return null; } + public static > ImmutableSortedSet of(E p0, E p1, E p2){ return null; } + public static > ImmutableSortedSet of(E p0, E p1, E p2, E p3){ return null; } + public static > ImmutableSortedSet of(E p0, E p1, E p2, E p3, E p4){ return null; } + public static > ImmutableSortedSet of(E p0, E p1, E p2, E p3, E p4, E p5, E... p6){ return null; } + public static Collector> toImmutableSortedSet(Comparator p0){ return null; } + public static ImmutableSortedSet.Builder orderedBy(Comparator p0){ return null; } + public static ImmutableSortedSet copyOf(Collection p0){ return null; } + public static ImmutableSortedSet copyOf(Comparator p0, Collection p1){ return null; } + public static ImmutableSortedSet copyOf(Comparator p0, Iterable p1){ return null; } + public static ImmutableSortedSet copyOf(Comparator p0, Iterator p1){ return null; } + public static ImmutableSortedSet copyOf(Iterable p0){ return null; } + public static ImmutableSortedSet copyOf(Iterator p0){ return null; } + public static ImmutableSortedSet copyOfSorted(SortedSet p0){ return null; } + public static ImmutableSortedSet of(){ return null; } + static public class Builder extends ImmutableSet.Builder + { + protected Builder() {} + public Builder(Comparator p0){} + public ImmutableSortedSet.Builder add(E p0){ return null; } + public ImmutableSortedSet.Builder add(E... p0){ return null; } + public ImmutableSortedSet.Builder addAll(Iterable p0){ return null; } + public ImmutableSortedSet.Builder addAll(Iterator p0){ return null; } + public ImmutableSortedSet build(){ return null; } } - - } - } diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedSetFauxverideShim.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedSetFauxverideShim.java new file mode 100644 index 00000000000..b2a0cff1ccb --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableSortedSetFauxverideShim.java @@ -0,0 +1,21 @@ +// Generated automatically from com.google.common.collect.ImmutableSortedSetFauxverideShim for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSortedSet; +import java.util.stream.Collector; + +abstract class ImmutableSortedSetFauxverideShim extends ImmutableSet +{ + public static Collector> toImmutableSet(){ return null; } + public static ImmutableSortedSet.Builder builder(){ return null; } + public static ImmutableSortedSet.Builder builderWithExpectedSize(int p0){ return null; } + public static ImmutableSortedSet copyOf(E[] p0){ return null; } + public static ImmutableSortedSet of(E p0){ return null; } + public static ImmutableSortedSet of(E p0, E p1){ return null; } + public static ImmutableSortedSet of(E p0, E p1, E p2){ return null; } + public static ImmutableSortedSet of(E p0, E p1, E p2, E p3){ return null; } + public static ImmutableSortedSet of(E p0, E p1, E p2, E p3, E p4){ return null; } + public static ImmutableSortedSet of(E p0, E p1, E p2, E p3, E p4, E p5, E... p6){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableTable.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableTable.java index 73b3907b352..88f28c9ab98 100644 --- a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableTable.java +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ImmutableTable.java @@ -1,124 +1,49 @@ -/* - * Copyright (C) 2009 The Guava Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Generated automatically from com.google.common.collect.ImmutableTable for testing purposes package com.google.common.collect; +import com.google.common.collect.AbstractTable; +import com.google.common.collect.ImmutableCollection; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Table; +import java.io.Serializable; +import java.util.Comparator; import java.util.Map; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.stream.Collector; -public abstract class ImmutableTable extends AbstractTable { - - public static ImmutableTable of() { - return null; - } - - public static ImmutableTable of(R rowKey, C columnKey, V value) { - return null; - } - - public static ImmutableTable copyOf( - Table table) { - return null; - } - - public static Builder builder() { - return null; - } - - public static final class Builder { - public Builder() {} - - public Builder put(R rowKey, C columnKey, V value) { - return null; +abstract public class ImmutableTable extends AbstractTable implements Serializable +{ + public ImmutableCollection values(){ return null; } + public ImmutableMap row(R p0){ return null; } + public ImmutableMap column(C p0){ return null; } + public ImmutableSet columnKeySet(){ return null; } + public ImmutableSet rowKeySet(){ return null; } + public ImmutableSet> cellSet(){ return null; } + public abstract ImmutableMap> columnMap(); + public abstract ImmutableMap> rowMap(); + public boolean contains(Object p0, Object p1){ return false; } + public boolean containsValue(Object p0){ return false; } + public final V put(R p0, C p1, V p2){ return null; } + public final V remove(Object p0, Object p1){ return null; } + public final void clear(){} + public final void putAll(Table p0){} + public static ImmutableTable.Builder builder(){ return null; } + public static ImmutableTable copyOf(Table p0){ return null; } + public static ImmutableTable of(){ return null; } + public static ImmutableTable of(R p0, C p1, V p2){ return null; } + public static Collector> toImmutableTable(Function p0, Function p1, Function p2){ return null; } + public static Collector> toImmutableTable(Function p0, Function p1, Function p2, BinaryOperator p3){ return null; } + static public class Builder + { + public Builder(){} + public ImmutableTable.Builder orderColumnsBy(Comparator p0){ return null; } + public ImmutableTable.Builder orderRowsBy(Comparator p0){ return null; } + public ImmutableTable.Builder put(R p0, C p1, V p2){ return null; } + public ImmutableTable.Builder put(Table.Cell p0){ return null; } + public ImmutableTable.Builder putAll(Table p0){ return null; } + public ImmutableTable build(){ return null; } } - - public Builder put(Cell cell) { - return null; - } - - public Builder putAll(Table table) { - return null; - } - - public ImmutableTable build() { - return null; - } - - } - @Override - public ImmutableSet> cellSet() { - return null; - } - - @Override - public ImmutableCollection values() { - return null; - } - - @Override - public ImmutableMap column(C columnKey) { - return null; - } - - @Override - public ImmutableSet columnKeySet() { - return null; - } - - @Override - public abstract ImmutableMap> columnMap(); - - @Override - public ImmutableMap row(R rowKey) { - return null; - } - - @Override - public ImmutableSet rowKeySet() { - return null; - } - - @Override - public abstract ImmutableMap> rowMap(); - - @Override - public boolean contains(Object rowKey, Object columnKey) { - return false; - } - - @Override - public boolean containsValue(Object value) { - return false; - } - - @Override - public final void clear() { - } - - @Override - public final V put(R rowKey, C columnKey, V value) { - return null; - } - - @Override - public final void putAll(Table table) { - } - - @Override - public final V remove(Object rowKey, Object columnKey) { - return null; - } - } diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/Iterables.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Iterables.java new file mode 100644 index 00000000000..6eb11f37e56 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Iterables.java @@ -0,0 +1,58 @@ +// Generated automatically from com.google.common.collect.Iterables for testing purposes + +package com.google.common.collect; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableCollection; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; + +public class Iterables +{ + protected Iterables() {} + public static Iterable unmodifiableIterable(ImmutableCollection p0){ return null; } + public static Iterable transform(Iterable p0, Function p1){ return null; } + public static Iterable> paddedPartition(Iterable p0, int p1){ return null; } + public static Iterable> partition(Iterable p0, int p1){ return null; } + public static Iterable concat(Iterable> p0){ return null; } + public static Iterable concat(Iterable p0, Iterable p1){ return null; } + public static Iterable concat(Iterable p0, Iterable p1, Iterable p2){ return null; } + public static Iterable concat(Iterable p0, Iterable p1, Iterable p2, Iterable p3){ return null; } + public static Iterable concat(Iterable... p0){ return null; } + public static Iterable consumingIterable(Iterable p0){ return null; } + public static Iterable cycle(Iterable p0){ return null; } + public static Iterable cycle(T... p0){ return null; } + public static Iterable filter(Iterable p0, Class p1){ return null; } + public static Iterable filter(Iterable p0, Predicate p1){ return null; } + public static Iterable limit(Iterable p0, int p1){ return null; } + public static Iterable mergeSorted(Iterable> p0, Comparator p1){ return null; } + public static Iterable skip(Iterable p0, int p1){ return null; } + public static Iterable unmodifiableIterable(Iterable p0){ return null; } + public static Optional tryFind(Iterable p0, Predicate p1){ return null; } + public static T find(Iterable p0, Predicate p1, T p2){ return null; } + public static T find(Iterable p0, Predicate p1){ return null; } + public static T get(Iterable p0, int p1, T p2){ return null; } + public static T get(Iterable p0, int p1){ return null; } + public static T getFirst(Iterable p0, T p1){ return null; } + public static T getLast(Iterable p0, T p1){ return null; } + public static T getLast(Iterable p0){ return null; } + public static T getOnlyElement(Iterable p0, T p1){ return null; } + public static T getOnlyElement(Iterable p0){ return null; } + public static T[] toArray(Iterable p0, Class p1){ return null; } + public static boolean addAll(Collection p0, Iterable p1){ return false; } + public static boolean all(Iterable p0, Predicate p1){ return false; } + public static boolean any(Iterable p0, Predicate p1){ return false; } + public static boolean removeIf(Iterable p0, Predicate p1){ return false; } + public static int indexOf(Iterable p0, Predicate p1){ return 0; } + public static String toString(Iterable p0){ return null; } + public static boolean contains(Iterable p0, Object p1){ return false; } + public static boolean elementsEqual(Iterable p0, Iterable p1){ return false; } + public static boolean isEmpty(Iterable p0){ return false; } + public static boolean removeAll(Iterable p0, Collection p1){ return false; } + public static boolean retainAll(Iterable p0, Collection p1){ return false; } + public static int frequency(Iterable p0, Object p1){ return 0; } + public static int size(Iterable p0){ return 0; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/Iterators.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Iterators.java new file mode 100644 index 00000000000..4560e35a912 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Iterators.java @@ -0,0 +1,66 @@ +// Generated automatically from com.google.common.collect.Iterators for testing purposes + +package com.google.common.collect; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.collect.PeekingIterator; +import com.google.common.collect.UnmodifiableIterator; +import java.util.Collection; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; + +public class Iterators +{ + protected Iterators() {} + public static Iterator transform(Iterator p0, Function p1){ return null; } + public static Enumeration asEnumeration(Iterator p0){ return null; } + public static Iterator concat(Iterator> p0){ return null; } + public static Iterator concat(Iterator p0, Iterator p1){ return null; } + public static Iterator concat(Iterator p0, Iterator p1, Iterator p2){ return null; } + public static Iterator concat(Iterator p0, Iterator p1, Iterator p2, Iterator p3){ return null; } + public static Iterator concat(Iterator... p0){ return null; } + public static Iterator consumingIterator(Iterator p0){ return null; } + public static Iterator cycle(Iterable p0){ return null; } + public static Iterator cycle(T... p0){ return null; } + public static Iterator limit(Iterator p0, int p1){ return null; } + public static Optional tryFind(Iterator p0, Predicate p1){ return null; } + public static PeekingIterator peekingIterator(Iterator p0){ return null; } + public static PeekingIterator peekingIterator(PeekingIterator p0){ return null; } + public static T find(Iterator p0, Predicate p1, T p2){ return null; } + public static T find(Iterator p0, Predicate p1){ return null; } + public static T get(Iterator p0, int p1, T p2){ return null; } + public static T get(Iterator p0, int p1){ return null; } + public static T getLast(Iterator p0, T p1){ return null; } + public static T getLast(Iterator p0){ return null; } + public static T getNext(Iterator p0, T p1){ return null; } + public static T getOnlyElement(Iterator p0, T p1){ return null; } + public static T getOnlyElement(Iterator p0){ return null; } + public static T[] toArray(Iterator p0, Class p1){ return null; } + public static UnmodifiableIterator> paddedPartition(Iterator p0, int p1){ return null; } + public static UnmodifiableIterator> partition(Iterator p0, int p1){ return null; } + public static UnmodifiableIterator filter(Iterator p0, Class p1){ return null; } + public static UnmodifiableIterator filter(Iterator p0, Predicate p1){ return null; } + public static UnmodifiableIterator forArray(T... p0){ return null; } + public static UnmodifiableIterator forEnumeration(Enumeration p0){ return null; } + public static UnmodifiableIterator mergeSorted(Iterable> p0, Comparator p1){ return null; } + public static UnmodifiableIterator singletonIterator(T p0){ return null; } + public static UnmodifiableIterator unmodifiableIterator(Iterator p0){ return null; } + public static UnmodifiableIterator unmodifiableIterator(UnmodifiableIterator p0){ return null; } + public static boolean addAll(Collection p0, Iterator p1){ return false; } + public static boolean all(Iterator p0, Predicate p1){ return false; } + public static boolean any(Iterator p0, Predicate p1){ return false; } + public static boolean removeIf(Iterator p0, Predicate p1){ return false; } + public static int indexOf(Iterator p0, Predicate p1){ return 0; } + public static String toString(Iterator p0){ return null; } + public static boolean contains(Iterator p0, Object p1){ return false; } + public static boolean elementsEqual(Iterator p0, Iterator p1){ return false; } + public static boolean removeAll(Iterator p0, Collection p1){ return false; } + public static boolean retainAll(Iterator p0, Collection p1){ return false; } + public static int advance(Iterator p0, int p1){ return 0; } + public static int frequency(Iterator p0, Object p1){ return 0; } + public static int size(Iterator p0){ return 0; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/LinkedHashMultimap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/LinkedHashMultimap.java new file mode 100644 index 00000000000..f6b539d1b58 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/LinkedHashMultimap.java @@ -0,0 +1,22 @@ +// Generated automatically from com.google.common.collect.LinkedHashMultimap for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.LinkedHashMultimapGwtSerializationDependencies; +import com.google.common.collect.Multimap; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +public class LinkedHashMultimap extends LinkedHashMultimapGwtSerializationDependencies +{ + protected LinkedHashMultimap() {} + public Collection values(){ return null; } + public Set keySet(){ return null; } + public Set> entries(){ return null; } + public Set replaceValues(K p0, Iterable p1){ return null; } + public static LinkedHashMultimap create(){ return null; } + public static LinkedHashMultimap create(Multimap p0){ return null; } + public static LinkedHashMultimap create(int p0, int p1){ return null; } + public void clear(){} +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/LinkedHashMultimapGwtSerializationDependencies.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/LinkedHashMultimapGwtSerializationDependencies.java new file mode 100644 index 00000000000..18f861e3ad0 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/LinkedHashMultimapGwtSerializationDependencies.java @@ -0,0 +1,10 @@ +// Generated automatically from com.google.common.collect.LinkedHashMultimapGwtSerializationDependencies for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.AbstractSetMultimap; + +abstract class LinkedHashMultimapGwtSerializationDependencies extends AbstractSetMultimap +{ + protected LinkedHashMultimapGwtSerializationDependencies() {} +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/LinkedHashMultiset.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/LinkedHashMultiset.java new file mode 100644 index 00000000000..e25143c06f6 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/LinkedHashMultiset.java @@ -0,0 +1,13 @@ +// Generated automatically from com.google.common.collect.LinkedHashMultiset for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.AbstractMapBasedMultiset; + +public class LinkedHashMultiset extends AbstractMapBasedMultiset +{ + protected LinkedHashMultiset() {} + public static LinkedHashMultiset create(){ return null; } + public static LinkedHashMultiset create(Iterable p0){ return null; } + public static LinkedHashMultiset create(int p0){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/LinkedListMultimap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/LinkedListMultimap.java new file mode 100644 index 00000000000..2fb2075f923 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/LinkedListMultimap.java @@ -0,0 +1,28 @@ +// Generated automatically from com.google.common.collect.LinkedListMultimap for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.AbstractMultimap; +import com.google.common.collect.ListMultimap; +import com.google.common.collect.Multimap; +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +public class LinkedListMultimap extends AbstractMultimap implements ListMultimap, Serializable +{ + public List> entries(){ return null; } + public List get(K p0){ return null; } + public List removeAll(Object p0){ return null; } + public List replaceValues(K p0, Iterable p1){ return null; } + public List values(){ return null; } + public boolean containsKey(Object p0){ return false; } + public boolean containsValue(Object p0){ return false; } + public boolean isEmpty(){ return false; } + public boolean put(K p0, V p1){ return false; } + public int size(){ return 0; } + public static LinkedListMultimap create(){ return null; } + public static LinkedListMultimap create(Multimap p0){ return null; } + public static LinkedListMultimap create(int p0){ return null; } + public void clear(){} +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ListMultimap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ListMultimap.java new file mode 100644 index 00000000000..da8c80f8bae --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ListMultimap.java @@ -0,0 +1,17 @@ +// Generated automatically from com.google.common.collect.ListMultimap for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.Multimap; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +public interface ListMultimap extends Multimap +{ + List get(K p0); + List removeAll(Object p0); + List replaceValues(K p0, Iterable p1); + Map> asMap(); + boolean equals(Object p0); +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/Lists.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Lists.java new file mode 100644 index 00000000000..6be1146dbef --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Lists.java @@ -0,0 +1,35 @@ +// Generated automatically from com.google.common.collect.Lists for testing purposes + +package com.google.common.collect; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +public class Lists +{ + protected Lists() {} + public static List> cartesianProduct(List... p0){ return null; } + public static List> cartesianProduct(List> p0){ return null; } + public static ArrayList newArrayList(){ return null; } + public static ArrayList newArrayList(E... p0){ return null; } + public static ArrayList newArrayList(Iterable p0){ return null; } + public static ArrayList newArrayList(Iterator p0){ return null; } + public static ArrayList newArrayListWithCapacity(int p0){ return null; } + public static ArrayList newArrayListWithExpectedSize(int p0){ return null; } + public static CopyOnWriteArrayList newCopyOnWriteArrayList(){ return null; } + public static CopyOnWriteArrayList newCopyOnWriteArrayList(Iterable p0){ return null; } + public static LinkedList newLinkedList(){ return null; } + public static LinkedList newLinkedList(Iterable p0){ return null; } + public static List asList(E p0, E p1, E[] p2){ return null; } + public static List asList(E p0, E[] p1){ return null; } + public static List transform(List p0, Function p1){ return null; } + public static List> partition(List p0, int p1){ return null; } + public static List reverse(List p0){ return null; } + public static ImmutableList charactersOf(String p0){ return null; } + public static List charactersOf(CharSequence p0){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/MapDifference.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/MapDifference.java new file mode 100644 index 00000000000..b1a2efcf548 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/MapDifference.java @@ -0,0 +1,23 @@ +// Generated automatically from com.google.common.collect.MapDifference for testing purposes + +package com.google.common.collect; + +import java.util.Map; + +public interface MapDifference +{ + Map> entriesDiffering(); + Map entriesInCommon(); + Map entriesOnlyOnLeft(); + Map entriesOnlyOnRight(); + boolean areEqual(); + boolean equals(Object p0); + int hashCode(); + static public interface ValueDifference + { + V leftValue(); + V rightValue(); + boolean equals(Object p0); + int hashCode(); + } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/Maps.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Maps.java new file mode 100644 index 00000000000..34779f28de0 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Maps.java @@ -0,0 +1,96 @@ +// Generated automatically from com.google.common.collect.Maps for testing purposes, and adjusted manually + +package com.google.common.collect; + +import com.google.common.base.Converter; +import com.google.common.base.Equivalence; +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.collect.BiMap; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.MapDifference; +import com.google.common.collect.Range; +import com.google.common.collect.SortedMapDifference; +import java.util.AbstractMap; +import java.util.Comparator; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.NavigableMap; +import java.util.NavigableSet; +import java.util.Properties; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.concurrent.ConcurrentMap; +import java.util.function.BinaryOperator; +import java.util.stream.Collector; + +public class Maps +{ + protected Maps() {} + abstract static class IteratorBasedAbstractMap extends AbstractMap { + public Set> entrySet(){ return null; } + public void clear(){} + } + public static Converter asConverter(BiMap p0){ return null; } + public static TreeMap newTreeMap(Comparator p0){ return null; } + public static TreeMap newTreeMap(){ return null; } + public static , V> NavigableMap subMap(NavigableMap p0, Range p1){ return null; } + public static , V> EnumMap newEnumMap(Class p0){ return null; } + public static , V> EnumMap newEnumMap(Map p0){ return null; } + public static , V> ImmutableMap immutableEnumMap(Map p0){ return null; } + public static Map transformEntries(Map p0, Maps.EntryTransformer p1){ return null; } + public static Map transformValues(Map p0, Function p1){ return null; } + public static NavigableMap transformEntries(NavigableMap p0, Maps.EntryTransformer p1){ return null; } + public static NavigableMap transformValues(NavigableMap p0, Function p1){ return null; } + public static SortedMap transformEntries(SortedMap p0, Maps.EntryTransformer p1){ return null; } + public static SortedMap transformValues(SortedMap p0, Function p1){ return null; } + public static BiMap filterEntries(BiMap p0, Predicate> p1){ return null; } + public static BiMap filterKeys(BiMap p0, Predicate p1){ return null; } + public static BiMap filterValues(BiMap p0, Predicate p1){ return null; } + public static BiMap synchronizedBiMap(BiMap p0){ return null; } + public static BiMap unmodifiableBiMap(BiMap p0){ return null; } + public static ConcurrentMap newConcurrentMap(){ return null; } + public static HashMap newHashMap(){ return null; } + public static HashMap newHashMap(Map p0){ return null; } + public static HashMap newHashMapWithExpectedSize(int p0){ return null; } + public static IdentityHashMap newIdentityHashMap(){ return null; } + public static ImmutableMap toMap(Iterable p0, Function p1){ return null; } + public static ImmutableMap toMap(Iterator p0, Function p1){ return null; } + public static ImmutableMap uniqueIndex(Iterable p0, Function p1){ return null; } + public static ImmutableMap uniqueIndex(Iterator p0, Function p1){ return null; } + public static LinkedHashMap newLinkedHashMap(){ return null; } + public static LinkedHashMap newLinkedHashMap(Map p0){ return null; } + public static LinkedHashMap newLinkedHashMapWithExpectedSize(int p0){ return null; } + public static Map.Entry immutableEntry(K p0, V p1){ return null; } + public static Map asMap(Set p0, Function p1){ return null; } + public static Map filterEntries(Map p0, Predicate> p1){ return null; } + public static Map filterKeys(Map p0, Predicate p1){ return null; } + public static Map filterValues(Map p0, Predicate p1){ return null; } + public static MapDifference difference(Map p0, Map p1){ return null; } + public static MapDifference difference(Map p0, Map p1, Equivalence p2){ return null; } + public static NavigableMap asMap(NavigableSet p0, Function p1){ return null; } + public static NavigableMap filterEntries(NavigableMap p0, Predicate> p1){ return null; } + public static NavigableMap filterKeys(NavigableMap p0, Predicate p1){ return null; } + public static NavigableMap filterValues(NavigableMap p0, Predicate p1){ return null; } + public static NavigableMap synchronizedNavigableMap(NavigableMap p0){ return null; } + public static NavigableMap unmodifiableNavigableMap(NavigableMap p0){ return null; } + public static SortedMap asMap(SortedSet p0, Function p1){ return null; } + public static SortedMap filterEntries(SortedMap p0, Predicate> p1){ return null; } + public static SortedMap filterKeys(SortedMap p0, Predicate p1){ return null; } + public static SortedMap filterValues(SortedMap p0, Predicate p1){ return null; } + public static SortedMapDifference difference(SortedMap p0, Map p1){ return null; } + public static TreeMap newTreeMap(SortedMap p0){ return null; } + public static , V> Collector> toImmutableEnumMap(Function p0, Function p1){ return null; } + public static , V> Collector> toImmutableEnumMap(Function p0, Function p1, BinaryOperator p2){ return null; } + public static ImmutableMap fromProperties(Properties p0){ return null; } + static public interface EntryTransformer + { + V2 transformEntry(K p0, V1 p1); + } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/Multimaps.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Multimaps.java new file mode 100644 index 00000000000..eef38c9636c --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Multimaps.java @@ -0,0 +1,64 @@ +// Generated automatically from com.google.common.collect.Multimaps for testing purposes, and adjusted manually + +package com.google.common.collect; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableListMultimap; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSetMultimap; +import com.google.common.collect.ListMultimap; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; +import com.google.common.collect.SetMultimap; +import com.google.common.collect.SortedSetMultimap; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.stream.Collector; +import java.util.stream.Stream; + +public class Multimaps +{ + protected Multimaps() {} + public static > M invertFrom(Multimap p0, M p1){ return null; } + public static ListMultimap transformEntries(ListMultimap p0, Maps.EntryTransformer p1){ return null; } + public static ListMultimap transformValues(ListMultimap p0, Function p1){ return null; } + public static Multimap transformEntries(Multimap p0, Maps.EntryTransformer p1){ return null; } + public static Multimap transformValues(Multimap p0, Function p1){ return null; } + public static ImmutableListMultimap index(Iterable p0, Function p1){ return null; } + public static ImmutableListMultimap index(Iterator p0, Function p1){ return null; } + public static ListMultimap filterKeys(ListMultimap p0, Predicate p1){ return null; } + public static ListMultimap newListMultimap(Map> p0, Supplier> p1){ return null; } + public static ListMultimap synchronizedListMultimap(ListMultimap p0){ return null; } + public static ListMultimap unmodifiableListMultimap(ImmutableListMultimap p0){ return null; } + public static ListMultimap unmodifiableListMultimap(ListMultimap p0){ return null; } + public static Map> asMap(Multimap p0){ return null; } + public static Map> asMap(ListMultimap p0){ return null; } + public static Map> asMap(SetMultimap p0){ return null; } + public static Map> asMap(SortedSetMultimap p0){ return null; } + public static Multimap filterEntries(Multimap p0, Predicate> p1){ return null; } + public static Multimap filterKeys(Multimap p0, Predicate p1){ return null; } + public static Multimap filterValues(Multimap p0, Predicate p1){ return null; } + public static Multimap newMultimap(Map> p0, Supplier> p1){ return null; } + public static Multimap synchronizedMultimap(Multimap p0){ return null; } + public static Multimap unmodifiableMultimap(ImmutableMultimap p0){ return null; } + public static Multimap unmodifiableMultimap(Multimap p0){ return null; } + public static SetMultimap filterEntries(SetMultimap p0, Predicate> p1){ return null; } + public static SetMultimap filterKeys(SetMultimap p0, Predicate p1){ return null; } + public static SetMultimap filterValues(SetMultimap p0, Predicate p1){ return null; } + public static SetMultimap forMap(Map p0){ return null; } + public static SetMultimap newSetMultimap(Map> p0, Supplier> p1){ return null; } + public static SetMultimap synchronizedSetMultimap(SetMultimap p0){ return null; } + public static SetMultimap unmodifiableSetMultimap(ImmutableSetMultimap p0){ return null; } + public static SetMultimap unmodifiableSetMultimap(SetMultimap p0){ return null; } + public static SortedSetMultimap newSortedSetMultimap(Map> p0, Supplier> p1){ return null; } + public static SortedSetMultimap synchronizedSortedSetMultimap(SortedSetMultimap p0){ return null; } + public static SortedSetMultimap unmodifiableSortedSetMultimap(SortedSetMultimap p0){ return null; } + public static > Collector flatteningToMultimap(Function p0, Function> p1, Supplier p2){ return null; } + public static > Collector toMultimap(Function p0, Function p1, Supplier p2){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/Multisets.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Multisets.java new file mode 100644 index 00000000000..13c58b5d703 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Multisets.java @@ -0,0 +1,32 @@ +// Generated automatically from com.google.common.collect.Multisets for testing purposes + +package com.google.common.collect; + +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableMultiset; +import com.google.common.collect.Multiset; +import com.google.common.collect.SortedMultiset; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.function.ToIntFunction; +import java.util.stream.Collector; + +public class Multisets +{ + protected Multisets() {} + public static ImmutableMultiset copyHighestCountFirst(Multiset p0){ return null; } + public static Multiset.Entry immutableEntry(E p0, int p1){ return null; } + public static Multiset difference(Multiset p0, Multiset p1){ return null; } + public static Multiset filter(Multiset p0, Predicate p1){ return null; } + public static Multiset intersection(Multiset p0, Multiset p1){ return null; } + public static Multiset sum(Multiset p0, Multiset p1){ return null; } + public static Multiset union(Multiset p0, Multiset p1){ return null; } + public static Multiset unmodifiableMultiset(ImmutableMultiset p0){ return null; } + public static Multiset unmodifiableMultiset(Multiset p0){ return null; } + public static SortedMultiset unmodifiableSortedMultiset(SortedMultiset p0){ return null; } + public static > Collector toMultiset(Function p0, ToIntFunction p1, Supplier p2){ return null; } + public static boolean containsOccurrences(Multiset p0, Multiset p1){ return false; } + public static boolean removeOccurrences(Multiset p0, Iterable p1){ return false; } + public static boolean removeOccurrences(Multiset p0, Multiset p1){ return false; } + public static boolean retainOccurrences(Multiset p0, Multiset p1){ return false; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/MutableClassToInstanceMap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/MutableClassToInstanceMap.java new file mode 100644 index 00000000000..02c7f11227f --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/MutableClassToInstanceMap.java @@ -0,0 +1,22 @@ +// Generated automatically from com.google.common.collect.MutableClassToInstanceMap for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.ClassToInstanceMap; +import com.google.common.collect.ForwardingMap; +import java.io.Serializable; +import java.util.Map; +import java.util.Set; + +public class MutableClassToInstanceMap extends ForwardingMap, B> implements ClassToInstanceMap, Serializable +{ + protected MutableClassToInstanceMap() {} + protected Map, B> delegate(){ return null; } + public T getInstance(Class p0){ return null; } + public T putInstance(Class p0, T p1){ return null; } + public B put(Class p0, B p1){ return null; } + public Set, B>> entrySet(){ return null; } + public static MutableClassToInstanceMap create(){ return null; } + public static MutableClassToInstanceMap create(Map, B> p0){ return null; } + public void putAll(Map, ? extends B> p0){} +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/ObjectArrays.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ObjectArrays.java new file mode 100644 index 00000000000..5999b1ba04e --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/ObjectArrays.java @@ -0,0 +1,14 @@ +// Generated automatically from com.google.common.collect.ObjectArrays for testing purposes + +package com.google.common.collect; + + +public class ObjectArrays +{ + protected ObjectArrays() {} + public static T[] concat(T p0, T[] p1){ return null; } + public static T[] concat(T[] p0, T p1){ return null; } + public static T[] concat(T[] p0, T[] p1, Class p2){ return null; } + public static T[] newArray(Class p0, int p1){ return null; } + public static T[] newArray(T[] p0, int p1){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/Ordering.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Ordering.java new file mode 100644 index 00000000000..a6114bdea3e --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Ordering.java @@ -0,0 +1,51 @@ +// Generated automatically from com.google.common.collect.Ordering for testing purposes + +package com.google.common.collect; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +abstract public class Ordering implements Comparator +{ + Ordering> onKeys(){ return null; } + protected Ordering(){} + public E max(E p0, E p1){ return null; } + public E max(E p0, E p1, E p2, E... p3){ return null; } + public E max(Iterable p0){ return null; } + public E max(Iterator p0){ return null; } + public E min(E p0, E p1){ return null; } + public E min(E p0, E p1, E p2, E... p3){ return null; } + public E min(Iterable p0){ return null; } + public E min(Iterator p0){ return null; } + public ImmutableList immutableSortedCopy(Iterable p0){ return null; } + public List greatestOf(Iterable p0, int p1){ return null; } + public List greatestOf(Iterator p0, int p1){ return null; } + public List leastOf(Iterable p0, int p1){ return null; } + public List leastOf(Iterator p0, int p1){ return null; } + public List sortedCopy(Iterable p0){ return null; } + public Ordering onResultOf(Function p0){ return null; } + public Ordering> lexicographical(){ return null; } + public Ordering nullsFirst(){ return null; } + public Ordering nullsLast(){ return null; } + public Ordering reverse(){ return null; } + public Ordering compound(Comparator p0){ return null; } + public abstract int compare(T p0, T p1); + public boolean isOrdered(Iterable p0){ return false; } + public boolean isStrictlyOrdered(Iterable p0){ return false; } + public int binarySearch(List p0, T p1){ return 0; } + public static Ordering natural(){ return null; } + public static Ordering compound(Iterable> p0){ return null; } + public static Ordering explicit(List p0){ return null; } + public static Ordering explicit(T p0, T... p1){ return null; } + public static Ordering from(Comparator p0){ return null; } + public static Ordering from(Ordering p0){ return null; } + public static Ordering allEqual(){ return null; } + public static Ordering arbitrary(){ return null; } + public static Ordering usingToString(){ return null; } + static int LEFT_IS_GREATER = 0; + static int RIGHT_IS_GREATER = 0; +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/PeekingIterator.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/PeekingIterator.java new file mode 100644 index 00000000000..f84b92e41f6 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/PeekingIterator.java @@ -0,0 +1,12 @@ +// Generated automatically from com.google.common.collect.PeekingIterator for testing purposes + +package com.google.common.collect; + +import java.util.Iterator; + +public interface PeekingIterator extends Iterator +{ + E next(); + E peek(); + void remove(); +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/Queues.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Queues.java new file mode 100644 index 00000000000..981720063fa --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Queues.java @@ -0,0 +1,45 @@ +// Generated automatically from com.google.common.collect.Queues for testing purposes + +package com.google.common.collect; + +import java.time.Duration; +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.Deque; +import java.util.PriorityQueue; +import java.util.Queue; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.PriorityBlockingQueue; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.TimeUnit; + +public class Queues +{ + protected Queues() {} + public static PriorityBlockingQueue newPriorityBlockingQueue(){ return null; } + public static PriorityBlockingQueue newPriorityBlockingQueue(Iterable p0){ return null; } + public static PriorityQueue newPriorityQueue(){ return null; } + public static PriorityQueue newPriorityQueue(Iterable p0){ return null; } + public static ArrayBlockingQueue newArrayBlockingQueue(int p0){ return null; } + public static ArrayDeque newArrayDeque(){ return null; } + public static ArrayDeque newArrayDeque(Iterable p0){ return null; } + public static ConcurrentLinkedQueue newConcurrentLinkedQueue(){ return null; } + public static ConcurrentLinkedQueue newConcurrentLinkedQueue(Iterable p0){ return null; } + public static Deque synchronizedDeque(Deque p0){ return null; } + public static LinkedBlockingDeque newLinkedBlockingDeque(){ return null; } + public static LinkedBlockingDeque newLinkedBlockingDeque(Iterable p0){ return null; } + public static LinkedBlockingDeque newLinkedBlockingDeque(int p0){ return null; } + public static LinkedBlockingQueue newLinkedBlockingQueue(){ return null; } + public static LinkedBlockingQueue newLinkedBlockingQueue(Iterable p0){ return null; } + public static LinkedBlockingQueue newLinkedBlockingQueue(int p0){ return null; } + public static Queue synchronizedQueue(Queue p0){ return null; } + public static SynchronousQueue newSynchronousQueue(){ return null; } + public static int drain(BlockingQueue p0, Collection p1, int p2, Duration p3){ return 0; } + public static int drain(BlockingQueue p0, Collection p1, int p2, long p3, TimeUnit p4){ return 0; } + public static int drainUninterruptibly(BlockingQueue p0, Collection p1, int p2, Duration p3){ return 0; } + public static int drainUninterruptibly(BlockingQueue p0, Collection p1, int p2, long p3, TimeUnit p4){ return 0; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/Range.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Range.java new file mode 100644 index 00000000000..15cfc94fc3d --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Range.java @@ -0,0 +1,47 @@ +// Generated automatically from com.google.common.collect.Range for testing purposes + +package com.google.common.collect; + +import com.google.common.base.Predicate; +import com.google.common.collect.BoundType; +import com.google.common.collect.DiscreteDomain; +import com.google.common.collect.RangeGwtSerializationDependencies; +import java.io.Serializable; + +public class Range extends RangeGwtSerializationDependencies implements Predicate, Serializable +{ + protected Range() {} + public BoundType lowerBoundType(){ return null; } + public BoundType upperBoundType(){ return null; } + public C lowerEndpoint(){ return null; } + public C upperEndpoint(){ return null; } + public Range canonical(DiscreteDomain p0){ return null; } + public Range gap(Range p0){ return null; } + public Range intersection(Range p0){ return null; } + public Range span(Range p0){ return null; } + public String toString(){ return null; } + public boolean apply(C p0){ return false; } + public boolean contains(C p0){ return false; } + public boolean containsAll(Iterable p0){ return false; } + public boolean encloses(Range p0){ return false; } + public boolean equals(Object p0){ return false; } + public boolean hasLowerBound(){ return false; } + public boolean hasUpperBound(){ return false; } + public boolean isConnected(Range p0){ return false; } + public boolean isEmpty(){ return false; } + public int hashCode(){ return 0; } + public static > Range all(){ return null; } + public static > Range atLeast(C p0){ return null; } + public static > Range atMost(C p0){ return null; } + public static > Range closed(C p0, C p1){ return null; } + public static > Range closedOpen(C p0, C p1){ return null; } + public static > Range downTo(C p0, BoundType p1){ return null; } + public static > Range encloseAll(Iterable p0){ return null; } + public static > Range greaterThan(C p0){ return null; } + public static > Range lessThan(C p0){ return null; } + public static > Range open(C p0, C p1){ return null; } + public static > Range openClosed(C p0, C p1){ return null; } + public static > Range range(C p0, BoundType p1, C p2, BoundType p3){ return null; } + public static > Range singleton(C p0){ return null; } + public static > Range upTo(C p0, BoundType p1){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/RangeGwtSerializationDependencies.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/RangeGwtSerializationDependencies.java new file mode 100644 index 00000000000..007eac594c6 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/RangeGwtSerializationDependencies.java @@ -0,0 +1,9 @@ +// Generated automatically from com.google.common.collect.RangeGwtSerializationDependencies for testing purposes + +package com.google.common.collect; + +import java.io.Serializable; + +abstract class RangeGwtSerializationDependencies implements Serializable +{ +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/RegularImmutableSortedSet.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/RegularImmutableSortedSet.java new file mode 100644 index 00000000000..5bf53b0b23d --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/RegularImmutableSortedSet.java @@ -0,0 +1,47 @@ +// Generated automatically from com.google.common.collect.RegularImmutableSortedSet for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSortedSet; +import com.google.common.collect.UnmodifiableIterator; +import java.util.Collection; +import java.util.Comparator; +import java.util.Spliterator; +import java.util.function.Consumer; + +class RegularImmutableSortedSet extends ImmutableSortedSet +{ + protected RegularImmutableSortedSet() {} + Comparator unsafeComparator(){ return null; } + ImmutableList createAsList(){ return null; } + ImmutableSortedSet createDescendingSet(){ return null; } + ImmutableSortedSet headSetImpl(E p0, boolean p1){ return null; } + ImmutableSortedSet subSetImpl(E p0, boolean p1, E p2, boolean p3){ return null; } + ImmutableSortedSet tailSetImpl(E p0, boolean p1){ return null; } + Object[] internalArray(){ return null; } + RegularImmutableSortedSet(ImmutableList p0, Comparator p1){} + RegularImmutableSortedSet getSubSet(int p0, int p1){ return null; } + boolean isPartialView(){ return false; } + int copyIntoArray(Object[] p0, int p1){ return 0; } + int headIndex(E p0, boolean p1){ return 0; } + int indexOf(Object p0){ return 0; } + int internalArrayEnd(){ return 0; } + int internalArrayStart(){ return 0; } + int tailIndex(E p0, boolean p1){ return 0; } + public E ceiling(E p0){ return null; } + public E first(){ return null; } + public E floor(E p0){ return null; } + public E higher(E p0){ return null; } + public E last(){ return null; } + public E lower(E p0){ return null; } + public Spliterator spliterator(){ return null; } + public UnmodifiableIterator descendingIterator(){ return null; } + public UnmodifiableIterator iterator(){ return null; } + public boolean contains(Object p0){ return false; } + public boolean containsAll(Collection p0){ return false; } + public boolean equals(Object p0){ return false; } + public int size(){ return 0; } + public void forEach(Consumer p0){} + static RegularImmutableSortedSet NATURAL_EMPTY_SET = null; +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/RowSortedTable.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/RowSortedTable.java new file mode 100644 index 00000000000..b4a1b74f25a --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/RowSortedTable.java @@ -0,0 +1,14 @@ +// Generated automatically from com.google.common.collect.RowSortedTable for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.Table; +import java.util.Map; +import java.util.SortedMap; +import java.util.SortedSet; + +public interface RowSortedTable extends Table +{ + SortedMap> rowMap(); + SortedSet rowKeySet(); +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/Sets.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Sets.java index 77d3812f082..4e77f5d3a3c 100644 --- a/java/ql/test/stubs/guava-30.0/com/google/common/collect/Sets.java +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Sets.java @@ -1,93 +1,79 @@ -/* - * Copyright (C) 2007 The Guava Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Generated automatically from com.google.common.collect.Sets for testing purposes, and adjusted manually package com.google.common.collect; +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Range; +import com.google.common.collect.UnmodifiableIterator; import java.util.AbstractSet; import java.util.Collection; +import java.util.Comparator; +import java.util.EnumSet; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.NavigableSet; -import java.util.NoSuchElementException; import java.util.Set; -import java.util.function.Predicate; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.stream.Collector; -public final class Sets { - private Sets() {} - - public static HashSet newHashSet() { - return null; - } - - public static HashSet newHashSet(E... elements) { - return null; - } - - public static HashSet newHashSet(Iterable elements) { - return null; - } - public abstract static class SetView extends AbstractSet { - private SetView() {} - } - - public static SetView union(final Set set1, final Set set2) { - return null; - } - - public static SetView intersection(final Set set1, final Set set2) { - return null; - } - - public static SetView difference(final Set set1, final Set set2) { - return null; - } - - public static SetView symmetricDifference( - final Set set1, final Set set2) { - return null; - } - - public static Set filter(Set unfiltered, Predicate predicate) { - return null; - } - - - public static Set> cartesianProduct(List> sets) { - return null; - } - - public static Set> cartesianProduct(Set... sets) { - return null; - } - - public static Set> powerSet(Set set) { - return null; - } - - public static Set> combinations(Set set, final int size) { - return null; - } - - public static NavigableSet synchronizedNavigableSet(NavigableSet navigableSet) { - return null; - } - - public static > NavigableSet subSet( - NavigableSet set, Object range) { - return null; - } +public class Sets +{ + protected Sets() {} + abstract static public class SetView extends AbstractSet + { + protected SetView() {} + public > S copyInto(S p0){ return null; } + public ImmutableSet immutableCopy(){ return null; } + public abstract UnmodifiableIterator iterator(); + public final boolean add(E p0){ return false; } + public final boolean addAll(Collection p0){ return false; } + public final boolean remove(Object p0){ return false; } + public final boolean removeAll(Collection p0){ return false; } + public final boolean removeIf(Predicate p0){ return false; } + public final boolean retainAll(Collection p0){ return false; } + public final void clear(){} + } + public static Set> cartesianProduct(List> p0){ return null; } + public static Set> cartesianProduct(Set... p0){ return null; } + public static TreeSet newTreeSet(){ return null; } + public static TreeSet newTreeSet(Iterable p0){ return null; } + public static > Collector> toImmutableEnumSet(){ return null; } + public static > EnumSet complementOf(Collection p0){ return null; } + public static > EnumSet complementOf(Collection p0, Class p1){ return null; } + public static > EnumSet newEnumSet(Iterable p0, Class p1){ return null; } + public static > ImmutableSet immutableEnumSet(E p0, E... p1){ return null; } + public static > ImmutableSet immutableEnumSet(Iterable p0){ return null; } + public static CopyOnWriteArraySet newCopyOnWriteArraySet(){ return null; } + public static CopyOnWriteArraySet newCopyOnWriteArraySet(Iterable p0){ return null; } + public static HashSet newHashSet(){ return null; } + public static HashSet newHashSet(E... p0){ return null; } + public static HashSet newHashSet(Iterable p0){ return null; } + public static HashSet newHashSet(Iterator p0){ return null; } + public static HashSet newHashSetWithExpectedSize(int p0){ return null; } + public static LinkedHashSet newLinkedHashSet(){ return null; } + public static LinkedHashSet newLinkedHashSet(Iterable p0){ return null; } + public static LinkedHashSet newLinkedHashSetWithExpectedSize(int p0){ return null; } + public static NavigableSet filter(NavigableSet p0, Predicate p1){ return null; } + public static NavigableSet synchronizedNavigableSet(NavigableSet p0){ return null; } + public static NavigableSet unmodifiableNavigableSet(NavigableSet p0){ return null; } + public static Set filter(Set p0, Predicate p1){ return null; } + public static Set newConcurrentHashSet(){ return null; } + public static Set newConcurrentHashSet(Iterable p0){ return null; } + public static Set newIdentityHashSet(){ return null; } + public static Set newSetFromMap(Map p0){ return null; } + public static Set> combinations(Set p0, int p1){ return null; } + public static Set> powerSet(Set p0){ return null; } + public static Sets.SetView difference(Set p0, Set p1){ return null; } + public static Sets.SetView intersection(Set p0, Set p1){ return null; } + public static Sets.SetView symmetricDifference(Set p0, Set p1){ return null; } + public static Sets.SetView union(Set p0, Set p1){ return null; } + public static SortedSet filter(SortedSet p0, Predicate p1){ return null; } + public static TreeSet newTreeSet(Comparator p0){ return null; } + public static > NavigableSet subSet(NavigableSet p0, Range p1){ return null; } } diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/SortedIterable.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/SortedIterable.java new file mode 100644 index 00000000000..41631eb4a3a --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/SortedIterable.java @@ -0,0 +1,12 @@ +// Generated automatically from com.google.common.collect.SortedIterable for testing purposes + +package com.google.common.collect; + +import java.util.Comparator; +import java.util.Iterator; + +interface SortedIterable extends Iterable +{ + Comparator comparator(); + Iterator iterator(); +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/SortedMapDifference.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/SortedMapDifference.java new file mode 100644 index 00000000000..c511f16d166 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/SortedMapDifference.java @@ -0,0 +1,14 @@ +// Generated automatically from com.google.common.collect.SortedMapDifference for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.MapDifference; +import java.util.SortedMap; + +public interface SortedMapDifference extends MapDifference +{ + SortedMap> entriesDiffering(); + SortedMap entriesInCommon(); + SortedMap entriesOnlyOnLeft(); + SortedMap entriesOnlyOnRight(); +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/SortedMultiset.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/SortedMultiset.java new file mode 100644 index 00000000000..33e26b12e56 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/SortedMultiset.java @@ -0,0 +1,28 @@ +// Generated automatically from com.google.common.collect.SortedMultiset for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.BoundType; +import com.google.common.collect.Multiset; +import com.google.common.collect.SortedIterable; +import com.google.common.collect.SortedMultisetBridge; +import java.util.Comparator; +import java.util.Iterator; +import java.util.NavigableSet; +import java.util.Set; + +public interface SortedMultiset extends SortedIterable, SortedMultisetBridge +{ + Comparator comparator(); + Iterator iterator(); + Multiset.Entry firstEntry(); + Multiset.Entry lastEntry(); + Multiset.Entry pollFirstEntry(); + Multiset.Entry pollLastEntry(); + NavigableSet elementSet(); + Set> entrySet(); + SortedMultiset descendingMultiset(); + SortedMultiset headMultiset(E p0, BoundType p1); + SortedMultiset subMultiset(E p0, BoundType p1, E p2, BoundType p3); + SortedMultiset tailMultiset(E p0, BoundType p1); +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/SortedMultisetBridge.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/SortedMultisetBridge.java new file mode 100644 index 00000000000..d61d1b242b9 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/SortedMultisetBridge.java @@ -0,0 +1,11 @@ +// Generated automatically from com.google.common.collect.SortedMultisetBridge for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.Multiset; +import java.util.SortedSet; + +interface SortedMultisetBridge extends Multiset +{ + SortedSet elementSet(); +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/SortedSetMultimap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/SortedSetMultimap.java new file mode 100644 index 00000000000..c2da3b40d85 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/SortedSetMultimap.java @@ -0,0 +1,18 @@ +// Generated automatically from com.google.common.collect.SortedSetMultimap for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.SetMultimap; +import java.util.Collection; +import java.util.Comparator; +import java.util.Map; +import java.util.SortedSet; + +public interface SortedSetMultimap extends SetMultimap +{ + Comparator valueComparator(); + Map> asMap(); + SortedSet get(K p0); + SortedSet removeAll(Object p0); + SortedSet replaceValues(K p0, Iterable p1); +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/StandardRowSortedTable.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/StandardRowSortedTable.java new file mode 100644 index 00000000000..6690519bddc --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/StandardRowSortedTable.java @@ -0,0 +1,16 @@ +// Generated automatically from com.google.common.collect.StandardRowSortedTable for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.RowSortedTable; +import com.google.common.collect.StandardTable; +import java.util.Map; +import java.util.SortedMap; +import java.util.SortedSet; + +class StandardRowSortedTable extends StandardTable implements RowSortedTable +{ + protected StandardRowSortedTable() {} + public SortedMap> rowMap(){ return null; } + public SortedSet rowKeySet(){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/StandardTable.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/StandardTable.java new file mode 100644 index 00000000000..68cc22b9469 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/StandardTable.java @@ -0,0 +1,33 @@ +// Generated automatically from com.google.common.collect.StandardTable for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.AbstractTable; +import com.google.common.collect.Table; +import java.io.Serializable; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +class StandardTable extends AbstractTable implements Serializable +{ + protected StandardTable() {} + public Collection values(){ return null; } + public Map> columnMap(){ return null; } + public Map row(R p0){ return null; } + public Map> rowMap(){ return null; } + public Map column(C p0){ return null; } + public Set columnKeySet(){ return null; } + public Set rowKeySet(){ return null; } + public Set> cellSet(){ return null; } + public V get(Object p0, Object p1){ return null; } + public V put(R p0, C p1, V p2){ return null; } + public V remove(Object p0, Object p1){ return null; } + public boolean contains(Object p0, Object p1){ return false; } + public boolean containsColumn(Object p0){ return false; } + public boolean containsRow(Object p0){ return false; } + public boolean containsValue(Object p0){ return false; } + public boolean isEmpty(){ return false; } + public int size(){ return 0; } + public void clear(){} +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/Table.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Table.java index d310bd99182..bd3192c8c9e 100644 --- a/java/ql/test/stubs/guava-30.0/com/google/common/collect/Table.java +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Table.java @@ -1,18 +1,4 @@ -/* - * Copyright (C) 2008 The Guava Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Generated automatically from com.google.common.collect.Table for testing purposes package com.google.common.collect; @@ -20,50 +6,35 @@ import java.util.Collection; import java.util.Map; import java.util.Set; -public interface Table { - boolean contains(Object rowKey, Object columnKey); - - boolean containsRow(Object rowKey); - - boolean containsColumn(Object columnKey); - - boolean containsValue(Object value); - - V get(Object rowKey, Object columnKey); - - boolean isEmpty(); - - int size(); - - void clear(); - - V put(R rowKey, C columnKey, V value); - - void putAll(Table table); - - V remove(Object rowKey, Object columnKey); - - Map row(R rowKey); - - Map column(C columnKey); - - Set> cellSet(); - - Set rowKeySet(); - - Set columnKeySet(); - - Collection values(); - - Map> rowMap(); - - Map> columnMap(); - - interface Cell { - R getRowKey(); - - C getColumnKey(); - - V getValue(); - } +public interface Table +{ + Collection values(); + Map> columnMap(); + Map row(R p0); + Map> rowMap(); + Map column(C p0); + Set columnKeySet(); + Set rowKeySet(); + Set> cellSet(); + V get(Object p0, Object p1); + V put(R p0, C p1, V p2); + V remove(Object p0, Object p1); + boolean contains(Object p0, Object p1); + boolean containsColumn(Object p0); + boolean containsRow(Object p0); + boolean containsValue(Object p0); + boolean equals(Object p0); + boolean isEmpty(); + int hashCode(); + int size(); + static public interface Cell + { + C getColumnKey(); + R getRowKey(); + V getValue(); + boolean equals(Object p0); + int hashCode(); + } + void clear(); + void putAll(Table p0); } diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/Tables.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Tables.java new file mode 100644 index 00000000000..9d5c157dca2 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/Tables.java @@ -0,0 +1,25 @@ +// Generated automatically from com.google.common.collect.Tables for testing purposes, and adjusted manually + +package com.google.common.collect; + +import com.google.common.base.Function; +import com.google.common.base.Supplier; +import com.google.common.collect.RowSortedTable; +import com.google.common.collect.Table; +import java.util.Map; +import java.util.function.BinaryOperator; +import java.util.stream.Collector; + +public class Tables +{ + protected Tables() {} + public static Table transformValues(Table p0, Function p1){ return null; } + public static RowSortedTable unmodifiableRowSortedTable(RowSortedTable p0){ return null; } + public static Table.Cell immutableCell(R p0, C p1, V p2){ return null; } + public static Table transpose(Table p0){ return null; } + public static Table newCustomTable(Map> p0, Supplier> p1){ return null; } + public static Table synchronizedTable(Table p0){ return null; } + public static Table unmodifiableTable(Table p0){ return null; } + public static > Collector toTable(Function p0, Function p1, Function p2, BinaryOperator p3, Supplier p4){ return null; } + public static > Collector toTable(Function p0, Function p1, Function p2, Supplier p3){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/TreeBasedTable.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/TreeBasedTable.java new file mode 100644 index 00000000000..030593c26c9 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/TreeBasedTable.java @@ -0,0 +1,22 @@ +// Generated automatically from com.google.common.collect.TreeBasedTable for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.StandardRowSortedTable; +import java.util.Comparator; +import java.util.Map; +import java.util.SortedMap; +import java.util.SortedSet; + +public class TreeBasedTable extends StandardRowSortedTable +{ + protected TreeBasedTable() {} + public Comparator columnComparator(){ return null; } + public Comparator rowComparator(){ return null; } + public SortedMap row(R p0){ return null; } + public SortedMap> rowMap(){ return null; } + public SortedSet rowKeySet(){ return null; } + public static TreeBasedTable create(){ return null; } + public static TreeBasedTable create(Comparator p0, Comparator p1){ return null; } + public static TreeBasedTable create(TreeBasedTable p0){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/TreeMultimap.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/TreeMultimap.java new file mode 100644 index 00000000000..97e9c26c95f --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/TreeMultimap.java @@ -0,0 +1,23 @@ +// Generated automatically from com.google.common.collect.TreeMultimap for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.AbstractSortedKeySortedSetMultimap; +import com.google.common.collect.Multimap; +import java.util.Collection; +import java.util.Comparator; +import java.util.NavigableMap; +import java.util.NavigableSet; + +public class TreeMultimap extends AbstractSortedKeySortedSetMultimap +{ + protected TreeMultimap() {} + public Comparator keyComparator(){ return null; } + public Comparator valueComparator(){ return null; } + public NavigableMap> asMap(){ return null; } + public NavigableSet keySet(){ return null; } + public NavigableSet get(K p0){ return null; } + public static TreeMultimap create(){ return null; } + public static TreeMultimap create(Multimap p0){ return null; } + public static TreeMultimap create(Comparator p0, Comparator p1){ return null; } +} diff --git a/java/ql/test/stubs/guava-30.0/com/google/common/collect/TreeMultiset.java b/java/ql/test/stubs/guava-30.0/com/google/common/collect/TreeMultiset.java new file mode 100644 index 00000000000..e76b3086159 --- /dev/null +++ b/java/ql/test/stubs/guava-30.0/com/google/common/collect/TreeMultiset.java @@ -0,0 +1,30 @@ +// Generated automatically from com.google.common.collect.TreeMultiset for testing purposes + +package com.google.common.collect; + +import com.google.common.collect.AbstractSortedMultiset; +import com.google.common.collect.BoundType; +import com.google.common.collect.SortedMultiset; +import java.io.Serializable; +import java.util.Comparator; +import java.util.Iterator; +import java.util.function.ObjIntConsumer; + +public class TreeMultiset extends AbstractSortedMultiset implements Serializable +{ + protected TreeMultiset() {} + public Iterator iterator(){ return null; } + public SortedMultiset headMultiset(E p0, BoundType p1){ return null; } + public SortedMultiset tailMultiset(E p0, BoundType p1){ return null; } + public boolean setCount(E p0, int p1, int p2){ return false; } + public int add(E p0, int p1){ return 0; } + public int count(Object p0){ return 0; } + public int remove(Object p0, int p1){ return 0; } + public int setCount(E p0, int p1){ return 0; } + public int size(){ return 0; } + public static TreeMultiset create(){ return null; } + public static TreeMultiset create(Iterable p0){ return null; } + public static TreeMultiset create(Comparator p0){ return null; } + public void clear(){} + public void forEachEntry(ObjIntConsumer p0){} +} diff --git a/java/ql/test/stubs/javax-faces-2.3/javax/faces/component/UIComponent.java b/java/ql/test/stubs/javax-faces-2.3/javax/faces/component/UIComponent.java new file mode 100644 index 00000000000..a7d9efd8391 --- /dev/null +++ b/java/ql/test/stubs/javax-faces-2.3/javax/faces/component/UIComponent.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package javax.faces.component; + +import java.util.Map; + +/** + *

    + * UIComponent is the base class for + * all user interface components in Jakarta Server Faces. The set of {@link UIComponent} + * instances associated with a particular request and response are organized into a + * component tree under a {@link UIViewRoot} that represents the entire content of the + * request or response. + *

    + * + *

    + * For the convenience of component developers, {@link UIComponentBase} provides the + * default behavior that is specified for a {@link UIComponent}, and is the base class for + * all of the concrete {@link UIComponent} "base" implementations. Component writers are + * encouraged to subclass {@link UIComponentBase}, instead of directly implementing this + * abstract class, to reduce the impact of any future changes to the method signatures. + *

    + * + *

    + * If the {@link javax.faces.event.ListenerFor} annotation is attached to the class + * definition of a Component, that class must also implement + * {@link javax.faces.event.ComponentSystemEventListener}. + *

    + * + *

    + * Dynamically modifying the component tree can happen at any time, during and after + * restoring the view, but not during state saving and needs to function properly with + * respect to rendering and state saving + *

    + */ +public abstract class UIComponent { + + /** + *

    + * Return a mutable Map representing the attributes (and properties, see + * below) associated wth this {@link UIComponent}, keyed by attribute name (which must + * be a String). The returned implementation must support all of the standard and + * optional Map methods, plus support the following additional + * requirements: + *

    + *
      + *
    • The Map implementation must implement the + * java.io.Serializable interface.
    • + *
    • Any attempt to add a null key or value must throw a + * NullPointerException.
    • + *
    • Any attempt to add a key that is not a String must throw a + * ClassCastException.
    • + *
    • If the attribute name specified as a key matches a property of this + * {@link UIComponent}'s implementation class, the following methods will have special + * behavior: + *
        + *
      • containsKey - Return false.
      • + *
      • get() - If the property is readable, call the getter method and + * return the returned value (wrapping primitive values in their corresponding wrapper + * classes); otherwise throw IllegalArgumentException.
      • + *
      • put() - If the property is writeable, call the setter method to + * set the corresponding value (unwrapping primitive values in their corresponding + * wrapper classes). If the property is not writeable, or an attempt is made to set a + * property of primitive type to null, throw + * IllegalArgumentException.
      • + *
      • remove - Throw IllegalArgumentException.
      • + *
      + *
    • + *
    + * + * @return the component attribute map. + */ + public abstract Map getAttributes(); +} diff --git a/java/ql/test/stubs/javax-faces-2.3/javax/faces/context/ExternalContext.java b/java/ql/test/stubs/javax-faces-2.3/javax/faces/context/ExternalContext.java new file mode 100644 index 00000000000..76b985e9788 --- /dev/null +++ b/java/ql/test/stubs/javax-faces-2.3/javax/faces/context/ExternalContext.java @@ -0,0 +1,1076 @@ +/* + * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package javax.faces.context; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Writer; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + + +/** + *

    + * This class allows the Faces API to be unaware of the nature of its containing + * application environment. In particular, this class allows Jakarta Server Faces based + * applications to run in either a Jakarta Servlet or a Portlet environment.

    + * + *

    The documentation for this class only + * specifies the behavior for the Jakarta Servlet implementation of + * ExternalContext. The Portlet implementation of + * ExternalContext is specified under the revision of the + * Portlet Bridge + * Specification for JavaServer Faces JSR that corresponds to + * this version of the Jakarta Server Faces specification. See the Preface of the + * "prose document", linked + * from the javadocs, for a reference.

    + + *

    If a reference to an + * ExternalContext is obtained during application startup or shutdown + * time, any method documented as "valid to call this method during + * application startup or shutdown" must be supported during application startup or shutdown + * time. The result of calling a method during application startup or shutdown time + * that does not have this designation is undefined.

    + * + *

    An ExternalContext can be injected into a CDI + * managed bean using @Inject ExternalContext externalContext; + *

    + */ + +public abstract class ExternalContext { + + /** + *

    Adds the cookie represented by the + * arguments to the response.

    + * + *
    + * + *

    Jakarta Servlet: This must be accomplished by calling the + * javax.servlet.http.HttpServletResponse method + * addCookie(). The Cookie argument must + * be constructed by passing the name and + * value parameters. If the properties + * arugument is non-null and not empty, the + * Cookie instance must be initialized as described + * below.

    + * + *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Cookie handling table
    Key in "values" MapExpected type of value.Name of setter method on Cookie instance to be + * set with the value from the Map.
    commentStringsetComment
    domainStringsetDomain
    maxAgeIntegersetMaxAge
    secureBooleansetSecure
    pathStringsetPath
    httpOnlyBooleansetHttpOnly
    + * + *

    The default implementation throws + * UnsupportedOperationException and is provided for + * the sole purpose of not breaking existing applications that + * extend this class.

    + * + * + * + * @param name To be passed as the first argument to the + * Cookie constructor. + * + * @param value To be passed as the second argument to the + * Cookie constructor. + * + * @param properties A Map containg key/value pairs to be passed + * as arguments to the setter methods as described above. + * + * @throws IllegalArgumentException if the properties + * Map is not-null and not empty and contains + * any keys that are not one of the keys listed above. + * + * @since 2.0 + */ + + public void addResponseCookie(String name, + String value, + Map properties) { + } + + + /** + *

    Dispatch a request to the specified resource to create output + * for this response.

    + * + *

    Jakarta Servlet: This must be accomplished by calling the + * javax.servlet.ServletContext method + * getRequestDispatcher(path), and calling the + * forward() method on the resulting object.

    + *

    If the call to getRequestDisatcher(path) + * returns null, send aServletResponse SC_NOT_FOUND + * error code.

    + * + * @param path Context relative path to the specified resource, + * which must start with a slash ("/") character + * + * @throws javax.faces.FacesException thrown if a ServletException occurs + * @throws IOException if an input/output error occurs + */ + public abstract void dispatch(String path) throws IOException; + + + /** + *

    Return the input URL, after performing any rewriting needed to + * ensure that it will correctly identify an addressable action in the + * current application.

    + * + *

    Encoding the {@link javax.faces.lifecycle.ClientWindow}

    + * + *
    + * + *

    Call {@link javax.faces.lifecycle.ClientWindow#isClientWindowRenderModeEnabled(javax.faces.context.FacesContext) }. + * If the result is false take no further action and return + * the rewritten URL. If the result is true, call {@link #getClientWindow()}. + * If the result is non-null, call {@link javax.faces.lifecycle.ClientWindow#getId()} + * and append the id to the query string of the URL, making the necessary + * allowances for a pre-existing query string or no query-string.

    + * + *

    Call {@link javax.faces.lifecycle.ClientWindow#getQueryURLParameters}. + * If the result is non-{@code null}, for each parameter in the map, + * unconditionally add that parameter to the URL.

    + * + *

    The name + * of the query string parameter is given by the value of the constant + * {@link javax.faces.render.ResponseStateManager#CLIENT_WINDOW_URL_PARAM}.

    + * + *
    + * + *

    Jakarta Servlet: This must be the value returned by the + * javax.servlet.http.HttpServletResponse method + * encodeURL(url).

    + * + * @param url The input URL to be encoded + * + * @return the encoded URL. + * + * @throws NullPointerException if url + * is null + */ + public abstract String encodeActionURL(String url); + + + /** + *

    Return the input URL, after performing any rewriting needed to + * ensure that it will correctly identify an addressable resource in the + * current application.

    + * + *

    Jakarta Servlet: This must be the value returned by the + * javax.servlet.http.HttpServletResponse method + * encodeURL(url).

    + * + * @param url The input URL to be encoded + * + * @return the encoded resource URL. + * + * @throws NullPointerException if url + * is null + */ + // PENDING(craigmcc) - Currently identical to encodeActionURL() + public abstract String encodeResourceURL(String url); + + + /** + *

    + * Return the websocket URL, after performing any rewriting needed to + * ensure that it will correctly identify an addressable websocket in the + * current application. + *

    + * + *

    + * Jakarta Servlet: This must ensure that the input URL is prefixed + * with the correct websocket scheme, domain and port and then + * encoded by {@link #encodeResourceURL(String)}. + *

    + * + * @param url The input URL to be encoded. + * + * @return the encoded websocket URL. + * + * @throws NullPointerException if url is null. + * + * @since 2.3 + */ + public abstract String encodeWebsocketURL(String url); + + + /** + *

    Returns the MIME type of the + * specified file or null if the MIME type is not + * known. The MIME type is determined by the container.

    + + *

    It is valid to call this method + * during application startup or shutdown. If called during application + * startup or shutdown, this method calls through to the + * getMimeType() method on the same container + * context instance (ServletContext or + * PortletContext) as the one used when calling + * getMimeType() on the + * ExternalContext returned by the + * FacesContext during an actual request.

    + + *
    + + *

    Jakarta Servlet: This must be the value returned by the + * javax.servlet.ServletContext method + * getMimeType().

    + * + *
    + * + * @param file The file for which the mime type should be obtained. + * + * @return the MIME type of the file. + * + * @since 2.0 + */ + public String getMimeType(String file) { + return null; + } + + + /** + *

    Return the + * application environment object instance for the current + * appication.

    + + *

    It is valid to call this method + * during application startup or shutdown. If called during application + * startup or shutdown, this returns the same container context instance + * (ServletContext or PortletContext) as + * the one returned when calling getContext() on the + * ExternalContext returned by the + * FacesContext during an actual request.

    + + * + *

    Jakarta Servlet: This must be the current application's + * javax.servlet.ServletContext instance.

    + * + * @return the object of the ServletContext. + * + */ + public abstract Object getContext(); + + + /** + * + *

    Return the name of the container + * context for this application.

    + * + *

    Jakarta Servlet: + * Return the result of calling + * getContextPath() on the + * ServletContext instance for this application.

    + + *

    It is valid to call this method during application startup or + * shutdown.

    + * + *

    The default implementation throws + * UnsupportedOperationException and is provided for + * the sole purpose of not breaking existing applications that + * extend this class.

    + * + * @return the context path of this application. + * + * @since 2.2 + */ + + public String getApplicationContextPath() { + return null; + } + + + /** + *

    Return the value of + * the specified application initialization parameter (if any).

    + * + *

    Jakarta Servlet: This must be the result of the + * javax.servlet.ServletContext method + * getInitParameter(name).

    + * + *

    It is valid to call this method + * during application startup or shutdown. If called during application + * startup or shutdown, this method calls through to the actual container + * context to return the init parameter value.

    + + * @param name Name of the requested initialization parameter + * + * @throws NullPointerException if name + * is null + * + * @return the value of the specified parameter. + * + */ + public abstract String getInitParameter(String name); + + + /** + *

    Return an + * immutable Map whose keys are the set of application + * initialization parameter names configured for this application, + * and whose values are the corresponding parameter values. The + * returned Map must implement the entire contract for + * an unmodifiable map as described in the JavaDocs for + * java.util.Map.

    + * + *

    It is valid to call this method + * during application startup or shutdown. If called during application + * startup or shutdown, this method returns a Map that is backed by + * the same container context instance (ServletContext + * or PortletContext) as the one returned by calling + * getInitParameterMap() on the + * ExternalContext returned by the + * FacesContext during an actual request.

    + * + *

    Jakarta Servlet: This result must be as if it were synthesized + * by calling the javax.servlet.ServletContext + * method getInitParameterNames, and putting + * each configured parameter name/value pair into the result.

    + * + * @return the init parameter map for this application. + * + */ + public abstract Map getInitParameterMap(); + + + /** + *

    Return the login name of the user making the current request + * if any; otherwise, return null.

    + * + *

    Jakarta Servlet: This must be the value returned by the + * javax.servlet.http.HttpServletRequest method + * getRemoteUser().

    + * + * @return the user name of the current request. + * + */ + public abstract String getRemoteUser(); + + + /** + *

    Return the environment-specific object instance for the current + * request.

    + * + *

    Jakarta Servlet: This must be the current request's + * javax.servlet.http.HttpServletRequest instance.

    + * + * @return the instance of the current request. + * + */ + public abstract Object getRequest(); + + + /** + *

    Set the environment-specific request to be returned by + * subsequent calls to {@link #getRequest}. This may be used to + * install a wrapper for the request.

    + * + *

    The default implementation throws + * UnsupportedOperationException and is provided + * for the sole purpose of not breaking existing applications that extend + * this class.

    + * + * @param request the request object to be set. + * + * @since 1.2 + */ + public void setRequest(Object request) { + } + + + /** + *

    Returns the name of the scheme used + * to make this request, for example, http, https, or ftp.

    + * + *
    + *

    Jakarta Servlet: This must be the value returned by the + * javax.servlet.ServletRequest method + * getScheme().

    + * + *

    The default implementation throws + * UnsupportedOperationException and is provided for + * the sole purpose of not breaking existing applications that + * extend this class.

    + * + *
    + * + * @return the name of the scheme. + * + * @since 2.0 + */ + public String getRequestScheme() { + return null; + } + + + /** + *

    Returns the host name of the server + * to which the request was sent.

    + * + *
    + * + *

    Jakarta Servlet: This must be the value returned by the + * javax.servlet.ServletRequest method + * getServerName().

    + * + *

    The default implementation throws + * UnsupportedOperationException and is provided for + * the sole purpose of not breaking existing applications that + * extend this class.

    + * + *
    + * + * @return the host name of the server. + * + * @since 2.0 + */ + public String getRequestServerName() { + return null; + } + + + /** + *

    Returns the port number to which + * the request was sent.

    + * + *
    + * + *

    Jakarta Servlet: This must be the value returned by the + * javax.servlet.ServletRequest method + * getServerPort().

    + * + *

    The default implementation throws + * UnsupportedOperationException and is provided for + * the sole purpose of not breaking existing applications that + * extend this class.

    + * + *
    + * + * @return the port number to which the request was sent. + * + * @since 2.0 + */ + public int getRequestServerPort() { + return -1; + } + + + /** + *

    Returns a String containing the real + * path for a given virtual path.

    + * + *

    It is valid to call this method + * during application startup or shutdown. If called during application + * startup or shutdown, this method calls through to the + * getRealPath() method on the same container + * context instance (ServletContext or + * PortletContext) as the one used when calling + * getRealPath() on the + * ExternalContext returned by the + * FacesContext during an actual request. + *

    + * + *
    + * + *

    Jakarta Servlet: This must be the value returned by the + * javax.servlet.ServletContext method + * getRealPath().

    + * + *

    The default implementation throws + * UnsupportedOperationException and is provided + * for the sole purpose of not breaking existing applications that extend + * this class.

    + * + *
    + * + * @param path The context of the requested initialization parameter + * + * @return the real path for the specified virtual path. + * + * @since 2.0 + */ + public String getRealPath(String path) { + return null; + } + + + /** + *

    Return the portion of the request URI that identifies the web + * application context for this request.

    + * + *

    Jakarta Servlet: This must be the value returned by the + * javax.servlet.http.HttpServletRequest method + * getContextPath().

    + * + * @return the context path for this request. + */ + public abstract String getRequestContextPath(); + + + /** + *

    Return an immutable Map whose keys are the set of + * cookie names included in the current request, and whose + * values (of type javax.servlet.http.Cookie) + * are the first (or only) cookie for each cookie name + * returned by the underlying request. The returned + * Map must implement the entire contract for an unmodifiable + * map as described in the JavaDocs for java.util.Map.

    + * + *

    Jakarta Servlet: This must be the value returned by the + * javax.servlet.http.HttpServletRequest method + * getCookies(), unless null was returned, + * in which case this must be a zero-length array.

    + * + * @return the cookie map in the current request. + * + */ + public abstract Map getRequestCookieMap(); + + + /** + *

    Return an immutable Map whose keys are the set of + * request header names included in the current request, and whose + * values (of type String) are the first (or only) value for each + * header name returned by the underlying request. The returned + * Map must implement the entire contract for an unmodifiable + * map as described in the JavaDocs for java.util.Map. In + * addition, key comparisons must be performed in a case insensitive + * manner.

    + * + *

    Jakarta Servlet: This must be the set of headers available via + * the javax.servlet.http.HttpServletRequest methods + * getHeader() and getHeaderNames().

    + * + * @return the header map in the current request. + * + */ + public abstract Map getRequestHeaderMap(); + + + /** + *

    Return an immutable Map whose keys are the set of + * request header names included in the current request, and whose + * values (of type String[]) are all of the value for each + * header name returned by the underlying request. The returned + * Map must implement the entire contract for an unmodifiable + * map as described in the JavaDocs for java.util.Map. In + * addition, key comparisons must be performed in a case insensitive + * manner.

    + * + *

    Jakarta Servlet: This must be the set of headers available via + * the javax.servlet.http.HttpServletRequest methods + * getHeaders() and getHeaderNames().

    + * + * @return the header values map in the current request. + */ + public abstract Map getRequestHeaderValuesMap(); + + + /** + *

    Return a mutable Map representing the request + * scope attributes for the current application. The returned + * Map must implement the entire contract for a + * modifiable map as described in the JavaDocs for + * java.util.Map. Modifications made in the + * Map must cause the corresponding changes in the set + * of request scope attributes. Particularly the + * clear(), remove(), put(), + * putAll(), and get() operations must + * take the appropriate action on the underlying data structure.

    + * + *

    For any of the Map methods that cause an element + * to be removed from the underlying data structure, the following + * action regarding managed-beans must be taken. If the element to + * be removed is a managed-bean, and it has one or more public + * no-argument void return methods annotated with + * javax.annotation.PreDestroy, each such method must + * be called before the element is removed from the underlying data + * structure. Elements that are not managed-beans, but do happen to + * have methods with that annotation must not have those methods + * called on removal. Any exception thrown by the + * PreDestroy annotated methods must by caught and not + * rethrown. The exception may be logged.

    + * + *

    Jakarta Servlet: This must be the set of attributes available via + * the javax.servlet.ServletRequest methods + * getAttribute(), getAttributeNames(), + * removeAttribute(), and setAttribute().

    + * + * @return the map including the attributes of the current request. + * + */ + public abstract Map getRequestMap(); + + + /** + *

    Return an immutable Map whose keys are the set of + * request parameters names included in the current request, and whose + * values (of type String) are the first (or only) value for each + * parameter name returned by the underlying request. The returned + * Map must implement the entire contract for an unmodifiable + * map as described in the JavaDocs for java.util.Map.

    + * + *

    Jakarta Servlet: This must be the set of parameters available via + * the javax.servlet.ServletRequest methods + * getParameter() and getParameterNames().

    + * + * @return the map for the current request parameters. + * + */ + public abstract Map getRequestParameterMap(); + + + /** + *

    Return an Iterator over the names of all request + * parameters included in the current request.

    + * + *

    Jakarta Servlet: This must be an Iterator over the + * values returned by the javax.servlet.ServletRequest + * method getParameterNames().

    + * + * @return the Iterator for the names of the current request parameters. + * + */ + public abstract Iterator getRequestParameterNames(); + + + /** + *

    Return an immutable Map whose keys are the set of + * request parameters names included in the current request, and whose + * values (of type String[]) are all of the values for each + * parameter name returned by the underlying request. The returned + * Map must implement the entire contract for an unmodifiable + * map as described in the JavaDocs for java.util.Map.

    + * + *

    Jakarta Servlet: This must be the set of parameters available via + * the javax.servlet.ServletRequest methods + * getParameterValues() and + * getParameterNames().

    + * + * @return the map for the parameter values of the current request. + * + */ + public abstract Map getRequestParameterValuesMap(); + + + /** + *

    Return the extra path information (if any) included in the + * request URI; otherwise, return null.

    + * + *

    Jakarta Servlet: This must be the value returned by the + * javax.servlet.http.HttpServletRequest method + * getPathInfo().

    + * + * @return the path information of the current request. + * + */ + public abstract String getRequestPathInfo(); + + + /** + *

    Return the Jakarta Servlet path information (if any) included in the + * request URI; otherwise, return null.

    + * + *

    Jakarta Servlet: This must be the value returned by the + * javax.servlet.http.HttpServletRequest method + * getServletPath().

    + * + * @return the Jakarta Servlet path information of the current request. + */ + public abstract String getRequestServletPath(); + + + /** + *

    Return a + * URL for the application resource mapped to the + * specified path, if it exists; otherwise, return + * null.

    + * + *

    It is valid to call this method + * during application startup or shutdown. If called during application + * startup or shutdown, this method calls through to the + * getResource() method on the same container + * context instance (ServletContext or + * PortletContext) as the one used when calling + * getResource() on the + * ExternalContext returned by the + * FacesContext during an actual request.

    + + *

    Jakarta Servlet: This must be the value returned by the + * javax.servlet.ServletContext method + * getResource(path).

    + * + * @param path The path to the requested resource, which must + * start with a slash ("/" character + * + * @return the URL of the resource. + * + * @throws MalformedURLException if the specified path + * is not in the correct form + * @throws NullPointerException if path + * is null + */ + public abstract URL getResource(String path) throws MalformedURLException; + + + /** + *

    Return an + * InputStream for an application resource mapped to + * the specified path, if it exists; otherwise, return + * null.

    + + *

    It is valid to call this method + * during application startup or shutdown. If called during application + * startup or shutdown, this method calls through to the + * getResourceAsStream() method on the same container + * context instance (ServletContext or + * PortletContext) as the one used when calling + * getResourceAsStream() on the + * ExternalContext returned by the + * FacesContext during an actual request.

    + * + *

    Jakarta Servlet: This must be the value returned by the + * javax.servlet.ServletContext method + * getResourceAsStream(path).

    + * + * @param path The path to the requested resource, which must + * start with a slash ("/" character + * + * @return the InputStream for the application resource. + * + * @throws NullPointerException if path + * is null + */ + public abstract InputStream getResourceAsStream(String path); + + + /** + *

    Return the + * Set of resource paths for all application resources + * whose resource path starts with the specified argument.

    + * + *

    It is valid to call this method + * during application startup or shutdown. If called during application + * startup or shutdown, this method calls through to the + * getResourcePaths() method on the same container + * context instance (ServletContext or + * PortletContext) as the one used when calling + * getResourcePaths() on the + * ExternalContext returned by the + * FacesContext during an actual request.

    + + *

    Jakarta Servlet: This must be the value returned by the + * javax.servlet.ServletContext method + * getResourcePaths(path).

    + * + * @param path Partial path used to match resources, which must + * start with a slash ("/") character + * + * @return the Set of resource paths for the application resources. + * + * @throws NullPointerException if path + * is null + */ + public abstract Set getResourcePaths(String path); + + + /** + *

    Return the environment-specific object instance for the current + * response.

    + * + *

    Jakarta Servlet: This is the current request's + * javax.servlet.http.HttpServletResponse instance.

    + * + * @return the instance of the current javax.servlet.http.HttpServletResponse. + */ + public abstract Object getResponse(); + + /** + *

    Set the environment-specific response to be returned by + * subsequent calls to {@link #getResponse}. This may be used to + * install a wrapper for the response.

    + * + *

    The default implementation throws + * UnsupportedOperationException and is provided + * for the sole purpose of not breaking existing applications that extend + * this class.

    + * + * @param response the response instance to be set. + * + * @since 1.2 + */ + public void setResponse(Object response) { + } + + + /** + *

    Returns an OutputStream + * suitable for writing binary data to the user-agent.

    + * + *
    + * + *

    Jakarta Servlet: This must return the value returned by the + * javax.servlet.ServletResponse method + * getOutputStream().

    + * + *

    The default implementation throws + * UnsupportedOperationException and is provided for + * the sole purpose of not breaking existing applications that + * extend this class.

    + * + *
    + * + * @return the OutputStream for the current response. + * + * @throws IOException any IO related exception. + * + * @since 2.0 + */ + public OutputStream getResponseOutputStream() throws IOException { + return null; + } + + + /** + *

    Returns a Writer + * suitable for writing character data to the user-agent.

    + * + *
    + * + *

    Jakarta Servlet: This must return the value returned by the + * {@link javax.servlet.ServletResponse#getWriter}.

    + * + *

    The default implementation throws + * UnsupportedOperationException and is provided for + * the sole purpose of not breaking existing applications that + * extend this class.

    + * + *
    + * + * @return the Writer for the current response. + * + * @throws IOException any IO related exception. + * + * @since 2.0 + */ + public Writer getResponseOutputWriter() throws IOException { + return null; + } + + + /** + *

    Redirect a request + * to the specified URL, and cause the + * responseComplete() method to be called on the + * {@link FacesContext} instance for the current request.

    + * + *

    The implementation must determine if + * the request is an Ajax request by obtaining a + * {@link PartialViewContext} instance from the {@link FacesContext} and + * calling {@link PartialViewContext#isAjaxRequest()}.

    + * + *

    Jakarta Servlet: For + * non Ajax requests, this must be accomplished by calling + * the javax.servlet.http.HttpServletResponse method + * sendRedirect().

    + * For Ajax requests, the implementation must: + *
    + *
      + *
    • Get a {@link PartialResponseWriter} instance from the + * {@link FacesContext}.
    • + *
    • Call {@link #setResponseContentType} with text/xml
    • + *
    • Call {@link #setResponseCharacterEncoding} with UTF-8
    • + *
    • Call {@link #addResponseHeader} with Cache-Control, + * no-cache
    • + *
    • Call {@link PartialResponseWriter#startDocument}
    • + *
    • Call {@link PartialResponseWriter#redirect} with the url + * argument.
    • + *
    • Call {@link PartialResponseWriter#endDocument}
    • + *
    + * + * @param url Absolute URL to which the client should be redirected + * + * @throws IllegalArgumentException if the specified url is relative + * @throws IllegalStateException if, in a portlet environment, + * the current response object is a RenderResponse + * instead of an ActionResponse + * @throws IllegalStateException if, in a Jakarta Servlet environment, + * the current response has already been committed + * @throws IOException if an input/output error occurs + */ + public abstract void redirect(String url) throws IOException; + + + /** + *

    Set the response header with the given name and value.

    + * + *

    Jakarta Servlet:This must be performed by calling the + * javax.servlet.http.HttpServletResponse setHeader + * method.

    + * + *

    The default implementation throws + * UnsupportedOperationException and is provided for + * the sole purpose of not breaking existing applications that + * extend this class.

    + * + * @param name The name of the response header. + * @param value The value of the response header. + * + * @since 2.0 + */ + public void setResponseHeader(String name, String value) { + } + + /** + *

    Add the given name and value to the response header.

    + * + *

    Jakarta Servlet:This must be performed by calling the + * javax.servlet.http.HttpServletResponse addHeader + * method.

    + * + *

    The default implementation throws + * UnsupportedOperationException and is provided for + * the sole purpose of not breaking existing applications that + * extend this class.

    + * + * @param name The name of the response header. + * @param value The value of the response header. + * + * @since 2.0 + */ + public void addResponseHeader(String name, String value) { + } + + + /** + *

    Sets the HTTP status code for the response.

    + * + *

    Jakarta Servlet: This must be performed by calling the + * javax.servlet.http.HttpServletResponse setStatus + * method.

    + * + *

    The default implementation throws + * UnsupportedOperationException and is provided for + * the sole purpose of not breaking existing applications that + * extend this class.

    + * + * @param statusCode an HTTP status code + * + * @since 2.0 + */ + public void setResponseStatus(int statusCode) { + } + + + /** + * The purpose of this method is to generate a query string from the collection of Parameter + * objects provided by the parameters argument and append that query string to the baseUrl. + * This method must be able to encode the parameters to a baseUrl that may or may not have existing query parameters. The parameter values should be encoded appropriately for the + * environment so that the resulting URL can be used as the target of a redirect. It's + * possible for an ExternalContext implementation to override this method to accomodate the + * definition of redirect for that environment. + * + *

    See {@link #encodeActionURL(java.lang.String)} + * for the required specification of how to encode the {@link javax.faces.lifecycle.ClientWindow}. + *

    + * + * @param baseUrl The base URL onto which the query string generated by this method will be appended. The URL may contain query parameters. + * @param parameters The collection of Parameter objects, representing name=value pairs that are used to produce a query string + * + * @return the result of encoding. + * @since 2.0 + */ + public String encodeRedirectURL(String baseUrl, + Map> parameters) { + return null; + } +} diff --git a/java/ql/test/stubs/javax-faces-2.3/javax/faces/context/FacesContext.java b/java/ql/test/stubs/javax-faces-2.3/javax/faces/context/FacesContext.java new file mode 100644 index 00000000000..9c56dd6340b --- /dev/null +++ b/java/ql/test/stubs/javax-faces-2.3/javax/faces/context/FacesContext.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package javax.faces.context; + + +import java.util.Iterator; +import java.util.Map; + +/** + *

    FacesContext contains all of the + * per-request state information related to the processing of a single + * Jakarta Server Faces request, and the rendering of the corresponding + * response. It is passed to, and potentially modified by, each phase + * of the request processing lifecycle.

    + * + *

    A {@link FacesContext} instance is associated with a particular + * request at the beginning of request processing, by a call to the + * getFacesContext() method of the {@link FacesContextFactory} + * instance associated with the current web application. The instance + * remains active until its release() method is called, after + * which no further references to this instance are allowed. While a + * {@link FacesContext} instance is active, it must not be referenced + * from any thread other than the one upon which the Jakarta Servlet container + * executing this web application utilizes for the processing of this request. + *

    + * + *

    A FacesContext can be injected into a request + * scoped bean using @Inject FacesContext facesContext; + *

    + */ + +public abstract class FacesContext { + + public FacesContext() { + } + + /** + *

    Return a mutable Map + * representing the attributes associated wth this + * FacesContext instance. This Map is + * useful to store attributes that you want to go out of scope when the + * Faces lifecycle for the current request ends, which is not always the same + * as the request ending, especially in the case of Jakarta Servlet filters + * that are invoked after the Faces lifecycle for this + * request completes. Accessing this Map does not cause any + * events to fire, as is the case with the other maps: for request, session, and + * application scope. When {@link #release()} is invoked, the attributes + * must be cleared.

    + * + *
    + * + *

    The Map returned by this method is not associated with + * the request. If you would like to get or set request attributes, + * see {@link ExternalContext#getRequestMap}. + * + *

    The default implementation throws + * UnsupportedOperationException and is provided + * for the sole purpose of not breaking existing applications that extend + * this class.

    + * + *
    + * + * @return mutable Map representing the attributes associated wth this + * FacesContext instance. + * + * @throws IllegalStateException if this method is called after + * this instance has been released + * + * @since 2.0 + */ + + public Map getAttributes() { + return null; + } + + /** + *

    Return an Iterator over the client identifiers for + * which at least one {@link javax.faces.application.FacesMessage} has been queued. If there are no + * such client identifiers, an empty Iterator is returned. + * If any messages have been queued that were not associated with any + * specific client identifier, a null value will be included + * in the iterated values. The elements in the Iterator must + * be returned in the order in which they were added with {@link #addMessage}.

    + * + * @return the Iterator over the client identifiers for + * which at least one {@link javax.faces.application.FacesMessage} has been queued. + * + * @throws IllegalStateException if this method is called after + * this instance has been released + */ + public abstract Iterator getClientIdsWithMessages(); + + /** + *

    Return the {@link + * ExternalContext} instance for this FacesContext + * instance.

    + + *

    It is valid to call this method + * during application startup or shutdown. If called during application + * startup or shutdown, this method returns an {@link ExternalContext} instance + * with the special behaviors indicated in the javadoc for that + * class. Methods document as being valid to call during + * application startup or shutdown must be supported.

    + * + * @return instance of ExternalContext + * + * @throws IllegalStateException if this method is called after + * this instance has been released + */ + public abstract ExternalContext getExternalContext(); + + /** + *

    Return the {@link ResponseStream} to which components should + * direct their binary output. Within a given response, components + * can use either the ResponseStream or the ResponseWriter, + * but not both. + * + * @return ResponseStream instance. + * + * @throws IllegalStateException if this method is called after + * this instance has been released + */ + public abstract ResponseStream getResponseStream(); + + /** + *

    Set the {@link ResponseStream} to which components should + * direct their binary output. + * + * @param responseStream The new ResponseStream for this response + * + * @throws NullPointerException if responseStream + * is null + * + * @throws IllegalStateException if this method is called after + * this instance has been released + */ + public abstract void setResponseStream(ResponseStream responseStream); + + /** + *

    Return the {@link ResponseWriter} to which components should + * direct their character-based output. Within a given response, + * components can use either the ResponseStream or the ResponseWriter, + * but not both.

    + * + * @return ResponseWriter instance. + * + * @throws IllegalStateException if this method is called after + * this instance has been released + */ + public abstract ResponseWriter getResponseWriter(); + + /** + *

    Set the {@link ResponseWriter} to which components should + * direct their character-based output. + * + * @param responseWriter The new ResponseWriter for this response + * + * @throws IllegalStateException if this method is called after + * this instance has been released + * @throws NullPointerException if responseWriter + * is null + */ + public abstract void setResponseWriter(ResponseWriter responseWriter); + + /** + *

    Return the {@link FacesContext} + * instance for the request that is being processed by the current + * thread. If called during application initialization or shutdown, + * any method documented as "valid to call this method during + * application startup or shutdown" must be supported during + * application startup or shutdown time. The result of calling a + * method during application startup or shutdown time that does not + * have this designation is undefined.

    + * + * @return the instance of FacesContext. + */ + public static FacesContext getCurrentInstance() { + return null; + } +} diff --git a/java/ql/test/stubs/javax-faces-2.3/javax/faces/context/ResponseStream.java b/java/ql/test/stubs/javax-faces-2.3/javax/faces/context/ResponseStream.java new file mode 100644 index 00000000000..7a3b63024ca --- /dev/null +++ b/java/ql/test/stubs/javax-faces-2.3/javax/faces/context/ResponseStream.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package javax.faces.context; + + +import java.io.OutputStream; + + +/** + *

    ResponseStream is an interface describing an adapter + * to an underlying output mechanism for binary output.

    + */ + +public abstract class ResponseStream extends OutputStream { +} diff --git a/java/ql/test/stubs/javax-faces-2.3/javax/faces/context/ResponseWriter.java b/java/ql/test/stubs/javax-faces-2.3/javax/faces/context/ResponseWriter.java new file mode 100644 index 00000000000..4ad2f53f843 --- /dev/null +++ b/java/ql/test/stubs/javax-faces-2.3/javax/faces/context/ResponseWriter.java @@ -0,0 +1,372 @@ +/* + * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package javax.faces.context; + + +import javax.faces.component.UIComponent; +import java.io.IOException; +import java.io.Writer; + + +/** + *

    ResponseWriter + * is an abstract class describing an adapter to an underlying output + * mechanism for character-based output. In addition to the low-level + * write() methods inherited from + * java.io.Writer, this class provides utility methods that + * are useful in producing elements and attributes for markup languages + * like HTML and XML.

    + */ + +public abstract class ResponseWriter extends Writer { + + + /** + *

    Return the content type (such as "text/html") for this {@link + * ResponseWriter}. Note: this must not include the "charset=" + * suffix.

    + * + * @return the content type + */ + public abstract String getContentType(); + + + /** + *

    Return the character encoding (such as "ISO-8859-1") for this + * {@link ResponseWriter}. Please see the + * IANA for a list of character encodings.

    + * + * @return the character encoding + */ + public abstract String getCharacterEncoding(); + + + /** + *

    Flush any ouput buffered by the output method to the + * underlying Writer or OutputStream. This method + * will not flush the underlying Writer or OutputStream; it + * simply clears any values buffered by this {@link ResponseWriter}.

    + */ + @Override + public abstract void flush() throws IOException; + + + /** + *

    Write whatever text should begin a response.

    + * + * @throws IOException if an input/output error occurs + */ + public abstract void startDocument() throws IOException; + + + /** + *

    Write whatever text should end a response. If there is an open + * element that has been created by a call to startElement(), + * that element will be closed first.

    + * + * @throws IOException if an input/output error occurs + */ + public abstract void endDocument() throws IOException; + + + /** + *

    Write the start of an element, + up to and including the + * element name. Once this method has been called, clients can + * call the writeAttribute() or + * writeURIAttribute() methods to add attributes and + * corresponding values. The starting element will be closed + * (that is, the trailing '>' character added) + * on any subsequent call to startElement(), + * writeComment(), + * writeText(), endElement(), + * endDocument(), close(), + * flush(), or write().

    + * + *
    + * + *

    If the argument component's pass through attributes + * includes an attribute of the name given by the value of the symbolic + * constant {@link javax.faces.render.Renderer#PASSTHROUGH_RENDERER_LOCALNAME_KEY}, + * use that as the element name, instead of the value passed as the first + * parameter to this method. Care must be taken so that this value + * is not also rendered when any other pass through attributes on this component + * are rendered.

    + * + *
    + * + * @param name Name of the element to be started + + * @param component The {@link UIComponent} (if any) to which this + * element corresponds. This component is + * inspected for its pass through attributes as + * described in the standard HTML_BASIC {@code + * RenderKit} specification. + + * @throws IOException if an input/output error occurs + * @throws NullPointerException if name + * is null + */ + public abstract void startElement(String name, UIComponent component) + throws IOException; + + + /** + *

    Write the end of an element, + * after closing any open element + * created by a call to startElement(). Elements must be + * closed in the inverse order from which they were opened; it is an + * error to do otherwise.

    + * + *
    + * + *

    If the argument component's pass through attributes + * includes an attribute of the name given by the value of the symbolic + * constant {@link javax.faces.render.Renderer#PASSTHROUGH_RENDERER_LOCALNAME_KEY}, + * use that as the element name, instead of the value passed as the first + * parameter to this method.

    + * + *
    + * + * @param name Name of the element to be ended + * @throws IOException if an input/output error occurs + * @throws NullPointerException if name + * is null + */ + public abstract void endElement(String name) throws IOException; + + + /** + *

    Write an attribute name and corresponding value, after converting + * that text to a String (if necessary), and after performing any escaping + * appropriate for the markup language being rendered. + * This method may only be called after a call to + * startElement(), and before the opened element has been + * closed.

    + * + * @param name Attribute name to be added + * @param value Attribute value to be added + * @param property Name of the property or attribute (if any) of the + * {@link UIComponent} associated with the containing element, + * to which this generated attribute corresponds + * @throws IllegalStateException if this method is called when there + * is no currently open element + * @throws IOException if an input/output error occurs + * @throws NullPointerException if name is + * null + */ + public abstract void writeAttribute(String name, Object value, + String property) + throws IOException; + + + /** + *

    Write a URI + * attribute name and corresponding value, after converting that + * text to a String (if necessary), and after performing any + * encoding or escaping + * appropriate to the markup language being rendered. When rendering in a WWW environment, + * the escaping conventions established in the W3C URI spec document + * <http://www.w3.org/Addressing/URL/uri-spec.html> + * must be followed. In particular, spaces ' ' must be encoded as + * %20 and not the plus character '+'. This method may only + * be called after a call to startElement(), and before + * the opened element has been closed.

    + * + * @param name Attribute name to be added + * @param value Attribute value to be added + * @param property Name of the property or attribute (if any) of the + * {@link UIComponent} associated with the containing element, + * to which this generated attribute corresponds + * @throws IllegalStateException if this method is called when there + * is no currently open element + * @throws IOException if an input/output error occurs + * @throws NullPointerException if name is + * null + */ + public abstract void writeURIAttribute(String name, Object value, + String property) + throws IOException; + + /** + *

    Open an XML CDATA + * block. Note that XML does not allow nested CDATA + * blocks, though this method does not enforce that constraint. The + * default implementation of this method takes no action when + * invoked.

    + * @throws IOException if input/output error occures + */ + public void startCDATA() throws IOException { + + } + + + /** + + *

    Close an XML CDATA + * block. The default implementation of this method takes no action + * when invoked.

    + + * @throws IOException if input/output error occures + */ + public void endCDATA() throws IOException { + throw new UnsupportedOperationException(); + } + + + /** + *

    Write a comment containing the specified text, after converting + * that text to a String (if necessary), and after performing any escaping + * appropriate for the markup language being rendered. If there is + * an open element that has been created by a call to + * startElement(), that element will be closed first.

    + * + * @param comment Text content of the comment + * @throws IOException if an input/output error occurs + * @throws NullPointerException if comment + * is null + */ + public abstract void writeComment(Object comment) throws IOException; + + + /** + *

    Write a string containing the markup specific + * preamble. + * No escaping is performed. The default + * implementation simply calls through to {@link #write(java.lang.String)} .

    + * + *
    + * + *

    The implementation makes no checks if this is the correct place + * in the response to have a preamble, nor does it prevent the preamble + * from being written more than once.

    + * + *
    + * + * @since 2.2 + * @param preamble Text content of the preamble + * @throws IOException if an input/output error occurs + */ + public void writePreamble(String preamble) throws IOException { + write(preamble); + } + + /** + *

    Write a string containing the markup specific + * doctype. + * No escaping is performed. The default + * implementation simply calls through to {@link #write(java.lang.String)} .

    + * + *
    + * + *

    The implementation makes no checks if this is the correct place + * in the response to have a doctype, nor does it prevent the doctype + * from being written more than once.

    + * + *
    + * + * @since 2.2 + * @param doctype Text content of the doctype + * @throws IOException if an input/output error occurs + */ + public void writeDoctype(String doctype) throws IOException { + write(doctype); + } + + + /** + *

    Write an object, after converting it to a String (if necessary), + * and after performing any escaping appropriate for the markup language + * being rendered. If there is an open element that has been created + * by a call to startElement(), that element will be closed + * first.

    + * + * @param text Text to be written + * @param property Name of the property or attribute (if any) of the + * {@link UIComponent} associated with the containing element, + * to which this generated text corresponds + * @throws IOException if an input/output error occurs + * @throws NullPointerException if text + * is null + */ + public abstract void writeText(Object text, String property) + throws IOException; + + /** + *

    Write an object, after converting it to a String (if + * necessary), and after performing any escaping appropriate for the + * markup language being rendered. This method is equivalent to + * {@link #writeText(java.lang.Object,java.lang.String)} but adds a + * component property to allow custom + * ResponseWriter implementations to associate a + * component with an arbitrary portion of text.

    + * + *

    The default implementation simply ignores the + * component argument and calls through to {@link + * #writeText(java.lang.Object,java.lang.String)}

    + * + * @param text Text to be written + * @param component The {@link UIComponent} (if any) to which + * this element corresponds + * @param property Name of the property or attribute (if any) of the + * {@link UIComponent} associated with the containing element, + * to which this generated text corresponds + * @throws IOException if an input/output error occurs + * @throws NullPointerException if text + * is null + * @since 1.2 + */ + public void writeText(Object text, UIComponent component, String property) + throws IOException { + writeText(text, property); + } + + + /** + *

    Write text from a character array, after any performing any + * escaping appropriate for the markup language being rendered. + * If there is an open element that has been created by a call to + * startElement(), that element will be closed first.

    + * + * @param text Text to be written + * @param off Starting offset (zero-relative) + * @param len Number of characters to be written + * @throws IndexOutOfBoundsException if the calculated starting or + * ending position is outside the bounds of the character array + * @throws IOException if an input/output error occurs + * @throws NullPointerException if text + * is null + */ + public abstract void writeText(char text[], int off, int len) + throws IOException; + + + /** + *

    Create and return a new instance of this {@link ResponseWriter}, + * using the specified Writer as the output destination.

    + * + * @param writer The Writer that is the output destination + * + * @return the new ResponseWriter + */ + public abstract ResponseWriter cloneWithWriter(Writer writer); +} diff --git a/java/ql/test/stubs/javax-faces-2.3/javax/faces/render/FacesRenderer.java b/java/ql/test/stubs/javax-faces-2.3/javax/faces/render/FacesRenderer.java new file mode 100644 index 00000000000..872b71d92d0 --- /dev/null +++ b/java/ql/test/stubs/javax-faces-2.3/javax/faces/render/FacesRenderer.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package javax.faces.render; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.Inherited; + +/** + *

    The presence of this annotation on a + * class automatically registers the class with the runtime as a {@link + * Renderer}. The value of the {@link #renderKitId} attribute is taken + * to be the render-kit-id to which an instance of this + * Renderer is to be added. There must be a public + * zero-argument constructor on any class where this annotation appears. + * The implementation must indicate a fatal error if such a constructor + * does not exist and the application must not be placed in service. + * Within that {@link RenderKit}, The value of the {@link #rendererType} + * attribute is taken to be the renderer-type, and the value of + * the {@link #componentFamily} attribute is to be taken as the + * component-family. The implementation must guarantee that + * for each class annotated with FacesRenderer, found with + * the algorithm in section JSF.11.5, + * the following actions are taken.

    + + *
    + + *
      + + *
    • Obtain a reference to the {@link RenderKitFactory} for + * this application.

    • + +
    • See if a RenderKit exists for + render-kit-id. If so, let that instance be + renderKit for discussion. If not, the implementation + must indicate a fatal error if such a RenderKit + does not exist and the application must not be placed in + service.

    • + +
    • Create an instance of this class using the public + zero-argument constructor.

    • + +
    • Call {@link RenderKit#addRenderer} on + renderKit, passing component-family as the + first argument, renderer-type as the second, and the + newly instantiated RenderKit instance as the + third argument.

    • + + *
    + + + *
    + + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Inherited +public @interface FacesRenderer { + + + /** + *

    The value of this annotation + * attribute is taken to be the render-kit-id in which an + * instance of this class of Renderer must be + * installed.

    + * + * @return the render-kit-id + */ + + String renderKitId() default ""; + + + /** + *

    The value of this annotation + * attribute is taken to be the renderer-type which, in + * combination with {@link #componentFamily} can be used to obtain a + * reference to an instance of this {@link Renderer} by calling + * {@link javax.faces.render.RenderKit#getRenderer(java.lang.String, + * java.lang.String)}.

    + * + * @return the renderer-type + */ + + String rendererType(); + + + /** + *

    The value of this annotation + * attribute is taken to be the component-family which, in + * combination with {@link #rendererType} can be used to obtain a + * reference to an instance of this {@link Renderer} by calling + * {@link javax.faces.render.RenderKit#getRenderer(java.lang.String, + * java.lang.String)}.

    + * + * @return the component-family + */ + + String componentFamily(); + +} diff --git a/java/ql/test/stubs/javax-faces-2.3/javax/faces/render/Renderer.java b/java/ql/test/stubs/javax-faces-2.3/javax/faces/render/Renderer.java new file mode 100644 index 00000000000..a5fc4b47799 --- /dev/null +++ b/java/ql/test/stubs/javax-faces-2.3/javax/faces/render/Renderer.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package javax.faces.render; + + +import java.io.IOException; +import java.util.Iterator; +import javax.faces.component.UIComponent; +import javax.faces.context.FacesContext; + + +/** + *

    A Renderer converts + * the internal representation of {@link UIComponent}s into the output + * stream (or writer) associated with the response we are creating for a + * particular request. Each Renderer knows how to render + * one or more {@link UIComponent} types (or classes), and advertises a + * set of render-dependent attributes that it recognizes for each + * supported {@link UIComponent}.

    + * + *

    Families of {@link Renderer}s are packaged as a {@link RenderKit}, + * and together support the rendering of all of the {@link UIComponent}s + * in a view associated with a {@link FacesContext}. Within the set of + * {@link Renderer}s for a particular {@link RenderKit}, each must be + * uniquely identified by the rendererType property.

    + * + *

    Individual {@link Renderer} instances will be instantiated as requested + * during the rendering process, and will remain in existence for the + * remainder of the lifetime of a web application. Because each instance + * may be invoked from more than one request processing thread simultaneously, + * they MUST be programmed in a thread-safe manner.

    + * + *
    + + *

    If the {@link javax.faces.event.ListenerFor} annotation is + * attached to the class definition of a Renderer, that + * class must also implement {@link + * javax.faces.event.ComponentSystemEventListener}, and the action + * pertaining to the processing of ResourceDependency on a + * Renderer described in {@link + * javax.faces.event.ListenerFor} must be taken.

    + + *

    If the {@link javax.faces.application.ResourceDependency} + * annotation is attached to the class definition of a + * Renderer, the action pertaining to the processing of + * ResourceDependency on a Renderer described + * in {@link UIComponent#getChildren} must be taken.

    + + *
    + */ + +public abstract class Renderer { + + /** + *

    Decode any new state of the specified {@link UIComponent} + * from the request contained in the specified {@link FacesContext}, + * and store that state on the {@link UIComponent}.

    + * + *

    During decoding, events may be enqueued for later processing + * (by event listeners that have registered an interest), by calling + * queueEvent() on the associated {@link UIComponent}. + *

    + * + * @param context {@link FacesContext} for the request we are processing + * @param component {@link UIComponent} to be decoded. + * + * @throws NullPointerException if context + * or component is null + */ + public void decode(FacesContext context, UIComponent component) { + } + + + /** + *

    Render the beginning specified {@link UIComponent} to the + * output stream or writer associated with the response we are creating. + * If the conversion attempted in a previous call to + * getConvertedValue() for this component failed, the state + * information saved during execution + * of decode() should be used to reproduce the incorrect + * input.

    + * + * @param context {@link FacesContext} for the request we are processing + * @param component {@link UIComponent} to be rendered + * + * @throws IOException if an input/output error occurs while rendering + * @throws NullPointerException if context + * or component is null + */ + public void encodeBegin(FacesContext context, + UIComponent component) + throws IOException { + } + + + /** + *

    Render the child components of this {@link UIComponent}, following + * the rules described for encodeBegin() to acquire the + * appropriate value to be rendered. This method will only be called + * if the rendersChildren property of this component + * is true.

    + * + * @param context {@link FacesContext} for the response we are creating + * @param component {@link UIComponent} whose children are to be rendered + * + * @throws IOException if an input/output error occurs while rendering + * @throws NullPointerException if context + * or component is null + */ + public void encodeChildren(FacesContext context, UIComponent component) + throws IOException { + } + + + /** + *

    Render the ending of the current state of the specified + * {@link UIComponent}, following the rules described for + * encodeBegin() to acquire the appropriate value + * to be rendered.

    + * + * @param context {@link FacesContext} for the response we are creating + * @param component {@link UIComponent} to be rendered + * + * @throws IOException if an input/output error occurs while rendering + * @throws NullPointerException if context + * or component is null + */ + public void encodeEnd(FacesContext context, + UIComponent component) + throws IOException { + } + + /** + *

    Convert the component generated client id to a form suitable + * for transmission to the client.

    + * + *

    The default implementation returns the argument + * clientId unchanged.

    + * + * @param context {@link FacesContext} for the current request + * @param clientId the client identifier to be converted to client a + * specific format. + * + * @throws NullPointerException if context + * or clientId is null + * + * @return the converted {@code clientId} + */ + public String convertClientId(FacesContext context, String clientId) { + return null; + } +} diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/container/ContainerRequestContext.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/container/ContainerRequestContext.java new file mode 100644 index 00000000000..049e42396dd --- /dev/null +++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/container/ContainerRequestContext.java @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package javax.ws.rs.container; + +import java.io.InputStream; +import java.net.URI; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import javax.ws.rs.core.Cookie; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Request; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.SecurityContext; +import javax.ws.rs.core.UriInfo; + +/** + * Container request filter context. + * + * A mutable class that provides request-specific information for the filter, such as request URI, message headers, + * message entity or request-scoped properties. The exposed setters allow modification of the exposed request-specific + * information. + * + * @author Marek Potociar + * @since 2.0 + */ +public interface ContainerRequestContext { + + /** + * Returns the property with the given name registered in the current request/response exchange context, or {@code null} + * if there is no property by that name. + *

    + * A property allows a JAX-RS filters and interceptors to exchange additional custom information not already provided by + * this interface. + *

    + *

    + * A list of supported properties can be retrieved using {@link #getPropertyNames()}. Custom property names should + * follow the same convention as package names. + *

    + *

    + * In a Servlet container, the properties are synchronized with the {@code ServletRequest} and expose all the attributes + * available in the {@code ServletRequest}. Any modifications of the properties are also reflected in the set of + * properties of the associated {@code ServletRequest}. + *

    + * + * @param name a {@code String} specifying the name of the property. + * @return an {@code Object} containing the value of the property, or {@code null} if no property exists matching the + * given name. + * @see #getPropertyNames() + */ + public Object getProperty(String name); + + /** + * Returns {@code true} if the property with the given name is registered in the current request/response exchange + * context, or {@code false} if there is no property by that name. + *

    + * Use the {@link #getProperty} method with a property name to get the value of a property. + *

    + * + * @param name a {@code String} specifying the name of the property. + * @return {@code true} if this property is registered in the context, or {@code false} if no property exists matching + * the given name. + * @see #getPropertyNames() + */ + public default boolean hasProperty(String name) { + return getProperty(name) != null; + } + + /** + * Returns an immutable {@link java.util.Collection collection} containing the property names available within the + * context of the current request/response exchange context. + *

    + * Use the {@link #getProperty} method with a property name to get the value of a property. + *

    + *

    + * In a Servlet container, the properties are synchronized with the {@code ServletRequest} and expose all the attributes + * available in the {@code ServletRequest}. Any modifications of the properties are also reflected in the set of + * properties of the associated {@code ServletRequest}. + *

    + * + * @return an immutable {@link java.util.Collection collection} of property names. + * @see #getProperty + */ + public Collection getPropertyNames(); + + /** + * Binds an object to a given property name in the current request/response exchange context. If the name specified is + * already used for a property, this method will replace the value of the property with the new value. + *

    + * A property allows a JAX-RS filters and interceptors to exchange additional custom information not already provided by + * this interface. + *

    + *

    + * A list of supported properties can be retrieved using {@link #getPropertyNames()}. Custom property names should + * follow the same convention as package names. + *

    + *

    + * If a {@code null} value is passed, the effect is the same as calling the {@link #removeProperty(String)} method. + *

    + *

    + * In a Servlet container, the properties are synchronized with the {@code ServletRequest} and expose all the attributes + * available in the {@code ServletRequest}. Any modifications of the properties are also reflected in the set of + * properties of the associated {@code ServletRequest}. + *

    + * + * @param name a {@code String} specifying the name of the property. + * @param object an {@code Object} representing the property to be bound. + */ + public void setProperty(String name, Object object); + + /** + * Removes a property with the given name from the current request/response exchange context. After removal, subsequent + * calls to {@link #getProperty} to retrieve the property value will return {@code null}. + *

    + * In a Servlet container, the properties are synchronized with the {@code ServletRequest} and expose all the attributes + * available in the {@code ServletRequest}. Any modifications of the properties are also reflected in the set of + * properties of the associated {@code ServletRequest}. + *

    + * + * @param name a {@code String} specifying the name of the property to be removed. + */ + public void removeProperty(String name); + + /** + * Get request URI information. + * + * The returned object contains "live" view of the request URI information in a sense that any changes made to the + * request URI using one of the {@code setRequestUri(...)} methods will be reflected in the previously returned + * {@link UriInfo} instance. + * + * @return request URI information. + */ + public UriInfo getUriInfo(); + + /** + * Set a new request URI using the current base URI of the application to resolve the application-specific request URI + * part. + *

    + * Note that the method is usable only in pre-matching filters, prior to the resource matching occurs. Trying to invoke + * the method in a filter bound to a resource method results in an {@link IllegalStateException} being thrown. + *

    + * + * @param requestUri new URI of the request. + * @throws IllegalStateException in case the method is not invoked from a {@link PreMatching pre-matching} request + * filter. + * @see #setRequestUri(java.net.URI, java.net.URI) + */ + public void setRequestUri(URI requestUri); + + /** + * Set a new request URI using a new base URI to resolve the application-specific request URI part. + *

    + * Note that the method is usable only in pre-matching filters, prior to the resource matching occurs. Trying to invoke + * the method in a filter bound to a resource method results in an {@link IllegalStateException} being thrown. + *

    + * + * @param baseUri base URI that will be used to resolve the application-specific part of the request URI. + * @param requestUri new URI of the request. + * @throws IllegalStateException in case the method is not invoked from a {@link PreMatching pre-matching} request + * filter. + * @see #setRequestUri(java.net.URI) + */ + public void setRequestUri(URI baseUri, URI requestUri); + + /** + * Get the injectable request information. + * + * @return injectable request information. + */ + public Request getRequest(); + + /** + * Get the request method. + * + * @return the request method. + * @see javax.ws.rs.HttpMethod + */ + public String getMethod(); + + /** + * Set the request method. + *

    + * Note that the method is usable only in pre-matching filters, prior to the resource matching occurs. Trying to invoke + * the method in a filter bound to a resource method results in an {@link IllegalStateException} being thrown. + *

    + * + * @param method new request method. + * @throws IllegalStateException in case the method is not invoked from a {@link PreMatching pre-matching} request + * filter. + * @see javax.ws.rs.HttpMethod + */ + public void setMethod(String method); + + /** + * Get the mutable request headers multivalued map. + * + * @return mutable multivalued map of request headers. + * @see #getHeaderString(String) + */ + public MultivaluedMap getHeaders(); + + /** + * Get a message header as a single string value. + * + * @param name the message header. + * @return the message header value. If the message header is not present then {@code null} is returned. If the message + * header is present but has no value then the empty string is returned. If the message header is present more than once + * then the values of joined together and separated by a ',' character. + * @see #getHeaders() + */ + public String getHeaderString(String name); + + /** + * Get message date. + * + * @return the message date, otherwise {@code null} if not present. + */ + public Date getDate(); + + /** + * Get the language of the entity. + * + * @return the language of the entity or {@code null} if not specified + */ + public Locale getLanguage(); + + /** + * Get Content-Length value. + * + * @return Content-Length as integer if present and valid number. In other cases returns {@code -1}. + */ + public int getLength(); + + /** + * Get the media type of the entity. + * + * @return the media type or {@code null} if not specified (e.g. there's no request entity). + */ + public MediaType getMediaType(); + + /** + * Get a list of media types that are acceptable for the response. + * + * @return a read-only list of requested response media types sorted according to their q-value, with highest preference + * first. + */ + public List getAcceptableMediaTypes(); + + /** + * Get a list of languages that are acceptable for the response. + * + * @return a read-only list of acceptable languages sorted according to their q-value, with highest preference first. + */ + public List getAcceptableLanguages(); + + /** + * Get any cookies that accompanied the request. + * + * @return a read-only map of cookie name (String) to {@link Cookie}. + */ + public Map getCookies(); + + /** + * Check if there is a non-empty entity input stream available in the request message. + * + * The method returns {@code true} if the entity is present, returns {@code false} otherwise. + * + * @return {@code true} if there is an entity present in the message, {@code false} otherwise. + */ + public boolean hasEntity(); + + /** + * Get the entity input stream. The JAX-RS runtime is responsible for closing the input stream. + * + * @return entity input stream. + */ + public InputStream getEntityStream(); + + /** + * Set a new entity input stream. The JAX-RS runtime is responsible for closing the input stream. + * + * @param input new entity input stream. + * @throws IllegalStateException in case the method is invoked from a response filter. + */ + public void setEntityStream(InputStream input); + + /** + * Get the injectable security context information for the current request. + * + * The {@link SecurityContext#getUserPrincipal()} must return {@code null} if the current request has not been + * authenticated. + * + * @return injectable request security context information. + */ + public SecurityContext getSecurityContext(); + + /** + * Set a new injectable security context information for the current request. + * + * The {@link SecurityContext#getUserPrincipal()} must return {@code null} if the current request has not been + * authenticated. + * + * @param context new injectable request security context information. + * @throws IllegalStateException in case the method is invoked from a response filter. + */ + public void setSecurityContext(SecurityContext context); + + /** + * Abort the filter chain with a response. + * + * This method breaks the filter chain processing and returns the provided response back to the client. The provided + * response goes through the chain of applicable response filters. + * + * @param response response to be sent back to the client. + * @throws IllegalStateException in case the method is invoked from a response filter. + */ + public void abortWith(Response response); +} diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Request.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Request.java new file mode 100644 index 00000000000..a452c4f4a1e --- /dev/null +++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Request.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2010, 2019 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package javax.ws.rs.core; + +import java.util.Date; +import java.util.List; + +import javax.ws.rs.core.Response.ResponseBuilder; + +/** + * An injectable helper for request processing, all methods throw an {@link IllegalStateException} if called outside the + * scope of a request (e.g. from a provider constructor). + * + * Precondition processing (see the {@code evaluatePreconditions} methods) can result in either a {@code null} return + * value to indicate that preconditions have been met and that the request should continue, or a non-{@code null} return + * value to indicate that preconditions were not met. In the event that preconditions were not met, the returned + * {@code ResponseBuilder} instance will have an appropriate status and will also include a {@code Vary} header if the + * {@link #selectVariant(List)} method was called prior to to calling {@code evaluatePreconditions}. It is the + * responsibility of the caller to check the status and add additional metadata if required. E.g., see + * HTTP/1.1, section 10.3.5 for details + * of the headers that are expected to accompany a {@code 304 Not Modified} response. + * + * @author Paul Sandoz + * @author Marc Hadley + * @author Marek Potociar + * @since 1.0 + */ +public interface Request { + + /** + * Get the request method, e.g. GET, POST, etc. + * + * @return the request method. + * @see javax.ws.rs.HttpMethod + */ + public String getMethod(); + + /** + * Select the representation variant that best matches the request. Returns {@code null} in case there is no matching + * variant in the list. + *

    + * More explicit variants are chosen ahead of less explicit ones. A vary header is computed from the supplied list and + * automatically added to the response. + *

    + * + * @param variants a list of Variant that describe all of the available representation variants. + * @return the variant that best matches the request or {@code null} if there's no match. + * @throws java.lang.IllegalArgumentException if variants is empty or {@code null}. + * @throws java.lang.IllegalStateException if called outside the scope of a request. + * @see Variant.VariantListBuilder + */ + public Variant selectVariant(List variants); + + /** + * Evaluate request preconditions based on the passed in value. + * + * @param eTag an ETag for the current state of the resource + * @return {@code null} if the preconditions are met or a {@code ResponseBuilder} set with the appropriate status if the + * preconditions are not met. A returned {@code ResponseBuilder} will include an ETag header set with the value of eTag, + * provided none of the precondition evaluation has failed, in which case the ETag header would not be included and the + * status code of the returned {@code ResponseBuilder} would be set to {@link Response.Status#PRECONDITION_FAILED}. + * @throws java.lang.IllegalArgumentException if eTag is {@code null}. + * @throws java.lang.IllegalStateException if called outside the scope of a request. + */ + public ResponseBuilder evaluatePreconditions(EntityTag eTag); + + /** + * Evaluate request preconditions based on the passed in value. + * + * @param lastModified a date that specifies the modification date of the resource + * @return {@code null} if the preconditions are met or a {@code ResponseBuilder} set with the appropriate status if the + * preconditions are not met. + * @throws java.lang.IllegalArgumentException if lastModified is {@code null}. + * @throws java.lang.IllegalStateException if called outside the scope of a request. + */ + public ResponseBuilder evaluatePreconditions(Date lastModified); + + /** + * Evaluate request preconditions based on the passed in value. + * + * @param lastModified a date that specifies the modification date of the resource + * @param eTag an ETag for the current state of the resource + * @return {@code null} if the preconditions are met or a {@code ResponseBuilder} set with the appropriate status if the + * preconditions are not met. A returned {@code ResponseBuilder} will include an ETag header set with the value of eTag, + * provided none of the precondition evaluation has failed, in which case the ETag header would not be included and the + * status code of the returned {@code ResponseBuilder} would be set to {@link Response.Status#PRECONDITION_FAILED}. + * @throws java.lang.IllegalArgumentException if lastModified or eTag is {@code null}. + * @throws java.lang.IllegalStateException if called outside the scope of a request. + */ + public ResponseBuilder evaluatePreconditions(Date lastModified, EntityTag eTag); + + /** + * Evaluate request preconditions for a resource that does not currently exist. The primary use of this method is to + * support the If-Match: * and + * If-None-Match: * preconditions. + * + *

    + * Note that precondition If-None-Match: something will never be + * considered to have been met, and it is the application's responsibility to enforce any additional method-specific + * semantics. E.g. a {@code PUT} on a resource that does not exist might succeed whereas a {@code GET} on a resource + * that does not exist would likely result in a 404 response. It would be the responsibility of the application to + * generate the 404 response. + *

    + * + * @return {@code null} if the preconditions are met or a {@code ResponseBuilder} set with the appropriate status if the + * preconditions are not met. + * @throws IllegalStateException if called outside the scope of a request. + * @since 1.1 + */ + public ResponseBuilder evaluatePreconditions(); + +} diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/SecurityContext.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/SecurityContext.java new file mode 100644 index 00000000000..65b27763b2b --- /dev/null +++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/SecurityContext.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2010, 2019 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package javax.ws.rs.core; + +import java.security.Principal; + +/** + * An injectable interface that provides access to security related information. + * + * @author Paul Sandoz + * @author Marc Hadley + * @see Context + * @since 1.0 + */ +public interface SecurityContext { + + /** + * String identifier for Basic authentication. Value "BASIC" + */ + public static final String BASIC_AUTH = "BASIC"; + /** + * String identifier for Client Certificate authentication. Value "CLIENT_CERT" + */ + public static final String CLIENT_CERT_AUTH = "CLIENT_CERT"; + /** + * String identifier for Digest authentication. Value "DIGEST" + */ + public static final String DIGEST_AUTH = "DIGEST"; + /** + * String identifier for Form authentication. Value "FORM" + */ + public static final String FORM_AUTH = "FORM"; + + /** + * Returns a java.security.Principal object containing the name of the current authenticated user. If the + * user has not been authenticated, the method returns null. + * + * @return a java.security.Principal containing the name of the user making this request; null if the user + * has not been authenticated + * @throws java.lang.IllegalStateException if called outside the scope of a request + */ + public Principal getUserPrincipal(); + + /** + * Returns a boolean indicating whether the authenticated user is included in the specified logical "role". If the user + * has not been authenticated, the method returns false. + * + * @param role a String specifying the name of the role + * @return a boolean indicating whether the user making the request belongs to a given role; + * false if the user has not been authenticated + * @throws java.lang.IllegalStateException if called outside the scope of a request + */ + public boolean isUserInRole(String role); + + /** + * Returns a boolean indicating whether this request was made using a secure channel, such as HTTPS. + * + * @return true if the request was made using a secure channel, false otherwise + * @throws java.lang.IllegalStateException if called outside the scope of a request + */ + public boolean isSecure(); + + /** + * Returns the string value of the authentication scheme used to protect the resource. If the resource is not + * authenticated, null is returned. + * + * Values are the same as the CGI variable AUTH_TYPE + * + * @return one of the static members BASIC_AUTH, FORM_AUTH, CLIENT_CERT_AUTH, DIGEST_AUTH (suitable for == comparison) + * or the container-specific string indicating the authentication scheme, or null if the request was not authenticated. + * @throws java.lang.IllegalStateException if called outside the scope of a request + */ + public String getAuthenticationScheme(); +} \ No newline at end of file diff --git a/java/ql/test/stubs/javax-ws-rs-api-3.0.0/jakarta/ws/rs/container/ContainerRequestContext.java b/java/ql/test/stubs/javax-ws-rs-api-3.0.0/jakarta/ws/rs/container/ContainerRequestContext.java new file mode 100644 index 00000000000..b7e593e279c --- /dev/null +++ b/java/ql/test/stubs/javax-ws-rs-api-3.0.0/jakarta/ws/rs/container/ContainerRequestContext.java @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package jakarta.ws.rs.container; + +import java.io.InputStream; +import java.net.URI; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import jakarta.ws.rs.core.Cookie; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.core.Request; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; +import jakarta.ws.rs.core.UriInfo; + +/** + * Container request filter context. + * + * A mutable class that provides request-specific information for the filter, such as request URI, message headers, + * message entity or request-scoped properties. The exposed setters allow modification of the exposed request-specific + * information. + * + * @author Marek Potociar + * @since 2.0 + */ +public interface ContainerRequestContext { + + /** + * Returns the property with the given name registered in the current request/response exchange context, or {@code null} + * if there is no property by that name. + *

    + * A property allows a JAX-RS filters and interceptors to exchange additional custom information not already provided by + * this interface. + *

    + *

    + * A list of supported properties can be retrieved using {@link #getPropertyNames()}. Custom property names should + * follow the same convention as package names. + *

    + *

    + * In a Servlet container, the properties are synchronized with the {@code ServletRequest} and expose all the attributes + * available in the {@code ServletRequest}. Any modifications of the properties are also reflected in the set of + * properties of the associated {@code ServletRequest}. + *

    + * + * @param name a {@code String} specifying the name of the property. + * @return an {@code Object} containing the value of the property, or {@code null} if no property exists matching the + * given name. + * @see #getPropertyNames() + */ + public Object getProperty(String name); + + /** + * Returns {@code true} if the property with the given name is registered in the current request/response exchange + * context, or {@code false} if there is no property by that name. + *

    + * Use the {@link #getProperty} method with a property name to get the value of a property. + *

    + * + * @param name a {@code String} specifying the name of the property. + * @return {@code true} if this property is registered in the context, or {@code false} if no property exists matching + * the given name. + * @see #getPropertyNames() + */ + public default boolean hasProperty(String name) { + return getProperty(name) != null; + } + + /** + * Returns an immutable {@link java.util.Collection collection} containing the property names available within the + * context of the current request/response exchange context. + *

    + * Use the {@link #getProperty} method with a property name to get the value of a property. + *

    + *

    + * In a Servlet container, the properties are synchronized with the {@code ServletRequest} and expose all the attributes + * available in the {@code ServletRequest}. Any modifications of the properties are also reflected in the set of + * properties of the associated {@code ServletRequest}. + *

    + * + * @return an immutable {@link java.util.Collection collection} of property names. + * @see #getProperty + */ + public Collection getPropertyNames(); + + /** + * Binds an object to a given property name in the current request/response exchange context. If the name specified is + * already used for a property, this method will replace the value of the property with the new value. + *

    + * A property allows a JAX-RS filters and interceptors to exchange additional custom information not already provided by + * this interface. + *

    + *

    + * A list of supported properties can be retrieved using {@link #getPropertyNames()}. Custom property names should + * follow the same convention as package names. + *

    + *

    + * If a {@code null} value is passed, the effect is the same as calling the {@link #removeProperty(String)} method. + *

    + *

    + * In a Servlet container, the properties are synchronized with the {@code ServletRequest} and expose all the attributes + * available in the {@code ServletRequest}. Any modifications of the properties are also reflected in the set of + * properties of the associated {@code ServletRequest}. + *

    + * + * @param name a {@code String} specifying the name of the property. + * @param object an {@code Object} representing the property to be bound. + */ + public void setProperty(String name, Object object); + + /** + * Removes a property with the given name from the current request/response exchange context. After removal, subsequent + * calls to {@link #getProperty} to retrieve the property value will return {@code null}. + *

    + * In a Servlet container, the properties are synchronized with the {@code ServletRequest} and expose all the attributes + * available in the {@code ServletRequest}. Any modifications of the properties are also reflected in the set of + * properties of the associated {@code ServletRequest}. + *

    + * + * @param name a {@code String} specifying the name of the property to be removed. + */ + public void removeProperty(String name); + + /** + * Get request URI information. + * + * The returned object contains "live" view of the request URI information in a sense that any changes made to the + * request URI using one of the {@code setRequestUri(...)} methods will be reflected in the previously returned + * {@link UriInfo} instance. + * + * @return request URI information. + */ + public UriInfo getUriInfo(); + + /** + * Set a new request URI using the current base URI of the application to resolve the application-specific request URI + * part. + *

    + * Note that the method is usable only in pre-matching filters, prior to the resource matching occurs. Trying to invoke + * the method in a filter bound to a resource method results in an {@link IllegalStateException} being thrown. + *

    + * + * @param requestUri new URI of the request. + * @throws IllegalStateException in case the method is not invoked from a {@link PreMatching pre-matching} request + * filter. + * @see #setRequestUri(java.net.URI, java.net.URI) + */ + public void setRequestUri(URI requestUri); + + /** + * Set a new request URI using a new base URI to resolve the application-specific request URI part. + *

    + * Note that the method is usable only in pre-matching filters, prior to the resource matching occurs. Trying to invoke + * the method in a filter bound to a resource method results in an {@link IllegalStateException} being thrown. + *

    + * + * @param baseUri base URI that will be used to resolve the application-specific part of the request URI. + * @param requestUri new URI of the request. + * @throws IllegalStateException in case the method is not invoked from a {@link PreMatching pre-matching} request + * filter. + * @see #setRequestUri(java.net.URI) + */ + public void setRequestUri(URI baseUri, URI requestUri); + + /** + * Get the injectable request information. + * + * @return injectable request information. + */ + public Request getRequest(); + + /** + * Get the request method. + * + * @return the request method. + * @see jakarta.ws.rs.HttpMethod + */ + public String getMethod(); + + /** + * Set the request method. + *

    + * Note that the method is usable only in pre-matching filters, prior to the resource matching occurs. Trying to invoke + * the method in a filter bound to a resource method results in an {@link IllegalStateException} being thrown. + *

    + * + * @param method new request method. + * @throws IllegalStateException in case the method is not invoked from a {@link PreMatching pre-matching} request + * filter. + * @see jakarta.ws.rs.HttpMethod + */ + public void setMethod(String method); + + /** + * Get the mutable request headers multivalued map. + * + * @return mutable multivalued map of request headers. + * @see #getHeaderString(String) + */ + public MultivaluedMap getHeaders(); + + /** + * Get a message header as a single string value. + * + * @param name the message header. + * @return the message header value. If the message header is not present then {@code null} is returned. If the message + * header is present but has no value then the empty string is returned. If the message header is present more than once + * then the values of joined together and separated by a ',' character. + * @see #getHeaders() + */ + public String getHeaderString(String name); + + /** + * Get message date. + * + * @return the message date, otherwise {@code null} if not present. + */ + public Date getDate(); + + /** + * Get the language of the entity. + * + * @return the language of the entity or {@code null} if not specified + */ + public Locale getLanguage(); + + /** + * Get Content-Length value. + * + * @return Content-Length as integer if present and valid number. In other cases returns {@code -1}. + */ + public int getLength(); + + /** + * Get the media type of the entity. + * + * @return the media type or {@code null} if not specified (e.g. there's no request entity). + */ + public MediaType getMediaType(); + + /** + * Get a list of media types that are acceptable for the response. + * + * @return a read-only list of requested response media types sorted according to their q-value, with highest preference + * first. + */ + public List getAcceptableMediaTypes(); + + /** + * Get a list of languages that are acceptable for the response. + * + * @return a read-only list of acceptable languages sorted according to their q-value, with highest preference first. + */ + public List getAcceptableLanguages(); + + /** + * Get any cookies that accompanied the request. + * + * @return a read-only map of cookie name (String) to {@link Cookie}. + */ + public Map getCookies(); + + /** + * Check if there is a non-empty entity input stream available in the request message. + * + * The method returns {@code true} if the entity is present, returns {@code false} otherwise. + * + * @return {@code true} if there is an entity present in the message, {@code false} otherwise. + */ + public boolean hasEntity(); + + /** + * Get the entity input stream. The JAX-RS runtime is responsible for closing the input stream. + * + * @return entity input stream. + */ + public InputStream getEntityStream(); + + /** + * Set a new entity input stream. The JAX-RS runtime is responsible for closing the input stream. + * + * @param input new entity input stream. + * @throws IllegalStateException in case the method is invoked from a response filter. + */ + public void setEntityStream(InputStream input); + + /** + * Get the injectable security context information for the current request. + * + * The {@link SecurityContext#getUserPrincipal()} must return {@code null} if the current request has not been + * authenticated. + * + * @return injectable request security context information. + */ + public SecurityContext getSecurityContext(); + + /** + * Set a new injectable security context information for the current request. + * + * The {@link SecurityContext#getUserPrincipal()} must return {@code null} if the current request has not been + * authenticated. + * + * @param context new injectable request security context information. + * @throws IllegalStateException in case the method is invoked from a response filter. + */ + public void setSecurityContext(SecurityContext context); + + /** + * Abort the filter chain with a response. + * + * This method breaks the filter chain processing and returns the provided response back to the client. The provided + * response goes through the chain of applicable response filters. + * + * @param response response to be sent back to the client. + * @throws IllegalStateException in case the method is invoked from a response filter. + */ + public void abortWith(Response response); +} diff --git a/java/ql/test/stubs/javax-ws-rs-api-3.0.0/jakarta/ws/rs/core/Request.java b/java/ql/test/stubs/javax-ws-rs-api-3.0.0/jakarta/ws/rs/core/Request.java new file mode 100644 index 00000000000..a9d06d6b5a3 --- /dev/null +++ b/java/ql/test/stubs/javax-ws-rs-api-3.0.0/jakarta/ws/rs/core/Request.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2010, 2019 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package jakarta.ws.rs.core; + +import java.util.Date; +import java.util.List; + +import jakarta.ws.rs.core.Response.ResponseBuilder; + +/** + * An injectable helper for request processing, all methods throw an {@link IllegalStateException} if called outside the + * scope of a request (e.g. from a provider constructor). + * + * Precondition processing (see the {@code evaluatePreconditions} methods) can result in either a {@code null} return + * value to indicate that preconditions have been met and that the request should continue, or a non-{@code null} return + * value to indicate that preconditions were not met. In the event that preconditions were not met, the returned + * {@code ResponseBuilder} instance will have an appropriate status and will also include a {@code Vary} header if the + * {@link #selectVariant(List)} method was called prior to to calling {@code evaluatePreconditions}. It is the + * responsibility of the caller to check the status and add additional metadata if required. E.g., see + * HTTP/1.1, section 10.3.5 for details + * of the headers that are expected to accompany a {@code 304 Not Modified} response. + * + * @author Paul Sandoz + * @author Marc Hadley + * @author Marek Potociar + * @since 1.0 + */ +public interface Request { + + /** + * Get the request method, e.g. GET, POST, etc. + * + * @return the request method. + * @see jakarta.ws.rs.HttpMethod + */ + public String getMethod(); + + /** + * Select the representation variant that best matches the request. Returns {@code null} in case there is no matching + * variant in the list. + *

    + * More explicit variants are chosen ahead of less explicit ones. A vary header is computed from the supplied list and + * automatically added to the response. + *

    + * + * @param variants a list of Variant that describe all of the available representation variants. + * @return the variant that best matches the request or {@code null} if there's no match. + * @throws java.lang.IllegalArgumentException if variants is empty or {@code null}. + * @throws java.lang.IllegalStateException if called outside the scope of a request. + * @see Variant.VariantListBuilder + */ + public Variant selectVariant(List variants); + + /** + * Evaluate request preconditions based on the passed in value. + * + * @param eTag an ETag for the current state of the resource + * @return {@code null} if the preconditions are met or a {@code ResponseBuilder} set with the appropriate status if the + * preconditions are not met. A returned {@code ResponseBuilder} will include an ETag header set with the value of eTag, + * provided none of the precondition evaluation has failed, in which case the ETag header would not be included and the + * status code of the returned {@code ResponseBuilder} would be set to {@link Response.Status#PRECONDITION_FAILED}. + * @throws java.lang.IllegalArgumentException if eTag is {@code null}. + * @throws java.lang.IllegalStateException if called outside the scope of a request. + */ + public ResponseBuilder evaluatePreconditions(EntityTag eTag); + + /** + * Evaluate request preconditions based on the passed in value. + * + * @param lastModified a date that specifies the modification date of the resource + * @return {@code null} if the preconditions are met or a {@code ResponseBuilder} set with the appropriate status if the + * preconditions are not met. + * @throws java.lang.IllegalArgumentException if lastModified is {@code null}. + * @throws java.lang.IllegalStateException if called outside the scope of a request. + */ + public ResponseBuilder evaluatePreconditions(Date lastModified); + + /** + * Evaluate request preconditions based on the passed in value. + * + * @param lastModified a date that specifies the modification date of the resource + * @param eTag an ETag for the current state of the resource + * @return {@code null} if the preconditions are met or a {@code ResponseBuilder} set with the appropriate status if the + * preconditions are not met. A returned {@code ResponseBuilder} will include an ETag header set with the value of eTag, + * provided none of the precondition evaluation has failed, in which case the ETag header would not be included and the + * status code of the returned {@code ResponseBuilder} would be set to {@link Response.Status#PRECONDITION_FAILED}. + * @throws java.lang.IllegalArgumentException if lastModified or eTag is {@code null}. + * @throws java.lang.IllegalStateException if called outside the scope of a request. + */ + public ResponseBuilder evaluatePreconditions(Date lastModified, EntityTag eTag); + + /** + * Evaluate request preconditions for a resource that does not currently exist. The primary use of this method is to + * support the If-Match: * and + * If-None-Match: * preconditions. + * + *

    + * Note that precondition If-None-Match: something will never be + * considered to have been met, and it is the application's responsibility to enforce any additional method-specific + * semantics. E.g. a {@code PUT} on a resource that does not exist might succeed whereas a {@code GET} on a resource + * that does not exist would likely result in a 404 response. It would be the responsibility of the application to + * generate the 404 response. + *

    + * + * @return {@code null} if the preconditions are met or a {@code ResponseBuilder} set with the appropriate status if the + * preconditions are not met. + * @throws IllegalStateException if called outside the scope of a request. + * @since 1.1 + */ + public ResponseBuilder evaluatePreconditions(); + +} diff --git a/java/ql/test/stubs/javax-ws-rs-api-3.0.0/jakarta/ws/rs/core/SecurityContext.java b/java/ql/test/stubs/javax-ws-rs-api-3.0.0/jakarta/ws/rs/core/SecurityContext.java new file mode 100644 index 00000000000..ee382639a07 --- /dev/null +++ b/java/ql/test/stubs/javax-ws-rs-api-3.0.0/jakarta/ws/rs/core/SecurityContext.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2010, 2019 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package jakarta.ws.rs.core; + +import java.security.Principal; + +/** + * An injectable interface that provides access to security related information. + * + * @author Paul Sandoz + * @author Marc Hadley + * @see Context + * @since 1.0 + */ +public interface SecurityContext { + + /** + * String identifier for Basic authentication. Value "BASIC" + */ + public static final String BASIC_AUTH = "BASIC"; + /** + * String identifier for Client Certificate authentication. Value "CLIENT_CERT" + */ + public static final String CLIENT_CERT_AUTH = "CLIENT_CERT"; + /** + * String identifier for Digest authentication. Value "DIGEST" + */ + public static final String DIGEST_AUTH = "DIGEST"; + /** + * String identifier for Form authentication. Value "FORM" + */ + public static final String FORM_AUTH = "FORM"; + + /** + * Returns a java.security.Principal object containing the name of the current authenticated user. If the + * user has not been authenticated, the method returns null. + * + * @return a java.security.Principal containing the name of the user making this request; null if the user + * has not been authenticated + * @throws java.lang.IllegalStateException if called outside the scope of a request + */ + public Principal getUserPrincipal(); + + /** + * Returns a boolean indicating whether the authenticated user is included in the specified logical "role". If the user + * has not been authenticated, the method returns false. + * + * @param role a String specifying the name of the role + * @return a boolean indicating whether the user making the request belongs to a given role; + * false if the user has not been authenticated + * @throws java.lang.IllegalStateException if called outside the scope of a request + */ + public boolean isUserInRole(String role); + + /** + * Returns a boolean indicating whether this request was made using a secure channel, such as HTTPS. + * + * @return true if the request was made using a secure channel, false otherwise + * @throws java.lang.IllegalStateException if called outside the scope of a request + */ + public boolean isSecure(); + + /** + * Returns the string value of the authentication scheme used to protect the resource. If the resource is not + * authenticated, null is returned. + * + * Values are the same as the CGI variable AUTH_TYPE + * + * @return one of the static members BASIC_AUTH, FORM_AUTH, CLIENT_CERT_AUTH, DIGEST_AUTH (suitable for == comparison) + * or the container-specific string indicating the authentication scheme, or null if the request was not authenticated. + * @throws java.lang.IllegalStateException if called outside the scope of a request + */ + public String getAuthenticationScheme(); +} \ No newline at end of file diff --git a/java/ql/test/stubs/rundeck-api-java-client-13.2/org/rundeck/api/parser/ParserHelper.java b/java/ql/test/stubs/rundeck-api-java-client-13.2/org/rundeck/api/parser/ParserHelper.java new file mode 100644 index 00000000000..34acd64f63e --- /dev/null +++ b/java/ql/test/stubs/rundeck-api-java-client-13.2/org/rundeck/api/parser/ParserHelper.java @@ -0,0 +1,13 @@ +package org.rundeck.api.parser; + +import java.io.InputStream; +import org.dom4j.Document; + +public class ParserHelper { + public ParserHelper() { + } + + public static Document loadDocument(InputStream inputStream) { + return null; + } +} diff --git a/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/Expression.java b/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/Expression.java index 2c3fc44075f..4556c65a518 100644 --- a/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/Expression.java +++ b/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/Expression.java @@ -1,14 +1,65 @@ +/* + * Copyright 2002-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + package org.springframework.expression; +import org.springframework.lang.Nullable; + public interface Expression { + String getExpressionString(); Object getValue() throws EvaluationException; + T getValue(@Nullable Class desiredResultType) throws EvaluationException; + + Object getValue(@Nullable Object rootObject) throws EvaluationException; + + T getValue(@Nullable Object rootObject, @Nullable Class desiredResultType) + throws EvaluationException; + Object getValue(EvaluationContext context) throws EvaluationException; + Object getValue(EvaluationContext context, @Nullable Object rootObject) + throws EvaluationException; + + T getValue(EvaluationContext context, @Nullable Class desiredResultType) + throws EvaluationException; + + T getValue(EvaluationContext context, @Nullable Object rootObject, + @Nullable Class desiredResultType) throws EvaluationException; + Class getValueType() throws EvaluationException; + Class getValueType(@Nullable Object rootObject) throws EvaluationException; + Class getValueType(EvaluationContext context) throws EvaluationException; - void setValue(Object rootObject, Object value) throws EvaluationException; -} \ No newline at end of file + Class getValueType(EvaluationContext context, @Nullable Object rootObject) + throws EvaluationException; + + boolean isWritable(@Nullable Object rootObject) throws EvaluationException; + + boolean isWritable(EvaluationContext context) throws EvaluationException; + + boolean isWritable(EvaluationContext context, @Nullable Object rootObject) + throws EvaluationException; + + void setValue(@Nullable Object rootObject, @Nullable Object value) throws EvaluationException; + + void setValue(EvaluationContext context, @Nullable Object value) throws EvaluationException; + + void setValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Object value) + throws EvaluationException; + +} diff --git a/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/ExpressionException.java b/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/ExpressionException.java new file mode 100644 index 00000000000..7cd8ed51fe9 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/ExpressionException.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.expression; + +import org.springframework.lang.Nullable; + +public class ExpressionException extends RuntimeException { + public ExpressionException(String message) {} + + public ExpressionException(String message, Throwable cause) {} + + public ExpressionException(@Nullable String expressionString, String message) {} + + public ExpressionException(@Nullable String expressionString, int position, String message) {} + + public ExpressionException(int position, String message) {} + + public ExpressionException(int position, String message, Throwable cause) {} + + public final String getExpressionString() { + return null; + } + + public final int getPosition() { + return 0; + } + + @Override + public String getMessage() { + return null; + } + + public String toDetailedString() { + return null; + } + + public String getSimpleMessage() { + return null; + } + +} diff --git a/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/ExpressionParser.java b/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/ExpressionParser.java index 4bfbf796c1e..f90848acc84 100644 --- a/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/ExpressionParser.java +++ b/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/ExpressionParser.java @@ -1,6 +1,23 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + package org.springframework.expression; public interface ExpressionParser { + Expression parseExpression(String expressionString) throws ParseException; - Expression parseExpression(String string); -} \ No newline at end of file + Expression parseExpression(String expressionString, ParserContext context) + throws ParseException; + +} diff --git a/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/ParseException.java b/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/ParseException.java new file mode 100644 index 00000000000..8a2a0ecd9d2 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/ParseException.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.expression; + +import org.springframework.lang.Nullable; + +public class ParseException extends ExpressionException { + public ParseException(@Nullable String expressionString, int position, String message) { + super(expressionString, message); + } + + public ParseException(int position, String message, Throwable cause) { + super(message, cause); + } + + public ParseException(int position, String message) { + super(message); + } + +} diff --git a/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/ParserContext.java b/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/ParserContext.java new file mode 100644 index 00000000000..5e772eb5971 --- /dev/null +++ b/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/ParserContext.java @@ -0,0 +1,26 @@ +/* + * Copyright 2002-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.expression; + +public interface ParserContext { + boolean isTemplate(); + + String getExpressionPrefix(); + + String getExpressionSuffix(); + + ParserContext TEMPLATE_EXPRESSION = null; + +} diff --git a/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/common/TemplateAwareExpressionParser.java b/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/common/TemplateAwareExpressionParser.java new file mode 100644 index 00000000000..55a2aa5756f --- /dev/null +++ b/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/common/TemplateAwareExpressionParser.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.expression.common; + +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.ParseException; +import org.springframework.expression.ParserContext; +import org.springframework.lang.Nullable; + +public abstract class TemplateAwareExpressionParser implements ExpressionParser { + @Override + public Expression parseExpression(String expressionString) throws ParseException { + return null; + } + + @Override + public Expression parseExpression(String expressionString, @Nullable ParserContext context) + throws ParseException { + return null; + } + +} diff --git a/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/spel/standard/SpelExpression.java b/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/spel/standard/SpelExpression.java new file mode 100644 index 00000000000..949eab02e2c --- /dev/null +++ b/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/spel/standard/SpelExpression.java @@ -0,0 +1,137 @@ +/* + * Copyright 2002-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package org.springframework.expression.spel.standard; + +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.Expression; +import org.springframework.lang.Nullable; + +public class SpelExpression implements Expression { + public void setEvaluationContext(EvaluationContext evaluationContext) {} + + public EvaluationContext getEvaluationContext() { + return null; + } + + @Override + public String getExpressionString() { + return null; + } + + @Override + public Object getValue() throws EvaluationException { + return null; + } + + @Override + public T getValue(@Nullable Class expectedResultType) throws EvaluationException { + return null; + } + + @Override + public Object getValue(@Nullable Object rootObject) throws EvaluationException { + return null; + } + + @Override + public T getValue(@Nullable Object rootObject, @Nullable Class expectedResultType) + throws EvaluationException { + return null; + } + + @Override + public Object getValue(EvaluationContext context) throws EvaluationException { + return null; + } + + @Override + public T getValue(EvaluationContext context, @Nullable Class expectedResultType) + throws EvaluationException { + return null; + } + + @Override + public Object getValue(EvaluationContext context, @Nullable Object rootObject) + throws EvaluationException { + return null; + } + + @Override + public T getValue(EvaluationContext context, @Nullable Object rootObject, + @Nullable Class expectedResultType) throws EvaluationException { + return null; + } + + @Override + public Class getValueType() throws EvaluationException { + return null; + } + + @Override + public Class getValueType(@Nullable Object rootObject) throws EvaluationException { + return null; + } + + @Override + public Class getValueType(EvaluationContext context) throws EvaluationException { + return null; + } + + @Override + public Class getValueType(EvaluationContext context, @Nullable Object rootObject) + throws EvaluationException { + return null; + } + + @Override + public boolean isWritable(@Nullable Object rootObject) throws EvaluationException { + return false; + } + + @Override + public boolean isWritable(EvaluationContext context) throws EvaluationException { + return false; + } + + @Override + public boolean isWritable(EvaluationContext context, @Nullable Object rootObject) + throws EvaluationException { + return false; + } + + @Override + public void setValue(@Nullable Object rootObject, @Nullable Object value) + throws EvaluationException {} + + @Override + public void setValue(EvaluationContext context, @Nullable Object value) + throws EvaluationException {} + + @Override + public void setValue(EvaluationContext context, @Nullable Object rootObject, + @Nullable Object value) throws EvaluationException {} + + public boolean compileExpression() { + return false; + } + + public void revertToInterpreted() {} + + public String toStringAST() { + return null; + } + +} diff --git a/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/spel/standard/SpelExpressionParser.java b/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/spel/standard/SpelExpressionParser.java index 4aee45beee9..033e0f07915 100644 --- a/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/spel/standard/SpelExpressionParser.java +++ b/java/ql/test/stubs/springframework-5.3.8/org/springframework/expression/spel/standard/SpelExpressionParser.java @@ -1,10 +1,26 @@ +/* + * Copyright 2002-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + package org.springframework.expression.spel.standard; -import org.springframework.expression.*; - -public class SpelExpressionParser implements ExpressionParser { +import org.springframework.expression.ParseException; +import org.springframework.expression.common.TemplateAwareExpressionParser; +public class SpelExpressionParser extends TemplateAwareExpressionParser { public SpelExpressionParser() {} - - public Expression parseExpression(String string) { return null; } -} \ No newline at end of file + + public SpelExpression parseRaw(String expressionString) throws ParseException { + return null; + } +} diff --git a/java/upgrades/8ab354e68e86100ee3abe28bd44f491ecc77c1dd/old.dbscheme b/java/upgrades/8ab354e68e86100ee3abe28bd44f491ecc77c1dd/old.dbscheme new file mode 100644 index 00000000000..8ab354e68e8 --- /dev/null +++ b/java/upgrades/8ab354e68e86100ee3abe28bd44f491ecc77c1dd/old.dbscheme @@ -0,0 +1,987 @@ +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * javac A.java B.java C.java + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * javac A.java B.java C.java + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--javac-args` + * 2 | A.java + * 3 | B.java + * 4 | C.java + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | A.java + * 1 | B.java + * 2 | C.java + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + * External artifacts + */ + +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +snapshotDate( + unique date snapshotDate : date ref +); + +sourceLocationPrefix( + string prefix : string ref +); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/* + * SMAP + */ + +smap_header( + int outputFileId: @file ref, + string outputFilename: string ref, + string defaultStratum: string ref +); + +smap_files( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + string inputFileName: string ref, + int inputFileId: @file ref +); + +smap_lines( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + int inputStartLine: int ref, + int inputLineCount: int ref, + int outputStartLine: int ref, + int outputLineIncrement: int ref +); + +/* + * Locations and files + */ + +@location = @location_default ; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +hasLocation( + int locatableid: @locatable ref, + int id: @location ref +); + +@sourceline = @locatable ; + +#keyset[element_id] +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref // deprecated +); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +/* + * Java + */ + +cupackage( + unique int id: @file ref, + int packageid: @package ref +); + +#keyset[fileid,keyName] +jarManifestMain( + int fileid: @file ref, + string keyName: string ref, + string value: string ref +); + +#keyset[fileid,entryName,keyName] +jarManifestEntries( + int fileid: @file ref, + string entryName: string ref, + string keyName: string ref, + string value: string ref +); + +packages( + unique int id: @package, + string nodeName: string ref +); + +primitives( + unique int id: @primitive, + string nodeName: string ref +); + +modifiers( + unique int id: @modifier, + string nodeName: string ref +); + +classes( + unique int id: @class, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @class ref +); + +isRecord( + unique int id: @class ref +); + +interfaces( + unique int id: @interface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @interface ref +); + +fielddecls( + unique int id: @fielddecl, + int parentid: @reftype ref +); + +#keyset[fieldId] #keyset[fieldDeclId,pos] +fieldDeclaredIn( + int fieldId: @field ref, + int fieldDeclId: @fielddecl ref, + int pos: int ref +); + +fields( + unique int id: @field, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @field ref +); + +constrs( + unique int id: @constructor, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @constructor ref +); + +methods( + unique int id: @method, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @method ref +); + +#keyset[parentid,pos] +params( + unique int id: @param, + int typeid: @type ref, + int pos: int ref, + int parentid: @callable ref, + int sourceid: @param ref +); + +paramName( + unique int id: @param ref, + string nodeName: string ref +); + +isVarargsParam( + int param: @param ref +); + +exceptions( + unique int id: @exception, + int typeid: @type ref, + int parentid: @callable ref +); + +isAnnotType( + int interfaceid: @interface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @class ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int kind: int ref, // deprecated + int parentid: @typeorcallable ref +); + +wildcards( + unique int id: @wildcard, + string nodeName: string ref, + int kind: int ref +); + +#keyset[parentid,pos] +typeBounds( + unique int id: @typebound, + int typeid: @reftype ref, + int pos: int ref, + int parentid: @boundedtype ref +); + +#keyset[parentid,pos] +typeArgs( + int argumentid: @reftype ref, + int pos: int ref, + int parentid: @typeorcallable ref +); + +isParameterized( + int memberid: @member ref +); + +isRaw( + int memberid: @member ref +); + +erasure( + unique int memberid: @member ref, + int erasureid: @member ref +); + +#keyset[classid] #keyset[parent] +isAnonymClass( + int classid: @class ref, + int parent: @classinstancexpr ref +); + +#keyset[typeid] #keyset[parent] +isLocalClassOrInterface( + int typeid: @classorinterface ref, + int parent: @localtypedeclstmt ref +); + +isDefConstr( + int constructorid: @constructor ref +); + +#keyset[exprId] +lambdaKind( + int exprId: @lambdaexpr ref, + int bodyKind: int ref +); + +arrays( + unique int id: @array, + string nodeName: string ref, + int elementtypeid: @type ref, + int dimension: int ref, + int componenttypeid: @type ref +); + +enclInReftype( + unique int child: @reftype ref, + int parent: @reftype ref +); + +extendsReftype( + int id1: @reftype ref, + int id2: @classorinterface ref +); + +implInterface( + int id1: @classorarray ref, + int id2: @interface ref +); + +permits( + int id1: @classorinterface ref, + int id2: @classorinterface ref +); + +hasModifier( + int id1: @modifiable ref, + int id2: @modifier ref +); + +imports( + unique int id: @import, + int holder: @typeorpackage ref, + string name: string ref, + int kind: int ref +); + +#keyset[parent,idx] +stmts( + unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + int bodydecl: @callable ref +); + +@stmtparent = @callable | @stmt | @switchexpr; + +case @stmt.kind of + 0 = @block +| 1 = @ifstmt +| 2 = @forstmt +| 3 = @enhancedforstmt +| 4 = @whilestmt +| 5 = @dostmt +| 6 = @trystmt +| 7 = @switchstmt +| 8 = @synchronizedstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @breakstmt +| 12 = @continuestmt +| 13 = @emptystmt +| 14 = @exprstmt +| 15 = @labeledstmt +| 16 = @assertstmt +| 17 = @localvariabledeclstmt +| 18 = @localtypedeclstmt +| 19 = @constructorinvocationstmt +| 20 = @superconstructorinvocationstmt +| 21 = @case +| 22 = @catchclause +| 23 = @yieldstmt +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +callableEnclosingExpr( + unique int id: @expr ref, + int callable_id: @callable ref +); + +statementEnclosingExpr( + unique int id: @expr ref, + int statement_id: @stmt ref +); + +isParenthesized( + unique int id: @expr ref, + int parentheses: int ref +); + +case @expr.kind of + 1 = @arrayaccess +| 2 = @arraycreationexpr +| 3 = @arrayinit +| 4 = @assignexpr +| 5 = @assignaddexpr +| 6 = @assignsubexpr +| 7 = @assignmulexpr +| 8 = @assigndivexpr +| 9 = @assignremexpr +| 10 = @assignandexpr +| 11 = @assignorexpr +| 12 = @assignxorexpr +| 13 = @assignlshiftexpr +| 14 = @assignrshiftexpr +| 15 = @assignurshiftexpr +| 16 = @booleanliteral +| 17 = @integerliteral +| 18 = @longliteral +| 19 = @floatingpointliteral +| 20 = @doubleliteral +| 21 = @characterliteral +| 22 = @stringliteral +| 23 = @nullliteral +| 24 = @mulexpr +| 25 = @divexpr +| 26 = @remexpr +| 27 = @addexpr +| 28 = @subexpr +| 29 = @lshiftexpr +| 30 = @rshiftexpr +| 31 = @urshiftexpr +| 32 = @andbitexpr +| 33 = @orbitexpr +| 34 = @xorbitexpr +| 35 = @andlogicalexpr +| 36 = @orlogicalexpr +| 37 = @ltexpr +| 38 = @gtexpr +| 39 = @leexpr +| 40 = @geexpr +| 41 = @eqexpr +| 42 = @neexpr +| 43 = @postincexpr +| 44 = @postdecexpr +| 45 = @preincexpr +| 46 = @predecexpr +| 47 = @minusexpr +| 48 = @plusexpr +| 49 = @bitnotexpr +| 50 = @lognotexpr +| 51 = @castexpr +| 52 = @newexpr +| 53 = @conditionalexpr +| 54 = @parexpr // deprecated +| 55 = @instanceofexpr +| 56 = @localvariabledeclexpr +| 57 = @typeliteral +| 58 = @thisaccess +| 59 = @superaccess +| 60 = @varaccess +| 61 = @methodaccess +| 62 = @unannotatedtypeaccess +| 63 = @arraytypeaccess +| 64 = @packageaccess +| 65 = @wildcardtypeaccess +| 66 = @declannotation +| 67 = @uniontypeaccess +| 68 = @lambdaexpr +| 69 = @memberref +| 70 = @annotatedtypeaccess +| 71 = @typeannotation +| 72 = @intersectiontypeaccess +| 73 = @switchexpr +; + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref + +@annotation = @declannotation | @typeannotation +@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess + +@assignment = @assignexpr + | @assignop; + +@unaryassignment = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr; + +@assignop = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + | @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignurshiftexpr; + +@literal = @booleanliteral + | @integerliteral + | @longliteral + | @floatingpointliteral + | @doubleliteral + | @characterliteral + | @stringliteral + | @nullliteral; + +@binaryexpr = @mulexpr + | @divexpr + | @remexpr + | @addexpr + | @subexpr + | @lshiftexpr + | @rshiftexpr + | @urshiftexpr + | @andbitexpr + | @orbitexpr + | @xorbitexpr + | @andlogicalexpr + | @orlogicalexpr + | @ltexpr + | @gtexpr + | @leexpr + | @geexpr + | @eqexpr + | @neexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr; + +@caller = @classinstancexpr + | @methodaccess + | @constructorinvocationstmt + | @superconstructorinvocationstmt; + +callableBinding( + unique int callerid: @caller ref, + int callee: @callable ref +); + +memberRefBinding( + unique int id: @expr ref, + int callable: @callable ref +); + +@exprparent = @stmt | @expr | @callable | @field | @fielddecl | @class | @interface | @param | @localvar | @typevariable; + +variableBinding( + unique int expr: @varaccess ref, + int variable: @variable ref +); + +@variable = @localscopevariable | @field; + +@localscopevariable = @localvar | @param; + +localvars( + unique int id: @localvar, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @localvariabledeclexpr ref +); + +@namedexprorstmt = @breakstmt + | @continuestmt + | @labeledstmt + | @literal; + +namestrings( + string name: string ref, + string value: string ref, + unique int parent: @namedexprorstmt ref +); + +/* + * Modules + */ + +#keyset[name] +modules( + unique int id: @module, + string name: string ref +); + +isOpen( + int id: @module ref +); + +#keyset[fileId] +cumodule( + int fileId: @file ref, + int moduleId: @module ref +); + +@directive = @requires + | @exports + | @opens + | @uses + | @provides + +#keyset[directive] +directives( + int id: @module ref, + int directive: @directive ref +); + +requires( + unique int id: @requires, + int target: @module ref +); + +isTransitive( + int id: @requires ref +); + +isStatic( + int id: @requires ref +); + +exports( + unique int id: @exports, + int target: @package ref +); + +exportsTo( + int id: @exports ref, + int target: @module ref +); + +opens( + unique int id: @opens, + int target: @package ref +); + +opensTo( + int id: @opens ref, + int target: @module ref +); + +uses( + unique int id: @uses, + string serviceInterface: string ref +); + +provides( + unique int id: @provides, + string serviceInterface: string ref +); + +providesWith( + int id: @provides ref, + string serviceImpl: string ref +); + +/* + * Javadoc + */ + +javadoc( + unique int id: @javadoc +); + +isNormalComment( + int commentid : @javadoc ref +); + +isEolComment( + int commentid : @javadoc ref +); + +hasJavadoc( + int documentableid: @member ref, + int javadocid: @javadoc ref +); + +#keyset[parentid,idx] +javadocTag( + unique int id: @javadocTag, + string name: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +#keyset[parentid,idx] +javadocText( + unique int id: @javadocText, + string text: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +@javadocParent = @javadoc | @javadocTag; +@javadocElement = @javadocTag | @javadocText; + +@typeorpackage = @type | @package; + +@typeorcallable = @type | @callable; +@classorinterface = @interface | @class; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype; +@classorarray = @class | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; +@element = @file | @package | @primitive | @class | @interface | @method | @constructor | @modifier | @param | @exception | @field | + @annotation | @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl; + +@modifiable = @member_modifiable| @param | @localvar ; + +@member_modifiable = @class | @interface | @method | @constructor | @field ; + +@member = @method | @constructor | @field | @reftype ; + +@locatable = @file | @class | @interface | @fielddecl | @field | @constructor | @method | @param | @exception + | @boundedtype | @typebound | @array | @primitive + | @import | @stmt | @expr | @localvar | @javadoc | @javadocTag | @javadocText + | @xmllocatable; + +@top = @element | @locatable | @folder; + +/* + * XML Files + */ + +xmlEncoding( + unique int id: @file ref, + string encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; diff --git a/java/upgrades/8ab354e68e86100ee3abe28bd44f491ecc77c1dd/semmlecode.dbscheme b/java/upgrades/8ab354e68e86100ee3abe28bd44f491ecc77c1dd/semmlecode.dbscheme new file mode 100755 index 00000000000..017ac1ed2df --- /dev/null +++ b/java/upgrades/8ab354e68e86100ee3abe28bd44f491ecc77c1dd/semmlecode.dbscheme @@ -0,0 +1,983 @@ +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * javac A.java B.java C.java + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * javac A.java B.java C.java + */ + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--javac-args` + * 2 | A.java + * 3 | B.java + * 4 | C.java + */ +#keyset[id, num] +compilation_args( + int id : @compilation ref, + int num : int ref, + string arg : string ref +); + +/** + * The source files that are compiled by a compiler invocation. + * If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | A.java + * 1 | B.java + * 2 | C.java + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The time taken by the extractor for a compiler invocation. + * + * For each file `num`, there will be rows for + * + * kind | seconds + * ---- | --- + * 1 | CPU seconds used by the extractor frontend + * 2 | Elapsed seconds during the extractor frontend + * 3 | CPU seconds used by the extractor backend + * 4 | Elapsed seconds during the extractor backend + */ +#keyset[id, num, kind] +compilation_time( + int id : @compilation ref, + int num : int ref, + /* kind: + 1 = frontend_cpu_seconds + 2 = frontend_elapsed_seconds + 3 = extractor_cpu_seconds + 4 = extractor_elapsed_seconds + */ + int kind : int ref, + float seconds : float ref +); + +/** + * An error or warning generated by the extractor. + * The diagnostic message `diagnostic` was generated during compiler + * invocation `compilation`, and is the `file_number_diagnostic_number`th + * message generated while extracting the `file_number`th file of that + * invocation. + */ +#keyset[compilation, file_number, file_number_diagnostic_number] +diagnostic_for( + unique int diagnostic : @diagnostic ref, + int compilation : @compilation ref, + int file_number : int ref, + int file_number_diagnostic_number : int ref +); + +/** + * If extraction was successful, then `cpu_seconds` and + * `elapsed_seconds` are the CPU time and elapsed time (respectively) + * that extraction took for compiler invocation `id`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +diagnostics( + unique int id: @diagnostic, + int severity: int ref, + string error_tag: string ref, + string error_message: string ref, + string full_error_message: string ref, + int location: @location_default ref +); + +/* + * External artifacts + */ + +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +snapshotDate( + unique date snapshotDate : date ref +); + +sourceLocationPrefix( + string prefix : string ref +); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/* + * SMAP + */ + +smap_header( + int outputFileId: @file ref, + string outputFilename: string ref, + string defaultStratum: string ref +); + +smap_files( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + string inputFileName: string ref, + int inputFileId: @file ref +); + +smap_lines( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + int inputStartLine: int ref, + int inputLineCount: int ref, + int outputStartLine: int ref, + int outputLineIncrement: int ref +); + +/* + * Locations and files + */ + +@location = @location_default ; + +locations_default( + unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref +); + +hasLocation( + int locatableid: @locatable ref, + int id: @location ref +); + +@sourceline = @locatable ; + +#keyset[element_id] +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref +); + +files( + unique int id: @file, + string name: string ref +); + +folders( + unique int id: @folder, + string name: string ref +); + +@container = @folder | @file + +containerparent( + int parent: @container ref, + unique int child: @container ref +); + +/* + * Java + */ + +cupackage( + unique int id: @file ref, + int packageid: @package ref +); + +#keyset[fileid,keyName] +jarManifestMain( + int fileid: @file ref, + string keyName: string ref, + string value: string ref +); + +#keyset[fileid,entryName,keyName] +jarManifestEntries( + int fileid: @file ref, + string entryName: string ref, + string keyName: string ref, + string value: string ref +); + +packages( + unique int id: @package, + string nodeName: string ref +); + +primitives( + unique int id: @primitive, + string nodeName: string ref +); + +modifiers( + unique int id: @modifier, + string nodeName: string ref +); + +classes( + unique int id: @class, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @class ref +); + +isRecord( + unique int id: @class ref +); + +interfaces( + unique int id: @interface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @interface ref +); + +fielddecls( + unique int id: @fielddecl, + int parentid: @reftype ref +); + +#keyset[fieldId] #keyset[fieldDeclId,pos] +fieldDeclaredIn( + int fieldId: @field ref, + int fieldDeclId: @fielddecl ref, + int pos: int ref +); + +fields( + unique int id: @field, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @field ref +); + +constrs( + unique int id: @constructor, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @constructor ref +); + +methods( + unique int id: @method, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @method ref +); + +#keyset[parentid,pos] +params( + unique int id: @param, + int typeid: @type ref, + int pos: int ref, + int parentid: @callable ref, + int sourceid: @param ref +); + +paramName( + unique int id: @param ref, + string nodeName: string ref +); + +isVarargsParam( + int param: @param ref +); + +exceptions( + unique int id: @exception, + int typeid: @type ref, + int parentid: @callable ref +); + +isAnnotType( + int interfaceid: @interface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @class ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int kind: int ref, // deprecated + int parentid: @typeorcallable ref +); + +wildcards( + unique int id: @wildcard, + string nodeName: string ref, + int kind: int ref +); + +#keyset[parentid,pos] +typeBounds( + unique int id: @typebound, + int typeid: @reftype ref, + int pos: int ref, + int parentid: @boundedtype ref +); + +#keyset[parentid,pos] +typeArgs( + int argumentid: @reftype ref, + int pos: int ref, + int parentid: @typeorcallable ref +); + +isParameterized( + int memberid: @member ref +); + +isRaw( + int memberid: @member ref +); + +erasure( + unique int memberid: @member ref, + int erasureid: @member ref +); + +#keyset[classid] #keyset[parent] +isAnonymClass( + int classid: @class ref, + int parent: @classinstancexpr ref +); + +#keyset[typeid] #keyset[parent] +isLocalClassOrInterface( + int typeid: @classorinterface ref, + int parent: @localtypedeclstmt ref +); + +isDefConstr( + int constructorid: @constructor ref +); + +#keyset[exprId] +lambdaKind( + int exprId: @lambdaexpr ref, + int bodyKind: int ref +); + +arrays( + unique int id: @array, + string nodeName: string ref, + int elementtypeid: @type ref, + int dimension: int ref, + int componenttypeid: @type ref +); + +enclInReftype( + unique int child: @reftype ref, + int parent: @reftype ref +); + +extendsReftype( + int id1: @reftype ref, + int id2: @classorinterface ref +); + +implInterface( + int id1: @classorarray ref, + int id2: @interface ref +); + +permits( + int id1: @classorinterface ref, + int id2: @classorinterface ref +); + +hasModifier( + int id1: @modifiable ref, + int id2: @modifier ref +); + +imports( + unique int id: @import, + int holder: @typeorpackage ref, + string name: string ref, + int kind: int ref +); + +#keyset[parent,idx] +stmts( + unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + int bodydecl: @callable ref +); + +@stmtparent = @callable | @stmt | @switchexpr; + +case @stmt.kind of + 0 = @block +| 1 = @ifstmt +| 2 = @forstmt +| 3 = @enhancedforstmt +| 4 = @whilestmt +| 5 = @dostmt +| 6 = @trystmt +| 7 = @switchstmt +| 8 = @synchronizedstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @breakstmt +| 12 = @continuestmt +| 13 = @emptystmt +| 14 = @exprstmt +| 15 = @labeledstmt +| 16 = @assertstmt +| 17 = @localvariabledeclstmt +| 18 = @localtypedeclstmt +| 19 = @constructorinvocationstmt +| 20 = @superconstructorinvocationstmt +| 21 = @case +| 22 = @catchclause +| 23 = @yieldstmt +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +callableEnclosingExpr( + unique int id: @expr ref, + int callable_id: @callable ref +); + +statementEnclosingExpr( + unique int id: @expr ref, + int statement_id: @stmt ref +); + +isParenthesized( + unique int id: @expr ref, + int parentheses: int ref +); + +case @expr.kind of + 1 = @arrayaccess +| 2 = @arraycreationexpr +| 3 = @arrayinit +| 4 = @assignexpr +| 5 = @assignaddexpr +| 6 = @assignsubexpr +| 7 = @assignmulexpr +| 8 = @assigndivexpr +| 9 = @assignremexpr +| 10 = @assignandexpr +| 11 = @assignorexpr +| 12 = @assignxorexpr +| 13 = @assignlshiftexpr +| 14 = @assignrshiftexpr +| 15 = @assignurshiftexpr +| 16 = @booleanliteral +| 17 = @integerliteral +| 18 = @longliteral +| 19 = @floatingpointliteral +| 20 = @doubleliteral +| 21 = @characterliteral +| 22 = @stringliteral +| 23 = @nullliteral +| 24 = @mulexpr +| 25 = @divexpr +| 26 = @remexpr +| 27 = @addexpr +| 28 = @subexpr +| 29 = @lshiftexpr +| 30 = @rshiftexpr +| 31 = @urshiftexpr +| 32 = @andbitexpr +| 33 = @orbitexpr +| 34 = @xorbitexpr +| 35 = @andlogicalexpr +| 36 = @orlogicalexpr +| 37 = @ltexpr +| 38 = @gtexpr +| 39 = @leexpr +| 40 = @geexpr +| 41 = @eqexpr +| 42 = @neexpr +| 43 = @postincexpr +| 44 = @postdecexpr +| 45 = @preincexpr +| 46 = @predecexpr +| 47 = @minusexpr +| 48 = @plusexpr +| 49 = @bitnotexpr +| 50 = @lognotexpr +| 51 = @castexpr +| 52 = @newexpr +| 53 = @conditionalexpr +| 54 = @parexpr // deprecated +| 55 = @instanceofexpr +| 56 = @localvariabledeclexpr +| 57 = @typeliteral +| 58 = @thisaccess +| 59 = @superaccess +| 60 = @varaccess +| 61 = @methodaccess +| 62 = @unannotatedtypeaccess +| 63 = @arraytypeaccess +| 64 = @packageaccess +| 65 = @wildcardtypeaccess +| 66 = @declannotation +| 67 = @uniontypeaccess +| 68 = @lambdaexpr +| 69 = @memberref +| 70 = @annotatedtypeaccess +| 71 = @typeannotation +| 72 = @intersectiontypeaccess +| 73 = @switchexpr +; + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref + +@annotation = @declannotation | @typeannotation +@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess + +@assignment = @assignexpr + | @assignop; + +@unaryassignment = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr; + +@assignop = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + | @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignurshiftexpr; + +@literal = @booleanliteral + | @integerliteral + | @longliteral + | @floatingpointliteral + | @doubleliteral + | @characterliteral + | @stringliteral + | @nullliteral; + +@binaryexpr = @mulexpr + | @divexpr + | @remexpr + | @addexpr + | @subexpr + | @lshiftexpr + | @rshiftexpr + | @urshiftexpr + | @andbitexpr + | @orbitexpr + | @xorbitexpr + | @andlogicalexpr + | @orlogicalexpr + | @ltexpr + | @gtexpr + | @leexpr + | @geexpr + | @eqexpr + | @neexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr; + +@caller = @classinstancexpr + | @methodaccess + | @constructorinvocationstmt + | @superconstructorinvocationstmt; + +callableBinding( + unique int callerid: @caller ref, + int callee: @callable ref +); + +memberRefBinding( + unique int id: @expr ref, + int callable: @callable ref +); + +@exprparent = @stmt | @expr | @callable | @field | @fielddecl | @class | @interface | @param | @localvar | @typevariable; + +variableBinding( + unique int expr: @varaccess ref, + int variable: @variable ref +); + +@variable = @localscopevariable | @field; + +@localscopevariable = @localvar | @param; + +localvars( + unique int id: @localvar, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @localvariabledeclexpr ref +); + +@namedexprorstmt = @breakstmt + | @continuestmt + | @labeledstmt + | @literal; + +namestrings( + string name: string ref, + string value: string ref, + unique int parent: @namedexprorstmt ref +); + +/* + * Modules + */ + +#keyset[name] +modules( + unique int id: @module, + string name: string ref +); + +isOpen( + int id: @module ref +); + +#keyset[fileId] +cumodule( + int fileId: @file ref, + int moduleId: @module ref +); + +@directive = @requires + | @exports + | @opens + | @uses + | @provides + +#keyset[directive] +directives( + int id: @module ref, + int directive: @directive ref +); + +requires( + unique int id: @requires, + int target: @module ref +); + +isTransitive( + int id: @requires ref +); + +isStatic( + int id: @requires ref +); + +exports( + unique int id: @exports, + int target: @package ref +); + +exportsTo( + int id: @exports ref, + int target: @module ref +); + +opens( + unique int id: @opens, + int target: @package ref +); + +opensTo( + int id: @opens ref, + int target: @module ref +); + +uses( + unique int id: @uses, + string serviceInterface: string ref +); + +provides( + unique int id: @provides, + string serviceInterface: string ref +); + +providesWith( + int id: @provides ref, + string serviceImpl: string ref +); + +/* + * Javadoc + */ + +javadoc( + unique int id: @javadoc +); + +isNormalComment( + int commentid : @javadoc ref +); + +isEolComment( + int commentid : @javadoc ref +); + +hasJavadoc( + int documentableid: @member ref, + int javadocid: @javadoc ref +); + +#keyset[parentid,idx] +javadocTag( + unique int id: @javadocTag, + string name: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +#keyset[parentid,idx] +javadocText( + unique int id: @javadocText, + string text: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +@javadocParent = @javadoc | @javadocTag; +@javadocElement = @javadocTag | @javadocText; + +@typeorpackage = @type | @package; + +@typeorcallable = @type | @callable; +@classorinterface = @interface | @class; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype; +@classorarray = @class | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; +@element = @file | @package | @primitive | @class | @interface | @method | @constructor | @modifier | @param | @exception | @field | + @annotation | @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl; + +@modifiable = @member_modifiable| @param | @localvar ; + +@member_modifiable = @class | @interface | @method | @constructor | @field ; + +@member = @method | @constructor | @field | @reftype ; + +@locatable = @file | @class | @interface | @fielddecl | @field | @constructor | @method | @param | @exception + | @boundedtype | @typebound | @array | @primitive + | @import | @stmt | @expr | @localvar | @javadoc | @javadocTag | @javadocText + | @xmllocatable; + +@top = @element | @locatable | @folder; + +/* + * XML Files + */ + +xmlEncoding( + unique int id: @file ref, + string encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; diff --git a/java/upgrades/8ab354e68e86100ee3abe28bd44f491ecc77c1dd/upgrade.properties b/java/upgrades/8ab354e68e86100ee3abe28bd44f491ecc77c1dd/upgrade.properties new file mode 100644 index 00000000000..a0c4ba602a1 --- /dev/null +++ b/java/upgrades/8ab354e68e86100ee3abe28bd44f491ecc77c1dd/upgrade.properties @@ -0,0 +1,4 @@ +description: Removed unused column from the `folders` and `files` relations +compatibility: full +files.rel: reorder files.rel (int id, string name, string simple, string ext, int fromSource) id name +folders.rel: reorder folders.rel (int id, string name, string simple) id name \ No newline at end of file diff --git a/javascript/change-notes/2021-09-01-clipboard-data.md b/javascript/change-notes/2021-09-01-clipboard-data.md new file mode 100644 index 00000000000..2d8e6775428 --- /dev/null +++ b/javascript/change-notes/2021-09-01-clipboard-data.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* The security queries now recognize clipboard data as a source, enabling the queries to flag additional alerts. diff --git a/javascript/change-notes/2021-09-01-typescript-4.4.md b/javascript/change-notes/2021-09-01-typescript-4.4.md new file mode 100644 index 00000000000..ec5eca5193c --- /dev/null +++ b/javascript/change-notes/2021-09-01-typescript-4.4.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* TypeScript 4.4 is now supported. diff --git a/javascript/change-notes/2021-09-07-static-initializer.md b/javascript/change-notes/2021-09-07-static-initializer.md new file mode 100644 index 00000000000..f4a4dd6a9ea --- /dev/null +++ b/javascript/change-notes/2021-09-07-static-initializer.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Support for the ECMAScript proposed feature "class static initialization blocks" has been added. diff --git a/javascript/extractor/lib/typescript/package.json b/javascript/extractor/lib/typescript/package.json index 6064cc946d9..f191604e7c8 100644 --- a/javascript/extractor/lib/typescript/package.json +++ b/javascript/extractor/lib/typescript/package.json @@ -2,7 +2,7 @@ "name": "typescript-parser-wrapper", "private": true, "dependencies": { - "typescript": "4.3.5" + "typescript": "4.4.2" }, "scripts": { "build": "tsc --project tsconfig.json", diff --git a/javascript/extractor/lib/typescript/yarn.lock b/javascript/extractor/lib/typescript/yarn.lock index c1254a4e73f..639a32d261e 100644 --- a/javascript/extractor/lib/typescript/yarn.lock +++ b/javascript/extractor/lib/typescript/yarn.lock @@ -6,7 +6,7 @@ version "12.7.11" resolved node-12.7.11.tgz#be879b52031cfb5d295b047f5462d8ef1a716446 -typescript@4.3.5: - version "4.3.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" - integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== +typescript@4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.2.tgz#6d618640d430e3569a1dfb44f7d7e600ced3ee86" + integrity sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ== diff --git a/javascript/extractor/src/com/semmle/jcorn/Parser.java b/javascript/extractor/src/com/semmle/jcorn/Parser.java index 5f7383813c6..6250e9d8ed6 100644 --- a/javascript/extractor/src/com/semmle/jcorn/Parser.java +++ b/javascript/extractor/src/com/semmle/jcorn/Parser.java @@ -83,6 +83,7 @@ import com.semmle.js.ast.SequenceExpression; import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.SpreadElement; import com.semmle.js.ast.Statement; +import com.semmle.js.ast.StaticInitializer; import com.semmle.js.ast.Super; import com.semmle.js.ast.SwitchCase; import com.semmle.js.ast.SwitchStatement; @@ -3244,6 +3245,10 @@ public class Parser { PropertyInfo pi = new PropertyInfo(false, isGenerator, methodStartLoc); this.parsePropertyName(pi); boolean isStatic = isMaybeStatic && this.type != TokenType.parenL; + if (isStatic && this.type == TokenType.braceL) { + BlockStatement block = parseBlock(false); + return new StaticInitializer(block.getLoc(), block); + } if (isStatic) { if (isGenerator) this.unexpected(); isGenerator = this.eat(TokenType.star); diff --git a/javascript/extractor/src/com/semmle/js/ast/DefaultVisitor.java b/javascript/extractor/src/com/semmle/js/ast/DefaultVisitor.java index 995f580edd2..c450fdd0468 100644 --- a/javascript/extractor/src/com/semmle/js/ast/DefaultVisitor.java +++ b/javascript/extractor/src/com/semmle/js/ast/DefaultVisitor.java @@ -782,4 +782,9 @@ public class DefaultVisitor implements Visitor { public R visit(GeneratedCodeExpr nd, C c) { return visit((Expression) nd, c); } + + @Override + public R visit(StaticInitializer nd, C c) { + return visit((MemberDefinition) nd, c); + } } diff --git a/javascript/extractor/src/com/semmle/js/ast/MemberDefinition.java b/javascript/extractor/src/com/semmle/js/ast/MemberDefinition.java index 7cacafa96ed..e3bbc6a1830 100644 --- a/javascript/extractor/src/com/semmle/js/ast/MemberDefinition.java +++ b/javascript/extractor/src/com/semmle/js/ast/MemberDefinition.java @@ -9,7 +9,7 @@ import java.util.List; *

    A member definition has a name and an optional initial value, whose type is given by the type * parameter {@code V}. */ -public abstract class MemberDefinition extends Node { +public abstract class MemberDefinition extends Node { /** A bitmask of flags defined in {@linkplain DeclarationFlags}. */ private final int flags; @@ -21,7 +21,7 @@ public abstract class MemberDefinition extends Node { */ private final Expression key; - /** The initial value of the member. */ + /** The initial value / initializer of the member. */ private final V value; /** The decorators applied to this member, if any. */ diff --git a/javascript/extractor/src/com/semmle/js/ast/NodeCopier.java b/javascript/extractor/src/com/semmle/js/ast/NodeCopier.java index 02fd40b12d8..83a37e11534 100644 --- a/javascript/extractor/src/com/semmle/js/ast/NodeCopier.java +++ b/javascript/extractor/src/com/semmle/js/ast/NodeCopier.java @@ -897,6 +897,11 @@ public class NodeCopier implements Visitor { @Override public INode visit(GeneratedCodeExpr nd, Void c) { - return new GeneratedCodeExpr(visit(nd.getLoc()), nd.getOpeningDelimiter(), nd.getClosingDelimiter(), nd.getBody()); + return new GeneratedCodeExpr(visit(nd.getLoc()), nd.getOpeningDelimiter(), nd.getClosingDelimiter(), nd.getBody()); + } + + @Override + public INode visit(StaticInitializer nd, Void c) { + return new StaticInitializer(visit(nd.getLoc()), copy(nd.getValue())); } } diff --git a/javascript/extractor/src/com/semmle/js/ast/StaticInitializer.java b/javascript/extractor/src/com/semmle/js/ast/StaticInitializer.java new file mode 100644 index 00000000000..d4287cd3f49 --- /dev/null +++ b/javascript/extractor/src/com/semmle/js/ast/StaticInitializer.java @@ -0,0 +1,21 @@ +package com.semmle.js.ast; + +/** + * A static initializer block in a class. E.g. ```TypeScript class Foo { static + * bar : number; static { Foo.bar = 42; } } + */ +public class StaticInitializer extends MemberDefinition { + public StaticInitializer(SourceLocation loc, BlockStatement body) { + super("StaticInitializer", loc, DeclarationFlags.static_, null, body); + } + + @Override + public boolean isConcrete() { + return false; + } + + @Override + public R accept(Visitor v, C c) { + return v.visit(this, c); + } +} diff --git a/javascript/extractor/src/com/semmle/js/ast/Visitor.java b/javascript/extractor/src/com/semmle/js/ast/Visitor.java index f7dfbd4e3aa..3d595b981b8 100644 --- a/javascript/extractor/src/com/semmle/js/ast/Visitor.java +++ b/javascript/extractor/src/com/semmle/js/ast/Visitor.java @@ -315,4 +315,6 @@ public interface Visitor { public R visit(XMLDotDotExpression nd, C c); public R visit(GeneratedCodeExpr generatedCodeExpr, C c); + + public R visit(StaticInitializer nd, C c); } diff --git a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java index 6796f262fef..158a33030a4 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java @@ -80,6 +80,7 @@ import com.semmle.js.ast.SourceElement; import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.SpreadElement; import com.semmle.js.ast.Statement; +import com.semmle.js.ast.StaticInitializer; import com.semmle.js.ast.Super; import com.semmle.js.ast.SwitchCase; import com.semmle.js.ast.SwitchStatement; @@ -1613,6 +1614,8 @@ public class ASTExtractor { int kind; if (nd instanceof MethodDefinition) { kind = getMethodKind((MethodDefinition) nd); + } else if (nd instanceof StaticInitializer) { + kind = 10; } else { kind = getFieldKind((FieldDefinition) nd); } diff --git a/javascript/extractor/src/com/semmle/js/extractor/CFGExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/CFGExtractor.java index 85dd13146fb..fa8452c0b43 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/CFGExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/CFGExtractor.java @@ -65,6 +65,7 @@ import com.semmle.js.ast.SequenceExpression; import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.SpreadElement; import com.semmle.js.ast.Statement; +import com.semmle.js.ast.StaticInitializer; import com.semmle.js.ast.Super; import com.semmle.js.ast.SwitchCase; import com.semmle.js.ast.SwitchStatement; @@ -1163,10 +1164,11 @@ public class CFGExtractor { private Map constructor2Class = new LinkedHashMap<>(); private Void visit(Node nd, AClass ac, SuccessorInfo i) { - for (MemberDefinition m : ac.getBody().getBody()) - if (m.isConstructor() && m.isConcrete()) constructor2Class.put(m.getValue(), ac); + for (MemberDefinition md : ac.getBody().getBody()) { + if (md.isConstructor() && md.isConcrete()) constructor2Class.put((Expression)md.getValue(), ac); + } visitSequence(ac.getId(), ac.getSuperClass(), ac.getBody(), nd); - writeSuccessors(nd, visitSequence(getStaticFields(ac.getBody()), getDecoratorsOfClass(ac), i.getAllSuccessors())); + writeSuccessors(nd, visitSequence(getStaticInitializers(ac.getBody()), getDecoratorsOfClass(ac), i.getAllSuccessors())); return null; } @@ -1618,19 +1620,24 @@ public class CFGExtractor { return mds; } - private List> getStaticFields(ClassBody nd) { - List> mds = new ArrayList<>(); - for (MemberDefinition md : nd.getBody()) { - if (md instanceof FieldDefinition && md.isStatic()) mds.add(md); + /** + * Gets the static fields, and static initializer blocks, from `nd`. + */ + private List getStaticInitializers(ClassBody nd) { + List nodes = new ArrayList<>(); + for (MemberDefinition node : nd.getBody()) { + if (node instanceof FieldDefinition && ((FieldDefinition)node).isStatic()) nodes.add(node); + if (node instanceof StaticInitializer) nodes.add(node.getValue()); } - return mds; + return nodes; } private List getConcreteInstanceFields(ClassBody nd) { List fds = new ArrayList<>(); - for (MemberDefinition md : nd.getBody()) + for (MemberDefinition md : nd.getBody()) { if (md instanceof FieldDefinition && !md.isStatic() && md.isConcrete()) fds.add((FieldDefinition) md); + } return fds; } diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java index a7c3074a64e..201f918f3e4 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -43,7 +43,7 @@ public class Main { * A version identifier that should be updated every time the extractor changes in such a way that * it may produce different tuples for the same file under the same {@link ExtractorConfig}. */ - public static final String EXTRACTOR_VERSION = "2021-07-28"; + public static final String EXTRACTOR_VERSION = "2021-09-01"; public static final Pattern NEWLINE = Pattern.compile("\n"); diff --git a/javascript/extractor/src/com/semmle/js/extractor/test/TrapTests.java b/javascript/extractor/src/com/semmle/js/extractor/test/TrapTests.java index 6f3f7e1e445..ae3a28cbc35 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/test/TrapTests.java +++ b/javascript/extractor/src/com/semmle/js/extractor/test/TrapTests.java @@ -11,6 +11,7 @@ import com.semmle.util.data.Pair; import com.semmle.util.data.StringUtil; import com.semmle.util.extraction.ExtractorOutputConfig; import com.semmle.util.io.WholeIO; +import com.semmle.util.process.Env; import com.semmle.util.srcarchive.DummySourceArchive; import com.semmle.util.trap.ITrapWriterFactory; import com.semmle.util.trap.TrapWriter; @@ -21,6 +22,7 @@ import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map.Entry; import org.junit.AfterClass; diff --git a/javascript/extractor/src/com/semmle/ts/extractor/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/ts/extractor/TypeScriptASTConverter.java index f8ad99915c9..affea7490a5 100644 --- a/javascript/extractor/src/com/semmle/ts/extractor/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/ts/extractor/TypeScriptASTConverter.java @@ -82,6 +82,7 @@ import com.semmle.js.ast.SequenceExpression; import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.SpreadElement; import com.semmle.js.ast.Statement; +import com.semmle.js.ast.StaticInitializer; import com.semmle.js.ast.Super; import com.semmle.js.ast.SwitchCase; import com.semmle.js.ast.SwitchStatement; @@ -632,6 +633,8 @@ public class TypeScriptASTConverter { return convertWithStatement(node, loc); case "YieldExpression": return convertYieldExpression(node, loc); + case "ClassStaticBlockDeclaration": + return convertStaticInitializerBlock(node, loc); default: throw new ParseError( "Unsupported TypeScript syntax " + kind, getSourceLocation(node).getStart()); @@ -866,6 +869,11 @@ public class TypeScriptASTConverter { } } + private Node convertStaticInitializerBlock(JsonObject node, SourceLocation loc) throws ParseError { + BlockStatement body = new BlockStatement(loc, convertChildren(node.get("body").getAsJsonObject(), "statements")); + return new StaticInitializer(loc, body); + } + private Node convertBlock(JsonObject node, SourceLocation loc) throws ParseError { return new BlockStatement(loc, convertChildren(node, "statements")); } diff --git a/javascript/extractor/tests/cfg/output/trap/classexpr1.js.trap b/javascript/extractor/tests/cfg/output/trap/classexpr1.js.trap index 29641d5961c..36170d46ce6 100644 --- a/javascript/extractor/tests/cfg/output/trap/classexpr1.js.trap +++ b/javascript/extractor/tests/cfg/output/trap/classexpr1.js.trap @@ -1,7 +1,7 @@ #10000=@"/classexpr1.js;sourcefile" -files(#10000,"/classexpr1.js","classexpr1","js",0) +files(#10000,"/classexpr1.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/cfg/output/trap/classexpr2.js.trap b/javascript/extractor/tests/cfg/output/trap/classexpr2.js.trap index d5d9b6aafc8..7dcf1ca7625 100644 --- a/javascript/extractor/tests/cfg/output/trap/classexpr2.js.trap +++ b/javascript/extractor/tests/cfg/output/trap/classexpr2.js.trap @@ -1,7 +1,7 @@ #10000=@"/classexpr2.js;sourcefile" -files(#10000,"/classexpr2.js","classexpr2","js",0) +files(#10000,"/classexpr2.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/cfg/output/trap/classexpr3.js.trap b/javascript/extractor/tests/cfg/output/trap/classexpr3.js.trap index 936c7c58180..4e7d7c4ea30 100644 --- a/javascript/extractor/tests/cfg/output/trap/classexpr3.js.trap +++ b/javascript/extractor/tests/cfg/output/trap/classexpr3.js.trap @@ -1,7 +1,7 @@ #10000=@"/classexpr3.js;sourcefile" -files(#10000,"/classexpr3.js","classexpr3","js",0) +files(#10000,"/classexpr3.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/cfg/output/trap/classexpr4.js.trap b/javascript/extractor/tests/cfg/output/trap/classexpr4.js.trap index a7f654473b3..db4c964d45e 100644 --- a/javascript/extractor/tests/cfg/output/trap/classexpr4.js.trap +++ b/javascript/extractor/tests/cfg/output/trap/classexpr4.js.trap @@ -1,7 +1,7 @@ #10000=@"/classexpr4.js;sourcefile" -files(#10000,"/classexpr4.js","classexpr4","js",0) +files(#10000,"/classexpr4.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/cfg/output/trap/fields.js.trap b/javascript/extractor/tests/cfg/output/trap/fields.js.trap index 14486f99c7e..a1892dea841 100644 --- a/javascript/extractor/tests/cfg/output/trap/fields.js.trap +++ b/javascript/extractor/tests/cfg/output/trap/fields.js.trap @@ -1,7 +1,7 @@ #10000=@"/fields.js;sourcefile" -files(#10000,"/fields.js","fields","js",0) +files(#10000,"/fields.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/cfg/output/trap/seq.js.trap b/javascript/extractor/tests/cfg/output/trap/seq.js.trap index bf660301f8e..e9aee318c82 100644 --- a/javascript/extractor/tests/cfg/output/trap/seq.js.trap +++ b/javascript/extractor/tests/cfg/output/trap/seq.js.trap @@ -1,7 +1,7 @@ #10000=@"/seq.js;sourcefile" -files(#10000,"/seq.js","seq","js",0) +files(#10000,"/seq.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/cfg/output/trap/short-circuit.js.trap b/javascript/extractor/tests/cfg/output/trap/short-circuit.js.trap index 563d7c3a428..63e56bb5c49 100644 --- a/javascript/extractor/tests/cfg/output/trap/short-circuit.js.trap +++ b/javascript/extractor/tests/cfg/output/trap/short-circuit.js.trap @@ -1,7 +1,7 @@ #10000=@"/short-circuit.js;sourcefile" -files(#10000,"/short-circuit.js","short-circuit","js",0) +files(#10000,"/short-circuit.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/cfg/output/trap/ternary.js.trap b/javascript/extractor/tests/cfg/output/trap/ternary.js.trap index 7b534184219..57230ac39cd 100644 --- a/javascript/extractor/tests/cfg/output/trap/ternary.js.trap +++ b/javascript/extractor/tests/cfg/output/trap/ternary.js.trap @@ -1,7 +1,7 @@ #10000=@"/ternary.js;sourcefile" -files(#10000,"/ternary.js","ternary","js",0) +files(#10000,"/ternary.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/cfg/output/trap/tst.js.trap b/javascript/extractor/tests/cfg/output/trap/tst.js.trap index c857f564069..7f7fc1ea383 100644 --- a/javascript/extractor/tests/cfg/output/trap/tst.js.trap +++ b/javascript/extractor/tests/cfg/output/trap/tst.js.trap @@ -1,7 +1,7 @@ #10000=@"/tst.js;sourcefile" -files(#10000,"/tst.js","tst","js",0) +files(#10000,"/tst.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/closure/output/trap/googDotDeclareModuleId.js.trap b/javascript/extractor/tests/closure/output/trap/googDotDeclareModuleId.js.trap index 64d67a4e74b..09719bdae19 100644 --- a/javascript/extractor/tests/closure/output/trap/googDotDeclareModuleId.js.trap +++ b/javascript/extractor/tests/closure/output/trap/googDotDeclareModuleId.js.trap @@ -1,7 +1,7 @@ #10000=@"/googDotDeclareModuleId.js;sourcefile" -files(#10000,"/googDotDeclareModuleId.js","googDotDeclareModuleId","js",0) +files(#10000,"/googDotDeclareModuleId.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/closure/output/trap/googDotModule.js.trap b/javascript/extractor/tests/closure/output/trap/googDotModule.js.trap index 55558520eb4..c38628f6a37 100644 --- a/javascript/extractor/tests/closure/output/trap/googDotModule.js.trap +++ b/javascript/extractor/tests/closure/output/trap/googDotModule.js.trap @@ -1,7 +1,7 @@ #10000=@"/googDotModule.js;sourcefile" -files(#10000,"/googDotModule.js","googDotModule","js",0) +files(#10000,"/googDotModule.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/closure/output/trap/googDotProvide.js.trap b/javascript/extractor/tests/closure/output/trap/googDotProvide.js.trap index 10a4d03bcfa..99979f50c2c 100644 --- a/javascript/extractor/tests/closure/output/trap/googDotProvide.js.trap +++ b/javascript/extractor/tests/closure/output/trap/googDotProvide.js.trap @@ -1,7 +1,7 @@ #10000=@"/googDotProvide.js;sourcefile" -files(#10000,"/googDotProvide.js","googDotProvide","js",0) +files(#10000,"/googDotProvide.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/comments/output/trap/comments.js.trap b/javascript/extractor/tests/comments/output/trap/comments.js.trap index 279e1aaba17..79a199f90ec 100644 --- a/javascript/extractor/tests/comments/output/trap/comments.js.trap +++ b/javascript/extractor/tests/comments/output/trap/comments.js.trap @@ -1,7 +1,7 @@ #10000=@"/comments.js;sourcefile" -files(#10000,"/comments.js","comments","js",0) +files(#10000,"/comments.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/comments/output/trap/empty_comment.js.trap b/javascript/extractor/tests/comments/output/trap/empty_comment.js.trap index b90f89ab061..51e9652b166 100644 --- a/javascript/extractor/tests/comments/output/trap/empty_comment.js.trap +++ b/javascript/extractor/tests/comments/output/trap/empty_comment.js.trap @@ -1,7 +1,7 @@ #10000=@"/empty_comment.js;sourcefile" -files(#10000,"/empty_comment.js","empty_comment","js",0) +files(#10000,"/empty_comment.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/comments/output/trap/jsdoc.js.trap b/javascript/extractor/tests/comments/output/trap/jsdoc.js.trap index f6e797abd13..736a6b2d19f 100644 --- a/javascript/extractor/tests/comments/output/trap/jsdoc.js.trap +++ b/javascript/extractor/tests/comments/output/trap/jsdoc.js.trap @@ -1,7 +1,7 @@ #10000=@"/jsdoc.js;sourcefile" -files(#10000,"/jsdoc.js","jsdoc","js",0) +files(#10000,"/jsdoc.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/default-encoding/output/trap/latin1.js.trap b/javascript/extractor/tests/default-encoding/output/trap/latin1.js.trap index 305d467baa2..1b2c513def0 100644 --- a/javascript/extractor/tests/default-encoding/output/trap/latin1.js.trap +++ b/javascript/extractor/tests/default-encoding/output/trap/latin1.js.trap @@ -1,7 +1,7 @@ #10000=@"/latin1.js;sourcefile" -files(#10000,"/latin1.js","latin1","js",0) +files(#10000,"/latin1.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/e4x/output/trap/regress.js.trap b/javascript/extractor/tests/e4x/output/trap/regress.js.trap index 42830ffef1d..1f14daae973 100644 --- a/javascript/extractor/tests/e4x/output/trap/regress.js.trap +++ b/javascript/extractor/tests/e4x/output/trap/regress.js.trap @@ -1,7 +1,7 @@ #10000=@"/regress.js;sourcefile" -files(#10000,"/regress.js","regress","js",0) +files(#10000,"/regress.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/e4x/output/trap/tst.js.trap b/javascript/extractor/tests/e4x/output/trap/tst.js.trap index 518cde0ecb8..a9636dd5fa4 100644 --- a/javascript/extractor/tests/e4x/output/trap/tst.js.trap +++ b/javascript/extractor/tests/e4x/output/trap/tst.js.trap @@ -1,7 +1,7 @@ #10000=@"/tst.js;sourcefile" -files(#10000,"/tst.js","tst","js",0) +files(#10000,"/tst.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/encoding/output/trap/surrogates.js.trap b/javascript/extractor/tests/encoding/output/trap/surrogates.js.trap index 47fdcdd7f8e..1e83bf1920e 100644 --- a/javascript/extractor/tests/encoding/output/trap/surrogates.js.trap +++ b/javascript/extractor/tests/encoding/output/trap/surrogates.js.trap @@ -1,7 +1,7 @@ #10000=@"/surrogates.js;sourcefile" -files(#10000,"/surrogates.js","surrogates","js",0) +files(#10000,"/surrogates.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/encoding/output/trap/unicode.js.trap b/javascript/extractor/tests/encoding/output/trap/unicode.js.trap index 1f4bf71cbb8..e30e1de8143 100644 --- a/javascript/extractor/tests/encoding/output/trap/unicode.js.trap +++ b/javascript/extractor/tests/encoding/output/trap/unicode.js.trap @@ -1,7 +1,7 @@ #10000=@"/unicode.js;sourcefile" -files(#10000,"/unicode.js","unicode","js",0) +files(#10000,"/unicode.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/encoding/output/trap/zwsp.js.trap b/javascript/extractor/tests/encoding/output/trap/zwsp.js.trap index f74356384ba..c9bab7a017d 100644 --- a/javascript/extractor/tests/encoding/output/trap/zwsp.js.trap +++ b/javascript/extractor/tests/encoding/output/trap/zwsp.js.trap @@ -1,7 +1,7 @@ #10000=@"/zwsp.js;sourcefile" -files(#10000,"/zwsp.js","zwsp","js",0) +files(#10000,"/zwsp.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/errors/output/trap/empty.js.trap b/javascript/extractor/tests/errors/output/trap/empty.js.trap index 977fc8c44af..c686cd023f4 100644 --- a/javascript/extractor/tests/errors/output/trap/empty.js.trap +++ b/javascript/extractor/tests/errors/output/trap/empty.js.trap @@ -1,7 +1,7 @@ #10000=@"/empty.js;sourcefile" -files(#10000,"/empty.js","empty","js",0) +files(#10000,"/empty.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/errors/output/trap/errors.js.trap b/javascript/extractor/tests/errors/output/trap/errors.js.trap index 56265a4cceb..87858ae4846 100644 --- a/javascript/extractor/tests/errors/output/trap/errors.js.trap +++ b/javascript/extractor/tests/errors/output/trap/errors.js.trap @@ -1,7 +1,7 @@ #10000=@"/errors.js;sourcefile" -files(#10000,"/errors.js","errors","js",0) +files(#10000,"/errors.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/errors/output/trap/incomplete.js.trap b/javascript/extractor/tests/errors/output/trap/incomplete.js.trap index 3e950d57691..5a8c0ad2f36 100644 --- a/javascript/extractor/tests/errors/output/trap/incomplete.js.trap +++ b/javascript/extractor/tests/errors/output/trap/incomplete.js.trap @@ -1,7 +1,7 @@ #10000=@"/incomplete.js;sourcefile" -files(#10000,"/incomplete.js","incomplete","js",0) +files(#10000,"/incomplete.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/errors/output/trap/invalid-assignment-pattern.js.trap b/javascript/extractor/tests/errors/output/trap/invalid-assignment-pattern.js.trap index 4d01e4e9373..108c822691b 100644 --- a/javascript/extractor/tests/errors/output/trap/invalid-assignment-pattern.js.trap +++ b/javascript/extractor/tests/errors/output/trap/invalid-assignment-pattern.js.trap @@ -1,7 +1,7 @@ #10000=@"/invalid-assignment-pattern.js;sourcefile" -files(#10000,"/invalid-assignment-pattern.js","invalid-assignment-pattern","js",0) +files(#10000,"/invalid-assignment-pattern.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/errors/output/trap/json.js.trap b/javascript/extractor/tests/errors/output/trap/json.js.trap index c0762090623..66eeec6d36a 100644 --- a/javascript/extractor/tests/errors/output/trap/json.js.trap +++ b/javascript/extractor/tests/errors/output/trap/json.js.trap @@ -1,7 +1,7 @@ #10000=@"/json.js;sourcefile" -files(#10000,"/json.js","json","js",0) +files(#10000,"/json.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/errors/output/trap/kwident.js.trap b/javascript/extractor/tests/errors/output/trap/kwident.js.trap index 14d3767ff8a..10b0e9ec392 100644 --- a/javascript/extractor/tests/errors/output/trap/kwident.js.trap +++ b/javascript/extractor/tests/errors/output/trap/kwident.js.trap @@ -1,7 +1,7 @@ #10000=@"/kwident.js;sourcefile" -files(#10000,"/kwident.js","kwident","js",0) +files(#10000,"/kwident.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/errors/output/trap/weirdassign.js.trap b/javascript/extractor/tests/errors/output/trap/weirdassign.js.trap index 9569931fc2a..314caccacae 100644 --- a/javascript/extractor/tests/errors/output/trap/weirdassign.js.trap +++ b/javascript/extractor/tests/errors/output/trap/weirdassign.js.trap @@ -1,7 +1,7 @@ #10000=@"/weirdassign.js;sourcefile" -files(#10000,"/weirdassign.js","weirdassign","js",0) +files(#10000,"/weirdassign.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/array_pattern_with_default.js.trap b/javascript/extractor/tests/es2015/output/trap/array_pattern_with_default.js.trap index 590dd38c38f..2351f1fa347 100644 --- a/javascript/extractor/tests/es2015/output/trap/array_pattern_with_default.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/array_pattern_with_default.js.trap @@ -1,7 +1,7 @@ #10000=@"/array_pattern_with_default.js;sourcefile" -files(#10000,"/array_pattern_with_default.js","array_pattern_with_default","js",0) +files(#10000,"/array_pattern_with_default.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/array_pattern_with_rest.js.trap b/javascript/extractor/tests/es2015/output/trap/array_pattern_with_rest.js.trap index db47ff2def7..7f8c2257eee 100644 --- a/javascript/extractor/tests/es2015/output/trap/array_pattern_with_rest.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/array_pattern_with_rest.js.trap @@ -1,7 +1,7 @@ #10000=@"/array_pattern_with_rest.js;sourcefile" -files(#10000,"/array_pattern_with_rest.js","array_pattern_with_rest","js",0) +files(#10000,"/array_pattern_with_rest.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/arrowfn.js.trap b/javascript/extractor/tests/es2015/output/trap/arrowfn.js.trap index 8224e9c70ad..44fe9bba129 100644 --- a/javascript/extractor/tests/es2015/output/trap/arrowfn.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/arrowfn.js.trap @@ -1,7 +1,7 @@ #10000=@"/arrowfn.js;sourcefile" -files(#10000,"/arrowfn.js","arrowfn","js",0) +files(#10000,"/arrowfn.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/class_accessors.js.trap b/javascript/extractor/tests/es2015/output/trap/class_accessors.js.trap index 87381be5e25..5c5c137c72d 100644 --- a/javascript/extractor/tests/es2015/output/trap/class_accessors.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/class_accessors.js.trap @@ -1,7 +1,7 @@ #10000=@"/class_accessors.js;sourcefile" -files(#10000,"/class_accessors.js","class_accessors","js",0) +files(#10000,"/class_accessors.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/class_ctor.js.trap b/javascript/extractor/tests/es2015/output/trap/class_ctor.js.trap index 834f78bc437..6ee7194f2b3 100644 --- a/javascript/extractor/tests/es2015/output/trap/class_ctor.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/class_ctor.js.trap @@ -1,7 +1,7 @@ #10000=@"/class_ctor.js;sourcefile" -files(#10000,"/class_ctor.js","class_ctor","js",0) +files(#10000,"/class_ctor.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/class_extends.js.trap b/javascript/extractor/tests/es2015/output/trap/class_extends.js.trap index c97a4abe506..8c15a580955 100644 --- a/javascript/extractor/tests/es2015/output/trap/class_extends.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/class_extends.js.trap @@ -1,7 +1,7 @@ #10000=@"/class_extends.js;sourcefile" -files(#10000,"/class_extends.js","class_extends","js",0) +files(#10000,"/class_extends.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/class_extends2.js.trap b/javascript/extractor/tests/es2015/output/trap/class_extends2.js.trap index d63cd3de396..faa9e6abbec 100644 --- a/javascript/extractor/tests/es2015/output/trap/class_extends2.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/class_extends2.js.trap @@ -1,7 +1,7 @@ #10000=@"/class_extends2.js;sourcefile" -files(#10000,"/class_extends2.js","class_extends2","js",0) +files(#10000,"/class_extends2.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/class_method.js.trap b/javascript/extractor/tests/es2015/output/trap/class_method.js.trap index 31fcacadab9..d0ccaee9508 100644 --- a/javascript/extractor/tests/es2015/output/trap/class_method.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/class_method.js.trap @@ -1,7 +1,7 @@ #10000=@"/class_method.js;sourcefile" -files(#10000,"/class_method.js","class_method","js",0) +files(#10000,"/class_method.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/class_static.js.trap b/javascript/extractor/tests/es2015/output/trap/class_static.js.trap index 74f7752d617..5c0d8f20d87 100644 --- a/javascript/extractor/tests/es2015/output/trap/class_static.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/class_static.js.trap @@ -1,7 +1,7 @@ #10000=@"/class_static.js;sourcefile" -files(#10000,"/class_static.js","class_static","js",0) +files(#10000,"/class_static.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/classdecl.js.trap b/javascript/extractor/tests/es2015/output/trap/classdecl.js.trap index b5617754b33..e5a40dab400 100644 --- a/javascript/extractor/tests/es2015/output/trap/classdecl.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/classdecl.js.trap @@ -1,7 +1,7 @@ #10000=@"/classdecl.js;sourcefile" -files(#10000,"/classdecl.js","classdecl","js",0) +files(#10000,"/classdecl.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/classexpr.js.trap b/javascript/extractor/tests/es2015/output/trap/classexpr.js.trap index 839909db531..ad02e4ce6e3 100644 --- a/javascript/extractor/tests/es2015/output/trap/classexpr.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/classexpr.js.trap @@ -1,7 +1,7 @@ #10000=@"/classexpr.js;sourcefile" -files(#10000,"/classexpr.js","classexpr","js",0) +files(#10000,"/classexpr.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/classexpr2.js.trap b/javascript/extractor/tests/es2015/output/trap/classexpr2.js.trap index 8bb09ea4bb9..0380ce770f4 100644 --- a/javascript/extractor/tests/es2015/output/trap/classexpr2.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/classexpr2.js.trap @@ -1,7 +1,7 @@ #10000=@"/classexpr2.js;sourcefile" -files(#10000,"/classexpr2.js","classexpr2","js",0) +files(#10000,"/classexpr2.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/complex_array_pattern.js.trap b/javascript/extractor/tests/es2015/output/trap/complex_array_pattern.js.trap index 1a8e3663ffd..2d46f91bfbb 100644 --- a/javascript/extractor/tests/es2015/output/trap/complex_array_pattern.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/complex_array_pattern.js.trap @@ -1,7 +1,7 @@ #10000=@"/complex_array_pattern.js;sourcefile" -files(#10000,"/complex_array_pattern.js","complex_array_pattern","js",0) +files(#10000,"/complex_array_pattern.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/complex_object_pattern.js.trap b/javascript/extractor/tests/es2015/output/trap/complex_object_pattern.js.trap index 3eb51acea42..aff5d4f9957 100644 --- a/javascript/extractor/tests/es2015/output/trap/complex_object_pattern.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/complex_object_pattern.js.trap @@ -1,7 +1,7 @@ #10000=@"/complex_object_pattern.js;sourcefile" -files(#10000,"/complex_object_pattern.js","complex_object_pattern","js",0) +files(#10000,"/complex_object_pattern.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/const.js.trap b/javascript/extractor/tests/es2015/output/trap/const.js.trap index 54080375486..08a72521d89 100644 --- a/javascript/extractor/tests/es2015/output/trap/const.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/const.js.trap @@ -1,7 +1,7 @@ #10000=@"/const.js;sourcefile" -files(#10000,"/const.js","const","js",0) +files(#10000,"/const.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/defaultargs.js.trap b/javascript/extractor/tests/es2015/output/trap/defaultargs.js.trap index c6303460489..00a6d7b38a5 100644 --- a/javascript/extractor/tests/es2015/output/trap/defaultargs.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/defaultargs.js.trap @@ -1,7 +1,7 @@ #10000=@"/defaultargs.js;sourcefile" -files(#10000,"/defaultargs.js","defaultargs","js",0) +files(#10000,"/defaultargs.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/delegating_yield.js.trap b/javascript/extractor/tests/es2015/output/trap/delegating_yield.js.trap index beb491f7738..6106dff7bdc 100644 --- a/javascript/extractor/tests/es2015/output/trap/delegating_yield.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/delegating_yield.js.trap @@ -1,7 +1,7 @@ #10000=@"/delegating_yield.js;sourcefile" -files(#10000,"/delegating_yield.js","delegating_yield","js",0) +files(#10000,"/delegating_yield.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/destructuring.js.trap b/javascript/extractor/tests/es2015/output/trap/destructuring.js.trap index 4021fd51b95..6f4bc769f19 100644 --- a/javascript/extractor/tests/es2015/output/trap/destructuring.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/destructuring.js.trap @@ -1,7 +1,7 @@ #10000=@"/destructuring.js;sourcefile" -files(#10000,"/destructuring.js","destructuring","js",0) +files(#10000,"/destructuring.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/export1.js.trap b/javascript/extractor/tests/es2015/output/trap/export1.js.trap index cf5eb993956..c1a7da9c4f4 100644 --- a/javascript/extractor/tests/es2015/output/trap/export1.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/export1.js.trap @@ -1,7 +1,7 @@ #10000=@"/export1.js;sourcefile" -files(#10000,"/export1.js","export1","js",0) +files(#10000,"/export1.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/export10.js.trap b/javascript/extractor/tests/es2015/output/trap/export10.js.trap index 38eb62634e4..518cb55c45c 100644 --- a/javascript/extractor/tests/es2015/output/trap/export10.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/export10.js.trap @@ -1,7 +1,7 @@ #10000=@"/export10.js;sourcefile" -files(#10000,"/export10.js","export10","js",0) +files(#10000,"/export10.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/export11.js.trap b/javascript/extractor/tests/es2015/output/trap/export11.js.trap index 05d580a2cdc..57c45f044a1 100644 --- a/javascript/extractor/tests/es2015/output/trap/export11.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/export11.js.trap @@ -1,7 +1,7 @@ #10000=@"/export11.js;sourcefile" -files(#10000,"/export11.js","export11","js",0) +files(#10000,"/export11.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/export2.js.trap b/javascript/extractor/tests/es2015/output/trap/export2.js.trap index 90c95bae4d0..27a07ed5c9e 100644 --- a/javascript/extractor/tests/es2015/output/trap/export2.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/export2.js.trap @@ -1,7 +1,7 @@ #10000=@"/export2.js;sourcefile" -files(#10000,"/export2.js","export2","js",0) +files(#10000,"/export2.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/export3.js.trap b/javascript/extractor/tests/es2015/output/trap/export3.js.trap index 01d09fe4d99..df259c34824 100644 --- a/javascript/extractor/tests/es2015/output/trap/export3.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/export3.js.trap @@ -1,7 +1,7 @@ #10000=@"/export3.js;sourcefile" -files(#10000,"/export3.js","export3","js",0) +files(#10000,"/export3.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/export4.js.trap b/javascript/extractor/tests/es2015/output/trap/export4.js.trap index ef826aaaf27..50a6952b59e 100644 --- a/javascript/extractor/tests/es2015/output/trap/export4.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/export4.js.trap @@ -1,7 +1,7 @@ #10000=@"/export4.js;sourcefile" -files(#10000,"/export4.js","export4","js",0) +files(#10000,"/export4.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/export5.js.trap b/javascript/extractor/tests/es2015/output/trap/export5.js.trap index 91989e69a7c..861ea6d12c1 100644 --- a/javascript/extractor/tests/es2015/output/trap/export5.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/export5.js.trap @@ -1,7 +1,7 @@ #10000=@"/export5.js;sourcefile" -files(#10000,"/export5.js","export5","js",0) +files(#10000,"/export5.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/export6.js.trap b/javascript/extractor/tests/es2015/output/trap/export6.js.trap index 9084fcda400..58381bfa820 100644 --- a/javascript/extractor/tests/es2015/output/trap/export6.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/export6.js.trap @@ -1,7 +1,7 @@ #10000=@"/export6.js;sourcefile" -files(#10000,"/export6.js","export6","js",0) +files(#10000,"/export6.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/export7.js.trap b/javascript/extractor/tests/es2015/output/trap/export7.js.trap index 5fe587f6dac..37370b5d502 100644 --- a/javascript/extractor/tests/es2015/output/trap/export7.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/export7.js.trap @@ -1,7 +1,7 @@ #10000=@"/export7.js;sourcefile" -files(#10000,"/export7.js","export7","js",0) +files(#10000,"/export7.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/export8.js.trap b/javascript/extractor/tests/es2015/output/trap/export8.js.trap index 6a38455df42..d79edbb8826 100644 --- a/javascript/extractor/tests/es2015/output/trap/export8.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/export8.js.trap @@ -1,7 +1,7 @@ #10000=@"/export8.js;sourcefile" -files(#10000,"/export8.js","export8","js",0) +files(#10000,"/export8.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/export9.js.trap b/javascript/extractor/tests/es2015/output/trap/export9.js.trap index 538bff491c5..7bfdace6530 100644 --- a/javascript/extractor/tests/es2015/output/trap/export9.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/export9.js.trap @@ -1,7 +1,7 @@ #10000=@"/export9.js;sourcefile" -files(#10000,"/export9.js","export9","js",0) +files(#10000,"/export9.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/forof.js.trap b/javascript/extractor/tests/es2015/output/trap/forof.js.trap index f0e1ea6a103..12ea8980cab 100644 --- a/javascript/extractor/tests/es2015/output/trap/forof.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/forof.js.trap @@ -1,7 +1,7 @@ #10000=@"/forof.js;sourcefile" -files(#10000,"/forof.js","forof","js",0) +files(#10000,"/forof.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/import1.js.trap b/javascript/extractor/tests/es2015/output/trap/import1.js.trap index 7be30f7c51b..b02b3375bba 100644 --- a/javascript/extractor/tests/es2015/output/trap/import1.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/import1.js.trap @@ -1,7 +1,7 @@ #10000=@"/import1.js;sourcefile" -files(#10000,"/import1.js","import1","js",0) +files(#10000,"/import1.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/import2.js.trap b/javascript/extractor/tests/es2015/output/trap/import2.js.trap index 2f0d9245d97..360b201cdc8 100644 --- a/javascript/extractor/tests/es2015/output/trap/import2.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/import2.js.trap @@ -1,7 +1,7 @@ #10000=@"/import2.js;sourcefile" -files(#10000,"/import2.js","import2","js",0) +files(#10000,"/import2.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/import3.js.trap b/javascript/extractor/tests/es2015/output/trap/import3.js.trap index c072fb40b7d..5d2c1a7c676 100644 --- a/javascript/extractor/tests/es2015/output/trap/import3.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/import3.js.trap @@ -1,7 +1,7 @@ #10000=@"/import3.js;sourcefile" -files(#10000,"/import3.js","import3","js",0) +files(#10000,"/import3.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/import4.js.trap b/javascript/extractor/tests/es2015/output/trap/import4.js.trap index 388e12fdef2..3d0694f2e03 100644 --- a/javascript/extractor/tests/es2015/output/trap/import4.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/import4.js.trap @@ -1,7 +1,7 @@ #10000=@"/import4.js;sourcefile" -files(#10000,"/import4.js","import4","js",0) +files(#10000,"/import4.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/import5.js.trap b/javascript/extractor/tests/es2015/output/trap/import5.js.trap index f4acf84ddfa..a410731eff4 100644 --- a/javascript/extractor/tests/es2015/output/trap/import5.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/import5.js.trap @@ -1,7 +1,7 @@ #10000=@"/import5.js;sourcefile" -files(#10000,"/import5.js","import5","js",0) +files(#10000,"/import5.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/import6.js.trap b/javascript/extractor/tests/es2015/output/trap/import6.js.trap index 40ae625b9f9..429035fa6ed 100644 --- a/javascript/extractor/tests/es2015/output/trap/import6.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/import6.js.trap @@ -1,7 +1,7 @@ #10000=@"/import6.js;sourcefile" -files(#10000,"/import6.js","import6","js",0) +files(#10000,"/import6.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/import7.js.trap b/javascript/extractor/tests/es2015/output/trap/import7.js.trap index c5174514a8f..315afa6d01b 100644 --- a/javascript/extractor/tests/es2015/output/trap/import7.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/import7.js.trap @@ -1,7 +1,7 @@ #10000=@"/import7.js;sourcefile" -files(#10000,"/import7.js","import7","js",0) +files(#10000,"/import7.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/let.js.trap b/javascript/extractor/tests/es2015/output/trap/let.js.trap index 674da07ba56..d02c8e0bd8d 100644 --- a/javascript/extractor/tests/es2015/output/trap/let.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/let.js.trap @@ -1,7 +1,7 @@ #10000=@"/let.js;sourcefile" -files(#10000,"/let.js","let","js",0) +files(#10000,"/let.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/let2.js.trap b/javascript/extractor/tests/es2015/output/trap/let2.js.trap index e04ee0bfa8a..a05cddac410 100644 --- a/javascript/extractor/tests/es2015/output/trap/let2.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/let2.js.trap @@ -1,7 +1,7 @@ #10000=@"/let2.js;sourcefile" -files(#10000,"/let2.js","let2","js",0) +files(#10000,"/let2.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/nested_import.js.trap b/javascript/extractor/tests/es2015/output/trap/nested_import.js.trap index f60d33bd0c9..8542482671d 100644 --- a/javascript/extractor/tests/es2015/output/trap/nested_import.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/nested_import.js.trap @@ -1,7 +1,7 @@ #10000=@"/nested_import.js;sourcefile" -files(#10000,"/nested_import.js","nested_import","js",0) +files(#10000,"/nested_import.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/new_target.js.trap b/javascript/extractor/tests/es2015/output/trap/new_target.js.trap index d716cf44fdb..4635fe2e09c 100644 --- a/javascript/extractor/tests/es2015/output/trap/new_target.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/new_target.js.trap @@ -1,7 +1,7 @@ #10000=@"/new_target.js;sourcefile" -files(#10000,"/new_target.js","new_target","js",0) +files(#10000,"/new_target.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/no-substitution.js.trap b/javascript/extractor/tests/es2015/output/trap/no-substitution.js.trap index 5f56469bb45..b7c9df13a7f 100644 --- a/javascript/extractor/tests/es2015/output/trap/no-substitution.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/no-substitution.js.trap @@ -1,7 +1,7 @@ #10000=@"/no-substitution.js;sourcefile" -files(#10000,"/no-substitution.js","no-substitution","js",0) +files(#10000,"/no-substitution.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/nullMethodName.js.trap b/javascript/extractor/tests/es2015/output/trap/nullMethodName.js.trap index 6988ef14232..21547848299 100644 --- a/javascript/extractor/tests/es2015/output/trap/nullMethodName.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/nullMethodName.js.trap @@ -1,7 +1,7 @@ #10000=@"/nullMethodName.js;sourcefile" -files(#10000,"/nullMethodName.js","nullMethodName","js",0) +files(#10000,"/nullMethodName.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/odasa-2593.js.trap b/javascript/extractor/tests/es2015/output/trap/odasa-2593.js.trap index 3e46083ca86..23711b8d6e3 100644 --- a/javascript/extractor/tests/es2015/output/trap/odasa-2593.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/odasa-2593.js.trap @@ -1,7 +1,7 @@ #10000=@"/odasa-2593.js;sourcefile" -files(#10000,"/odasa-2593.js","odasa-2593","js",0) +files(#10000,"/odasa-2593.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/properties.js.trap b/javascript/extractor/tests/es2015/output/trap/properties.js.trap index ab37310808a..bcc637655b3 100644 --- a/javascript/extractor/tests/es2015/output/trap/properties.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/properties.js.trap @@ -1,7 +1,7 @@ #10000=@"/properties.js;sourcefile" -files(#10000,"/properties.js","properties","js",0) +files(#10000,"/properties.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/property_pattern_with_default.js.trap b/javascript/extractor/tests/es2015/output/trap/property_pattern_with_default.js.trap index ce82f7c7e51..2cc1015094f 100644 --- a/javascript/extractor/tests/es2015/output/trap/property_pattern_with_default.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/property_pattern_with_default.js.trap @@ -1,7 +1,7 @@ #10000=@"/property_pattern_with_default.js;sourcefile" -files(#10000,"/property_pattern_with_default.js","property_pattern_with_default","js",0) +files(#10000,"/property_pattern_with_default.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/restparms.js.trap b/javascript/extractor/tests/es2015/output/trap/restparms.js.trap index 8a848b74cd7..627aaa15bcb 100644 --- a/javascript/extractor/tests/es2015/output/trap/restparms.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/restparms.js.trap @@ -1,7 +1,7 @@ #10000=@"/restparms.js;sourcefile" -files(#10000,"/restparms.js","restparms","js",0) +files(#10000,"/restparms.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/restparms2.js.trap b/javascript/extractor/tests/es2015/output/trap/restparms2.js.trap index d1ace3d0446..e6faa776dd5 100644 --- a/javascript/extractor/tests/es2015/output/trap/restparms2.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/restparms2.js.trap @@ -1,7 +1,7 @@ #10000=@"/restparms2.js;sourcefile" -files(#10000,"/restparms2.js","restparms2","js",0) +files(#10000,"/restparms2.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/spreadelement.js.trap b/javascript/extractor/tests/es2015/output/trap/spreadelement.js.trap index 05311f206ff..8c5c7723280 100644 --- a/javascript/extractor/tests/es2015/output/trap/spreadelement.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/spreadelement.js.trap @@ -1,7 +1,7 @@ #10000=@"/spreadelement.js;sourcefile" -files(#10000,"/spreadelement.js","spreadelement","js",0) +files(#10000,"/spreadelement.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/super_call.js.trap b/javascript/extractor/tests/es2015/output/trap/super_call.js.trap index 3580b430c07..e92324e4b75 100644 --- a/javascript/extractor/tests/es2015/output/trap/super_call.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/super_call.js.trap @@ -1,7 +1,7 @@ #10000=@"/super_call.js;sourcefile" -files(#10000,"/super_call.js","super_call","js",0) +files(#10000,"/super_call.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/super_ctor.js.trap b/javascript/extractor/tests/es2015/output/trap/super_ctor.js.trap index c4cdbb2b941..e96ad048d60 100644 --- a/javascript/extractor/tests/es2015/output/trap/super_ctor.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/super_ctor.js.trap @@ -1,7 +1,7 @@ #10000=@"/super_ctor.js;sourcefile" -files(#10000,"/super_ctor.js","super_ctor","js",0) +files(#10000,"/super_ctor.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/templates.js.trap b/javascript/extractor/tests/es2015/output/trap/templates.js.trap index 9926e3c42cd..452ac61c6f5 100644 --- a/javascript/extractor/tests/es2015/output/trap/templates.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/templates.js.trap @@ -1,7 +1,7 @@ #10000=@"/templates.js;sourcefile" -files(#10000,"/templates.js","templates","js",0) +files(#10000,"/templates.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/unknown_meta_property.js.trap b/javascript/extractor/tests/es2015/output/trap/unknown_meta_property.js.trap index abaddc6dba2..7599d6eb87e 100644 --- a/javascript/extractor/tests/es2015/output/trap/unknown_meta_property.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/unknown_meta_property.js.trap @@ -1,7 +1,7 @@ #10000=@"/unknown_meta_property.js;sourcefile" -files(#10000,"/unknown_meta_property.js","unknown_meta_property","js",0) +files(#10000,"/unknown_meta_property.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/yield.js.trap b/javascript/extractor/tests/es2015/output/trap/yield.js.trap index 569bd957de7..6ebac9325d2 100644 --- a/javascript/extractor/tests/es2015/output/trap/yield.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/yield.js.trap @@ -1,7 +1,7 @@ #10000=@"/yield.js;sourcefile" -files(#10000,"/yield.js","yield","js",0) +files(#10000,"/yield.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2015/output/trap/yield2.js.trap b/javascript/extractor/tests/es2015/output/trap/yield2.js.trap index 6316227a2e3..70a3c2464f1 100644 --- a/javascript/extractor/tests/es2015/output/trap/yield2.js.trap +++ b/javascript/extractor/tests/es2015/output/trap/yield2.js.trap @@ -1,7 +1,7 @@ #10000=@"/yield2.js;sourcefile" -files(#10000,"/yield2.js","yield2","js",0) +files(#10000,"/yield2.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2016/output/trap/exp.js.trap b/javascript/extractor/tests/es2016/output/trap/exp.js.trap index ff512e1fd2a..c5103a7932f 100644 --- a/javascript/extractor/tests/es2016/output/trap/exp.js.trap +++ b/javascript/extractor/tests/es2016/output/trap/exp.js.trap @@ -1,7 +1,7 @@ #10000=@"/exp.js;sourcefile" -files(#10000,"/exp.js","exp","js",0) +files(#10000,"/exp.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2016/output/trap/usestrict.js.trap b/javascript/extractor/tests/es2016/output/trap/usestrict.js.trap index 77c7f003cd4..a1e1b27cd25 100644 --- a/javascript/extractor/tests/es2016/output/trap/usestrict.js.trap +++ b/javascript/extractor/tests/es2016/output/trap/usestrict.js.trap @@ -1,7 +1,7 @@ #10000=@"/usestrict.js;sourcefile" -files(#10000,"/usestrict.js","usestrict","js",0) +files(#10000,"/usestrict.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2017/output/trap/async-await.js.trap b/javascript/extractor/tests/es2017/output/trap/async-await.js.trap index cd79c3985ef..6330dce7940 100644 --- a/javascript/extractor/tests/es2017/output/trap/async-await.js.trap +++ b/javascript/extractor/tests/es2017/output/trap/async-await.js.trap @@ -1,7 +1,7 @@ #10000=@"/async-await.js;sourcefile" -files(#10000,"/async-await.js","async-await","js",0) +files(#10000,"/async-await.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2017/output/trap/export-async-1.js.trap b/javascript/extractor/tests/es2017/output/trap/export-async-1.js.trap index 86da62095d0..62404dcc656 100644 --- a/javascript/extractor/tests/es2017/output/trap/export-async-1.js.trap +++ b/javascript/extractor/tests/es2017/output/trap/export-async-1.js.trap @@ -1,7 +1,7 @@ #10000=@"/export-async-1.js;sourcefile" -files(#10000,"/export-async-1.js","export-async-1","js",0) +files(#10000,"/export-async-1.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2017/output/trap/export-async-2.js.trap b/javascript/extractor/tests/es2017/output/trap/export-async-2.js.trap index d13cc444d29..1fb2e0a1419 100644 --- a/javascript/extractor/tests/es2017/output/trap/export-async-2.js.trap +++ b/javascript/extractor/tests/es2017/output/trap/export-async-2.js.trap @@ -1,7 +1,7 @@ #10000=@"/export-async-2.js;sourcefile" -files(#10000,"/export-async-2.js","export-async-2","js",0) +files(#10000,"/export-async-2.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2017/output/trap/invalid-async-fn.js.trap b/javascript/extractor/tests/es2017/output/trap/invalid-async-fn.js.trap index 03b1c5fb16c..9572541ae8d 100644 --- a/javascript/extractor/tests/es2017/output/trap/invalid-async-fn.js.trap +++ b/javascript/extractor/tests/es2017/output/trap/invalid-async-fn.js.trap @@ -1,7 +1,7 @@ #10000=@"/invalid-async-fn.js;sourcefile" -files(#10000,"/invalid-async-fn.js","invalid-async-fn","js",0) +files(#10000,"/invalid-async-fn.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2017/output/trap/shorthand-prop-async.js.trap b/javascript/extractor/tests/es2017/output/trap/shorthand-prop-async.js.trap index c70e37f425d..1c62daca205 100644 --- a/javascript/extractor/tests/es2017/output/trap/shorthand-prop-async.js.trap +++ b/javascript/extractor/tests/es2017/output/trap/shorthand-prop-async.js.trap @@ -1,7 +1,7 @@ #10000=@"/shorthand-prop-async.js;sourcefile" -files(#10000,"/shorthand-prop-async.js","shorthand-prop-async","js",0) +files(#10000,"/shorthand-prop-async.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2018/output/trap/asyncIter.js.trap b/javascript/extractor/tests/es2018/output/trap/asyncIter.js.trap index cd9b4fbd27e..dcb18552587 100644 --- a/javascript/extractor/tests/es2018/output/trap/asyncIter.js.trap +++ b/javascript/extractor/tests/es2018/output/trap/asyncIter.js.trap @@ -1,7 +1,7 @@ #10000=@"/asyncIter.js;sourcefile" -files(#10000,"/asyncIter.js","asyncIter","js",0) +files(#10000,"/asyncIter.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2018/output/trap/templates.js.trap b/javascript/extractor/tests/es2018/output/trap/templates.js.trap index e9fefd43ae1..5f5ef870acd 100644 --- a/javascript/extractor/tests/es2018/output/trap/templates.js.trap +++ b/javascript/extractor/tests/es2018/output/trap/templates.js.trap @@ -1,7 +1,7 @@ #10000=@"/templates.js;sourcefile" -files(#10000,"/templates.js","templates","js",0) +files(#10000,"/templates.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2019/output/trap/json-superset.js.trap b/javascript/extractor/tests/es2019/output/trap/json-superset.js.trap index 8b3fdb48e3f..afc0749206a 100644 --- a/javascript/extractor/tests/es2019/output/trap/json-superset.js.trap +++ b/javascript/extractor/tests/es2019/output/trap/json-superset.js.trap @@ -1,7 +1,7 @@ #10000=@"/json-superset.js;sourcefile" -files(#10000,"/json-superset.js","json-superset","js",0) +files(#10000,"/json-superset.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2021/output/trap/assign.js.trap b/javascript/extractor/tests/es2021/output/trap/assign.js.trap index f844eb1ccfb..d0aaa18558b 100644 --- a/javascript/extractor/tests/es2021/output/trap/assign.js.trap +++ b/javascript/extractor/tests/es2021/output/trap/assign.js.trap @@ -1,7 +1,7 @@ #10000=@"/assign.js;sourcefile" -files(#10000,"/assign.js","assign","js",0) +files(#10000,"/assign.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/es2021/output/trap/numeric.js.trap b/javascript/extractor/tests/es2021/output/trap/numeric.js.trap index afcf1627f2d..f6f86e94853 100644 --- a/javascript/extractor/tests/es2021/output/trap/numeric.js.trap +++ b/javascript/extractor/tests/es2021/output/trap/numeric.js.trap @@ -1,7 +1,7 @@ #10000=@"/numeric.js;sourcefile" -files(#10000,"/numeric.js","numeric","js",0) +files(#10000,"/numeric.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/esnext/output/trap/async-generators.js.trap b/javascript/extractor/tests/esnext/output/trap/async-generators.js.trap index 67f29efe9f8..058ac988fac 100644 --- a/javascript/extractor/tests/esnext/output/trap/async-generators.js.trap +++ b/javascript/extractor/tests/esnext/output/trap/async-generators.js.trap @@ -1,7 +1,7 @@ #10000=@"/async-generators.js;sourcefile" -files(#10000,"/async-generators.js","async-generators","js",0) +files(#10000,"/async-generators.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/esnext/output/trap/catchGuardAndNoBinding.js.trap b/javascript/extractor/tests/esnext/output/trap/catchGuardAndNoBinding.js.trap index 664211c9a42..49ae2b30eb0 100644 --- a/javascript/extractor/tests/esnext/output/trap/catchGuardAndNoBinding.js.trap +++ b/javascript/extractor/tests/esnext/output/trap/catchGuardAndNoBinding.js.trap @@ -1,7 +1,7 @@ #10000=@"/catchGuardAndNoBinding.js;sourcefile" -files(#10000,"/catchGuardAndNoBinding.js","catchGuardAndNoBinding","js",0) +files(#10000,"/catchGuardAndNoBinding.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/esnext/output/trap/catchNoBinding.js.trap b/javascript/extractor/tests/esnext/output/trap/catchNoBinding.js.trap index 67df355b2bc..aa264fa302a 100644 --- a/javascript/extractor/tests/esnext/output/trap/catchNoBinding.js.trap +++ b/javascript/extractor/tests/esnext/output/trap/catchNoBinding.js.trap @@ -1,7 +1,7 @@ #10000=@"/catchNoBinding.js;sourcefile" -files(#10000,"/catchNoBinding.js","catchNoBinding","js",0) +files(#10000,"/catchNoBinding.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/esnext/output/trap/dynamic-import.js.trap b/javascript/extractor/tests/esnext/output/trap/dynamic-import.js.trap index a4028832386..5e5b460a756 100644 --- a/javascript/extractor/tests/esnext/output/trap/dynamic-import.js.trap +++ b/javascript/extractor/tests/esnext/output/trap/dynamic-import.js.trap @@ -1,7 +1,7 @@ #10000=@"/dynamic-import.js;sourcefile" -files(#10000,"/dynamic-import.js","dynamic-import","js",0) +files(#10000,"/dynamic-import.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/esnext/output/trap/fields.js.trap b/javascript/extractor/tests/esnext/output/trap/fields.js.trap index 7245dcb37d6..f73fd5fa6ba 100644 --- a/javascript/extractor/tests/esnext/output/trap/fields.js.trap +++ b/javascript/extractor/tests/esnext/output/trap/fields.js.trap @@ -1,7 +1,7 @@ #10000=@"/fields.js;sourcefile" -files(#10000,"/fields.js","fields","js",0) +files(#10000,"/fields.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/esnext/output/trap/nullish-coalescing.js.trap b/javascript/extractor/tests/esnext/output/trap/nullish-coalescing.js.trap index 1e8793de0a1..234c05a9446 100644 --- a/javascript/extractor/tests/esnext/output/trap/nullish-coalescing.js.trap +++ b/javascript/extractor/tests/esnext/output/trap/nullish-coalescing.js.trap @@ -1,7 +1,7 @@ #10000=@"/nullish-coalescing.js;sourcefile" -files(#10000,"/nullish-coalescing.js","nullish-coalescing","js",0) +files(#10000,"/nullish-coalescing.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/esnext/output/trap/optional-chaining.js.trap b/javascript/extractor/tests/esnext/output/trap/optional-chaining.js.trap index 9f38ea14f81..fb44a997170 100644 --- a/javascript/extractor/tests/esnext/output/trap/optional-chaining.js.trap +++ b/javascript/extractor/tests/esnext/output/trap/optional-chaining.js.trap @@ -1,7 +1,7 @@ #10000=@"/optional-chaining.js;sourcefile" -files(#10000,"/optional-chaining.js","optional-chaining","js",0) +files(#10000,"/optional-chaining.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad1.js.trap b/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad1.js.trap index 5e4dc3945c1..d3853a902e4 100644 --- a/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad1.js.trap +++ b/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad1.js.trap @@ -1,7 +1,7 @@ #10000=@"/optional-chaining_bad1.js;sourcefile" -files(#10000,"/optional-chaining_bad1.js","optional-chaining_bad1","js",0) +files(#10000,"/optional-chaining_bad1.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad2.js.trap b/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad2.js.trap index 49cf106dca3..e0a8491e8cf 100644 --- a/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad2.js.trap +++ b/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad2.js.trap @@ -1,7 +1,7 @@ #10000=@"/optional-chaining_bad2.js;sourcefile" -files(#10000,"/optional-chaining_bad2.js","optional-chaining_bad2","js",0) +files(#10000,"/optional-chaining_bad2.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad3.js.trap b/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad3.js.trap index b697e0f4da1..d0eaaadb172 100644 --- a/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad3.js.trap +++ b/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad3.js.trap @@ -1,7 +1,7 @@ #10000=@"/optional-chaining_bad3.js;sourcefile" -files(#10000,"/optional-chaining_bad3.js","optional-chaining_bad3","js",0) +files(#10000,"/optional-chaining_bad3.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad4.js.trap b/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad4.js.trap index 05a06c72b23..a046c8a9c92 100644 --- a/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad4.js.trap +++ b/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad4.js.trap @@ -1,7 +1,7 @@ #10000=@"/optional-chaining_bad4.js;sourcefile" -files(#10000,"/optional-chaining_bad4.js","optional-chaining_bad4","js",0) +files(#10000,"/optional-chaining_bad4.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad5.js.trap b/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad5.js.trap index 6e5c528aa5f..3605fa2dc73 100644 --- a/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad5.js.trap +++ b/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad5.js.trap @@ -1,7 +1,7 @@ #10000=@"/optional-chaining_bad5.js;sourcefile" -files(#10000,"/optional-chaining_bad5.js","optional-chaining_bad5","js",0) +files(#10000,"/optional-chaining_bad5.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad6.js.trap b/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad6.js.trap index cb078002809..34c257b9bcd 100644 --- a/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad6.js.trap +++ b/javascript/extractor/tests/esnext/output/trap/optional-chaining_bad6.js.trap @@ -1,7 +1,7 @@ #10000=@"/optional-chaining_bad6.js;sourcefile" -files(#10000,"/optional-chaining_bad6.js","optional-chaining_bad6","js",0) +files(#10000,"/optional-chaining_bad6.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/esnext/output/trap/optional-chaining_short-circuiting.js.trap b/javascript/extractor/tests/esnext/output/trap/optional-chaining_short-circuiting.js.trap index e253ec8fa5f..1ae6f531362 100644 --- a/javascript/extractor/tests/esnext/output/trap/optional-chaining_short-circuiting.js.trap +++ b/javascript/extractor/tests/esnext/output/trap/optional-chaining_short-circuiting.js.trap @@ -1,7 +1,7 @@ #10000=@"/optional-chaining_short-circuiting.js;sourcefile" -files(#10000,"/optional-chaining_short-circuiting.js","optional-chaining_short-circuiting","js",0) +files(#10000,"/optional-chaining_short-circuiting.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/esnext/output/trap/top-level-await.js.trap b/javascript/extractor/tests/esnext/output/trap/top-level-await.js.trap index 98d5bd56131..1b436f9a6b8 100644 --- a/javascript/extractor/tests/esnext/output/trap/top-level-await.js.trap +++ b/javascript/extractor/tests/esnext/output/trap/top-level-await.js.trap @@ -1,7 +1,7 @@ #10000=@"/top-level-await.js;sourcefile" -files(#10000,"/top-level-await.js","top-level-await","js",0) +files(#10000,"/top-level-await.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/esnext/output/trap/yield-import.js.trap b/javascript/extractor/tests/esnext/output/trap/yield-import.js.trap index c25e397bc29..4f2b6485042 100644 --- a/javascript/extractor/tests/esnext/output/trap/yield-import.js.trap +++ b/javascript/extractor/tests/esnext/output/trap/yield-import.js.trap @@ -1,7 +1,7 @@ #10000=@"/yield-import.js;sourcefile" -files(#10000,"/yield-import.js","yield-import","js",0) +files(#10000,"/yield-import.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/exprs/output/trap/assignment.js.trap b/javascript/extractor/tests/exprs/output/trap/assignment.js.trap index 895731068cc..42df8f6fe5b 100644 --- a/javascript/extractor/tests/exprs/output/trap/assignment.js.trap +++ b/javascript/extractor/tests/exprs/output/trap/assignment.js.trap @@ -1,7 +1,7 @@ #10000=@"/assignment.js;sourcefile" -files(#10000,"/assignment.js","assignment","js",0) +files(#10000,"/assignment.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/exprs/output/trap/binary.js.trap b/javascript/extractor/tests/exprs/output/trap/binary.js.trap index 49b7a4461e4..0b29d03b73a 100644 --- a/javascript/extractor/tests/exprs/output/trap/binary.js.trap +++ b/javascript/extractor/tests/exprs/output/trap/binary.js.trap @@ -1,7 +1,7 @@ #10000=@"/binary.js;sourcefile" -files(#10000,"/binary.js","binary","js",0) +files(#10000,"/binary.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/exprs/output/trap/comparison.js.trap b/javascript/extractor/tests/exprs/output/trap/comparison.js.trap index c2ab0c3958f..40cd1291c1d 100644 --- a/javascript/extractor/tests/exprs/output/trap/comparison.js.trap +++ b/javascript/extractor/tests/exprs/output/trap/comparison.js.trap @@ -1,7 +1,7 @@ #10000=@"/comparison.js;sourcefile" -files(#10000,"/comparison.js","comparison","js",0) +files(#10000,"/comparison.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/exprs/output/trap/fnnesting.js.trap b/javascript/extractor/tests/exprs/output/trap/fnnesting.js.trap index 98fc3347002..c2b52eb4df8 100644 --- a/javascript/extractor/tests/exprs/output/trap/fnnesting.js.trap +++ b/javascript/extractor/tests/exprs/output/trap/fnnesting.js.trap @@ -1,7 +1,7 @@ #10000=@"/fnnesting.js;sourcefile" -files(#10000,"/fnnesting.js","fnnesting","js",0) +files(#10000,"/fnnesting.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/exprs/output/trap/others.js.trap b/javascript/extractor/tests/exprs/output/trap/others.js.trap index 80173fba1fe..5fc397235e8 100644 --- a/javascript/extractor/tests/exprs/output/trap/others.js.trap +++ b/javascript/extractor/tests/exprs/output/trap/others.js.trap @@ -1,7 +1,7 @@ #10000=@"/others.js;sourcefile" -files(#10000,"/others.js","others","js",0) +files(#10000,"/others.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/exprs/output/trap/parens.js.trap b/javascript/extractor/tests/exprs/output/trap/parens.js.trap index 06dc43f1d79..8b8d9b592ba 100644 --- a/javascript/extractor/tests/exprs/output/trap/parens.js.trap +++ b/javascript/extractor/tests/exprs/output/trap/parens.js.trap @@ -1,7 +1,7 @@ #10000=@"/parens.js;sourcefile" -files(#10000,"/parens.js","parens","js",0) +files(#10000,"/parens.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/exprs/output/trap/primaries.js.trap b/javascript/extractor/tests/exprs/output/trap/primaries.js.trap index 6c3d10a84f9..034ff1c98c0 100644 --- a/javascript/extractor/tests/exprs/output/trap/primaries.js.trap +++ b/javascript/extractor/tests/exprs/output/trap/primaries.js.trap @@ -1,7 +1,7 @@ #10000=@"/primaries.js;sourcefile" -files(#10000,"/primaries.js","primaries","js",0) +files(#10000,"/primaries.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/exprs/output/trap/regexp.js.trap b/javascript/extractor/tests/exprs/output/trap/regexp.js.trap index 854393c7bfd..3b58a28545b 100644 --- a/javascript/extractor/tests/exprs/output/trap/regexp.js.trap +++ b/javascript/extractor/tests/exprs/output/trap/regexp.js.trap @@ -1,7 +1,7 @@ #10000=@"/regexp.js;sourcefile" -files(#10000,"/regexp.js","regexp","js",0) +files(#10000,"/regexp.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/exprs/output/trap/unary.js.trap b/javascript/extractor/tests/exprs/output/trap/unary.js.trap index 06529bd4e21..aca29eb7033 100644 --- a/javascript/extractor/tests/exprs/output/trap/unary.js.trap +++ b/javascript/extractor/tests/exprs/output/trap/unary.js.trap @@ -1,7 +1,7 @@ #10000=@"/unary.js;sourcefile" -files(#10000,"/unary.js","unary","js",0) +files(#10000,"/unary.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/exprs/output/trap/update.js.trap b/javascript/extractor/tests/exprs/output/trap/update.js.trap index ae4dc55d514..dba8253323f 100644 --- a/javascript/extractor/tests/exprs/output/trap/update.js.trap +++ b/javascript/extractor/tests/exprs/output/trap/update.js.trap @@ -1,7 +1,7 @@ #10000=@"/update.js;sourcefile" -files(#10000,"/update.js","update","js",0) +files(#10000,"/update.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/extensions/output/trap/tst.es6.trap b/javascript/extractor/tests/extensions/output/trap/tst.es6.trap index c8df5a4bbf8..1f8496da9b0 100644 --- a/javascript/extractor/tests/extensions/output/trap/tst.es6.trap +++ b/javascript/extractor/tests/extensions/output/trap/tst.es6.trap @@ -1,7 +1,7 @@ #10000=@"/tst.es6;sourcefile" -files(#10000,"/tst.es6","tst","es6",0) +files(#10000,"/tst.es6") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/extensions/output/trap/tst2.es.trap b/javascript/extractor/tests/extensions/output/trap/tst2.es.trap index 2241616144e..e07f93a1571 100644 --- a/javascript/extractor/tests/extensions/output/trap/tst2.es.trap +++ b/javascript/extractor/tests/extensions/output/trap/tst2.es.trap @@ -1,7 +1,7 @@ #10000=@"/tst2.es;sourcefile" -files(#10000,"/tst2.es","tst2","es",0) +files(#10000,"/tst2.es") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/extensions/output/trap/tst4.cjs.trap b/javascript/extractor/tests/extensions/output/trap/tst4.cjs.trap index 13a0a7225da..4323614bf4d 100644 --- a/javascript/extractor/tests/extensions/output/trap/tst4.cjs.trap +++ b/javascript/extractor/tests/extensions/output/trap/tst4.cjs.trap @@ -1,7 +1,7 @@ #10000=@"/tst4.cjs;sourcefile" -files(#10000,"/tst4.cjs","tst4","cjs",0) +files(#10000,"/tst4.cjs") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/externs/output/trap/Point.js.trap b/javascript/extractor/tests/externs/output/trap/Point.js.trap index 5d5cd7e9b76..d69c901ea89 100644 --- a/javascript/extractor/tests/externs/output/trap/Point.js.trap +++ b/javascript/extractor/tests/externs/output/trap/Point.js.trap @@ -1,7 +1,7 @@ #10000=@"/Point.js;sourcefile" -files(#10000,"/Point.js","Point","js",0) +files(#10000,"/Point.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/ambig.js.trap b/javascript/extractor/tests/flow/output/trap/ambig.js.trap index e340560e4a6..5c03f0309c2 100644 --- a/javascript/extractor/tests/flow/output/trap/ambig.js.trap +++ b/javascript/extractor/tests/flow/output/trap/ambig.js.trap @@ -1,7 +1,7 @@ #10000=@"/ambig.js;sourcefile" -files(#10000,"/ambig.js","ambig","js",0) +files(#10000,"/ambig.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/anonFunctionOptionalParm.js.trap b/javascript/extractor/tests/flow/output/trap/anonFunctionOptionalParm.js.trap index 3b9210e53da..8a5bb69f6ab 100644 --- a/javascript/extractor/tests/flow/output/trap/anonFunctionOptionalParm.js.trap +++ b/javascript/extractor/tests/flow/output/trap/anonFunctionOptionalParm.js.trap @@ -1,7 +1,7 @@ #10000=@"/anonFunctionOptionalParm.js;sourcefile" -files(#10000,"/anonFunctionOptionalParm.js","anonFunctionOptionalParm","js",0) +files(#10000,"/anonFunctionOptionalParm.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/anonFunctionReturnType.js.trap b/javascript/extractor/tests/flow/output/trap/anonFunctionReturnType.js.trap index b35eb8c87e3..6118bba7388 100644 --- a/javascript/extractor/tests/flow/output/trap/anonFunctionReturnType.js.trap +++ b/javascript/extractor/tests/flow/output/trap/anonFunctionReturnType.js.trap @@ -1,7 +1,7 @@ #10000=@"/anonFunctionReturnType.js;sourcefile" -files(#10000,"/anonFunctionReturnType.js","anonFunctionReturnType","js",0) +files(#10000,"/anonFunctionReturnType.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/anonFunctionWithoutParens.js.trap b/javascript/extractor/tests/flow/output/trap/anonFunctionWithoutParens.js.trap index 9134ec656db..999173d6a30 100644 --- a/javascript/extractor/tests/flow/output/trap/anonFunctionWithoutParens.js.trap +++ b/javascript/extractor/tests/flow/output/trap/anonFunctionWithoutParens.js.trap @@ -1,7 +1,7 @@ #10000=@"/anonFunctionWithoutParens.js;sourcefile" -files(#10000,"/anonFunctionWithoutParens.js","anonFunctionWithoutParens","js",0) +files(#10000,"/anonFunctionWithoutParens.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/anonIndexer.js.trap b/javascript/extractor/tests/flow/output/trap/anonIndexer.js.trap index 7299e6ff1fb..fbfaf50aaee 100644 --- a/javascript/extractor/tests/flow/output/trap/anonIndexer.js.trap +++ b/javascript/extractor/tests/flow/output/trap/anonIndexer.js.trap @@ -1,7 +1,7 @@ #10000=@"/anonIndexer.js;sourcefile" -files(#10000,"/anonIndexer.js","anonIndexer","js",0) +files(#10000,"/anonIndexer.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/array-types.js.trap b/javascript/extractor/tests/flow/output/trap/array-types.js.trap index cf3f193d686..de8a4aa77d9 100644 --- a/javascript/extractor/tests/flow/output/trap/array-types.js.trap +++ b/javascript/extractor/tests/flow/output/trap/array-types.js.trap @@ -1,7 +1,7 @@ #10000=@"/array-types.js;sourcefile" -files(#10000,"/array-types.js","array-types","js",0) +files(#10000,"/array-types.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/async.js.trap b/javascript/extractor/tests/flow/output/trap/async.js.trap index b53ba8247ff..c1a1fbdaa7f 100644 --- a/javascript/extractor/tests/flow/output/trap/async.js.trap +++ b/javascript/extractor/tests/flow/output/trap/async.js.trap @@ -1,7 +1,7 @@ #10000=@"/async.js;sourcefile" -files(#10000,"/async.js","async","js",0) +files(#10000,"/async.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/atAtIteratorProp.js.trap b/javascript/extractor/tests/flow/output/trap/atAtIteratorProp.js.trap index c735c3ae0eb..3e4fbaa2bec 100644 --- a/javascript/extractor/tests/flow/output/trap/atAtIteratorProp.js.trap +++ b/javascript/extractor/tests/flow/output/trap/atAtIteratorProp.js.trap @@ -1,7 +1,7 @@ #10000=@"/atAtIteratorProp.js;sourcefile" -files(#10000,"/atAtIteratorProp.js","atAtIteratorProp","js",0) +files(#10000,"/atAtIteratorProp.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/boundExplicitTypeParameters.js.trap b/javascript/extractor/tests/flow/output/trap/boundExplicitTypeParameters.js.trap index 64fd25704ad..b7a4873216a 100644 --- a/javascript/extractor/tests/flow/output/trap/boundExplicitTypeParameters.js.trap +++ b/javascript/extractor/tests/flow/output/trap/boundExplicitTypeParameters.js.trap @@ -1,7 +1,7 @@ #10000=@"/boundExplicitTypeParameters.js;sourcefile" -files(#10000,"/boundExplicitTypeParameters.js","boundExplicitTypeParameters","js",0) +files(#10000,"/boundExplicitTypeParameters.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/complexParamTypes.js.trap b/javascript/extractor/tests/flow/output/trap/complexParamTypes.js.trap index 9292cb46dbb..d6b8e03674e 100644 --- a/javascript/extractor/tests/flow/output/trap/complexParamTypes.js.trap +++ b/javascript/extractor/tests/flow/output/trap/complexParamTypes.js.trap @@ -1,7 +1,7 @@ #10000=@"/complexParamTypes.js;sourcefile" -files(#10000,"/complexParamTypes.js","complexParamTypes","js",0) +files(#10000,"/complexParamTypes.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/complexParamTypes2.js.trap b/javascript/extractor/tests/flow/output/trap/complexParamTypes2.js.trap index 9ba6f8f8f0f..e03ae461c44 100644 --- a/javascript/extractor/tests/flow/output/trap/complexParamTypes2.js.trap +++ b/javascript/extractor/tests/flow/output/trap/complexParamTypes2.js.trap @@ -1,7 +1,7 @@ #10000=@"/complexParamTypes2.js;sourcefile" -files(#10000,"/complexParamTypes2.js","complexParamTypes2","js",0) +files(#10000,"/complexParamTypes2.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/declareExport.js.trap b/javascript/extractor/tests/flow/output/trap/declareExport.js.trap index 9e34dd0ddfc..5a01cf475c0 100644 --- a/javascript/extractor/tests/flow/output/trap/declareExport.js.trap +++ b/javascript/extractor/tests/flow/output/trap/declareExport.js.trap @@ -1,7 +1,7 @@ #10000=@"/declareExport.js;sourcefile" -files(#10000,"/declareExport.js","declareExport","js",0) +files(#10000,"/declareExport.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/declareModuleExports.js.trap b/javascript/extractor/tests/flow/output/trap/declareModuleExports.js.trap index 2c92f20b158..b65fd64d976 100644 --- a/javascript/extractor/tests/flow/output/trap/declareModuleExports.js.trap +++ b/javascript/extractor/tests/flow/output/trap/declareModuleExports.js.trap @@ -1,7 +1,7 @@ #10000=@"/declareModuleExports.js;sourcefile" -files(#10000,"/declareModuleExports.js","declareModuleExports","js",0) +files(#10000,"/declareModuleExports.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/declared-module-imports.js.trap b/javascript/extractor/tests/flow/output/trap/declared-module-imports.js.trap index 8d9bc30f647..1eedda348e3 100644 --- a/javascript/extractor/tests/flow/output/trap/declared-module-imports.js.trap +++ b/javascript/extractor/tests/flow/output/trap/declared-module-imports.js.trap @@ -1,7 +1,7 @@ #10000=@"/declared-module-imports.js;sourcefile" -files(#10000,"/declared-module-imports.js","declared-module-imports","js",0) +files(#10000,"/declared-module-imports.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/explicitTypeParameters.js.trap b/javascript/extractor/tests/flow/output/trap/explicitTypeParameters.js.trap index 586f1dc3aa4..0d12524a168 100644 --- a/javascript/extractor/tests/flow/output/trap/explicitTypeParameters.js.trap +++ b/javascript/extractor/tests/flow/output/trap/explicitTypeParameters.js.trap @@ -1,7 +1,7 @@ #10000=@"/explicitTypeParameters.js;sourcefile" -files(#10000,"/explicitTypeParameters.js","explicitTypeParameters","js",0) +files(#10000,"/explicitTypeParameters.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/explicitTypeParametersForArgumentlessConstructorCall.js.trap b/javascript/extractor/tests/flow/output/trap/explicitTypeParametersForArgumentlessConstructorCall.js.trap index 550f69bf88a..e96f25d995b 100644 --- a/javascript/extractor/tests/flow/output/trap/explicitTypeParametersForArgumentlessConstructorCall.js.trap +++ b/javascript/extractor/tests/flow/output/trap/explicitTypeParametersForArgumentlessConstructorCall.js.trap @@ -1,7 +1,7 @@ #10000=@"/explicitTypeParametersForArgumentlessConstructorCall.js;sourcefile" -files(#10000,"/explicitTypeParametersForArgumentlessConstructorCall.js","explicitTypeParametersForArgumentlessConstructorCall","js",0) +files(#10000,"/explicitTypeParametersForArgumentlessConstructorCall.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/export.js.trap b/javascript/extractor/tests/flow/output/trap/export.js.trap index 0e4b9242e9f..94465ac5a54 100644 --- a/javascript/extractor/tests/flow/output/trap/export.js.trap +++ b/javascript/extractor/tests/flow/output/trap/export.js.trap @@ -1,7 +1,7 @@ #10000=@"/export.js;sourcefile" -files(#10000,"/export.js","export","js",0) +files(#10000,"/export.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/exportOpaqueType.js.trap b/javascript/extractor/tests/flow/output/trap/exportOpaqueType.js.trap index 1a1a943871a..5cdd7537e30 100644 --- a/javascript/extractor/tests/flow/output/trap/exportOpaqueType.js.trap +++ b/javascript/extractor/tests/flow/output/trap/exportOpaqueType.js.trap @@ -1,7 +1,7 @@ #10000=@"/exportOpaqueType.js;sourcefile" -files(#10000,"/exportOpaqueType.js","exportOpaqueType","js",0) +files(#10000,"/exportOpaqueType.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/get-set-methods.js.trap b/javascript/extractor/tests/flow/output/trap/get-set-methods.js.trap index c347c677bb6..1a55904a396 100644 --- a/javascript/extractor/tests/flow/output/trap/get-set-methods.js.trap +++ b/javascript/extractor/tests/flow/output/trap/get-set-methods.js.trap @@ -1,7 +1,7 @@ #10000=@"/get-set-methods.js;sourcefile" -files(#10000,"/get-set-methods.js","get-set-methods","js",0) +files(#10000,"/get-set-methods.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/importNonTypeInDeclaredModule.js.trap b/javascript/extractor/tests/flow/output/trap/importNonTypeInDeclaredModule.js.trap index 6d98783360f..24a6d896086 100644 --- a/javascript/extractor/tests/flow/output/trap/importNonTypeInDeclaredModule.js.trap +++ b/javascript/extractor/tests/flow/output/trap/importNonTypeInDeclaredModule.js.trap @@ -1,7 +1,7 @@ #10000=@"/importNonTypeInDeclaredModule.js;sourcefile" -files(#10000,"/importNonTypeInDeclaredModule.js","importNonTypeInDeclaredModule","js",0) +files(#10000,"/importNonTypeInDeclaredModule.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/importType.js.trap b/javascript/extractor/tests/flow/output/trap/importType.js.trap index d323164a8b0..9e2e2885049 100644 --- a/javascript/extractor/tests/flow/output/trap/importType.js.trap +++ b/javascript/extractor/tests/flow/output/trap/importType.js.trap @@ -1,7 +1,7 @@ #10000=@"/importType.js;sourcefile" -files(#10000,"/importType.js","importType","js",0) +files(#10000,"/importType.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/importTypeInDeclaredModule.js.trap b/javascript/extractor/tests/flow/output/trap/importTypeInDeclaredModule.js.trap index d7724bfaca2..188033df9a1 100644 --- a/javascript/extractor/tests/flow/output/trap/importTypeInDeclaredModule.js.trap +++ b/javascript/extractor/tests/flow/output/trap/importTypeInDeclaredModule.js.trap @@ -1,7 +1,7 @@ #10000=@"/importTypeInDeclaredModule.js;sourcefile" -files(#10000,"/importTypeInDeclaredModule.js","importTypeInDeclaredModule","js",0) +files(#10000,"/importTypeInDeclaredModule.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/methodTypeParams.js.trap b/javascript/extractor/tests/flow/output/trap/methodTypeParams.js.trap index 926ee570de2..9b4ae6666b5 100644 --- a/javascript/extractor/tests/flow/output/trap/methodTypeParams.js.trap +++ b/javascript/extractor/tests/flow/output/trap/methodTypeParams.js.trap @@ -1,7 +1,7 @@ #10000=@"/methodTypeParams.js;sourcefile" -files(#10000,"/methodTypeParams.js","methodTypeParams","js",0) +files(#10000,"/methodTypeParams.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/notExplicitTypeParameters1.js.trap b/javascript/extractor/tests/flow/output/trap/notExplicitTypeParameters1.js.trap index 8a148b8e75c..f7fd599eb4b 100644 --- a/javascript/extractor/tests/flow/output/trap/notExplicitTypeParameters1.js.trap +++ b/javascript/extractor/tests/flow/output/trap/notExplicitTypeParameters1.js.trap @@ -1,7 +1,7 @@ #10000=@"/notExplicitTypeParameters1.js;sourcefile" -files(#10000,"/notExplicitTypeParameters1.js","notExplicitTypeParameters1","js",0) +files(#10000,"/notExplicitTypeParameters1.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/notExplicitTypeParameters2.js.trap b/javascript/extractor/tests/flow/output/trap/notExplicitTypeParameters2.js.trap index 5880cdc6798..a7d9edcc6eb 100644 --- a/javascript/extractor/tests/flow/output/trap/notExplicitTypeParameters2.js.trap +++ b/javascript/extractor/tests/flow/output/trap/notExplicitTypeParameters2.js.trap @@ -1,7 +1,7 @@ #10000=@"/notExplicitTypeParameters2.js;sourcefile" -files(#10000,"/notExplicitTypeParameters2.js","notExplicitTypeParameters2","js",0) +files(#10000,"/notExplicitTypeParameters2.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/notExplicitTypeParameters3.js.trap b/javascript/extractor/tests/flow/output/trap/notExplicitTypeParameters3.js.trap index dd07d4d9711..0758eddced7 100644 --- a/javascript/extractor/tests/flow/output/trap/notExplicitTypeParameters3.js.trap +++ b/javascript/extractor/tests/flow/output/trap/notExplicitTypeParameters3.js.trap @@ -1,7 +1,7 @@ #10000=@"/notExplicitTypeParameters3.js;sourcefile" -files(#10000,"/notExplicitTypeParameters3.js","notExplicitTypeParameters3","js",0) +files(#10000,"/notExplicitTypeParameters3.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/objectTypeSpread.js.trap b/javascript/extractor/tests/flow/output/trap/objectTypeSpread.js.trap index f7c948b9ba8..b6bb522eb5d 100644 --- a/javascript/extractor/tests/flow/output/trap/objectTypeSpread.js.trap +++ b/javascript/extractor/tests/flow/output/trap/objectTypeSpread.js.trap @@ -1,7 +1,7 @@ #10000=@"/objectTypeSpread.js;sourcefile" -files(#10000,"/objectTypeSpread.js","objectTypeSpread","js",0) +files(#10000,"/objectTypeSpread.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/optParms.js.trap b/javascript/extractor/tests/flow/output/trap/optParms.js.trap index ea0f8c09d4e..44212bfc13e 100644 --- a/javascript/extractor/tests/flow/output/trap/optParms.js.trap +++ b/javascript/extractor/tests/flow/output/trap/optParms.js.trap @@ -1,7 +1,7 @@ #10000=@"/optParms.js;sourcefile" -files(#10000,"/optParms.js","optParms","js",0) +files(#10000,"/optParms.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/parmAnonFunctionType.js.trap b/javascript/extractor/tests/flow/output/trap/parmAnonFunctionType.js.trap index aab0d8a6e56..ab1e66273cd 100644 --- a/javascript/extractor/tests/flow/output/trap/parmAnonFunctionType.js.trap +++ b/javascript/extractor/tests/flow/output/trap/parmAnonFunctionType.js.trap @@ -1,7 +1,7 @@ #10000=@"/parmAnonFunctionType.js;sourcefile" -files(#10000,"/parmAnonFunctionType.js","parmAnonFunctionType","js",0) +files(#10000,"/parmAnonFunctionType.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/practicallyAmbigiousExplicitTypeParameters.js.trap b/javascript/extractor/tests/flow/output/trap/practicallyAmbigiousExplicitTypeParameters.js.trap index e63bdcf39d6..8d579436330 100644 --- a/javascript/extractor/tests/flow/output/trap/practicallyAmbigiousExplicitTypeParameters.js.trap +++ b/javascript/extractor/tests/flow/output/trap/practicallyAmbigiousExplicitTypeParameters.js.trap @@ -1,7 +1,7 @@ #10000=@"/practicallyAmbigiousExplicitTypeParameters.js;sourcefile" -files(#10000,"/practicallyAmbigiousExplicitTypeParameters.js","practicallyAmbigiousExplicitTypeParameters","js",0) +files(#10000,"/practicallyAmbigiousExplicitTypeParameters.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/predicate-function-annotation.js.trap b/javascript/extractor/tests/flow/output/trap/predicate-function-annotation.js.trap index 25ef0f6f879..57e41fef661 100644 --- a/javascript/extractor/tests/flow/output/trap/predicate-function-annotation.js.trap +++ b/javascript/extractor/tests/flow/output/trap/predicate-function-annotation.js.trap @@ -1,7 +1,7 @@ #10000=@"/predicate-function-annotation.js;sourcefile" -files(#10000,"/predicate-function-annotation.js","predicate-function-annotation","js",0) +files(#10000,"/predicate-function-annotation.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/qualifiedInterface.js.trap b/javascript/extractor/tests/flow/output/trap/qualifiedInterface.js.trap index 30e2744f7c1..e384b03c9d3 100644 --- a/javascript/extractor/tests/flow/output/trap/qualifiedInterface.js.trap +++ b/javascript/extractor/tests/flow/output/trap/qualifiedInterface.js.trap @@ -1,7 +1,7 @@ #10000=@"/qualifiedInterface.js;sourcefile" -files(#10000,"/qualifiedInterface.js","qualifiedInterface","js",0) +files(#10000,"/qualifiedInterface.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/tst.js.trap b/javascript/extractor/tests/flow/output/trap/tst.js.trap index 69ddbb3cc52..dac8b56dea0 100644 --- a/javascript/extractor/tests/flow/output/trap/tst.js.trap +++ b/javascript/extractor/tests/flow/output/trap/tst.js.trap @@ -1,7 +1,7 @@ #10000=@"/tst.js;sourcefile" -files(#10000,"/tst.js","tst","js",0) +files(#10000,"/tst.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/flow/output/trap/variance.js.trap b/javascript/extractor/tests/flow/output/trap/variance.js.trap index b739bf79598..b6955639fe9 100644 --- a/javascript/extractor/tests/flow/output/trap/variance.js.trap +++ b/javascript/extractor/tests/flow/output/trap/variance.js.trap @@ -1,7 +1,7 @@ #10000=@"/variance.js;sourcefile" -files(#10000,"/variance.js","variance","js",0) +files(#10000,"/variance.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/functionbind/output/trap/tst.js.trap b/javascript/extractor/tests/functionbind/output/trap/tst.js.trap index ccbadc43d8c..8ec6dfe8c8a 100644 --- a/javascript/extractor/tests/functionbind/output/trap/tst.js.trap +++ b/javascript/extractor/tests/functionbind/output/trap/tst.js.trap @@ -1,7 +1,7 @@ #10000=@"/tst.js;sourcefile" -files(#10000,"/tst.js","tst","js",0) +files(#10000,"/tst.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/generatedcode/output/trap/ejs.js.trap b/javascript/extractor/tests/generatedcode/output/trap/ejs.js.trap index 78151c8ca2d..ac5756b042e 100644 --- a/javascript/extractor/tests/generatedcode/output/trap/ejs.js.trap +++ b/javascript/extractor/tests/generatedcode/output/trap/ejs.js.trap @@ -1,7 +1,7 @@ #10000=@"/ejs.js;sourcefile" -files(#10000,"/ejs.js","ejs","js",0) +files(#10000,"/ejs.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/generatedcode/output/trap/test.html.trap b/javascript/extractor/tests/generatedcode/output/trap/test.html.trap index 1cb0292dd84..2446f220c7e 100644 --- a/javascript/extractor/tests/generatedcode/output/trap/test.html.trap +++ b/javascript/extractor/tests/generatedcode/output/trap/test.html.trap @@ -1,7 +1,7 @@ #10000=@"/test.html;sourcefile" -files(#10000,"/test.html","test","html",0) +files(#10000,"/test.html") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/generatedcode/output/trap/tst.js.trap b/javascript/extractor/tests/generatedcode/output/trap/tst.js.trap index 852d0001206..b9f05be663c 100644 --- a/javascript/extractor/tests/generatedcode/output/trap/tst.js.trap +++ b/javascript/extractor/tests/generatedcode/output/trap/tst.js.trap @@ -1,7 +1,7 @@ #10000=@"/tst.js;sourcefile" -files(#10000,"/tst.js","tst","js",0) +files(#10000,"/tst.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/helloworld/output/trap/hello.js.trap b/javascript/extractor/tests/helloworld/output/trap/hello.js.trap index e04c9e06faf..610ae0392b4 100644 --- a/javascript/extractor/tests/helloworld/output/trap/hello.js.trap +++ b/javascript/extractor/tests/helloworld/output/trap/hello.js.trap @@ -1,7 +1,7 @@ #10000=@"/hello.js;sourcefile" -files(#10000,"/hello.js","hello","js",0) +files(#10000,"/hello.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/html-text-extraction/output/trap/text-examples.html.trap b/javascript/extractor/tests/html-text-extraction/output/trap/text-examples.html.trap index ed529bef3c3..f318f201006 100644 --- a/javascript/extractor/tests/html-text-extraction/output/trap/text-examples.html.trap +++ b/javascript/extractor/tests/html-text-extraction/output/trap/text-examples.html.trap @@ -1,7 +1,7 @@ #10000=@"/text-examples.html;sourcefile" -files(#10000,"/text-examples.html","text-examples","html",0) +files(#10000,"/text-examples.html") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/html/output/trap/doctype.html.trap b/javascript/extractor/tests/html/output/trap/doctype.html.trap index 2624d53f031..983c8c168f8 100644 --- a/javascript/extractor/tests/html/output/trap/doctype.html.trap +++ b/javascript/extractor/tests/html/output/trap/doctype.html.trap @@ -1,7 +1,7 @@ #10000=@"/doctype.html;sourcefile" -files(#10000,"/doctype.html","doctype","html",0) +files(#10000,"/doctype.html") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/html/output/trap/empty_script.html.trap b/javascript/extractor/tests/html/output/trap/empty_script.html.trap index bcb4c5adf87..502e7267ddf 100644 --- a/javascript/extractor/tests/html/output/trap/empty_script.html.trap +++ b/javascript/extractor/tests/html/output/trap/empty_script.html.trap @@ -1,7 +1,7 @@ #10000=@"/empty_script.html;sourcefile" -files(#10000,"/empty_script.html","empty_script","html",0) +files(#10000,"/empty_script.html") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/html/output/trap/entities.html.trap b/javascript/extractor/tests/html/output/trap/entities.html.trap index 217c18f7378..2b1ad973920 100644 --- a/javascript/extractor/tests/html/output/trap/entities.html.trap +++ b/javascript/extractor/tests/html/output/trap/entities.html.trap @@ -1,7 +1,7 @@ #10000=@"/entities.html;sourcefile" -files(#10000,"/entities.html","entities","html",0) +files(#10000,"/entities.html") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/html/output/trap/json_in_script.html.trap b/javascript/extractor/tests/html/output/trap/json_in_script.html.trap index 651012c8360..439f6fcfb0b 100644 --- a/javascript/extractor/tests/html/output/trap/json_in_script.html.trap +++ b/javascript/extractor/tests/html/output/trap/json_in_script.html.trap @@ -1,7 +1,7 @@ #10000=@"/json_in_script.html;sourcefile" -files(#10000,"/json_in_script.html","json_in_script","html",0) +files(#10000,"/json_in_script.html") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/html/output/trap/module.html.trap b/javascript/extractor/tests/html/output/trap/module.html.trap index 4b497e2972e..cb4a5874429 100644 --- a/javascript/extractor/tests/html/output/trap/module.html.trap +++ b/javascript/extractor/tests/html/output/trap/module.html.trap @@ -1,7 +1,7 @@ #10000=@"/module.html;sourcefile" -files(#10000,"/module.html","module","html",0) +files(#10000,"/module.html") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/html/output/trap/q.html.trap b/javascript/extractor/tests/html/output/trap/q.html.trap index ebf42cf0b91..9f2155c4892 100644 --- a/javascript/extractor/tests/html/output/trap/q.html.trap +++ b/javascript/extractor/tests/html/output/trap/q.html.trap @@ -1,7 +1,7 @@ #10000=@"/q.html;sourcefile" -files(#10000,"/q.html","q","html",0) +files(#10000,"/q.html") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/html/output/trap/tst.html.trap b/javascript/extractor/tests/html/output/trap/tst.html.trap index 3f7e9362823..369947fc766 100644 --- a/javascript/extractor/tests/html/output/trap/tst.html.trap +++ b/javascript/extractor/tests/html/output/trap/tst.html.trap @@ -1,7 +1,7 @@ #10000=@"/tst.html;sourcefile" -files(#10000,"/tst.html","tst","html",0) +files(#10000,"/tst.html") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/html/output/trap/tst.xhtml.trap b/javascript/extractor/tests/html/output/trap/tst.xhtml.trap index 286c6f0175c..def8d3b124d 100644 --- a/javascript/extractor/tests/html/output/trap/tst.xhtml.trap +++ b/javascript/extractor/tests/html/output/trap/tst.xhtml.trap @@ -1,7 +1,7 @@ #10000=@"/tst.xhtml;sourcefile" -files(#10000,"/tst.xhtml","tst","xhtml",0) +files(#10000,"/tst.xhtml") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/html/output/trap/tst2.html.trap b/javascript/extractor/tests/html/output/trap/tst2.html.trap index d47d40c899d..bff75920f0b 100644 --- a/javascript/extractor/tests/html/output/trap/tst2.html.trap +++ b/javascript/extractor/tests/html/output/trap/tst2.html.trap @@ -1,7 +1,7 @@ #10000=@"/tst2.html;sourcefile" -files(#10000,"/tst2.html","tst2","html",0) +files(#10000,"/tst2.html") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/html/output/trap/tst2.xhtml.trap b/javascript/extractor/tests/html/output/trap/tst2.xhtml.trap index 0b8bd6ff552..bd10b9de6ab 100644 --- a/javascript/extractor/tests/html/output/trap/tst2.xhtml.trap +++ b/javascript/extractor/tests/html/output/trap/tst2.xhtml.trap @@ -1,7 +1,7 @@ #10000=@"/tst2.xhtml;sourcefile" -files(#10000,"/tst2.xhtml","tst2","xhtml",0) +files(#10000,"/tst2.xhtml") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/jscript/output/trap/tst.js.trap b/javascript/extractor/tests/jscript/output/trap/tst.js.trap index 1e74407bd62..91510d288bb 100644 --- a/javascript/extractor/tests/jscript/output/trap/tst.js.trap +++ b/javascript/extractor/tests/jscript/output/trap/tst.js.trap @@ -1,7 +1,7 @@ #10000=@"/tst.js;sourcefile" -files(#10000,"/tst.js","tst","js",0) +files(#10000,"/tst.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/json/output/trap/array.json.trap b/javascript/extractor/tests/json/output/trap/array.json.trap index 090161de744..51f73d2d216 100644 --- a/javascript/extractor/tests/json/output/trap/array.json.trap +++ b/javascript/extractor/tests/json/output/trap/array.json.trap @@ -1,7 +1,7 @@ #10000=@"/array.json;sourcefile" -files(#10000,"/array.json","array","json",0) +files(#10000,"/array.json") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/json/output/trap/comments.json.trap b/javascript/extractor/tests/json/output/trap/comments.json.trap index 0b2666a3e62..320a172e3df 100644 --- a/javascript/extractor/tests/json/output/trap/comments.json.trap +++ b/javascript/extractor/tests/json/output/trap/comments.json.trap @@ -1,7 +1,7 @@ #10000=@"/comments.json;sourcefile" -files(#10000,"/comments.json","comments","json",0) +files(#10000,"/comments.json") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/json/output/trap/duplicate-keys.json.trap b/javascript/extractor/tests/json/output/trap/duplicate-keys.json.trap index e537d1054a9..ddaa82a206b 100644 --- a/javascript/extractor/tests/json/output/trap/duplicate-keys.json.trap +++ b/javascript/extractor/tests/json/output/trap/duplicate-keys.json.trap @@ -1,7 +1,7 @@ #10000=@"/duplicate-keys.json;sourcefile" -files(#10000,"/duplicate-keys.json","duplicate-keys","json",0) +files(#10000,"/duplicate-keys.json") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/json/output/trap/empty.json.trap b/javascript/extractor/tests/json/output/trap/empty.json.trap index e8a3aa4d813..545672c63e2 100644 --- a/javascript/extractor/tests/json/output/trap/empty.json.trap +++ b/javascript/extractor/tests/json/output/trap/empty.json.trap @@ -1,7 +1,7 @@ #10000=@"/empty.json;sourcefile" -files(#10000,"/empty.json","empty","json",0) +files(#10000,"/empty.json") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/json/output/trap/error.json.trap b/javascript/extractor/tests/json/output/trap/error.json.trap index dd2dc094850..8b8a62726d1 100644 --- a/javascript/extractor/tests/json/output/trap/error.json.trap +++ b/javascript/extractor/tests/json/output/trap/error.json.trap @@ -1,7 +1,7 @@ #10000=@"/error.json;sourcefile" -files(#10000,"/error.json","error","json",0) +files(#10000,"/error.json") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/json/output/trap/invalid.json.trap b/javascript/extractor/tests/json/output/trap/invalid.json.trap index d607af95198..039148161f6 100644 --- a/javascript/extractor/tests/json/output/trap/invalid.json.trap +++ b/javascript/extractor/tests/json/output/trap/invalid.json.trap @@ -1,7 +1,7 @@ #10000=@"/invalid.json;sourcefile" -files(#10000,"/invalid.json","invalid","json",0) +files(#10000,"/invalid.json") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/json/output/trap/neg.json.trap b/javascript/extractor/tests/json/output/trap/neg.json.trap index 32f1a2fe752..10545cc7560 100644 --- a/javascript/extractor/tests/json/output/trap/neg.json.trap +++ b/javascript/extractor/tests/json/output/trap/neg.json.trap @@ -1,7 +1,7 @@ #10000=@"/neg.json;sourcefile" -files(#10000,"/neg.json","neg","json",0) +files(#10000,"/neg.json") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/json/output/trap/neg2.json.trap b/javascript/extractor/tests/json/output/trap/neg2.json.trap index d2bd7dde5db..4c7a157cebc 100644 --- a/javascript/extractor/tests/json/output/trap/neg2.json.trap +++ b/javascript/extractor/tests/json/output/trap/neg2.json.trap @@ -1,7 +1,7 @@ #10000=@"/neg2.json;sourcefile" -files(#10000,"/neg2.json","neg2","json",0) +files(#10000,"/neg2.json") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/json/output/trap/null.json.trap b/javascript/extractor/tests/json/output/trap/null.json.trap index f2d1bad90d5..a0025092110 100644 --- a/javascript/extractor/tests/json/output/trap/null.json.trap +++ b/javascript/extractor/tests/json/output/trap/null.json.trap @@ -1,7 +1,7 @@ #10000=@"/null.json;sourcefile" -files(#10000,"/null.json","null","json",0) +files(#10000,"/null.json") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/json/output/trap/omitted.json.trap b/javascript/extractor/tests/json/output/trap/omitted.json.trap index 581d3f2f103..2d28d1699db 100644 --- a/javascript/extractor/tests/json/output/trap/omitted.json.trap +++ b/javascript/extractor/tests/json/output/trap/omitted.json.trap @@ -1,7 +1,7 @@ #10000=@"/omitted.json;sourcefile" -files(#10000,"/omitted.json","omitted","json",0) +files(#10000,"/omitted.json") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/json/output/trap/tst.json.trap b/javascript/extractor/tests/json/output/trap/tst.json.trap index 5efbaa73228..c40cd479a63 100644 --- a/javascript/extractor/tests/json/output/trap/tst.json.trap +++ b/javascript/extractor/tests/json/output/trap/tst.json.trap @@ -1,7 +1,7 @@ #10000=@"/tst.json;sourcefile" -files(#10000,"/tst.json","tst","json",0) +files(#10000,"/tst.json") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/jsx/output/trap/err1.jsx.trap b/javascript/extractor/tests/jsx/output/trap/err1.jsx.trap index 93201c3cb72..93a6175965d 100644 --- a/javascript/extractor/tests/jsx/output/trap/err1.jsx.trap +++ b/javascript/extractor/tests/jsx/output/trap/err1.jsx.trap @@ -1,7 +1,7 @@ #10000=@"/err1.jsx;sourcefile" -files(#10000,"/err1.jsx","err1","jsx",0) +files(#10000,"/err1.jsx") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/jsx/output/trap/err2.jsx.trap b/javascript/extractor/tests/jsx/output/trap/err2.jsx.trap index 0e01749f43a..e71c04cbce2 100644 --- a/javascript/extractor/tests/jsx/output/trap/err2.jsx.trap +++ b/javascript/extractor/tests/jsx/output/trap/err2.jsx.trap @@ -1,7 +1,7 @@ #10000=@"/err2.jsx;sourcefile" -files(#10000,"/err2.jsx","err2","jsx",0) +files(#10000,"/err2.jsx") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/jsx/output/trap/err3.jsx.trap b/javascript/extractor/tests/jsx/output/trap/err3.jsx.trap index 9105d2a0dcd..caf6e92c5aa 100644 --- a/javascript/extractor/tests/jsx/output/trap/err3.jsx.trap +++ b/javascript/extractor/tests/jsx/output/trap/err3.jsx.trap @@ -1,7 +1,7 @@ #10000=@"/err3.jsx;sourcefile" -files(#10000,"/err3.jsx","err3","jsx",0) +files(#10000,"/err3.jsx") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/jsx/output/trap/err4.jsx.trap b/javascript/extractor/tests/jsx/output/trap/err4.jsx.trap index 7b73628781e..aa92643a05c 100644 --- a/javascript/extractor/tests/jsx/output/trap/err4.jsx.trap +++ b/javascript/extractor/tests/jsx/output/trap/err4.jsx.trap @@ -1,7 +1,7 @@ #10000=@"/err4.jsx;sourcefile" -files(#10000,"/err4.jsx","err4","jsx",0) +files(#10000,"/err4.jsx") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/jsx/output/trap/tst.js.trap b/javascript/extractor/tests/jsx/output/trap/tst.js.trap index 1c8307b25c9..874901be084 100644 --- a/javascript/extractor/tests/jsx/output/trap/tst.js.trap +++ b/javascript/extractor/tests/jsx/output/trap/tst.js.trap @@ -1,7 +1,7 @@ #10000=@"/tst.js;sourcefile" -files(#10000,"/tst.js","tst","js",0) +files(#10000,"/tst.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/jsx/output/trap/tst.jsx.trap b/javascript/extractor/tests/jsx/output/trap/tst.jsx.trap index 52253369d16..2f5d17f2332 100644 --- a/javascript/extractor/tests/jsx/output/trap/tst.jsx.trap +++ b/javascript/extractor/tests/jsx/output/trap/tst.jsx.trap @@ -1,7 +1,7 @@ #10000=@"/tst.jsx;sourcefile" -files(#10000,"/tst.jsx","tst","jsx",0) +files(#10000,"/tst.jsx") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/jsx/output/trap/tst2.js.trap b/javascript/extractor/tests/jsx/output/trap/tst2.js.trap index 7acae1995e7..48e8891b95d 100644 --- a/javascript/extractor/tests/jsx/output/trap/tst2.js.trap +++ b/javascript/extractor/tests/jsx/output/trap/tst2.js.trap @@ -1,7 +1,7 @@ #10000=@"/tst2.js;sourcefile" -files(#10000,"/tst2.js","tst2","js",0) +files(#10000,"/tst2.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/keywords/output/trap/tst.js.trap b/javascript/extractor/tests/keywords/output/trap/tst.js.trap index 749aad7d305..9526d353d8f 100644 --- a/javascript/extractor/tests/keywords/output/trap/tst.js.trap +++ b/javascript/extractor/tests/keywords/output/trap/tst.js.trap @@ -1,7 +1,7 @@ #10000=@"/tst.js;sourcefile" -files(#10000,"/tst.js","tst","js",0) +files(#10000,"/tst.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/moduleTypes1/output/trap/package.json.trap b/javascript/extractor/tests/moduleTypes1/output/trap/package.json.trap index 2f945dcaaf2..28c4c087216 100644 --- a/javascript/extractor/tests/moduleTypes1/output/trap/package.json.trap +++ b/javascript/extractor/tests/moduleTypes1/output/trap/package.json.trap @@ -1,7 +1,7 @@ #10000=@"/package.json;sourcefile" -files(#10000,"/package.json","package","json",0) +files(#10000,"/package.json") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/moduleTypes1/output/trap/tst.js.trap b/javascript/extractor/tests/moduleTypes1/output/trap/tst.js.trap index cedeb436b92..1896ecff4b3 100644 --- a/javascript/extractor/tests/moduleTypes1/output/trap/tst.js.trap +++ b/javascript/extractor/tests/moduleTypes1/output/trap/tst.js.trap @@ -1,7 +1,7 @@ #10000=@"/tst.js;sourcefile" -files(#10000,"/tst.js","tst","js",0) +files(#10000,"/tst.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/moduleTypes2/output/trap/package.json.trap b/javascript/extractor/tests/moduleTypes2/output/trap/package.json.trap index 71e31b4820d..1f090b6eacc 100644 --- a/javascript/extractor/tests/moduleTypes2/output/trap/package.json.trap +++ b/javascript/extractor/tests/moduleTypes2/output/trap/package.json.trap @@ -1,7 +1,7 @@ #10000=@"/package.json;sourcefile" -files(#10000,"/package.json","package","json",0) +files(#10000,"/package.json") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/moduleTypes2/output/trap/tst2.js.trap b/javascript/extractor/tests/moduleTypes2/output/trap/tst2.js.trap index 31ab093a62b..84299e50279 100644 --- a/javascript/extractor/tests/moduleTypes2/output/trap/tst2.js.trap +++ b/javascript/extractor/tests/moduleTypes2/output/trap/tst2.js.trap @@ -1,7 +1,7 @@ #10000=@"/tst2.js;sourcefile" -files(#10000,"/tst2.js","tst2","js",0) +files(#10000,"/tst2.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/moduleTypes3/output/trap/package.json.trap b/javascript/extractor/tests/moduleTypes3/output/trap/package.json.trap index eed0d0523d5..2d207d55c7a 100644 --- a/javascript/extractor/tests/moduleTypes3/output/trap/package.json.trap +++ b/javascript/extractor/tests/moduleTypes3/output/trap/package.json.trap @@ -1,7 +1,7 @@ #10000=@"/package.json;sourcefile" -files(#10000,"/package.json","package","json",0) +files(#10000,"/package.json") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/moduleTypes3/output/trap/tst.js.trap b/javascript/extractor/tests/moduleTypes3/output/trap/tst.js.trap index cedeb436b92..1896ecff4b3 100644 --- a/javascript/extractor/tests/moduleTypes3/output/trap/tst.js.trap +++ b/javascript/extractor/tests/moduleTypes3/output/trap/tst.js.trap @@ -1,7 +1,7 @@ #10000=@"/tst.js;sourcefile" -files(#10000,"/tst.js","tst","js",0) +files(#10000,"/tst.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/mozilla/output/trap/array_comprehensions.js.trap b/javascript/extractor/tests/mozilla/output/trap/array_comprehensions.js.trap index cf80f8e18be..ab2e9e4a1ab 100644 --- a/javascript/extractor/tests/mozilla/output/trap/array_comprehensions.js.trap +++ b/javascript/extractor/tests/mozilla/output/trap/array_comprehensions.js.trap @@ -1,7 +1,7 @@ #10000=@"/array_comprehensions.js;sourcefile" -files(#10000,"/array_comprehensions.js","array_comprehensions","js",0) +files(#10000,"/array_comprehensions.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/mozilla/output/trap/exprfns.js.trap b/javascript/extractor/tests/mozilla/output/trap/exprfns.js.trap index 8a4feb66d03..db738b83deb 100644 --- a/javascript/extractor/tests/mozilla/output/trap/exprfns.js.trap +++ b/javascript/extractor/tests/mozilla/output/trap/exprfns.js.trap @@ -1,7 +1,7 @@ #10000=@"/exprfns.js;sourcefile" -files(#10000,"/exprfns.js","exprfns","js",0) +files(#10000,"/exprfns.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/mozilla/output/trap/foreach.js.trap b/javascript/extractor/tests/mozilla/output/trap/foreach.js.trap index 0d2e7bc4a56..28f0598a994 100644 --- a/javascript/extractor/tests/mozilla/output/trap/foreach.js.trap +++ b/javascript/extractor/tests/mozilla/output/trap/foreach.js.trap @@ -1,7 +1,7 @@ #10000=@"/foreach.js;sourcefile" -files(#10000,"/foreach.js","foreach","js",0) +files(#10000,"/foreach.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/mozilla/output/trap/generator_expressions.js.trap b/javascript/extractor/tests/mozilla/output/trap/generator_expressions.js.trap index f8da052b6f8..e1abfa519c7 100644 --- a/javascript/extractor/tests/mozilla/output/trap/generator_expressions.js.trap +++ b/javascript/extractor/tests/mozilla/output/trap/generator_expressions.js.trap @@ -1,7 +1,7 @@ #10000=@"/generator_expressions.js;sourcefile" -files(#10000,"/generator_expressions.js","generator_expressions","js",0) +files(#10000,"/generator_expressions.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/mozilla/output/trap/guardedCatch.js.trap b/javascript/extractor/tests/mozilla/output/trap/guardedCatch.js.trap index fe588ef567e..28200e7e028 100644 --- a/javascript/extractor/tests/mozilla/output/trap/guardedCatch.js.trap +++ b/javascript/extractor/tests/mozilla/output/trap/guardedCatch.js.trap @@ -1,7 +1,7 @@ #10000=@"/guardedCatch.js;sourcefile" -files(#10000,"/guardedCatch.js","guardedCatch","js",0) +files(#10000,"/guardedCatch.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/mozilla/output/trap/letExpr.js.trap b/javascript/extractor/tests/mozilla/output/trap/letExpr.js.trap index 703e9e69cbf..28e3fd45bf9 100644 --- a/javascript/extractor/tests/mozilla/output/trap/letExpr.js.trap +++ b/javascript/extractor/tests/mozilla/output/trap/letExpr.js.trap @@ -1,7 +1,7 @@ #10000=@"/letExpr.js;sourcefile" -files(#10000,"/letExpr.js","letExpr","js",0) +files(#10000,"/letExpr.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/mozilla/output/trap/letStmt.js.trap b/javascript/extractor/tests/mozilla/output/trap/letStmt.js.trap index 6925f668b3f..38bed9aeab6 100644 --- a/javascript/extractor/tests/mozilla/output/trap/letStmt.js.trap +++ b/javascript/extractor/tests/mozilla/output/trap/letStmt.js.trap @@ -1,7 +1,7 @@ #10000=@"/letStmt.js;sourcefile" -files(#10000,"/letStmt.js","letStmt","js",0) +files(#10000,"/letStmt.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/mozilla/output/trap/letStmt2.js.trap b/javascript/extractor/tests/mozilla/output/trap/letStmt2.js.trap index baeeb086f72..d81fb77a243 100644 --- a/javascript/extractor/tests/mozilla/output/trap/letStmt2.js.trap +++ b/javascript/extractor/tests/mozilla/output/trap/letStmt2.js.trap @@ -1,7 +1,7 @@ #10000=@"/letStmt2.js;sourcefile" -files(#10000,"/letStmt2.js","letStmt2","js",0) +files(#10000,"/letStmt2.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/mozilla/output/trap/new-with-trailing-arg.js.trap b/javascript/extractor/tests/mozilla/output/trap/new-with-trailing-arg.js.trap index 05b4e28d159..a2a88241cd2 100644 --- a/javascript/extractor/tests/mozilla/output/trap/new-with-trailing-arg.js.trap +++ b/javascript/extractor/tests/mozilla/output/trap/new-with-trailing-arg.js.trap @@ -1,7 +1,7 @@ #10000=@"/new-with-trailing-arg.js;sourcefile" -files(#10000,"/new-with-trailing-arg.js","new-with-trailing-arg","js",0) +files(#10000,"/new-with-trailing-arg.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/mozilla/output/trap/odasa-2593.js.trap b/javascript/extractor/tests/mozilla/output/trap/odasa-2593.js.trap index abe232b6e7f..cc974f12339 100644 --- a/javascript/extractor/tests/mozilla/output/trap/odasa-2593.js.trap +++ b/javascript/extractor/tests/mozilla/output/trap/odasa-2593.js.trap @@ -1,7 +1,7 @@ #10000=@"/odasa-2593.js;sourcefile" -files(#10000,"/odasa-2593.js","odasa-2593","js",0) +files(#10000,"/odasa-2593.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ng-templates/output/trap/component.js.trap b/javascript/extractor/tests/ng-templates/output/trap/component.js.trap index 0d475cc7080..3f03793bcc2 100644 --- a/javascript/extractor/tests/ng-templates/output/trap/component.js.trap +++ b/javascript/extractor/tests/ng-templates/output/trap/component.js.trap @@ -1,7 +1,7 @@ #10000=@"/component.js;sourcefile" -files(#10000,"/component.js","component","js",0) +files(#10000,"/component.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/node/output/trap/constlet.js.trap b/javascript/extractor/tests/node/output/trap/constlet.js.trap index 659ac0a76de..c7080134983 100644 --- a/javascript/extractor/tests/node/output/trap/constlet.js.trap +++ b/javascript/extractor/tests/node/output/trap/constlet.js.trap @@ -1,7 +1,7 @@ #10000=@"/constlet.js;sourcefile" -files(#10000,"/constlet.js","constlet","js",0) +files(#10000,"/constlet.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/node/output/trap/hello.trap b/javascript/extractor/tests/node/output/trap/hello.trap index 83ba4b94239..8c083879437 100644 --- a/javascript/extractor/tests/node/output/trap/hello.trap +++ b/javascript/extractor/tests/node/output/trap/hello.trap @@ -1,9 +1,9 @@ #10000=@"/g/hello;sourcefile" -files(#10000,"/g/hello","hello","",0) +files(#10000,"/g/hello") #10001=@"/g;folder" -folders(#10001,"/g","g") +folders(#10001,"/g") #10002=@"/;folder" -folders(#10002,"/","") +folders(#10002,"/") containerparent(#10002,#10001) containerparent(#10001,#10000) #10003=@"loc,{#10000},0,0,0,0" diff --git a/javascript/extractor/tests/node/output/trap/package.json.trap b/javascript/extractor/tests/node/output/trap/package.json.trap index f35a6af005a..80f58515e69 100644 --- a/javascript/extractor/tests/node/output/trap/package.json.trap +++ b/javascript/extractor/tests/node/output/trap/package.json.trap @@ -1,9 +1,9 @@ #10000=@"/f/package.json;sourcefile" -files(#10000,"/f/package.json","package","json",0) +files(#10000,"/f/package.json") #10001=@"/f;folder" -folders(#10001,"/f","f") +folders(#10001,"/f") #10002=@"/;folder" -folders(#10002,"/","") +folders(#10002,"/") containerparent(#10002,#10001) containerparent(#10001,#10000) #10003=@"loc,{#10000},0,0,0,0" diff --git a/javascript/extractor/tests/node/output/trap/tst.html.trap b/javascript/extractor/tests/node/output/trap/tst.html.trap index 7f045ba240a..56817f8f03a 100644 --- a/javascript/extractor/tests/node/output/trap/tst.html.trap +++ b/javascript/extractor/tests/node/output/trap/tst.html.trap @@ -1,7 +1,7 @@ #10000=@"/tst.html;sourcefile" -files(#10000,"/tst.html","tst","html",0) +files(#10000,"/tst.html") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/node/output/trap/tst.js.trap b/javascript/extractor/tests/node/output/trap/tst.js.trap index d53970788a3..58f71f4717b 100644 --- a/javascript/extractor/tests/node/output/trap/tst.js.trap +++ b/javascript/extractor/tests/node/output/trap/tst.js.trap @@ -1,7 +1,7 @@ #10000=@"/tst.js;sourcefile" -files(#10000,"/tst.js","tst","js",0) +files(#10000,"/tst.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/node/output/trap/tst.mjs.trap b/javascript/extractor/tests/node/output/trap/tst.mjs.trap index 81ea919abfb..f097709a21a 100644 --- a/javascript/extractor/tests/node/output/trap/tst.mjs.trap +++ b/javascript/extractor/tests/node/output/trap/tst.mjs.trap @@ -1,7 +1,7 @@ #10000=@"/tst.mjs;sourcefile" -files(#10000,"/tst.mjs","tst","mjs",0) +files(#10000,"/tst.mjs") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/rcfiles/output/trap/.babelrc.trap b/javascript/extractor/tests/rcfiles/output/trap/.babelrc.trap index ba9b6ada1b6..6f2bd6b61d5 100644 --- a/javascript/extractor/tests/rcfiles/output/trap/.babelrc.trap +++ b/javascript/extractor/tests/rcfiles/output/trap/.babelrc.trap @@ -1,7 +1,7 @@ #10000=@"/.babelrc;sourcefile" -files(#10000,"/.babelrc",".babelrc","",0) +files(#10000,"/.babelrc") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/rcfiles/output/trap/.eslintrc.trap b/javascript/extractor/tests/rcfiles/output/trap/.eslintrc.trap index 756d841bdb4..f9a74acff80 100644 --- a/javascript/extractor/tests/rcfiles/output/trap/.eslintrc.trap +++ b/javascript/extractor/tests/rcfiles/output/trap/.eslintrc.trap @@ -1,7 +1,7 @@ #10000=@"/.eslintrc;sourcefile" -files(#10000,"/.eslintrc",".eslintrc","",0) +files(#10000,"/.eslintrc") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/regexp/output/trap/es2018.js.trap b/javascript/extractor/tests/regexp/output/trap/es2018.js.trap index 44cccd78fec..0e4dbc5d3aa 100644 --- a/javascript/extractor/tests/regexp/output/trap/es2018.js.trap +++ b/javascript/extractor/tests/regexp/output/trap/es2018.js.trap @@ -1,7 +1,7 @@ #10000=@"/es2018.js;sourcefile" -files(#10000,"/es2018.js","es2018","js",0) +files(#10000,"/es2018.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/regexp/output/trap/nonstandard.js.trap b/javascript/extractor/tests/regexp/output/trap/nonstandard.js.trap index e6038ba4580..e0b648118d9 100644 --- a/javascript/extractor/tests/regexp/output/trap/nonstandard.js.trap +++ b/javascript/extractor/tests/regexp/output/trap/nonstandard.js.trap @@ -1,7 +1,7 @@ #10000=@"/nonstandard.js;sourcefile" -files(#10000,"/nonstandard.js","nonstandard","js",0) +files(#10000,"/nonstandard.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/regexp/output/trap/odasa-1934.js.trap b/javascript/extractor/tests/regexp/output/trap/odasa-1934.js.trap index 416c92e2594..6e90c62e6a6 100644 --- a/javascript/extractor/tests/regexp/output/trap/odasa-1934.js.trap +++ b/javascript/extractor/tests/regexp/output/trap/odasa-1934.js.trap @@ -1,7 +1,7 @@ #10000=@"/odasa-1934.js;sourcefile" -files(#10000,"/odasa-1934.js","odasa-1934","js",0) +files(#10000,"/odasa-1934.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/regexp/output/trap/tst.js.trap b/javascript/extractor/tests/regexp/output/trap/tst.js.trap index be1f55ad776..80ab7ab1ed7 100644 Binary files a/javascript/extractor/tests/regexp/output/trap/tst.js.trap and b/javascript/extractor/tests/regexp/output/trap/tst.js.trap differ diff --git a/javascript/extractor/tests/restprops/output/trap/tst.js.trap b/javascript/extractor/tests/restprops/output/trap/tst.js.trap index 3c481774da3..afa92ddc8b5 100644 --- a/javascript/extractor/tests/restprops/output/trap/tst.js.trap +++ b/javascript/extractor/tests/restprops/output/trap/tst.js.trap @@ -1,7 +1,7 @@ #10000=@"/tst.js;sourcefile" -files(#10000,"/tst.js","tst","js",0) +files(#10000,"/tst.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/shebang/output/trap/tst.html.trap b/javascript/extractor/tests/shebang/output/trap/tst.html.trap index 08d0f35bc2f..8588fd8be55 100644 --- a/javascript/extractor/tests/shebang/output/trap/tst.html.trap +++ b/javascript/extractor/tests/shebang/output/trap/tst.html.trap @@ -1,7 +1,7 @@ #10000=@"/tst.html;sourcefile" -files(#10000,"/tst.html","tst","html",0) +files(#10000,"/tst.html") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/shebang/output/trap/tst.js.trap b/javascript/extractor/tests/shebang/output/trap/tst.js.trap index 7c5ded4aead..59f7c049bfe 100644 --- a/javascript/extractor/tests/shebang/output/trap/tst.js.trap +++ b/javascript/extractor/tests/shebang/output/trap/tst.js.trap @@ -1,7 +1,7 @@ #10000=@"/tst.js;sourcefile" -files(#10000,"/tst.js","tst","js",0) +files(#10000,"/tst.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/shebang/output/trap/typescript-with-shebang.ts.trap b/javascript/extractor/tests/shebang/output/trap/typescript-with-shebang.ts.trap index 20220279fe5..82ba041bb8b 100644 --- a/javascript/extractor/tests/shebang/output/trap/typescript-with-shebang.ts.trap +++ b/javascript/extractor/tests/shebang/output/trap/typescript-with-shebang.ts.trap @@ -1,7 +1,7 @@ #10000=@"/typescript-with-shebang.ts;sourcefile" -files(#10000,"/typescript-with-shebang.ts","typescript-with-shebang","ts",0) +files(#10000,"/typescript-with-shebang.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/shebang/output/trap/typescript.ts.trap b/javascript/extractor/tests/shebang/output/trap/typescript.ts.trap index b987065937e..ea81b8525ee 100644 --- a/javascript/extractor/tests/shebang/output/trap/typescript.ts.trap +++ b/javascript/extractor/tests/shebang/output/trap/typescript.ts.trap @@ -1,7 +1,7 @@ #10000=@"/typescript.ts;sourcefile" -files(#10000,"/typescript.ts","typescript","ts",0) +files(#10000,"/typescript.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/stmts/output/trap/conditionals.js.trap b/javascript/extractor/tests/stmts/output/trap/conditionals.js.trap index 38f4d596c67..9e96f57790e 100644 --- a/javascript/extractor/tests/stmts/output/trap/conditionals.js.trap +++ b/javascript/extractor/tests/stmts/output/trap/conditionals.js.trap @@ -1,7 +1,7 @@ #10000=@"/conditionals.js;sourcefile" -files(#10000,"/conditionals.js","conditionals","js",0) +files(#10000,"/conditionals.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/stmts/output/trap/forvardefault.js.trap b/javascript/extractor/tests/stmts/output/trap/forvardefault.js.trap index d0a9f15240a..1e676b70d98 100644 --- a/javascript/extractor/tests/stmts/output/trap/forvardefault.js.trap +++ b/javascript/extractor/tests/stmts/output/trap/forvardefault.js.trap @@ -1,7 +1,7 @@ #10000=@"/forvardefault.js;sourcefile" -files(#10000,"/forvardefault.js","forvardefault","js",0) +files(#10000,"/forvardefault.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/stmts/output/trap/functions.js.trap b/javascript/extractor/tests/stmts/output/trap/functions.js.trap index 30a902de478..7eb1f5a04c1 100644 --- a/javascript/extractor/tests/stmts/output/trap/functions.js.trap +++ b/javascript/extractor/tests/stmts/output/trap/functions.js.trap @@ -1,7 +1,7 @@ #10000=@"/functions.js;sourcefile" -files(#10000,"/functions.js","functions","js",0) +files(#10000,"/functions.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/stmts/output/trap/loops.js.trap b/javascript/extractor/tests/stmts/output/trap/loops.js.trap index a06fd852b42..3b6519e9479 100644 --- a/javascript/extractor/tests/stmts/output/trap/loops.js.trap +++ b/javascript/extractor/tests/stmts/output/trap/loops.js.trap @@ -1,7 +1,7 @@ #10000=@"/loops.js;sourcefile" -files(#10000,"/loops.js","loops","js",0) +files(#10000,"/loops.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/stmts/output/trap/others.js.trap b/javascript/extractor/tests/stmts/output/trap/others.js.trap index 2015fc6fad8..cbb132ca1b2 100644 --- a/javascript/extractor/tests/stmts/output/trap/others.js.trap +++ b/javascript/extractor/tests/stmts/output/trap/others.js.trap @@ -1,7 +1,7 @@ #10000=@"/others.js;sourcefile" -files(#10000,"/others.js","others","js",0) +files(#10000,"/others.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/stmts/output/trap/switch.js.trap b/javascript/extractor/tests/stmts/output/trap/switch.js.trap index a6e5f8cbd2b..7e6d831b38f 100644 --- a/javascript/extractor/tests/stmts/output/trap/switch.js.trap +++ b/javascript/extractor/tests/stmts/output/trap/switch.js.trap @@ -1,7 +1,7 @@ #10000=@"/switch.js;sourcefile" -files(#10000,"/switch.js","switch","js",0) +files(#10000,"/switch.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/stmts/output/trap/switch2.js.trap b/javascript/extractor/tests/stmts/output/trap/switch2.js.trap index 28e97b932a7..bd5de336d09 100644 --- a/javascript/extractor/tests/stmts/output/trap/switch2.js.trap +++ b/javascript/extractor/tests/stmts/output/trap/switch2.js.trap @@ -1,7 +1,7 @@ #10000=@"/switch2.js;sourcefile" -files(#10000,"/switch2.js","switch2","js",0) +files(#10000,"/switch2.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/stmts/output/trap/trivial-switch.js.trap b/javascript/extractor/tests/stmts/output/trap/trivial-switch.js.trap index 46acbaefbbd..5eda7dbc53d 100644 --- a/javascript/extractor/tests/stmts/output/trap/trivial-switch.js.trap +++ b/javascript/extractor/tests/stmts/output/trap/trivial-switch.js.trap @@ -1,7 +1,7 @@ #10000=@"/trivial-switch.js;sourcefile" -files(#10000,"/trivial-switch.js","trivial-switch","js",0) +files(#10000,"/trivial-switch.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/stmts/output/trap/try.js.trap b/javascript/extractor/tests/stmts/output/trap/try.js.trap index a439edd69a8..607d91d6f64 100644 --- a/javascript/extractor/tests/stmts/output/trap/try.js.trap +++ b/javascript/extractor/tests/stmts/output/trap/try.js.trap @@ -1,7 +1,7 @@ #10000=@"/try.js;sourcefile" -files(#10000,"/try.js","try","js",0) +files(#10000,"/try.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/strictmode/output/trap/assignargs.js.trap b/javascript/extractor/tests/strictmode/output/trap/assignargs.js.trap index c40d0118989..8b34d3f5ad6 100644 --- a/javascript/extractor/tests/strictmode/output/trap/assignargs.js.trap +++ b/javascript/extractor/tests/strictmode/output/trap/assignargs.js.trap @@ -1,7 +1,7 @@ #10000=@"/assignargs.js;sourcefile" -files(#10000,"/assignargs.js","assignargs","js",0) +files(#10000,"/assignargs.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/strictmode/output/trap/tst.js.trap b/javascript/extractor/tests/strictmode/output/trap/tst.js.trap index 8b45e865618..ac5f9e60cdb 100644 --- a/javascript/extractor/tests/strictmode/output/trap/tst.js.trap +++ b/javascript/extractor/tests/strictmode/output/trap/tst.js.trap @@ -1,7 +1,7 @@ #10000=@"/tst.js;sourcefile" -files(#10000,"/tst.js","tst","js",0) +files(#10000,"/tst.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/arrayBindingPattern.ts.trap b/javascript/extractor/tests/ts/output/trap/arrayBindingPattern.ts.trap index 4436f4cdf8a..dfd38cc13c4 100644 --- a/javascript/extractor/tests/ts/output/trap/arrayBindingPattern.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/arrayBindingPattern.ts.trap @@ -1,7 +1,7 @@ #10000=@"/arrayBindingPattern.ts;sourcefile" -files(#10000,"/arrayBindingPattern.ts","arrayBindingPattern","ts",0) +files(#10000,"/arrayBindingPattern.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/badimport.ts.trap b/javascript/extractor/tests/ts/output/trap/badimport.ts.trap index e6a8f014dd9..e0f6b16abe3 100644 --- a/javascript/extractor/tests/ts/output/trap/badimport.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/badimport.ts.trap @@ -1,7 +1,7 @@ #10000=@"/badimport.ts;sourcefile" -files(#10000,"/badimport.ts","badimport","ts",0) +files(#10000,"/badimport.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/bindingpattern.ts.trap b/javascript/extractor/tests/ts/output/trap/bindingpattern.ts.trap index 16709a9b5c6..b0b28377295 100644 --- a/javascript/extractor/tests/ts/output/trap/bindingpattern.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/bindingpattern.ts.trap @@ -1,7 +1,7 @@ #10000=@"/bindingpattern.ts;sourcefile" -files(#10000,"/bindingpattern.ts","bindingpattern","ts",0) +files(#10000,"/bindingpattern.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/bom.ts.trap b/javascript/extractor/tests/ts/output/trap/bom.ts.trap index 166d8c30704..3049dd9aa91 100644 --- a/javascript/extractor/tests/ts/output/trap/bom.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/bom.ts.trap @@ -1,7 +1,7 @@ #10000=@"/bom.ts;sourcefile" -files(#10000,"/bom.ts","bom","ts",0) +files(#10000,"/bom.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/classes.ts.trap b/javascript/extractor/tests/ts/output/trap/classes.ts.trap index ce17a42019e..e91be374bf0 100644 --- a/javascript/extractor/tests/ts/output/trap/classes.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/classes.ts.trap @@ -1,7 +1,7 @@ #10000=@"/classes.ts;sourcefile" -files(#10000,"/classes.ts","classes","ts",0) +files(#10000,"/classes.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/comments.ts.trap b/javascript/extractor/tests/ts/output/trap/comments.ts.trap index 495b0656a82..4898c710e95 100644 --- a/javascript/extractor/tests/ts/output/trap/comments.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/comments.ts.trap @@ -1,7 +1,7 @@ #10000=@"/comments.ts;sourcefile" -files(#10000,"/comments.ts","comments","ts",0) +files(#10000,"/comments.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/conditionalTypes.ts.trap b/javascript/extractor/tests/ts/output/trap/conditionalTypes.ts.trap index 744b1f7e9dd..c8d26a9b983 100644 --- a/javascript/extractor/tests/ts/output/trap/conditionalTypes.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/conditionalTypes.ts.trap @@ -1,7 +1,7 @@ #10000=@"/conditionalTypes.ts;sourcefile" -files(#10000,"/conditionalTypes.ts","conditionalTypes","ts",0) +files(#10000,"/conditionalTypes.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/ctordecl.ts.trap b/javascript/extractor/tests/ts/output/trap/ctordecl.ts.trap index 99f891a12a0..9653669e31f 100644 --- a/javascript/extractor/tests/ts/output/trap/ctordecl.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/ctordecl.ts.trap @@ -1,7 +1,7 @@ #10000=@"/ctordecl.ts;sourcefile" -files(#10000,"/ctordecl.ts","ctordecl","ts",0) +files(#10000,"/ctordecl.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/declareClass.ts.trap b/javascript/extractor/tests/ts/output/trap/declareClass.ts.trap index f43447e82df..6bc9fb5ffb2 100644 --- a/javascript/extractor/tests/ts/output/trap/declareClass.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/declareClass.ts.trap @@ -1,7 +1,7 @@ #10000=@"/declareClass.ts;sourcefile" -files(#10000,"/declareClass.ts","declareClass","ts",0) +files(#10000,"/declareClass.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/decorators.ts.trap b/javascript/extractor/tests/ts/output/trap/decorators.ts.trap index a538cf72b5e..de7745b6427 100644 --- a/javascript/extractor/tests/ts/output/trap/decorators.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/decorators.ts.trap @@ -1,7 +1,7 @@ #10000=@"/decorators.ts;sourcefile" -files(#10000,"/decorators.ts","decorators","ts",0) +files(#10000,"/decorators.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/emptydecls.ts.trap b/javascript/extractor/tests/ts/output/trap/emptydecls.ts.trap index 29c9d49c18f..5a1b6c45cdf 100644 --- a/javascript/extractor/tests/ts/output/trap/emptydecls.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/emptydecls.ts.trap @@ -1,7 +1,7 @@ #10000=@"/emptydecls.ts;sourcefile" -files(#10000,"/emptydecls.ts","emptydecls","ts",0) +files(#10000,"/emptydecls.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/enum.ts.trap b/javascript/extractor/tests/ts/output/trap/enum.ts.trap index 3f9eab0e26d..146d34fb6cc 100644 --- a/javascript/extractor/tests/ts/output/trap/enum.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/enum.ts.trap @@ -1,7 +1,7 @@ #10000=@"/enum.ts;sourcefile" -files(#10000,"/enum.ts","enum","ts",0) +files(#10000,"/enum.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/export.ts.trap b/javascript/extractor/tests/ts/output/trap/export.ts.trap index dbc791ea5cc..18fdbb8f7c2 100644 --- a/javascript/extractor/tests/ts/output/trap/export.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/export.ts.trap @@ -1,7 +1,7 @@ #10000=@"/export.ts;sourcefile" -files(#10000,"/export.ts","export","ts",0) +files(#10000,"/export.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/export2.ts.trap b/javascript/extractor/tests/ts/output/trap/export2.ts.trap index 27610aaa6a6..7b433d0d1d3 100644 --- a/javascript/extractor/tests/ts/output/trap/export2.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/export2.ts.trap @@ -1,7 +1,7 @@ #10000=@"/export2.ts;sourcefile" -files(#10000,"/export2.ts","export2","ts",0) +files(#10000,"/export2.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/exportasnamespace.d.ts.trap b/javascript/extractor/tests/ts/output/trap/exportasnamespace.d.ts.trap index adb7bffc606..441258563a3 100644 --- a/javascript/extractor/tests/ts/output/trap/exportasnamespace.d.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/exportasnamespace.d.ts.trap @@ -1,7 +1,7 @@ #10000=@"/exportasnamespace.d.ts;sourcefile" -files(#10000,"/exportasnamespace.d.ts","exportasnamespace.d","ts",0) +files(#10000,"/exportasnamespace.d.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/exportassign.ts.trap b/javascript/extractor/tests/ts/output/trap/exportassign.ts.trap index c6b8a8f3557..792efab2932 100644 --- a/javascript/extractor/tests/ts/output/trap/exportassign.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/exportassign.ts.trap @@ -1,7 +1,7 @@ #10000=@"/exportassign.ts;sourcefile" -files(#10000,"/exportassign.ts","exportassign","ts",0) +files(#10000,"/exportassign.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/exportclass.ts.trap b/javascript/extractor/tests/ts/output/trap/exportclass.ts.trap index a22f30820b0..7c8bd5baf2d 100644 --- a/javascript/extractor/tests/ts/output/trap/exportclass.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/exportclass.ts.trap @@ -1,7 +1,7 @@ #10000=@"/exportclass.ts;sourcefile" -files(#10000,"/exportclass.ts","exportclass","ts",0) +files(#10000,"/exportclass.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/exprs.ts.trap b/javascript/extractor/tests/ts/output/trap/exprs.ts.trap index c87826abd82..fdd477046a5 100644 --- a/javascript/extractor/tests/ts/output/trap/exprs.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/exprs.ts.trap @@ -1,7 +1,7 @@ #10000=@"/exprs.ts;sourcefile" -files(#10000,"/exprs.ts","exprs","ts",0) +files(#10000,"/exprs.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/externalmodule.ts.trap b/javascript/extractor/tests/ts/output/trap/externalmodule.ts.trap index c778ac25d4c..0c2d918cd91 100644 --- a/javascript/extractor/tests/ts/output/trap/externalmodule.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/externalmodule.ts.trap @@ -1,7 +1,7 @@ #10000=@"/externalmodule.ts;sourcefile" -files(#10000,"/externalmodule.ts","externalmodule","ts",0) +files(#10000,"/externalmodule.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/functiondecorators.ts.trap b/javascript/extractor/tests/ts/output/trap/functiondecorators.ts.trap index efabc3e8dcb..89cd1760443 100644 --- a/javascript/extractor/tests/ts/output/trap/functiondecorators.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/functiondecorators.ts.trap @@ -1,7 +1,7 @@ #10000=@"/functiondecorators.ts;sourcefile" -files(#10000,"/functiondecorators.ts","functiondecorators","ts",0) +files(#10000,"/functiondecorators.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/hello.ts.trap b/javascript/extractor/tests/ts/output/trap/hello.ts.trap index 049108cd90a..73c0ba7df7c 100644 --- a/javascript/extractor/tests/ts/output/trap/hello.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/hello.ts.trap @@ -1,7 +1,7 @@ #10000=@"/hello.ts;sourcefile" -files(#10000,"/hello.ts","hello","ts",0) +files(#10000,"/hello.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/importExport.ts.trap b/javascript/extractor/tests/ts/output/trap/importExport.ts.trap index 9c36c4b973e..5b4b6d1cdcf 100644 --- a/javascript/extractor/tests/ts/output/trap/importExport.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/importExport.ts.trap @@ -1,7 +1,7 @@ #10000=@"/importExport.ts;sourcefile" -files(#10000,"/importExport.ts","importExport","ts",0) +files(#10000,"/importExport.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/importNonStrings.ts.trap b/javascript/extractor/tests/ts/output/trap/importNonStrings.ts.trap index af044be98c8..82e087ceca7 100644 --- a/javascript/extractor/tests/ts/output/trap/importNonStrings.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/importNonStrings.ts.trap @@ -1,7 +1,7 @@ #10000=@"/importNonStrings.ts;sourcefile" -files(#10000,"/importNonStrings.ts","importNonStrings","ts",0) +files(#10000,"/importNonStrings.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/importassign.ts.trap b/javascript/extractor/tests/ts/output/trap/importassign.ts.trap index 993e69d0bb9..6b1400b59fb 100644 --- a/javascript/extractor/tests/ts/output/trap/importassign.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/importassign.ts.trap @@ -1,7 +1,7 @@ #10000=@"/importassign.ts;sourcefile" -files(#10000,"/importassign.ts","importassign","ts",0) +files(#10000,"/importassign.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/interfaces.ts.trap b/javascript/extractor/tests/ts/output/trap/interfaces.ts.trap index 5176fb38002..5ceae62d1ba 100644 --- a/javascript/extractor/tests/ts/output/trap/interfaces.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/interfaces.ts.trap @@ -1,7 +1,7 @@ #10000=@"/interfaces.ts;sourcefile" -files(#10000,"/interfaces.ts","interfaces","ts",0) +files(#10000,"/interfaces.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/invalidModuleSpecifier.ts.trap b/javascript/extractor/tests/ts/output/trap/invalidModuleSpecifier.ts.trap index a6f530abf78..68cc255f7c5 100644 --- a/javascript/extractor/tests/ts/output/trap/invalidModuleSpecifier.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/invalidModuleSpecifier.ts.trap @@ -1,7 +1,7 @@ #10000=@"/invalidModuleSpecifier.ts;sourcefile" -files(#10000,"/invalidModuleSpecifier.ts","invalidModuleSpecifier","ts",0) +files(#10000,"/invalidModuleSpecifier.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/let.ts.trap b/javascript/extractor/tests/ts/output/trap/let.ts.trap index fe3482ffb96..cdc760eb16c 100644 --- a/javascript/extractor/tests/ts/output/trap/let.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/let.ts.trap @@ -1,7 +1,7 @@ #10000=@"/let.ts;sourcefile" -files(#10000,"/let.ts","let","ts",0) +files(#10000,"/let.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/logicalOr.ts.trap b/javascript/extractor/tests/ts/output/trap/logicalOr.ts.trap index 14ad91bef9d..abd1cbd3be5 100644 --- a/javascript/extractor/tests/ts/output/trap/logicalOr.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/logicalOr.ts.trap @@ -1,7 +1,7 @@ #10000=@"/logicalOr.ts;sourcefile" -files(#10000,"/logicalOr.ts","logicalOr","ts",0) +files(#10000,"/logicalOr.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/mappedTypeModifiers.ts.trap b/javascript/extractor/tests/ts/output/trap/mappedTypeModifiers.ts.trap index c04e8462a40..536d31ce459 100644 --- a/javascript/extractor/tests/ts/output/trap/mappedTypeModifiers.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/mappedTypeModifiers.ts.trap @@ -1,7 +1,7 @@ #10000=@"/mappedTypeModifiers.ts;sourcefile" -files(#10000,"/mappedTypeModifiers.ts","mappedTypeModifiers","ts",0) +files(#10000,"/mappedTypeModifiers.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/namespaces.ts.trap b/javascript/extractor/tests/ts/output/trap/namespaces.ts.trap index 5c21d441a15..fa7d897c6ff 100644 --- a/javascript/extractor/tests/ts/output/trap/namespaces.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/namespaces.ts.trap @@ -1,7 +1,7 @@ #10000=@"/namespaces.ts;sourcefile" -files(#10000,"/namespaces.ts","namespaces","ts",0) +files(#10000,"/namespaces.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/nestedNamespace.ts.trap b/javascript/extractor/tests/ts/output/trap/nestedNamespace.ts.trap index b47c45b1ae2..72f567e6ebb 100644 --- a/javascript/extractor/tests/ts/output/trap/nestedNamespace.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/nestedNamespace.ts.trap @@ -1,7 +1,7 @@ #10000=@"/nestedNamespace.ts;sourcefile" -files(#10000,"/nestedNamespace.ts","nestedNamespace","ts",0) +files(#10000,"/nestedNamespace.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/nobody.ts.trap b/javascript/extractor/tests/ts/output/trap/nobody.ts.trap index 1aa25844b45..44a32603e09 100644 --- a/javascript/extractor/tests/ts/output/trap/nobody.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/nobody.ts.trap @@ -1,7 +1,7 @@ #10000=@"/nobody.ts;sourcefile" -files(#10000,"/nobody.ts","nobody","ts",0) +files(#10000,"/nobody.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/objectLiteralAccessor.ts.trap b/javascript/extractor/tests/ts/output/trap/objectLiteralAccessor.ts.trap index feb4e8fb3d9..4ee94b2a313 100644 --- a/javascript/extractor/tests/ts/output/trap/objectLiteralAccessor.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/objectLiteralAccessor.ts.trap @@ -1,7 +1,7 @@ #10000=@"/objectLiteralAccessor.ts;sourcefile" -files(#10000,"/objectLiteralAccessor.ts","objectLiteralAccessor","ts",0) +files(#10000,"/objectLiteralAccessor.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/omitted.ts.trap b/javascript/extractor/tests/ts/output/trap/omitted.ts.trap index 35d92b897fd..ad6845df6f8 100644 --- a/javascript/extractor/tests/ts/output/trap/omitted.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/omitted.ts.trap @@ -1,7 +1,7 @@ #10000=@"/omitted.ts;sourcefile" -files(#10000,"/omitted.ts","omitted","ts",0) +files(#10000,"/omitted.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/optionalChaining.ts.trap b/javascript/extractor/tests/ts/output/trap/optionalChaining.ts.trap index 3e819798690..754aae68649 100644 --- a/javascript/extractor/tests/ts/output/trap/optionalChaining.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/optionalChaining.ts.trap @@ -1,7 +1,7 @@ #10000=@"/optionalChaining.ts;sourcefile" -files(#10000,"/optionalChaining.ts","optionalChaining","ts",0) +files(#10000,"/optionalChaining.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/privateField.ts.trap b/javascript/extractor/tests/ts/output/trap/privateField.ts.trap index 5fca9ab2ec7..334f1de6f83 100644 --- a/javascript/extractor/tests/ts/output/trap/privateField.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/privateField.ts.trap @@ -1,7 +1,7 @@ #10000=@"/privateField.ts;sourcefile" -files(#10000,"/privateField.ts","privateField","ts",0) +files(#10000,"/privateField.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/regexp.ts.trap b/javascript/extractor/tests/ts/output/trap/regexp.ts.trap index f461efc6f39..9b26fb5f75a 100644 --- a/javascript/extractor/tests/ts/output/trap/regexp.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/regexp.ts.trap @@ -1,7 +1,7 @@ #10000=@"/regexp.ts;sourcefile" -files(#10000,"/regexp.ts","regexp","ts",0) +files(#10000,"/regexp.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/restPatternWithDefault.ts.trap b/javascript/extractor/tests/ts/output/trap/restPatternWithDefault.ts.trap index ca7c7ca97bc..53629b31304 100644 --- a/javascript/extractor/tests/ts/output/trap/restPatternWithDefault.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/restPatternWithDefault.ts.trap @@ -1,7 +1,7 @@ #10000=@"/restPatternWithDefault.ts;sourcefile" -files(#10000,"/restPatternWithDefault.ts","restPatternWithDefault","ts",0) +files(#10000,"/restPatternWithDefault.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/templates.ts.trap b/javascript/extractor/tests/ts/output/trap/templates.ts.trap index f0040b384d9..5193508e1ed 100644 --- a/javascript/extractor/tests/ts/output/trap/templates.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/templates.ts.trap @@ -1,7 +1,7 @@ #10000=@"/templates.ts;sourcefile" -files(#10000,"/templates.ts","templates","ts",0) +files(#10000,"/templates.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/thisparameter.ts.trap b/javascript/extractor/tests/ts/output/trap/thisparameter.ts.trap index ba715d4498f..0e766cf77b9 100644 --- a/javascript/extractor/tests/ts/output/trap/thisparameter.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/thisparameter.ts.trap @@ -1,7 +1,7 @@ #10000=@"/thisparameter.ts;sourcefile" -files(#10000,"/thisparameter.ts","thisparameter","ts",0) +files(#10000,"/thisparameter.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/tryfinally.ts.trap b/javascript/extractor/tests/ts/output/trap/tryfinally.ts.trap index f65dd18d42c..d3c660c7d6e 100644 --- a/javascript/extractor/tests/ts/output/trap/tryfinally.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/tryfinally.ts.trap @@ -1,7 +1,7 @@ #10000=@"/tryfinally.ts;sourcefile" -files(#10000,"/tryfinally.ts","tryfinally","ts",0) +files(#10000,"/tryfinally.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/tsx.tsx.trap b/javascript/extractor/tests/ts/output/trap/tsx.tsx.trap index 64533b92396..3bcca05687c 100644 --- a/javascript/extractor/tests/ts/output/trap/tsx.tsx.trap +++ b/javascript/extractor/tests/ts/output/trap/tsx.tsx.trap @@ -1,7 +1,7 @@ #10000=@"/tsx.tsx;sourcefile" -files(#10000,"/tsx.tsx","tsx","tsx",0) +files(#10000,"/tsx.tsx") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/typeannotations.ts.trap b/javascript/extractor/tests/ts/output/trap/typeannotations.ts.trap index d1186ba2a40..ccedb72e42f 100644 --- a/javascript/extractor/tests/ts/output/trap/typeannotations.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/typeannotations.ts.trap @@ -1,7 +1,7 @@ #10000=@"/typeannotations.ts;sourcefile" -files(#10000,"/typeannotations.ts","typeannotations","ts",0) +files(#10000,"/typeannotations.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/unicode.ts.trap b/javascript/extractor/tests/ts/output/trap/unicode.ts.trap index 5eb51f0c4b5..749725d9a46 100644 --- a/javascript/extractor/tests/ts/output/trap/unicode.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/unicode.ts.trap @@ -1,7 +1,7 @@ #10000=@"/unicode.ts;sourcefile" -files(#10000,"/unicode.ts","unicode","ts",0) +files(#10000,"/unicode.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/unicodeId.ts.trap b/javascript/extractor/tests/ts/output/trap/unicodeId.ts.trap index 52a8099534a..d5655de7c32 100644 --- a/javascript/extractor/tests/ts/output/trap/unicodeId.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/unicodeId.ts.trap @@ -1,7 +1,7 @@ #10000=@"/unicodeId.ts;sourcefile" -files(#10000,"/unicodeId.ts","unicodeId","ts",0) +files(#10000,"/unicodeId.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/ts/output/trap/uninstantiatedNamespace.ts.trap b/javascript/extractor/tests/ts/output/trap/uninstantiatedNamespace.ts.trap index ad546cdc0fa..7cc993e08e3 100644 --- a/javascript/extractor/tests/ts/output/trap/uninstantiatedNamespace.ts.trap +++ b/javascript/extractor/tests/ts/output/trap/uninstantiatedNamespace.ts.trap @@ -1,7 +1,7 @@ #10000=@"/uninstantiatedNamespace.ts;sourcefile" -files(#10000,"/uninstantiatedNamespace.ts","uninstantiatedNamespace","ts",0) +files(#10000,"/uninstantiatedNamespace.ts") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/v8/output/trap/tst.js.trap b/javascript/extractor/tests/v8/output/trap/tst.js.trap index 9496f4b4533..4eb025bd9d3 100644 --- a/javascript/extractor/tests/v8/output/trap/tst.js.trap +++ b/javascript/extractor/tests/v8/output/trap/tst.js.trap @@ -1,7 +1,7 @@ #10000=@"/tst.js;sourcefile" -files(#10000,"/tst.js","tst","js",0) +files(#10000,"/tst.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/variables/output/trap/const.js.trap b/javascript/extractor/tests/variables/output/trap/const.js.trap index 8ad53c7fbb1..6b4f41cd0b8 100644 --- a/javascript/extractor/tests/variables/output/trap/const.js.trap +++ b/javascript/extractor/tests/variables/output/trap/const.js.trap @@ -1,7 +1,7 @@ #10000=@"/const.js;sourcefile" -files(#10000,"/const.js","const","js",0) +files(#10000,"/const.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/variables/output/trap/finally.js.trap b/javascript/extractor/tests/variables/output/trap/finally.js.trap index d0926525120..0b20c915634 100644 --- a/javascript/extractor/tests/variables/output/trap/finally.js.trap +++ b/javascript/extractor/tests/variables/output/trap/finally.js.trap @@ -1,7 +1,7 @@ #10000=@"/finally.js;sourcefile" -files(#10000,"/finally.js","finally","js",0) +files(#10000,"/finally.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/variables/output/trap/switch.js.trap b/javascript/extractor/tests/variables/output/trap/switch.js.trap index 2e0c2f85544..9127e02831a 100644 --- a/javascript/extractor/tests/variables/output/trap/switch.js.trap +++ b/javascript/extractor/tests/variables/output/trap/switch.js.trap @@ -1,7 +1,7 @@ #10000=@"/switch.js;sourcefile" -files(#10000,"/switch.js","switch","js",0) +files(#10000,"/switch.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/variables/output/trap/try.js.trap b/javascript/extractor/tests/variables/output/trap/try.js.trap index f6c502439ed..062b593b72d 100644 --- a/javascript/extractor/tests/variables/output/trap/try.js.trap +++ b/javascript/extractor/tests/variables/output/trap/try.js.trap @@ -1,7 +1,7 @@ #10000=@"/try.js;sourcefile" -files(#10000,"/try.js","try","js",0) +files(#10000,"/try.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/variables/output/trap/variables.js.trap b/javascript/extractor/tests/variables/output/trap/variables.js.trap index b4c5c6f4b23..ebc1bc00e19 100644 --- a/javascript/extractor/tests/variables/output/trap/variables.js.trap +++ b/javascript/extractor/tests/variables/output/trap/variables.js.trap @@ -1,7 +1,7 @@ #10000=@"/variables.js;sourcefile" -files(#10000,"/variables.js","variables","js",0) +files(#10000,"/variables.js") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/vue/output/trap/test.vue.trap b/javascript/extractor/tests/vue/output/trap/test.vue.trap index 8b2e7e79195..c5be0998bc7 100644 --- a/javascript/extractor/tests/vue/output/trap/test.vue.trap +++ b/javascript/extractor/tests/vue/output/trap/test.vue.trap @@ -1,7 +1,7 @@ #10000=@"/test.vue;sourcefile" -files(#10000,"/test.vue","test","vue",0) +files(#10000,"/test.vue") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/yaml/output/trap/bad_1022_1_1.yml.trap b/javascript/extractor/tests/yaml/output/trap/bad_1022_1_1.yml.trap index 1f29931bddd..378c0faa514 100644 --- a/javascript/extractor/tests/yaml/output/trap/bad_1022_1_1.yml.trap +++ b/javascript/extractor/tests/yaml/output/trap/bad_1022_1_1.yml.trap @@ -1,7 +1,7 @@ #10000=@"/bad_1022_1_1.yml;sourcefile" -files(#10000,"/bad_1022_1_1.yml","bad_1022_1_1","yml",0) +files(#10000,"/bad_1022_1_1.yml") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/yaml/output/trap/cyclic.yaml.trap b/javascript/extractor/tests/yaml/output/trap/cyclic.yaml.trap index 3e6350b33ee..7410b8eef7d 100644 --- a/javascript/extractor/tests/yaml/output/trap/cyclic.yaml.trap +++ b/javascript/extractor/tests/yaml/output/trap/cyclic.yaml.trap @@ -1,7 +1,7 @@ #10000=@"/cyclic.yaml;sourcefile" -files(#10000,"/cyclic.yaml","cyclic","yaml",0) +files(#10000,"/cyclic.yaml") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/yaml/output/trap/good_1021_1_1.yml.trap b/javascript/extractor/tests/yaml/output/trap/good_1021_1_1.yml.trap index 14263fee8ae..b55660d0043 100644 --- a/javascript/extractor/tests/yaml/output/trap/good_1021_1_1.yml.trap +++ b/javascript/extractor/tests/yaml/output/trap/good_1021_1_1.yml.trap @@ -1,7 +1,7 @@ #10000=@"/good_1021_1_1.yml;sourcefile" -files(#10000,"/good_1021_1_1.yml","good_1021_1_1","yml",0) +files(#10000,"/good_1021_1_1.yml") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/yaml/output/trap/good_1_1_1021.yml.trap b/javascript/extractor/tests/yaml/output/trap/good_1_1_1021.yml.trap index 1dfc7236156..b41b53c33f3 100644 --- a/javascript/extractor/tests/yaml/output/trap/good_1_1_1021.yml.trap +++ b/javascript/extractor/tests/yaml/output/trap/good_1_1_1021.yml.trap @@ -1,7 +1,7 @@ #10000=@"/good_1_1_1021.yml;sourcefile" -files(#10000,"/good_1_1_1021.yml","good_1_1_1021","yml",0) +files(#10000,"/good_1_1_1021.yml") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/yaml/output/trap/merge.yaml.trap b/javascript/extractor/tests/yaml/output/trap/merge.yaml.trap index 7fda9367720..b083875f4e0 100644 --- a/javascript/extractor/tests/yaml/output/trap/merge.yaml.trap +++ b/javascript/extractor/tests/yaml/output/trap/merge.yaml.trap @@ -1,7 +1,7 @@ #10000=@"/merge.yaml;sourcefile" -files(#10000,"/merge.yaml","merge","yaml",0) +files(#10000,"/merge.yaml") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/yaml/output/trap/orig.yml.trap b/javascript/extractor/tests/yaml/output/trap/orig.yml.trap index fe8da2ea09f..b7b72d425d5 100644 --- a/javascript/extractor/tests/yaml/output/trap/orig.yml.trap +++ b/javascript/extractor/tests/yaml/output/trap/orig.yml.trap @@ -1,7 +1,7 @@ #10000=@"/orig.yml;sourcefile" -files(#10000,"/orig.yml","orig","yml",0) +files(#10000,"/orig.yml") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/yaml/output/trap/tst.yml.trap b/javascript/extractor/tests/yaml/output/trap/tst.yml.trap index e119ddc19aa..cc92c452438 100644 --- a/javascript/extractor/tests/yaml/output/trap/tst.yml.trap +++ b/javascript/extractor/tests/yaml/output/trap/tst.yml.trap @@ -1,7 +1,7 @@ #10000=@"/tst.yml;sourcefile" -files(#10000,"/tst.yml","tst","yml",0) +files(#10000,"/tst.yml") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/extractor/tests/yaml/output/trap/x_bad_1_1_1022.yml.trap b/javascript/extractor/tests/yaml/output/trap/x_bad_1_1_1022.yml.trap index 4bab6838e52..5f6a0e1e0e3 100644 --- a/javascript/extractor/tests/yaml/output/trap/x_bad_1_1_1022.yml.trap +++ b/javascript/extractor/tests/yaml/output/trap/x_bad_1_1_1022.yml.trap @@ -1,7 +1,7 @@ #10000=@"/x_bad_1_1_1022.yml;sourcefile" -files(#10000,"/x_bad_1_1_1022.yml","x_bad_1_1_1022","yml",0) +files(#10000,"/x_bad_1_1_1022.yml") #10001=@"/;folder" -folders(#10001,"/","") +folders(#10001,"/") containerparent(#10001,#10000) #10002=@"loc,{#10000},0,0,0,0" locations_default(#10002,#10000,0,0,0,0) diff --git a/javascript/ql/lib/javascript.qll b/javascript/ql/lib/javascript.qll index eed95edcd7d..3a0aa544348 100644 --- a/javascript/ql/lib/javascript.qll +++ b/javascript/ql/lib/javascript.qll @@ -78,6 +78,7 @@ import semmle.javascript.frameworks.ComposedFunctions import semmle.javascript.frameworks.Classnames import semmle.javascript.frameworks.ClassValidator import semmle.javascript.frameworks.ClientRequests +import semmle.javascript.frameworks.Clipboard import semmle.javascript.frameworks.ClosureLibrary import semmle.javascript.frameworks.CookieLibraries import semmle.javascript.frameworks.Credentials diff --git a/javascript/ql/lib/semmle/javascript/Base64.qll b/javascript/ql/lib/semmle/javascript/Base64.qll index f2e91a7060c..b9743fb4ec2 100644 --- a/javascript/ql/lib/semmle/javascript/Base64.qll +++ b/javascript/ql/lib/semmle/javascript/Base64.qll @@ -6,16 +6,12 @@ import javascript module Base64 { /** A call to a base64 encoder. */ - class Encode extends DataFlow::Node { - Encode::Range encode; - - Encode() { this = encode } - + class Encode extends DataFlow::Node instanceof Encode::Range { /** Gets the input passed to the encoder. */ - DataFlow::Node getInput() { result = encode.getInput() } + DataFlow::Node getInput() { result = super.getInput() } /** Gets the base64-encoded output of the encoder. */ - DataFlow::Node getOutput() { result = encode.getOutput() } + DataFlow::Node getOutput() { result = super.getOutput() } } module Encode { @@ -34,16 +30,12 @@ module Base64 { } /** A call to a base64 decoder. */ - class Decode extends DataFlow::Node { - Decode::Range encode; - - Decode() { this = encode } - + class Decode extends DataFlow::Node instanceof Decode::Range { /** Gets the base64-encoded input passed to the decoder. */ - DataFlow::Node getInput() { result = encode.getInput() } + DataFlow::Node getInput() { result = super.getInput() } /** Gets the output of the decoder. */ - DataFlow::Node getOutput() { result = encode.getOutput() } + DataFlow::Node getOutput() { result = super.getOutput() } } module Decode { diff --git a/javascript/ql/lib/semmle/javascript/Classes.qll b/javascript/ql/lib/semmle/javascript/Classes.qll index 82e782c4690..eccc005e273 100644 --- a/javascript/ql/lib/semmle/javascript/Classes.qll +++ b/javascript/ql/lib/semmle/javascript/Classes.qll @@ -258,6 +258,13 @@ class ClassDefinition extends @class_definition, ClassOrInterface, AST::ValueNod } override string getAPrimaryQlClass() { result = "ClassDefinition" } + + /** + * Gets a static initializer of this class, if any. + */ + BlockStmt getAStaticInitializerBlock() { + exists(StaticInitializer init | init.getDeclaringClass() = this | result = init.getBody()) + } } /** @@ -1134,6 +1141,18 @@ class ParameterField extends FieldDeclaration, @parameter_field { override TypeAnnotation getTypeAnnotation() { result = getParameter().getTypeAnnotation() } } +/** + * A static initializer in a class. + */ +class StaticInitializer extends MemberDefinition, @static_initializer { + /** + * Gets the body of the static initializer. + */ + BlockStmt getBody() { result.getParent() = this } + + override Expr getNameExpr() { none() } +} + /** * A call signature declared in an interface. * diff --git a/javascript/ql/lib/semmle/javascript/Closure.qll b/javascript/ql/lib/semmle/javascript/Closure.qll index d517b4a07ea..37934f30af0 100644 --- a/javascript/ql/lib/semmle/javascript/Closure.qll +++ b/javascript/ql/lib/semmle/javascript/Closure.qll @@ -8,15 +8,11 @@ module Closure { /** * A reference to a Closure namespace. */ - class ClosureNamespaceRef extends DataFlow::Node { - ClosureNamespaceRef::Range range; - - ClosureNamespaceRef() { this = range } - + class ClosureNamespaceRef extends DataFlow::Node instanceof ClosureNamespaceRef::Range { /** * Gets the namespace being referenced. */ - string getClosureNamespace() { result = range.getClosureNamespace() } + string getClosureNamespace() { result = super.getClosureNamespace() } } module ClosureNamespaceRef { @@ -36,8 +32,7 @@ module Closure { /** * A data flow node that returns the value of a closure namespace. */ - class ClosureNamespaceAccess extends ClosureNamespaceRef { - override ClosureNamespaceAccess::Range range; + class ClosureNamespaceAccess extends ClosureNamespaceRef instanceof ClosureNamespaceAccess::Range { } module ClosureNamespaceAccess { @@ -81,7 +76,7 @@ module Closure { * A top-level call to `goog.provide`. */ class ClosureProvideCall extends ClosureNamespaceRef, DataFlow::MethodCallNode { - override DefaultClosureProvideCall range; + ClosureProvideCall() { this instanceof DefaultClosureProvideCall } } /** @@ -95,7 +90,7 @@ module Closure { * A call to `goog.require`. */ class ClosureRequireCall extends ClosureNamespaceAccess, DataFlow::MethodCallNode { - override DefaultClosureRequireCall range; + ClosureRequireCall() { this instanceof DefaultClosureRequireCall } } /** @@ -112,7 +107,7 @@ module Closure { * A top-level call to `goog.module` or `goog.declareModuleId`. */ class ClosureModuleDeclaration extends ClosureNamespaceRef, DataFlow::MethodCallNode { - override DefaultClosureModuleDeclaration range; + ClosureModuleDeclaration() { this instanceof DefaultClosureModuleDeclaration } } private GlobalVariable googVariable() { variables(result, "goog", any(GlobalScope sc)) } diff --git a/javascript/ql/lib/semmle/javascript/DOM.qll b/javascript/ql/lib/semmle/javascript/DOM.qll index 4956502d7d2..5d721858de8 100644 --- a/javascript/ql/lib/semmle/javascript/DOM.qll +++ b/javascript/ql/lib/semmle/javascript/DOM.qll @@ -450,6 +450,8 @@ module DOM { result = domValueRef(DataFlow::TypeTracker::end()) or result.hasUnderlyingType("Element") + or + result.hasUnderlyingType(any(string s | s.matches("HTML%Element"))) } module LocationSource { diff --git a/javascript/ql/lib/semmle/javascript/Files.qll b/javascript/ql/lib/semmle/javascript/Files.qll index 7fe0201f940..7bb0bb5b314 100644 --- a/javascript/ql/lib/semmle/javascript/Files.qll +++ b/javascript/ql/lib/semmle/javascript/Files.qll @@ -156,7 +156,7 @@ abstract class Container extends @container { /** A folder. */ class Folder extends Container, @folder { - override string getAbsolutePath() { folders(this, result, _) } + override string getAbsolutePath() { folders(this, result) } /** Gets the file or subfolder in this folder that has the given `name`, if any. */ Container getChildContainer(string name) { @@ -203,7 +203,7 @@ class File extends Container, @file { */ Location getLocation() { hasLocation(this, result) } - override string getAbsolutePath() { files(this, result, _, _, _) } + override string getAbsolutePath() { files(this, result) } /** Gets the number of lines in this file. */ int getNumberOfLines() { result = sum(int loc | numlines(this, loc, _, _) | loc) } diff --git a/javascript/ql/lib/semmle/javascript/InclusionTests.qll b/javascript/ql/lib/semmle/javascript/InclusionTests.qll index 2d0cf1752a4..b714c670b19 100644 --- a/javascript/ql/lib/semmle/javascript/InclusionTests.qll +++ b/javascript/ql/lib/semmle/javascript/InclusionTests.qll @@ -16,16 +16,12 @@ private import javascript * ~A.indexOf(B) * ``` */ -class InclusionTest extends DataFlow::Node { - InclusionTest::Range range; - - InclusionTest() { this = range } - +class InclusionTest extends DataFlow::Node instanceof InclusionTest::Range { /** Gets the `A` in `A.includes(B)`. */ - DataFlow::Node getContainerNode() { result = range.getContainerNode() } + DataFlow::Node getContainerNode() { result = super.getContainerNode() } /** Gets the `B` in `A.includes(B)`. */ - DataFlow::Node getContainedNode() { result = range.getContainedNode() } + DataFlow::Node getContainedNode() { result = super.getContainedNode() } /** * Gets the polarity of the check. @@ -33,7 +29,7 @@ class InclusionTest extends DataFlow::Node { * If the polarity is `false` the check returns `true` if the container does not contain * the given element. */ - boolean getPolarity() { result = range.getPolarity() } + boolean getPolarity() { result = super.getPolarity() } } module InclusionTest { diff --git a/javascript/ql/lib/semmle/javascript/MembershipCandidates.qll b/javascript/ql/lib/semmle/javascript/MembershipCandidates.qll index 89573252ab5..fe46eff040e 100644 --- a/javascript/ql/lib/semmle/javascript/MembershipCandidates.qll +++ b/javascript/ql/lib/semmle/javascript/MembershipCandidates.qll @@ -9,27 +9,23 @@ import javascript * * Additional candidates can be added by subclassing `MembershipCandidate::Range` */ -class MembershipCandidate extends DataFlow::Node { - MembershipCandidate::Range range; - - MembershipCandidate() { this = range } - +class MembershipCandidate extends DataFlow::Node instanceof MembershipCandidate::Range { /** * Gets the expression that performs the membership test, if any. */ - DataFlow::Node getTest() { result = range.getTest() } + DataFlow::Node getTest() { result = super.getTest() } /** * Gets a string that this candidate is tested against, if * it can be determined. */ - string getAMemberString() { result = range.getAMemberString() } + string getAMemberString() { result = super.getAMemberString() } /** * Gets a node that this candidate is tested against, if * it can be determined. */ - DataFlow::Node getAMemberNode() { result = range.getAMemberNode() } + DataFlow::Node getAMemberNode() { result = super.getAMemberNode() } /** * Gets the polarity of the test. @@ -37,7 +33,7 @@ class MembershipCandidate extends DataFlow::Node { * If the polarity is `false` the test returns `true` if the * collection does not contain this candidate. */ - boolean getTestPolarity() { result = range.getTestPolarity() } + boolean getTestPolarity() { result = super.getTestPolarity() } } /** diff --git a/javascript/ql/lib/semmle/javascript/Regexp.qll b/javascript/ql/lib/semmle/javascript/Regexp.qll index 5eb20b5f915..877db09c9ea 100644 --- a/javascript/ql/lib/semmle/javascript/Regexp.qll +++ b/javascript/ql/lib/semmle/javascript/Regexp.qll @@ -258,8 +258,8 @@ class RegExpConstant extends RegExpTerm, @regexp_constant { class RegExpCharEscape extends RegExpEscape, RegExpConstant, @regexp_char_escape { override predicate isCharacter() { not ( - // unencodable characters are represented as '?' in the database - getValue() = "?" and + // unencodable characters are represented as '?' or \uFFFD in the database + getValue() = ["?", 65533.toUnicode()] and exists(string s | s = toString().toLowerCase() | // only Unicode escapes give rise to unencodable characters s.matches("\\\\u%") and diff --git a/javascript/ql/lib/semmle/javascript/StringOps.qll b/javascript/ql/lib/semmle/javascript/StringOps.qll index a82ffe95a13..53390c4230d 100644 --- a/javascript/ql/lib/semmle/javascript/StringOps.qll +++ b/javascript/ql/lib/semmle/javascript/StringOps.qll @@ -8,20 +8,16 @@ module StringOps { /** * A expression that is equivalent to `A.startsWith(B)` or `!A.startsWith(B)`. */ - class StartsWith extends DataFlow::Node { - StartsWith::Range range; - - StartsWith() { range = this } - + class StartsWith extends DataFlow::Node instanceof StartsWith::Range { /** * Gets the `A` in `A.startsWith(B)`. */ - DataFlow::Node getBaseString() { result = range.getBaseString() } + DataFlow::Node getBaseString() { result = super.getBaseString() } /** * Gets the `B` in `A.startsWith(B)`. */ - DataFlow::Node getSubstring() { result = range.getSubstring() } + DataFlow::Node getSubstring() { result = super.getSubstring() } /** * Gets the polarity of the check. @@ -29,7 +25,7 @@ module StringOps { * If the polarity is `false` the check returns `true` if the string does not start * with the given substring. */ - boolean getPolarity() { result = range.getPolarity() } + boolean getPolarity() { result = super.getPolarity() } } module StartsWith { @@ -237,20 +233,16 @@ module StringOps { /** * An expression that is equivalent to `A.endsWith(B)` or `!A.endsWith(B)`. */ - class EndsWith extends DataFlow::Node { - EndsWith::Range range; - - EndsWith() { this = range } - + class EndsWith extends DataFlow::Node instanceof EndsWith::Range { /** * Gets the `A` in `A.startsWith(B)`. */ - DataFlow::Node getBaseString() { result = range.getBaseString() } + DataFlow::Node getBaseString() { result = super.getBaseString() } /** * Gets the `B` in `A.startsWith(B)`. */ - DataFlow::Node getSubstring() { result = range.getSubstring() } + DataFlow::Node getSubstring() { result = super.getSubstring() } /** * Gets the polarity if the check. @@ -258,7 +250,7 @@ module StringOps { * If the polarity is `false` the check returns `true` if the string does not end * with the given substring. */ - boolean getPolarity() { result = range.getPolarity() } + boolean getPolarity() { result = super.getPolarity() } } module EndsWith { @@ -662,18 +654,14 @@ module StringOps { * if (!match) { ... } // <--- 'match' is the RegExpTest * ``` */ - class RegExpTest extends DataFlow::Node { - RegExpTest::Range range; - - RegExpTest() { this = range } - + class RegExpTest extends DataFlow::Node instanceof RegExpTest::Range { /** * Gets the AST of the regular expression used in the test, if it can be seen locally. */ RegExpTerm getRegExp() { result = getRegExpOperand().getALocalSource().(DataFlow::RegExpCreationNode).getRoot() or - result = range.getRegExpOperand(true).asExpr().(StringLiteral).asRegExp() + result = super.getRegExpOperand(true).asExpr().(StringLiteral).asRegExp() } /** @@ -681,12 +669,12 @@ module StringOps { * * In some cases this represents a string value being coerced to a RegExp object. */ - DataFlow::Node getRegExpOperand() { result = range.getRegExpOperand(_) } + DataFlow::Node getRegExpOperand() { result = super.getRegExpOperand(_) } /** * Gets the data flow node corresponding to the string being tested against the regular expression. */ - DataFlow::Node getStringOperand() { result = range.getStringOperand() } + DataFlow::Node getStringOperand() { result = super.getStringOperand() } /** * Gets the return value indicating that the string matched the regular expression. @@ -694,7 +682,7 @@ module StringOps { * For example, for `regexp.exec(str) == null`, the polarity is `false`, and for * `regexp.exec(str) != null` the polarity is `true`. */ - boolean getPolarity() { result = range.getPolarity() } + boolean getPolarity() { result = super.getPolarity() } } /** diff --git a/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll index 40747f56f39..2d49693d6aa 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll @@ -947,7 +947,7 @@ private predicate exploratoryFlowStep( isAdditionalLoadStoreStep(pred, succ, _, _, cfg) or // the following three disjuncts taken together over-approximate flow through // higher-order calls - callback(pred, succ) or + exploratoryCallbackStep(pred, succ) or succ = pred.(DataFlow::FunctionNode).getAParameter() or exploratoryBoundInvokeStep(pred, succ) } diff --git a/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll b/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll index 7c832e20aed..c697c43dcce 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll @@ -702,13 +702,9 @@ class ArrayCreationNode extends DataFlow::ValueNode, DataFlow::SourceNode { * define(["fs"], function(fs) { ... }); // AMD module * ``` */ -class ModuleImportNode extends DataFlow::SourceNode { - ModuleImportNode::Range range; - - ModuleImportNode() { this = range } - +class ModuleImportNode extends DataFlow::SourceNode instanceof ModuleImportNode::Range { /** Gets the path of the imported module. */ - string getPath() { result = range.getPath() } + string getPath() { result = super.getPath() } } module ModuleImportNode { @@ -844,25 +840,21 @@ module MemberKind { * * Additional patterns can be recognized as class nodes, by extending `DataFlow::ClassNode::Range`. */ -class ClassNode extends DataFlow::SourceNode { - ClassNode::Range impl; - - ClassNode() { this = impl } - +class ClassNode extends DataFlow::SourceNode instanceof ClassNode::Range { /** * Gets the unqualified name of the class, if it has one or one can be determined from the context. */ - string getName() { result = impl.getName() } + string getName() { result = super.getName() } /** * Gets a description of the class. */ - string describe() { result = impl.describe() } + string describe() { result = super.describe() } /** * Gets the constructor function of this class. */ - FunctionNode getConstructor() { result = impl.getConstructor() } + FunctionNode getConstructor() { result = super.getConstructor() } /** * Gets an instance method declared in this class, with the given name, if any. @@ -870,7 +862,7 @@ class ClassNode extends DataFlow::SourceNode { * Does not include methods from superclasses. */ FunctionNode getInstanceMethod(string name) { - result = impl.getInstanceMember(name, MemberKind::method()) + result = super.getInstanceMember(name, MemberKind::method()) } /** @@ -880,7 +872,7 @@ class ClassNode extends DataFlow::SourceNode { * * Does not include methods from superclasses. */ - FunctionNode getAnInstanceMethod() { result = impl.getAnInstanceMember(MemberKind::method()) } + FunctionNode getAnInstanceMethod() { result = super.getAnInstanceMember(MemberKind::method()) } /** * Gets the instance method, getter, or setter with the given name and kind. @@ -888,7 +880,7 @@ class ClassNode extends DataFlow::SourceNode { * Does not include members from superclasses. */ FunctionNode getInstanceMember(string name, MemberKind kind) { - result = impl.getInstanceMember(name, kind) + result = super.getInstanceMember(name, kind) } /** @@ -896,31 +888,31 @@ class ClassNode extends DataFlow::SourceNode { * * Does not include members from superclasses. */ - FunctionNode getAnInstanceMember(MemberKind kind) { result = impl.getAnInstanceMember(kind) } + FunctionNode getAnInstanceMember(MemberKind kind) { result = super.getAnInstanceMember(kind) } /** * Gets an instance method, getter, or setter declared in this class. * * Does not include members from superclasses. */ - FunctionNode getAnInstanceMember() { result = impl.getAnInstanceMember(_) } + FunctionNode getAnInstanceMember() { result = super.getAnInstanceMember(_) } /** * Gets the static method declared in this class with the given name. */ - FunctionNode getStaticMethod(string name) { result = impl.getStaticMethod(name) } + FunctionNode getStaticMethod(string name) { result = super.getStaticMethod(name) } /** * Gets a static method declared in this class. * * The constructor is not considered a static method. */ - FunctionNode getAStaticMethod() { result = impl.getAStaticMethod() } + FunctionNode getAStaticMethod() { result = super.getAStaticMethod() } /** * Gets a dataflow node that refers to the superclass of this class. */ - DataFlow::Node getASuperClassNode() { result = impl.getASuperClassNode() } + DataFlow::Node getASuperClassNode() { result = super.getASuperClassNode() } /** * Gets a direct super class of this class. @@ -1066,13 +1058,13 @@ class ClassNode extends DataFlow::SourceNode { * Gets the type annotation for the field `fieldName`, if any. */ TypeAnnotation getFieldTypeAnnotation(string fieldName) { - result = impl.getFieldTypeAnnotation(fieldName) + result = super.getFieldTypeAnnotation(fieldName) } /** * Gets a decorator applied to this class. */ - DataFlow::Node getADecorator() { result = impl.getADecorator() } + DataFlow::Node getADecorator() { result = super.getADecorator() } } module ClassNode { @@ -1358,11 +1350,7 @@ module ClassNode { * _.partial(fn, x, y, z) * ``` */ -class PartialInvokeNode extends DataFlow::Node { - PartialInvokeNode::Range range; - - PartialInvokeNode() { this = range } - +class PartialInvokeNode extends DataFlow::Node instanceof PartialInvokeNode::Range { /** Gets a node holding a callback invoked by this partial invocation node. */ DataFlow::Node getACallbackNode() { isPartialArgument(result, _, _) @@ -1374,26 +1362,26 @@ class PartialInvokeNode extends DataFlow::Node { * Holds if `argument` is passed as argument `index` to the function in `callback`. */ predicate isPartialArgument(DataFlow::Node callback, DataFlow::Node argument, int index) { - range.isPartialArgument(callback, argument, index) + super.isPartialArgument(callback, argument, index) } /** * Gets a node referring to a bound version of `callback` with `boundArgs` arguments bound. */ DataFlow::SourceNode getBoundFunction(DataFlow::Node callback, int boundArgs) { - result = range.getBoundFunction(callback, boundArgs) + result = super.getBoundFunction(callback, boundArgs) } /** * Gets the node holding the receiver to be passed to the bound function, if specified. */ - DataFlow::Node getBoundReceiver() { result = range.getBoundReceiver(_) } + DataFlow::Node getBoundReceiver() { result = super.getBoundReceiver(_) } /** * Gets the node holding the receiver to be passed to the bound function, if specified. */ DataFlow::Node getBoundReceiver(DataFlow::Node callback) { - result = range.getBoundReceiver(callback) + result = super.getBoundReceiver(callback) } } diff --git a/javascript/ql/lib/semmle/javascript/dataflow/TrackedNodes.qll b/javascript/ql/lib/semmle/javascript/dataflow/TrackedNodes.qll index 28d9a432341..58ecb5ae54b 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/TrackedNodes.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/TrackedNodes.qll @@ -154,7 +154,7 @@ private module NodeTracking { or basicLoadStep(mid, nd, _) or - callback(mid, nd) + exploratoryCallbackStep(mid, nd) or nd = mid.(DataFlow::FunctionNode).getAParameter() ) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSteps.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSteps.qll index 50575460da7..6ba9ed3cfa2 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSteps.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSteps.qll @@ -434,7 +434,7 @@ private module CachedSteps { * invocation. */ cached - predicate callback(DataFlow::Node arg, DataFlow::SourceNode cb) { + predicate exploratoryCallbackStep(DataFlow::Node arg, DataFlow::SourceNode cb) { Stages::TypeTracking::ref() and exists(DataFlow::InvokeNode invk, DataFlow::ParameterNode cbParm, DataFlow::Node cbArg | arg = invk.getAnArgument() and @@ -444,12 +444,24 @@ private module CachedSteps { ) or exists(DataFlow::ParameterNode cbParm, DataFlow::Node cbArg | - callback(arg, cbParm) and + exploratoryCallbackStep(arg, cbParm) and callStep(cbArg, cbParm) and cb.flowsTo(cbArg) ) } + /** Gets a function that flows to `parameter` via one or more parameter-passing steps. */ + cached + DataFlow::FunctionNode getACallbackSource(DataFlow::ParameterNode parameter) { + Stages::TypeTracking::ref() and + callStep(result.getALocalUse(), parameter) + or + exists(DataFlow::ParameterNode mid | + callStep(mid.getALocalUse(), parameter) and + result = getACallbackSource(mid) + ) + } + /** * Holds if `f` may return `base`, which has a write of property `prop` with right-hand side `rhs`. */ diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/StepSummary.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/StepSummary.qll index 14a6cdf0d1e..065bb1b75a8 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/StepSummary.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/StepSummary.qll @@ -156,6 +156,13 @@ private module Cached { succ = fun.getAnInvocation() ) ) + or + // Add 'return' steps from callback arguments to callback parameters + exists(DataFlow::ParameterNode parameter, int i | + pred = parameter.getAnInvocation().getArgument(i) and + succ = getACallbackSource(parameter).getParameter(i) and + summary = ReturnStep() + ) } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Cheerio.qll b/javascript/ql/lib/semmle/javascript/frameworks/Cheerio.qll index b9705aebfbd..beffe148ee3 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Cheerio.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Cheerio.qll @@ -32,10 +32,7 @@ module Cheerio { * Creation of `cheerio` object, a collection of virtual DOM elements * with an interface similar to that of a jQuery object. */ - class CheerioObjectCreation extends DataFlow::SourceNode { - CheerioObjectCreation::Range range; - - CheerioObjectCreation() { this = range } + class CheerioObjectCreation extends DataFlow::SourceNode instanceof CheerioObjectCreation::Range { } module CheerioObjectCreation { diff --git a/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll index 3d496f28177..82670947d3d 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll @@ -18,25 +18,21 @@ import javascript * To model additional APIs, extend `ClientRequest::Range` and implement its abstract member * predicates. */ -class ClientRequest extends DataFlow::InvokeNode { - ClientRequest::Range self; - - ClientRequest() { this = self } - +class ClientRequest extends DataFlow::InvokeNode instanceof ClientRequest::Range { /** * Gets the URL of the request. */ - DataFlow::Node getUrl() { result = self.getUrl() } + DataFlow::Node getUrl() { result = super.getUrl() } /** * Gets the host of the request. */ - DataFlow::Node getHost() { result = self.getHost() } + DataFlow::Node getHost() { result = super.getHost() } /** * Gets a node that contributes to the data-part this request. */ - DataFlow::Node getADataNode() { result = self.getADataNode() } + DataFlow::Node getADataNode() { result = super.getADataNode() } /** * Gets a data flow node that refers to some representation of the response, possibly @@ -60,7 +56,7 @@ class ClientRequest extends DataFlow::InvokeNode { * - Any value provided by custom implementations of `ClientRequest::Range`. */ DataFlow::Node getAResponseDataNode(string responseType, boolean promise) { - result = self.getAResponseDataNode(responseType, promise) + result = super.getAResponseDataNode(responseType, promise) } /** @@ -72,7 +68,7 @@ class ClientRequest extends DataFlow::InvokeNode { /** * Gets a data-flow node that determines where in the file-system the result of the request should be saved. */ - DataFlow::Node getASavePath() { result = self.getASavePath() } + DataFlow::Node getASavePath() { result = super.getASavePath() } } deprecated class CustomClientRequest = ClientRequest::Range; diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Clipboard.qll b/javascript/ql/lib/semmle/javascript/frameworks/Clipboard.qll new file mode 100644 index 00000000000..be7e414eb28 --- /dev/null +++ b/javascript/ql/lib/semmle/javascript/frameworks/Clipboard.qll @@ -0,0 +1,63 @@ +/** + * Provides predicates for reasoning about clipboard data. + */ + +import javascript + +/** + * Gets a jQuery "paste" event. + * E.g. `e` in `$("#foo").on("paste", function(e) { ... })`. + */ +private DataFlow::SourceNode jQueryPasteEvent(DataFlow::TypeTracker t) { + t.start() and + exists(DataFlow::CallNode call | + call = JQuery::objectRef().getAMethodCall(["bind", "on", "live", "one", "delegate"]) and + call.getArgument(0).mayHaveStringValue("paste") + | + result = call.getCallback(call.getNumArgument() - 1).getParameter(0) + ) + or + exists(DataFlow::TypeTracker t2 | result = jQueryPasteEvent(t2).track(t2, t)) +} + +/** + * Gets a DOM "paste" event. + * E.g. `e` in `document.addEventListener("paste", e => { ... })`. + */ +private DataFlow::SourceNode pasteEvent(DataFlow::TypeTracker t) { + t.start() and + exists(DataFlow::CallNode call | call = DOM::domValueRef().getAMemberCall("addEventListener") | + call.getArgument(0).mayHaveStringValue("paste") and + result = call.getCallback(1).getParameter(0) + ) + or + t.start() and + result = jQueryPasteEvent(DataFlow::TypeTracker::end()).getAPropertyRead("originalEvent") + or + exists(DataFlow::TypeTracker t2 | result = pasteEvent(t2).track(t2, t)) +} + +/** + * Gets a reference to the clipboardData DataTransfer object. + * https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent/clipboardData + */ +private DataFlow::SourceNode clipboardDataTransferSource(DataFlow::TypeTracker t) { + t.start() and + exists(DataFlow::PropRead read | read = result | + read.getPropertyName() = "clipboardData" and + read.getBase().getALocalSource() = pasteEvent(DataFlow::TypeTracker::end()) + ) + or + exists(DataFlow::TypeTracker t2 | result = clipboardDataTransferSource(t2).track(t2, t)) +} + +/** + * A reference to data from the clipboard. Seen as a source for DOM-based XSS. + */ +private class ClipboardSource extends RemoteFlowSource { + ClipboardSource() { + this = clipboardDataTransferSource(DataFlow::TypeTracker::end()).getAMethodCall("getData") + } + + override string getSourceType() { result = "Clipboard data" } +} diff --git a/javascript/ql/lib/semmle/javascript/frameworks/ComposedFunctions.qll b/javascript/ql/lib/semmle/javascript/frameworks/ComposedFunctions.qll index b1016ce56be..6887758b064 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/ComposedFunctions.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/ComposedFunctions.qll @@ -8,18 +8,14 @@ import javascript * A call to a function that constructs a function composition `f(g(h(...)))` from a * series of functions `f, g, h, ...`. */ -class FunctionCompositionCall extends DataFlow::CallNode { - FunctionCompositionCall::Range range; - - FunctionCompositionCall() { this = range } - +class FunctionCompositionCall extends DataFlow::CallNode instanceof FunctionCompositionCall::Range { /** * Gets the `i`th function in the composition `f(g(h(...)))`, counting from left to right. * * Note that this is the opposite of the order in which the function are invoked, * that is, `g` occurs later than `f` in `f(g(...))` but is invoked before `f`. */ - DataFlow::Node getOperandNode(int i) { result = range.getOperandNode(i) } + DataFlow::Node getOperandNode(int i) { result = super.getOperandNode(i) } /** Gets a node holding one of the functions to be composed. */ final DataFlow::Node getAnOperandNode() { result = getOperandNode(_) } @@ -38,7 +34,7 @@ class FunctionCompositionCall extends DataFlow::CallNode { final DataFlow::FunctionNode getAnOperandFunction() { result = getOperandFunction(_) } /** Gets the number of functions being composed. */ - int getNumOperand() { result = range.getNumOperand() } + int getNumOperand() { result = super.getNumOperand() } } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Electron.qll b/javascript/ql/lib/semmle/javascript/frameworks/Electron.qll index 7d099932738..2c326e7cd31 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Electron.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Electron.qll @@ -182,7 +182,7 @@ module Electron { * A Node.js-style HTTP or HTTPS request made using an Electron module. */ class ElectronClientRequest extends NodeJSLib::NodeJSClientRequest { - override ElectronClientRequest::Range self; + ElectronClientRequest() { this instanceof ElectronClientRequest::Range } } module ElectronClientRequest { diff --git a/javascript/ql/lib/semmle/javascript/frameworks/EventEmitter.qll b/javascript/ql/lib/semmle/javascript/frameworks/EventEmitter.qll index f044d69524d..67b746e4473 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/EventEmitter.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/EventEmitter.qll @@ -68,40 +68,32 @@ module EventEmitter { * An EventEmitter instance that implements the EventEmitter API. * Extend EventEmitter::Range to mark something as being an EventEmitter. */ -class EventEmitter extends DataFlow::Node { - EventEmitter::Range range; - - EventEmitter() { this = range } -} +class EventEmitter extends DataFlow::Node instanceof EventEmitter::Range { } /** * A registration of an event handler on an EventEmitter. */ -class EventRegistration extends DataFlow::Node { - EventRegistration::Range range; - - EventRegistration() { this = range } - +class EventRegistration extends DataFlow::Node instanceof EventRegistration::Range { /** Gets the EventEmitter that the event handler is registered on. */ - final EventEmitter getEmitter() { result = range.getEmitter() } + final EventEmitter getEmitter() { result = super.getEmitter() } /** Gets the name of the channel if possible. */ - string getChannel() { result = range.getChannel() } + string getChannel() { result = super.getChannel() } /** Gets the `i`th parameter in the event handler. */ - DataFlow::Node getReceivedItem(int i) { result = range.getReceivedItem(i) } + DataFlow::Node getReceivedItem(int i) { result = super.getReceivedItem(i) } /** * Gets a value that is returned by the event handler. * The default implementation is that no value can be returned. */ - DataFlow::Node getAReturnedValue() { result = range.getAReturnedValue() } + DataFlow::Node getAReturnedValue() { result = super.getAReturnedValue() } /** * Get a dispatch that this event handler can return a value to. * The default implementation is that there exists no such dispatch. */ - EventDispatch getAReturnDispatch() { result = range.getAReturnDispatch() } + EventDispatch getAReturnDispatch() { result = super.getAReturnDispatch() } } module EventRegistration { @@ -140,26 +132,22 @@ module EventRegistration { /** * A dispatch of an event on an EventEmitter. */ -class EventDispatch extends DataFlow::Node { - EventDispatch::Range range; - - EventDispatch() { this = range } - +class EventDispatch extends DataFlow::Node instanceof EventDispatch::Range { /** Gets the emitter that the event dispatch happens on. */ - EventEmitter getEmitter() { result = range.getEmitter() } + EventEmitter getEmitter() { result = super.getEmitter() } /** Gets the name of the channel if possible. */ - string getChannel() { result = range.getChannel() } + string getChannel() { result = super.getChannel() } /** Gets the `i`th argument that is send to the event handler. */ - DataFlow::Node getSentItem(int i) { result = range.getSentItem(i) } + DataFlow::Node getSentItem(int i) { result = super.getSentItem(i) } /** * Get an EventRegistration that this event dispatch can send an event to. * The default implementation is that the emitters of the dispatch and registration have to be equal. * Channels are by default ignored. */ - EventRegistration getAReceiver() { result = range.getAReceiver() } + EventRegistration getAReceiver() { result = super.getAReceiver() } } module EventDispatch { diff --git a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll index 9475c32eeab..94f9c4245b1 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll @@ -540,16 +540,12 @@ module HTTP { /** * An object that contains one or more potential route handlers. */ - class RouteHandlerCandidateContainer extends DataFlow::Node { - RouteHandlerCandidateContainer::Range self; - - RouteHandlerCandidateContainer() { this = self } - + class RouteHandlerCandidateContainer extends DataFlow::Node instanceof RouteHandlerCandidateContainer::Range { /** * Gets the route handler in this container that is accessed at `access`. */ DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access) { - result = self.getRouteHandler(access) + result = super.getRouteHandler(access) } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll index fa753220005..43fde9639c2 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll @@ -825,9 +825,7 @@ module NodeJSLib { * A data flow node that is an HTTP or HTTPS client request made by a Node.js application, * for example `http.request(url)`. */ - class NodeJSClientRequest extends ClientRequest { - override NodeJSClientRequest::Range self; - } + class NodeJSClientRequest extends ClientRequest instanceof NodeJSClientRequest::Range { } module NodeJSClientRequest { /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/PropertyProjection.qll b/javascript/ql/lib/semmle/javascript/frameworks/PropertyProjection.qll index e3fe62be164..730669abfaf 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/PropertyProjection.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/PropertyProjection.qll @@ -14,20 +14,16 @@ import javascript * To model additional APIs, extend `PropertyProjection::Range` and implement its abstract member * predicates. */ -class PropertyProjection extends DataFlow::CallNode { - PropertyProjection::Range self; - - PropertyProjection() { this = self } - +class PropertyProjection extends DataFlow::CallNode instanceof PropertyProjection::Range { /** * Gets the argument for the object to project properties from, such as `o` in `_.get(o, 'a.b')`. */ - DataFlow::Node getObject() { result = self.getObject() } + DataFlow::Node getObject() { result = super.getObject() } /** * Gets an argument that selects the properties to project, such as `'a.b'` in `_.get(o, 'a.b')`. */ - DataFlow::Node getASelector() { result = self.getASelector() } + DataFlow::Node getASelector() { result = super.getASelector() } /** * Holds if this call returns the value of a single projected property, as opposed to an object that can contain multiple projected properties. @@ -36,7 +32,7 @@ class PropertyProjection extends DataFlow::CallNode { * - This predicate holds for `_.get({a: 'b'}, 'a')`, which returns `'b'`, * - This predicate does not hold for `_.pick({a: 'b', c: 'd'}}, 'a')`, which returns `{a: 'b'}`, */ - predicate isSingletonProjection() { self.isSingletonProjection() } + predicate isSingletonProjection() { super.isSingletonProjection() } } module PropertyProjection { diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Redux.qll b/javascript/ql/lib/semmle/javascript/frameworks/Redux.qll index ad3f985c397..d26982cef7f 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Redux.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Redux.qll @@ -56,11 +56,7 @@ module Redux { /** * Creation of a redux store, usually via a call to `createStore`. */ - class StoreCreation extends DataFlow::SourceNode { - StoreCreation::Range range; - - StoreCreation() { this = range } - + class StoreCreation extends DataFlow::SourceNode instanceof StoreCreation::Range { /** Gets a reference to the store. */ DataFlow::SourceNode ref() { result = asApiNode().getAUse() } @@ -68,7 +64,7 @@ module Redux { API::Node asApiNode() { result.getAnImmediateUse() = this } /** Gets the data flow node holding the root reducer for this store. */ - DataFlow::Node getReducerArg() { result = range.getReducerArg() } + DataFlow::Node getReducerArg() { result = super.getReducerArg() } /** Gets a data flow node referring to the root reducer. */ DataFlow::SourceNode getAReducerSource() { result = getReducerArg().(ReducerArg).getASource() } @@ -423,13 +419,9 @@ module Redux { * Some action creators dispatch the action to a store, while for others, the value is returned and it is simply assumed to be dispatched * at some point. We model all action creators as if they dispatch the action they create. */ - class ActionCreator extends DataFlow::SourceNode { - ActionCreator::Range range; - - ActionCreator() { this = range } - + class ActionCreator extends DataFlow::SourceNode instanceof ActionCreator::Range { /** Gets the `type` property of actions created by this action creator, if it is known. */ - string getTypeTag() { result = range.getTypeTag() } + string getTypeTag() { result = super.getTypeTag() } /** * Gets the middleware function that transforms arguments passed to this function into the @@ -442,7 +434,7 @@ module Redux { * the action payload. Otherwise, the return value is the payload itself. */ DataFlow::FunctionNode getMiddlewareFunction(boolean async) { - result = range.getMiddlewareFunction(async) + result = super.getMiddlewareFunction(async) } /** Gets a data flow node referring to this action creator. */ diff --git a/javascript/ql/lib/semmle/javascript/frameworks/ShellJS.qll b/javascript/ql/lib/semmle/javascript/frameworks/ShellJS.qll index 3fc1644fdfd..4ba780b0480 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/ShellJS.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/ShellJS.qll @@ -14,13 +14,9 @@ module ShellJS { } /** A member of the `shelljs` library. */ - class Member extends DataFlow::SourceNode { - Member::Range range; - - Member() { this = range } - + class Member extends DataFlow::SourceNode instanceof Member::Range { /** Gets the name of `shelljs` member being referenced, such as `cat` in `shelljs.cat`. */ - string getName() { result = range.getName() } + string getName() { result = super.getName() } } module Member { diff --git a/javascript/ql/lib/semmlecode.javascript.dbscheme b/javascript/ql/lib/semmlecode.javascript.dbscheme index 9ca3692b65f..e54b35a8a12 100644 --- a/javascript/ql/lib/semmlecode.javascript.dbscheme +++ b/javascript/ql/lib/semmlecode.javascript.dbscheme @@ -20,21 +20,11 @@ numlines(int element_id: @sourceline ref, int num_comment: int ref ); - -/* - fromSource(0) = unknown, - fromSource(1) = from source, - fromSource(2) = from library -*/ files(unique int id: @file, - varchar(900) name: string ref, - varchar(900) simple: string ref, - varchar(900) ext: string ref, - int fromSource: int ref); + varchar(900) name: string ref); folders(unique int id: @folder, - varchar(900) name: string ref, - varchar(900) simple: string ref); + varchar(900) name: string ref); @container = @folder | @file ; @@ -156,7 +146,7 @@ stmt_containers (unique int stmt: @stmt ref, jump_targets (unique int jump: @stmt ref, int target: @stmt ref); -@stmt_parent = @stmt | @toplevel | @function_expr | @arrow_function_expr; +@stmt_parent = @stmt | @toplevel | @function_expr | @arrow_function_expr | @static_initializer; @stmt_container = @toplevel | @function | @namespace_declaration | @external_module_declaration | @global_augmentation_declaration; case @stmt.kind of @@ -531,6 +521,7 @@ case @property.kind of | 7 = @enum_member | 8 = @proper_field | 9 = @parameter_field +| 10 = @static_initializer ; @property_parent = @obj_expr | @object_pattern | @class_definition | @jsx_element | @interface_definition | @enum_declaration; diff --git a/javascript/ql/lib/semmlecode.javascript.dbscheme.stats b/javascript/ql/lib/semmlecode.javascript.dbscheme.stats index 80d8efb088a..ed051cd16ac 100644 --- a/javascript/ql/lib/semmlecode.javascript.dbscheme.stats +++ b/javascript/ql/lib/semmlecode.javascript.dbscheme.stats @@ -774,6 +774,10 @@ 2693 +@static_initializer +100 + + @local_type_access 25491 @@ -4840,18 +4844,6 @@ name 6457 - -simple -4188 - - -ext -4 - - -fromSource -1 - @@ -4871,54 +4863,6 @@ -id -simple - - -12 - - -1 -2 -6457 - - - - - - -id -ext - - -12 - - -1 -2 -6457 - - - - - - -id -fromSource - - -12 - - -1 -2 -6457 - - - - - - name id @@ -4934,316 +4878,6 @@ - -name -simple - - -12 - - -1 -2 -6457 - - - - - - -name -ext - - -12 - - -1 -2 -6457 - - - - - - -name -fromSource - - -12 - - -1 -2 -6457 - - - - - - -simple -id - - -12 - - -1 -2 -3423 - - -2 -3 -507 - - -3 -305 -258 - - - - - - -simple -name - - -12 - - -1 -2 -3423 - - -2 -3 -507 - - -3 -305 -258 - - - - - - -simple -ext - - -12 - - -1 -2 -3960 - - -2 -4 -228 - - - - - - -simple -fromSource - - -12 - - -1 -2 -4188 - - - - - - -ext -id - - -12 - - -21 -22 -1 - - -480 -481 -1 - - -756 -757 -1 - - -5200 -5201 -1 - - - - - - -ext -name - - -12 - - -21 -22 -1 - - -480 -481 -1 - - -756 -757 -1 - - -5200 -5201 -1 - - - - - - -ext -simple - - -12 - - -21 -22 -1 - - -118 -119 -1 - - -428 -429 -1 - - -3858 -3859 -1 - - - - - - -ext -fromSource - - -12 - - -1 -2 -4 - - - - - - -fromSource -id - - -12 - - -6457 -6458 -1 - - - - - - -fromSource -name - - -12 - - -6457 -6458 -1 - - - - - - -fromSource -simple - - -12 - - -4188 -4189 -1 - - - - - - -fromSource -ext - - -12 - - -4 -5 -1 - - - - - @@ -5259,10 +4893,6 @@ name 1590 - -simple -645 - @@ -5282,22 +4912,6 @@ -id -simple - - -12 - - -1 -2 -1590 - - - - - - name id @@ -5313,84 +4927,6 @@ - -name -simple - - -12 - - -1 -2 -1590 - - - - - - -simple -id - - -12 - - -1 -2 -425 - - -2 -3 -127 - - -3 -6 -58 - - -6 -113 -35 - - - - - - -simple -name - - -12 - - -1 -2 -425 - - -2 -3 -127 - - -3 -6 -58 - - -6 -113 -35 - - - - - diff --git a/javascript/ql/src/Expressions/SelfAssignment.ql b/javascript/ql/src/Expressions/SelfAssignment.ql index 50d55a50bfe..ff324831cf6 100644 --- a/javascript/ql/src/Expressions/SelfAssignment.ql +++ b/javascript/ql/src/Expressions/SelfAssignment.ql @@ -43,5 +43,8 @@ where // exclude DOM properties not isDOMProperty(e.(PropAccess).getPropertyName()) and // exclude self-assignments that have been inserted to satisfy the TypeScript JS-checker - not e.getAssignment().getParent().(ExprStmt).getDocumentation().getATag().getTitle() = "type" + not e.getAssignment().getParent().(ExprStmt).getDocumentation().getATag().getTitle() = "type" and + // exclude self-assignments in speculatively parsed template files + // named arguments may be incorrectly parsed as assignments + not e.getTopLevel() instanceof Templating::TemplateTopLevel select e.getParent(), "This expression assigns " + dsc + " to itself." diff --git a/javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql index 45e6ab2572c..6abe955c7f0 100644 --- a/javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql +++ b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql @@ -8,6 +8,7 @@ * @id js/exposure-of-private-files * @tags security * external/cwe/cwe-200 + * external/cwe/cwe-548 * @precision high */ diff --git a/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.ql b/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.ql index 2f785bace35..0b24235801d 100644 --- a/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.ql +++ b/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.ql @@ -7,7 +7,7 @@ * @precision very-high * @id js/disabling-certificate-validation * @tags security - * external/cwe-295 + * external/cwe/cwe-295 */ import javascript diff --git a/javascript/ql/src/Security/CWE-313/PasswordInConfigurationFile.ql b/javascript/ql/src/Security/CWE-313/PasswordInConfigurationFile.ql index 4d534248f45..1418a219698 100644 --- a/javascript/ql/src/Security/CWE-313/PasswordInConfigurationFile.ql +++ b/javascript/ql/src/Security/CWE-313/PasswordInConfigurationFile.ql @@ -10,6 +10,7 @@ * external/cwe/cwe-256 * external/cwe/cwe-260 * external/cwe/cwe-313 + * external/cwe/cwe-522 */ import javascript diff --git a/javascript/ql/src/experimental/Security/CWE-079/ClipboardXss.qhelp b/javascript/ql/src/experimental/Security/CWE-079/ClipboardXss.qhelp deleted file mode 100644 index 302dc170d37..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-079/ClipboardXss.qhelp +++ /dev/null @@ -1,57 +0,0 @@ - - - - -

    -Directly pasting user input from the clipboard to a webpage -without properly sanitizing the input first, allows for a cross-site scripting vulnerability. -

    - - - -

    -To guard against cross-site scripting, consider using contextual output encoding/escaping before -writing user input to the page, or one of the other solutions that are mentioned in the -references. -

    -
    - - -

    -The following example shows a div element whose HTML content comes directly from the clipboard being written to the DOM, -leaving the website vulnerable to cross-site scripting. -

    - -
    - - -
  • -OWASP: -DOM based -XSS Prevention Cheat Sheet. -
  • -
  • -OWASP: -XSS -(Cross Site Scripting) Prevention Cheat Sheet. -
  • -
  • -OWASP -DOM Based XSS. -
  • -
  • -OWASP -Types of Cross-Site -Scripting. -
  • -
  • -Wikipedia: Cross-site scripting. -
  • -
  • -Securitum: -Clipboard security research. -
  • -
    - diff --git a/javascript/ql/src/experimental/Security/CWE-079/ClipboardXss.ql b/javascript/ql/src/experimental/Security/CWE-079/ClipboardXss.ql deleted file mode 100644 index c6ae4e1fed6..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-079/ClipboardXss.ql +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @name Client-side clipboard-based cross-site scripting - * @description Pasting clipboard input directly to the DOM without proper sanitization allows for - * a cross-site scripting vulnerability. - * @kind path-problem - * @problem.severity error - * @security-severity 3.1 - * @precision high - * @id js/clipboard-xss - * @tags security - * external/cwe/cwe-079 - */ - -import javascript -import DataFlow -import semmle.javascript.security.dataflow.DomBasedXssQuery as DomBasedXss -import DataFlow::PathGraph - -/* - * Gets references to clipboardData DataTransfer objects - * https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent/clipboardData - */ - -SourceNode clipboardDataTransferSource(TypeTracker t) { - t.start() and - exists(DataFlow::PropRead pr | pr.getPropertyName() = "clipboardData" and result = pr) - or - exists(TypeTracker t2 | result = clipboardDataTransferSource(t2).track(t2, t)) -} - -SourceNode clipboardDataTransferSource() { - result = clipboardDataTransferSource(TypeTracker::end()) -} - -/* - * Gets references to the result of a call to getData on a DataTransfer object - * https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/getData - */ - -SourceNode clipboardDataSource(TypeTracker t) { - t.start() and - result = clipboardDataTransferSource().getAMethodCall("getData") - or - exists(TypeTracker t2 | result = clipboardDataSource(t2).track(t2, t)) -} - -SourceNode clipboardDataSource() { result = clipboardDataSource(TypeTracker::end()) } - -class ClipboardSource extends DataFlow::Node { - ClipboardSource() { this = clipboardDataSource() } -} - -class ClipboardHtmlInjectionConfiguration extends DomBasedXss::HtmlInjectionConfiguration { - override predicate isSource(DataFlow::Node source) { source instanceof ClipboardSource } -} - -class ClipboardJQueryHtmlOrSelectorInjectionConfiguration extends DomBasedXss::JQueryHtmlOrSelectorInjectionConfiguration { - override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) { - // Reuse any source not derived from location - source instanceof ClipboardSource and - ( - label.isTaint() - or - label.isData() // Require transformation before reaching sink - ) - } -} - -from DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where - ( - cfg instanceof ClipboardHtmlInjectionConfiguration or - cfg instanceof ClipboardJQueryHtmlOrSelectorInjectionConfiguration - ) and - cfg.hasFlowPath(source, sink) -select sink.getNode(), source, sink, - sink.getNode().(DomBasedXss::Sink).getVulnerabilityKind() + " vulnerability due to $@.", - source.getNode(), "user-provided clipboard value" diff --git a/javascript/ql/src/experimental/Security/CWE-079/examples/clipboard-xss-sample.js b/javascript/ql/src/experimental/Security/CWE-079/examples/clipboard-xss-sample.js deleted file mode 100644 index 98ca88bcb25..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-079/examples/clipboard-xss-sample.js +++ /dev/null @@ -1,18 +0,0 @@ -function paste(e) { - const { clipboardData } = e.originalEvent; - if (!clipboardData) return; - - const text = clipboardData.getData('text/plain'); - const html = clipboardData.getData('text/html'); - if (!text && !html) return; - - e.preventDefault(); - - const div = document.createElement('div'); - if (html) { - div.innerHTML = html; - } else { - div.textContent = text; - } - document.body.append(div); -} \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-094/ExpressionInjection.ql b/javascript/ql/src/experimental/Security/CWE-094/ExpressionInjection.ql index a015c5f5147..29a34897880 100644 --- a/javascript/ql/src/experimental/Security/CWE-094/ExpressionInjection.ql +++ b/javascript/ql/src/experimental/Security/CWE-094/ExpressionInjection.ql @@ -65,6 +65,12 @@ private predicate isExternalUserControlledCommit(string context) { context.regexpMatch("\\bgithub\\s*\\.\\s*head_ref\\b") } +bindingset[context] +private predicate isExternalUserControlledDiscussion(string context) { + context.regexpMatch("\\bgithub\\s*\\.\\s*event\\s*\\.\\s*discussion\\s*\\.\\s*title\\b") or + context.regexpMatch("\\bgithub\\s*\\.\\s*event\\s*\\.\\s*discussion\\s*\\.\\s*body\\b") +} + from Actions::Run run, string context, Actions::On on where run.getAReferencedExpression() = context and @@ -87,6 +93,9 @@ where or exists(on.getNode("pull_request_target")) and isExternalUserControlledCommit(context) + or + (exists(on.getNode("discussion")) or exists(on.getNode("discussion_comment"))) and + isExternalUserControlledDiscussion(context) ) select run, "Potential injection from the " + context + diff --git a/javascript/ql/test/library-tests/CFG/CFG.expected b/javascript/ql/test/library-tests/CFG/CFG.expected index a41f1c4999a..235b4f73183 100644 --- a/javascript/ql/test/library-tests/CFG/CFG.expected +++ b/javascript/ql/test/library-tests/CFG/CFG.expected @@ -770,7 +770,37 @@ | staticFieldsTS | 6 | D | 6 | new D() | | staticFieldsTS | 6 | instance | 6 | D | | staticFieldsTS | 6 | new D() | 6 | static ... ew D(); | -| staticFieldsTS | 6 | static ... ew D(); | 8 | exit node of | +| staticFieldsTS | 6 | static ... ew D(); | 9 | export ... ;\\n }\\n} | +| staticFieldsTS | 9 | E | 9 | constructor | +| staticFieldsTS | 9 | class E ... ;\\n }\\n} | 10 | f | +| staticFieldsTS | 9 | constructor | 9 | function in constructor() {} | +| staticFieldsTS | 9 | constructor() {} | 9 | class E ... ;\\n }\\n} | +| staticFieldsTS | 9 | entry node of () {} | 9 | {} | +| staticFieldsTS | 9 | export ... ;\\n }\\n} | 9 | E | +| staticFieldsTS | 9 | function in constructor() {} | 9 | constructor() {} | +| staticFieldsTS | 9 | {} | 9 | exit node of () {} | +| staticFieldsTS | 10 | f | 10 | false | +| staticFieldsTS | 10 | false | 10 | static ... false; | +| staticFieldsTS | 10 | static ... false; | 11 | static ... ();\\n } | +| staticFieldsTS | 11 | static ... ();\\n } | 12 | E.f = new C(); | +| staticFieldsTS | 12 | C | 12 | new C() | +| staticFieldsTS | 12 | E | 12 | f | +| staticFieldsTS | 12 | E.f | 12 | C | +| staticFieldsTS | 12 | E.f = new C() | 14 | g | +| staticFieldsTS | 12 | E.f = new C(); | 12 | E | +| staticFieldsTS | 12 | f | 12 | E.f | +| staticFieldsTS | 12 | new C() | 12 | E.f = new C() | +| staticFieldsTS | 14 | 1337 | 14 | static ... = 1337; | +| staticFieldsTS | 14 | g | 14 | 1337 | +| staticFieldsTS | 14 | static ... = 1337; | 15 | static ... ();\\n } | +| staticFieldsTS | 15 | static ... ();\\n } | 16 | E.g = new D(); | +| staticFieldsTS | 16 | D | 16 | new D() | +| staticFieldsTS | 16 | E | 16 | g | +| staticFieldsTS | 16 | E.g | 16 | D | +| staticFieldsTS | 16 | E.g = new D() | 18 | exit node of | +| staticFieldsTS | 16 | E.g = new D(); | 16 | E | +| staticFieldsTS | 16 | g | 16 | E.g | +| staticFieldsTS | 16 | new D() | 16 | E.g = new D() | | switch | 1 | entry node of | 14 | f | | switch | 1 | switch ... 19;\\n} | 2 | x | | switch | 2 | x | 6 | case\\n ... 19; | diff --git a/javascript/ql/test/library-tests/CFG/StaticInit.expected b/javascript/ql/test/library-tests/CFG/StaticInit.expected index 95e41584cdc..1da2f66503c 100644 --- a/javascript/ql/test/library-tests/CFG/StaticInit.expected +++ b/javascript/ql/test/library-tests/CFG/StaticInit.expected @@ -14,3 +14,5 @@ | staticFields.js:2:3:2:28 | static ... ew C(); | Field initializer occurs after its class is created | | staticFieldsTS.ts:2:3:2:31 | static ... ew C(); | Field initializer occurs after its class is created | | staticFieldsTS.ts:6:3:6:31 | static ... ew D(); | Field initializer occurs after its class is created | +| staticFieldsTS.ts:10:3:10:32 | static ... false; | Field initializer occurs after its class is created | +| staticFieldsTS.ts:14:3:14:30 | static ... = 1337; | Field initializer occurs after its class is created | diff --git a/javascript/ql/test/library-tests/CFG/staticFieldsTS.ts b/javascript/ql/test/library-tests/CFG/staticFieldsTS.ts index ca394de8265..77a17831958 100644 --- a/javascript/ql/test/library-tests/CFG/staticFieldsTS.ts +++ b/javascript/ql/test/library-tests/CFG/staticFieldsTS.ts @@ -5,3 +5,14 @@ class C { export class D { static instance: D = new D(); } + +export class E { + static f: C | boolean = false; + static { + E.f = new C(); + } + static g: D | number = 1337; + static { + E.g = new D(); + } +} \ No newline at end of file diff --git a/javascript/ql/test/library-tests/Classes/staticInitializer.js b/javascript/ql/test/library-tests/Classes/staticInitializer.js new file mode 100644 index 00000000000..453840ca57c --- /dev/null +++ b/javascript/ql/test/library-tests/Classes/staticInitializer.js @@ -0,0 +1,18 @@ +class MyClass { + static x = 1; + constructor() { + this.y = 2; + } + static { + MyClass.z = 3; + } + foo() { + this.t = 4; + } + static bar() { + this.u = 5; + } + static { + this.v = 6; + } +} \ No newline at end of file diff --git a/javascript/ql/test/library-tests/Classes/tests.expected b/javascript/ql/test/library-tests/Classes/tests.expected index e200256b70c..9097aafc8db 100644 --- a/javascript/ql/test/library-tests/Classes/tests.expected +++ b/javascript/ql/test/library-tests/Classes/tests.expected @@ -4,6 +4,7 @@ test_FieldInits | privateFields.js:2:2:2:15 | #privDecl = 3; | privateFields.js:2:14:2:14 | 3 | | privateFields.js:3:2:3:12 | #if = "if"; | privateFields.js:3:8:3:11 | "if" | | privateFields.js:21:2:21:22 | ["#publ ... "] = 6; | privateFields.js:21:21:21:21 | 6 | +| staticInitializer.js:2:3:2:15 | static x = 1; | staticInitializer.js:2:14:2:14 | 1 | test_ComputedMethods | tst.js:3:3:3:56 | ["const ... r. */ } | | tst.js:13:3:13:10 | [m]() {} | @@ -11,6 +12,7 @@ test_StaticMethods | points.js:15:3:17:3 | static ... t";\\n } | | points.js:30:3:32:3 | static ... t";\\n } | | staticConstructor.js:2:3:2:59 | static ... tor"; } | +| staticInitializer.js:12:3:14:3 | static ... 5;\\n } | test_ClassDefinition_getSuperClass | points.js:20:1:33:1 | class C ... ;\\n }\\n} | points.js:20:29:20:33 | Point | | tst.js:6:1:8:1 | class B ... t); }\\n} | tst.js:6:17:6:17 | A | @@ -18,6 +20,7 @@ test_ClassNodeStaticMethod | points.js:1:1:18:1 | class P ... ;\\n }\\n} | className | points.js:15:19:17:3 | () {\\n ... t";\\n } | | points.js:20:1:33:1 | class C ... ;\\n }\\n} | className | points.js:30:19:32:3 | () {\\n ... t";\\n } | | staticConstructor.js:1:1:3:1 | class M ... r"; }\\n} | constructor | staticConstructor.js:2:21:2:59 | () { re ... tor"; } | +| staticInitializer.js:1:1:18:1 | class M ... ;\\n }\\n} | bar | staticInitializer.js:12:13:14:3 | () {\\n ... 5;\\n } | test_ClassDefinitions | dataflow.js:4:2:13:2 | class F ... \\n\\t\\t}\\n\\t} | | fields.js:1:1:4:1 | class C ... = 42\\n} | @@ -25,6 +28,7 @@ test_ClassDefinitions | points.js:20:1:33:1 | class C ... ;\\n }\\n} | | privateFields.js:1:1:27:1 | class F ... );\\n\\t}\\n} | | staticConstructor.js:1:1:3:1 | class M ... r"; }\\n} | +| staticInitializer.js:1:1:18:1 | class M ... ;\\n }\\n} | | tst.js:1:9:4:1 | class { ... */ }\\n} | | tst.js:6:1:8:1 | class B ... t); }\\n} | | tst.js:11:1:14:1 | class C ... () {}\\n} | @@ -38,6 +42,7 @@ test_Fields | privateFields.js:3:2:3:12 | #if = "if"; | privateFields.js:3:2:3:4 | #if | | privateFields.js:19:2:19:13 | #privSecond; | privateFields.js:19:2:19:12 | #privSecond | | privateFields.js:21:2:21:22 | ["#publ ... "] = 6; | privateFields.js:21:3:21:16 | "#publicField" | +| staticInitializer.js:2:3:2:15 | static x = 1; | staticInitializer.js:2:10:2:10 | x | test_ClassDefinition_getName | dataflow.js:4:2:13:2 | class F ... \\n\\t\\t}\\n\\t} | Foo | | fields.js:1:1:4:1 | class C ... = 42\\n} | C | @@ -45,6 +50,7 @@ test_ClassDefinition_getName | points.js:20:1:33:1 | class C ... ;\\n }\\n} | ColouredPoint | | privateFields.js:1:1:27:1 | class F ... );\\n\\t}\\n} | Foo | | staticConstructor.js:1:1:3:1 | class M ... r"; }\\n} | MyClass | +| staticInitializer.js:1:1:18:1 | class M ... ;\\n }\\n} | MyClass | | tst.js:1:9:4:1 | class { ... */ }\\n} | A | | tst.js:6:1:8:1 | class B ... t); }\\n} | B | | tst.js:11:1:14:1 | class C ... () {}\\n} | C | @@ -67,6 +73,9 @@ test_MethodDefinitions | privateFields.js:23:2:26:2 | calls() ... l();\\n\\t} | privateFields.js:23:2:23:6 | calls | privateFields.js:23:7:26:2 | () {\\n\\t\\t ... l();\\n\\t} | privateFields.js:1:1:27:1 | class F ... );\\n\\t}\\n} | | staticConstructor.js:1:15:1:14 | constructor() {} | staticConstructor.js:1:15:1:14 | constructor | staticConstructor.js:1:15:1:14 | () {} | staticConstructor.js:1:1:3:1 | class M ... r"; }\\n} | | staticConstructor.js:2:3:2:59 | static ... tor"; } | staticConstructor.js:2:10:2:20 | constructor | staticConstructor.js:2:21:2:59 | () { re ... tor"; } | staticConstructor.js:1:1:3:1 | class M ... r"; }\\n} | +| staticInitializer.js:3:3:5:3 | constru ... 2;\\n } | staticInitializer.js:3:3:3:13 | constructor | staticInitializer.js:3:14:5:3 | () {\\n ... 2;\\n } | staticInitializer.js:1:1:18:1 | class M ... ;\\n }\\n} | +| staticInitializer.js:9:3:11:3 | foo() { ... 4;\\n } | staticInitializer.js:9:3:9:5 | foo | staticInitializer.js:9:6:11:3 | () {\\n ... 4;\\n } | staticInitializer.js:1:1:18:1 | class M ... ;\\n }\\n} | +| staticInitializer.js:12:3:14:3 | static ... 5;\\n } | staticInitializer.js:12:10:12:12 | bar | staticInitializer.js:12:13:14:3 | () {\\n ... 5;\\n } | staticInitializer.js:1:1:18:1 | class M ... ;\\n }\\n} | | tst.js:2:3:2:50 | "constr ... r. */ } | tst.js:2:3:2:15 | "constructor" | tst.js:2:16:2:50 | () { /* ... r. */ } | tst.js:1:9:4:1 | class { ... */ }\\n} | | tst.js:3:3:3:56 | ["const ... r. */ } | tst.js:3:4:3:16 | "constructor" | tst.js:3:18:3:56 | () { /* ... r. */ } | tst.js:1:9:4:1 | class { ... */ }\\n} | | tst.js:7:3:7:38 | constru ... get); } | tst.js:7:3:7:13 | constructor | tst.js:7:14:7:38 | () { su ... get); } | tst.js:6:1:8:1 | class B ... t); }\\n} | @@ -99,6 +108,12 @@ test_getAMember | privateFields.js:1:1:27:1 | class F ... );\\n\\t}\\n} | privateFields.js:23:2:26:2 | calls() ... l();\\n\\t} | | staticConstructor.js:1:1:3:1 | class M ... r"; }\\n} | staticConstructor.js:1:15:1:14 | constructor() {} | | staticConstructor.js:1:1:3:1 | class M ... r"; }\\n} | staticConstructor.js:2:3:2:59 | static ... tor"; } | +| staticInitializer.js:1:1:18:1 | class M ... ;\\n }\\n} | staticInitializer.js:2:3:2:15 | static x = 1; | +| staticInitializer.js:1:1:18:1 | class M ... ;\\n }\\n} | staticInitializer.js:3:3:5:3 | constru ... 2;\\n } | +| staticInitializer.js:1:1:18:1 | class M ... ;\\n }\\n} | staticInitializer.js:6:10:8:3 | {\\n M ... 3;\\n } | +| staticInitializer.js:1:1:18:1 | class M ... ;\\n }\\n} | staticInitializer.js:9:3:11:3 | foo() { ... 4;\\n } | +| staticInitializer.js:1:1:18:1 | class M ... ;\\n }\\n} | staticInitializer.js:12:3:14:3 | static ... 5;\\n } | +| staticInitializer.js:1:1:18:1 | class M ... ;\\n }\\n} | staticInitializer.js:15:10:17:3 | {\\n t ... 6;\\n } | | tst.js:1:9:4:1 | class { ... */ }\\n} | tst.js:2:3:2:50 | "constr ... r. */ } | | tst.js:1:9:4:1 | class { ... */ }\\n} | tst.js:3:3:3:56 | ["const ... r. */ } | | tst.js:6:1:8:1 | class B ... t); }\\n} | tst.js:7:3:7:38 | constru ... get); } | @@ -124,6 +139,9 @@ test_MethodNames | privateFields.js:23:2:26:2 | calls() ... l();\\n\\t} | calls | | staticConstructor.js:1:15:1:14 | constructor() {} | constructor | | staticConstructor.js:2:3:2:59 | static ... tor"; } | constructor | +| staticInitializer.js:3:3:5:3 | constru ... 2;\\n } | constructor | +| staticInitializer.js:9:3:11:3 | foo() { ... 4;\\n } | foo | +| staticInitializer.js:12:3:14:3 | static ... 5;\\n } | bar | | tst.js:2:3:2:50 | "constr ... r. */ } | constructor | | tst.js:3:3:3:56 | ["const ... r. */ } | constructor | | tst.js:7:3:7:38 | constru ... get); } | constructor | @@ -148,6 +166,7 @@ test_ConstructorDefinitions | points.js:21:3:24:3 | constru ... c;\\n } | | privateFields.js:1:11:1:10 | constructor() {} | | staticConstructor.js:1:15:1:14 | constructor() {} | +| staticInitializer.js:3:3:5:3 | constru ... 2;\\n } | | tst.js:2:3:2:50 | "constr ... r. */ } | | tst.js:7:3:7:38 | constru ... get); } | | tst.js:11:9:11:8 | constructor() {} | @@ -158,6 +177,7 @@ test_ClassNodeConstructor | points.js:20:1:33:1 | class C ... ;\\n }\\n} | points.js:21:14:24:3 | (x, y, ... c;\\n } | | privateFields.js:1:1:27:1 | class F ... );\\n\\t}\\n} | privateFields.js:1:11:1:10 | () {} | | staticConstructor.js:1:1:3:1 | class M ... r"; }\\n} | staticConstructor.js:1:15:1:14 | () {} | +| staticInitializer.js:1:1:18:1 | class M ... ;\\n }\\n} | staticInitializer.js:3:14:5:3 | () {\\n ... 2;\\n } | | tst.js:1:9:4:1 | class { ... */ }\\n} | tst.js:2:16:2:50 | () { /* ... r. */ } | | tst.js:6:1:8:1 | class B ... t); }\\n} | tst.js:7:14:7:38 | () { su ... get); } | | tst.js:11:1:14:1 | class C ... () {}\\n} | tst.js:11:9:11:8 | () {} | @@ -170,6 +190,7 @@ test_ClassNodeInstanceMethod | privateFields.js:1:1:27:1 | class F ... );\\n\\t}\\n} | equals | privateFields.js:10:8:12:2 | (o) {\\n\\t ... ecl;\\n\\t} | | privateFields.js:1:1:27:1 | class F ... );\\n\\t}\\n} | reads | privateFields.js:4:7:8:2 | () {\\n\\t\\t ... #if;\\n\\t} | | privateFields.js:1:1:27:1 | class F ... );\\n\\t}\\n} | writes | privateFields.js:14:8:17:2 | () {\\n\\t\\t ... = 5;\\n\\t} | +| staticInitializer.js:1:1:18:1 | class M ... ;\\n }\\n} | foo | staticInitializer.js:9:6:11:3 | () {\\n ... 4;\\n } | | tst.js:1:9:4:1 | class { ... */ }\\n} | constructor | tst.js:3:18:3:56 | () { /* ... r. */ } | | tst.js:11:1:14:1 | class C ... () {}\\n} | m | tst.js:12:4:12:8 | () {} | getAccessModifier @@ -223,6 +244,15 @@ getAccessModifier | staticConstructor.js:2:3:2:59 | static ... tor"; } | staticConstructor.js:2:10:2:20 | constructor | Public | | staticConstructor.js:4:1:4:11 | console.log | staticConstructor.js:4:9:4:11 | log | Public | | staticConstructor.js:4:13:4:31 | MyClass.constructor | staticConstructor.js:4:21:4:31 | constructor | Public | +| staticInitializer.js:2:3:2:15 | static x = 1; | staticInitializer.js:2:10:2:10 | x | Public | +| staticInitializer.js:3:3:5:3 | constru ... 2;\\n } | staticInitializer.js:3:3:3:13 | constructor | Public | +| staticInitializer.js:4:5:4:10 | this.y | staticInitializer.js:4:10:4:10 | y | Public | +| staticInitializer.js:7:5:7:13 | MyClass.z | staticInitializer.js:7:13:7:13 | z | Public | +| staticInitializer.js:9:3:11:3 | foo() { ... 4;\\n } | staticInitializer.js:9:3:9:5 | foo | Public | +| staticInitializer.js:10:5:10:10 | this.t | staticInitializer.js:10:10:10:10 | t | Public | +| staticInitializer.js:12:3:14:3 | static ... 5;\\n } | staticInitializer.js:12:10:12:12 | bar | Public | +| staticInitializer.js:13:5:13:10 | this.u | staticInitializer.js:13:10:13:10 | u | Public | +| staticInitializer.js:16:5:16:10 | this.v | staticInitializer.js:16:10:16:10 | v | Public | | tst.js:2:3:2:50 | "constr ... r. */ } | tst.js:2:3:2:15 | "constructor" | Public | | tst.js:3:3:3:56 | ["const ... r. */ } | tst.js:3:4:3:16 | "constructor" | Public | | tst.js:7:3:7:38 | constru ... get); } | tst.js:7:3:7:13 | constructor | Public | @@ -233,3 +263,6 @@ getAccessModifier dataflow | dataflow.js:2:15:2:22 | "source" | dataflow.js:14:7:14:25 | new Foo().getPriv() | | dataflow.js:2:15:2:22 | "source" | dataflow.js:16:7:16:33 | new Foo ... ivate() | +staticInitializer +| staticInitializer.js:1:1:18:1 | class M ... ;\\n }\\n} | staticInitializer.js:6:10:8:3 | {\\n M ... 3;\\n } | +| staticInitializer.js:1:1:18:1 | class M ... ;\\n }\\n} | staticInitializer.js:15:10:17:3 | {\\n t ... 6;\\n } | diff --git a/javascript/ql/test/library-tests/Classes/tests.ql b/javascript/ql/test/library-tests/Classes/tests.ql index 5cb3c90db85..5231f51c552 100644 --- a/javascript/ql/test/library-tests/Classes/tests.ql +++ b/javascript/ql/test/library-tests/Classes/tests.ql @@ -1,20 +1,76 @@ -import FieldInits -import ComputedMethods -import StaticMethods -import ClassDefinition_getSuperClass -import ClassNodeStaticMethod -import ClassDefinitions -import AccessorMethods -import Fields -import ClassDefinition_getName -import MethodDefinitions -import getAMember -import MethodNames -import NewTargetExpr -import SuperExpr -import SyntheticConstructors -import ConstructorDefinitions -import ClassNodeConstructor -import ClassNodeInstanceMethod -import PrivateField -import ClassFlow +import javascript + +query predicate test_FieldInits(FieldDefinition field, Expr res) { res = field.getInit() } + +query predicate test_ComputedMethods(MethodDefinition md) { md.isComputed() } + +query predicate test_StaticMethods(MethodDefinition md) { md.isStatic() } + +query predicate test_ClassDefinition_getSuperClass(ClassDefinition cd, Expr res) { + res = cd.getSuperClass() +} + +query predicate test_ClassNodeStaticMethod( + DataFlow::ClassNode class_, string name, DataFlow::FunctionNode res +) { + res = class_.getStaticMethod(name) +} + +query predicate test_ClassDefinitions(ClassDefinition cd) { any() } + +query predicate test_AccessorMethods(AccessorMethodDefinition amd) { any() } + +query predicate test_Fields(FieldDefinition field, Expr res) { res = field.getNameExpr() } + +query predicate test_ClassDefinition_getName(ClassDefinition cd, string res) { res = cd.getName() } + +query predicate test_MethodDefinitions( + MethodDefinition md, Expr res0, FunctionExpr res1, ClassDefinition res2 +) { + res0 = md.getNameExpr() and res1 = md.getBody() and res2 = md.getDeclaringClass() +} + +query predicate test_getAMember(ClassDefinition c, MemberDeclaration res) { res = c.getAMember() } + +query predicate test_MethodNames(MethodDefinition md, string res) { res = md.getName() } + +query predicate test_NewTargetExpr(NewTargetExpr e) { any() } + +query predicate test_SuperExpr(SuperExpr s) { any() } + +query predicate test_SyntheticConstructors(ConstructorDefinition cd) { cd.isSynthetic() } + +query predicate test_ConstructorDefinitions(ConstructorDefinition cd) { any() } + +query predicate test_ClassNodeConstructor(DataFlow::ClassNode class_, DataFlow::FunctionNode res) { + res = class_.getConstructor() +} + +query predicate test_ClassNodeInstanceMethod( + DataFlow::ClassNode class_, string name, DataFlow::FunctionNode res +) { + res = class_.getInstanceMethod(name) +} + +query string getAccessModifier(DataFlow::PropRef ref, Expr prop) { + prop = ref.getPropertyNameExpr() and + if ref.isPrivateField() then result = "Private" else result = "Public" +} + +class Configuration extends DataFlow::Configuration { + Configuration() { this = "ClassDataFlowTestingConfig" } + + override predicate isSource(DataFlow::Node source) { + source.getEnclosingExpr().(StringLiteral).getValue().toLowerCase() = "source" + } + + override predicate isSink(DataFlow::Node sink) { + any(DataFlow::CallNode call | call.getCalleeName() = "sink").getAnArgument() = sink + } +} + +query predicate dataflow(DataFlow::Node pred, DataFlow::Node succ) { + any(Configuration c).hasFlow(pred, succ) +} + +query BlockStmt staticInitializer(ClassDefinition cd) { result = cd.getAStaticInitializerBlock() } diff --git a/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected b/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected index d05b3228025..37df1d045b8 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected +++ b/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected @@ -87,6 +87,14 @@ nodes | dummy.ts:4:22:4:22 | [RegExpNormalConstant] c | semmle.label | [RegExpNormalConstant] c | | file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | | file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | | file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | | file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | | file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | @@ -591,17 +599,208 @@ nodes | tst.ts:127:14:127:17 | [ThisExpr] this | semmle.label | [ThisExpr] this | | tst.ts:127:14:127:28 | [DotExpr] this.#someValue | semmle.label | [DotExpr] this.#someValue | | tst.ts:127:19:127:28 | [Label] #someValue | semmle.label | [Label] #someValue | +| tst.ts:132:1:193:1 | [NamespaceDeclaration] module ... } } | semmle.label | [NamespaceDeclaration] module ... } } | +| tst.ts:132:1:193:1 | [NamespaceDeclaration] module ... } } | semmle.order | 56 | +| tst.ts:132:8:132:11 | [VarDecl] TS44 | semmle.label | [VarDecl] TS44 | +| tst.ts:133:3:138:3 | [FunctionDeclStmt] functio ... } } | semmle.label | [FunctionDeclStmt] functio ... } } | +| tst.ts:133:12:133:14 | [VarDecl] foo | semmle.label | [VarDecl] foo | +| tst.ts:133:16:133:18 | [SimpleParameter] arg | semmle.label | [SimpleParameter] arg | +| tst.ts:133:21:133:27 | [KeywordTypeExpr] unknown | semmle.label | [KeywordTypeExpr] unknown | +| tst.ts:133:30:138:3 | [BlockStmt] { c ... } } | semmle.label | [BlockStmt] { c ... } } | +| tst.ts:134:5:134:48 | [DeclStmt] const argIsString = ... | semmle.label | [DeclStmt] const argIsString = ... | +| tst.ts:134:11:134:21 | [VarDecl] argIsString | semmle.label | [VarDecl] argIsString | +| tst.ts:134:11:134:47 | [VariableDeclarator] argIsSt ... string" | semmle.label | [VariableDeclarator] argIsSt ... string" | +| tst.ts:134:25:134:34 | [UnaryExpr] typeof arg | semmle.label | [UnaryExpr] typeof arg | +| tst.ts:134:25:134:47 | [BinaryExpr] typeof ... string" | semmle.label | [BinaryExpr] typeof ... string" | +| tst.ts:134:32:134:34 | [VarRef] arg | semmle.label | [VarRef] arg | +| tst.ts:134:40:134:47 | [Literal] "string" | semmle.label | [Literal] "string" | +| tst.ts:135:5:137:5 | [IfStmt] if (arg ... ; } | semmle.label | [IfStmt] if (arg ... ; } | +| tst.ts:135:9:135:19 | [VarRef] argIsString | semmle.label | [VarRef] argIsString | +| tst.ts:135:22:137:5 | [BlockStmt] { ... ; } | semmle.label | [BlockStmt] { ... ; } | +| tst.ts:136:9:136:40 | [DeclStmt] const upper = ... | semmle.label | [DeclStmt] const upper = ... | +| tst.ts:136:15:136:19 | [VarDecl] upper | semmle.label | [VarDecl] upper | +| tst.ts:136:15:136:39 | [VariableDeclarator] upper = ... rCase() | semmle.label | [VariableDeclarator] upper = ... rCase() | +| tst.ts:136:23:136:25 | [VarRef] arg | semmle.label | [VarRef] arg | +| tst.ts:136:23:136:37 | [DotExpr] arg.toUpperCase | semmle.label | [DotExpr] arg.toUpperCase | +| tst.ts:136:23:136:39 | [MethodCallExpr] arg.toUpperCase() | semmle.label | [MethodCallExpr] arg.toUpperCase() | +| tst.ts:136:27:136:37 | [Label] toUpperCase | semmle.label | [Label] toUpperCase | +| tst.ts:140:3:142:47 | [TypeAliasDeclaration,TypeDefinition] type Sh ... mber }; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Sh ... mber }; | +| tst.ts:140:8:140:12 | [Identifier] Shape | semmle.label | [Identifier] Shape | +| tst.ts:141:7:142:46 | [UnionTypeExpr] \| { kin ... umber } | semmle.label | [UnionTypeExpr] \| { kin ... umber } | +| tst.ts:141:9:141:42 | [InterfaceTypeExpr] { kind: ... umber } | semmle.label | [InterfaceTypeExpr] { kind: ... umber } | +| tst.ts:141:11:141:14 | [Label] kind | semmle.label | [Label] kind | +| tst.ts:141:11:141:25 | [FieldDeclaration] kind: "circle", | semmle.label | [FieldDeclaration] kind: "circle", | +| tst.ts:141:17:141:24 | [LiteralTypeExpr] "circle" | semmle.label | [LiteralTypeExpr] "circle" | +| tst.ts:141:27:141:32 | [Label] radius | semmle.label | [Label] radius | +| tst.ts:141:27:141:40 | [FieldDeclaration] radius: number | semmle.label | [FieldDeclaration] radius: number | +| tst.ts:141:35:141:40 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | +| tst.ts:142:9:142:46 | [InterfaceTypeExpr] { kind: ... umber } | semmle.label | [InterfaceTypeExpr] { kind: ... umber } | +| tst.ts:142:11:142:14 | [Label] kind | semmle.label | [Label] kind | +| tst.ts:142:11:142:25 | [FieldDeclaration] kind: "square", | semmle.label | [FieldDeclaration] kind: "square", | +| tst.ts:142:17:142:24 | [LiteralTypeExpr] "square" | semmle.label | [LiteralTypeExpr] "square" | +| tst.ts:142:27:142:36 | [Label] sideLength | semmle.label | [Label] sideLength | +| tst.ts:142:27:142:44 | [FieldDeclaration] sideLength: number | semmle.label | [FieldDeclaration] sideLength: number | +| tst.ts:142:39:142:44 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | +| tst.ts:144:3:149:3 | [FunctionDeclStmt] functio ... ; } } | semmle.label | [FunctionDeclStmt] functio ... ; } } | +| tst.ts:144:12:144:15 | [VarDecl] side | semmle.label | [VarDecl] side | +| tst.ts:144:17:144:21 | [SimpleParameter] shape | semmle.label | [SimpleParameter] shape | +| tst.ts:144:24:144:28 | [LocalTypeAccess] Shape | semmle.label | [LocalTypeAccess] Shape | +| tst.ts:144:32:144:37 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | +| tst.ts:144:39:149:3 | [BlockStmt] { ... ; } } | semmle.label | [BlockStmt] { ... ; } } | +| tst.ts:145:7:145:29 | [DeclStmt] const { ... shape; | semmle.label | [DeclStmt] const { ... shape; | +| tst.ts:145:13:145:20 | [ObjectPattern] { kind } | semmle.label | [ObjectPattern] { kind } | +| tst.ts:145:13:145:28 | [VariableDeclarator] { kind } = shape | semmle.label | [VariableDeclarator] { kind } = shape | +| tst.ts:145:15:145:18 | [Label] kind | semmle.label | [Label] kind | +| tst.ts:145:15:145:18 | [PropertyPattern] kind | semmle.label | [PropertyPattern] kind | +| tst.ts:145:15:145:18 | [VarDecl] kind | semmle.label | [VarDecl] kind | +| tst.ts:145:24:145:28 | [VarRef] shape | semmle.label | [VarRef] shape | +| tst.ts:147:7:148:39 | [IfStmt] if (kin ... ngth; } | semmle.label | [IfStmt] if (kin ... ngth; } | +| tst.ts:147:11:147:14 | [VarRef] kind | semmle.label | [VarRef] kind | +| tst.ts:147:11:147:27 | [BinaryExpr] kind === "circle" | semmle.label | [BinaryExpr] kind === "circle" | +| tst.ts:147:20:147:27 | [Literal] "circle" | semmle.label | [Literal] "circle" | +| tst.ts:147:30:147:52 | [BlockStmt] { retur ... adius;} | semmle.label | [BlockStmt] { retur ... adius;} | +| tst.ts:147:32:147:51 | [ReturnStmt] return shape.radius; | semmle.label | [ReturnStmt] return shape.radius; | +| tst.ts:147:39:147:43 | [VarRef] shape | semmle.label | [VarRef] shape | +| tst.ts:147:39:147:50 | [DotExpr] shape.radius | semmle.label | [DotExpr] shape.radius | +| tst.ts:147:45:147:50 | [Label] radius | semmle.label | [Label] radius | +| tst.ts:148:12:148:39 | [BlockStmt] { retur ... ngth; } | semmle.label | [BlockStmt] { retur ... ngth; } | +| tst.ts:148:14:148:37 | [ReturnStmt] return ... Length; | semmle.label | [ReturnStmt] return ... Length; | +| tst.ts:148:21:148:25 | [VarRef] shape | semmle.label | [VarRef] shape | +| tst.ts:148:21:148:36 | [DotExpr] shape.sideLength | semmle.label | [DotExpr] shape.sideLength | +| tst.ts:148:27:148:36 | [Label] sideLength | semmle.label | [Label] sideLength | +| tst.ts:151:3:162:3 | [FunctionDeclStmt] functio ... 2]; } | semmle.label | [FunctionDeclStmt] functio ... 2]; } | +| tst.ts:151:12:151:22 | [VarDecl] symbolIndex | semmle.label | [VarDecl] symbolIndex | +| tst.ts:151:26:162:3 | [BlockStmt] { i ... 2]; } | semmle.label | [BlockStmt] { i ... 2]; } | +| tst.ts:152:5:156:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | semmle.label | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | +| tst.ts:152:15:152:20 | [Identifier] Colors | semmle.label | [Identifier] Colors | +| tst.ts:153:7:153:28 | [FunctionExpr] [sym: s ... number; | semmle.label | [FunctionExpr] [sym: s ... number; | +| tst.ts:153:7:153:28 | [IndexSignature] [sym: s ... number; | semmle.label | [IndexSignature] [sym: s ... number; | +| tst.ts:153:8:153:10 | [SimpleParameter] sym | semmle.label | [SimpleParameter] sym | +| tst.ts:153:13:153:18 | [KeywordTypeExpr] symbol | semmle.label | [KeywordTypeExpr] symbol | +| tst.ts:153:22:153:27 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | +| tst.ts:154:7:154:28 | [FunctionExpr] [key: s ... string; | semmle.label | [FunctionExpr] [key: s ... string; | +| tst.ts:154:7:154:28 | [IndexSignature] [key: s ... string; | semmle.label | [IndexSignature] [key: s ... string; | +| tst.ts:154:8:154:10 | [SimpleParameter] key | semmle.label | [SimpleParameter] key | +| tst.ts:154:13:154:18 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | +| tst.ts:154:22:154:27 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | +| tst.ts:155:7:155:29 | [FunctionExpr] [num: n ... oolean; | semmle.label | [FunctionExpr] [num: n ... oolean; | +| tst.ts:155:7:155:29 | [IndexSignature] [num: n ... oolean; | semmle.label | [IndexSignature] [num: n ... oolean; | +| tst.ts:155:8:155:10 | [SimpleParameter] num | semmle.label | [SimpleParameter] num | +| tst.ts:155:13:155:18 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | +| tst.ts:155:22:155:28 | [KeywordTypeExpr] boolean | semmle.label | [KeywordTypeExpr] boolean | +| tst.ts:158:5:158:28 | [DeclStmt] let colors = ... | semmle.label | [DeclStmt] let colors = ... | +| tst.ts:158:9:158:14 | [VarDecl] colors | semmle.label | [VarDecl] colors | +| tst.ts:158:9:158:27 | [VariableDeclarator] colors: Colors = {} | semmle.label | [VariableDeclarator] colors: Colors = {} | +| tst.ts:158:17:158:22 | [LocalTypeAccess] Colors | semmle.label | [LocalTypeAccess] Colors | +| tst.ts:158:26:158:27 | [ObjectExpr] {} | semmle.label | [ObjectExpr] {} | +| tst.ts:159:5:159:38 | [DeclStmt] const red = ... | semmle.label | [DeclStmt] const red = ... | +| tst.ts:159:11:159:13 | [VarDecl] red | semmle.label | [VarDecl] red | +| tst.ts:159:11:159:37 | [VariableDeclarator] red = c ... "red")] | semmle.label | [VariableDeclarator] red = c ... "red")] | +| tst.ts:159:17:159:22 | [VarRef] colors | semmle.label | [VarRef] colors | +| tst.ts:159:17:159:37 | [IndexExpr] colors[ ... "red")] | semmle.label | [IndexExpr] colors[ ... "red")] | +| tst.ts:159:24:159:29 | [VarRef] Symbol | semmle.label | [VarRef] Symbol | +| tst.ts:159:24:159:36 | [CallExpr] Symbol("red") | semmle.label | [CallExpr] Symbol("red") | +| tst.ts:159:31:159:35 | [Literal] "red" | semmle.label | [Literal] "red" | +| tst.ts:160:5:160:34 | [DeclStmt] const green = ... | semmle.label | [DeclStmt] const green = ... | +| tst.ts:160:11:160:15 | [VarDecl] green | semmle.label | [VarDecl] green | +| tst.ts:160:11:160:33 | [VariableDeclarator] green = ... green"] | semmle.label | [VariableDeclarator] green = ... green"] | +| tst.ts:160:19:160:24 | [VarRef] colors | semmle.label | [VarRef] colors | +| tst.ts:160:19:160:33 | [IndexExpr] colors["green"] | semmle.label | [IndexExpr] colors["green"] | +| tst.ts:160:26:160:32 | [Literal] "green" | semmle.label | [Literal] "green" | +| tst.ts:161:5:161:27 | [DeclStmt] const blue = ... | semmle.label | [DeclStmt] const blue = ... | +| tst.ts:161:11:161:14 | [VarDecl] blue | semmle.label | [VarDecl] blue | +| tst.ts:161:11:161:26 | [VariableDeclarator] blue = colors[2] | semmle.label | [VariableDeclarator] blue = colors[2] | +| tst.ts:161:18:161:23 | [VarRef] colors | semmle.label | [VarRef] colors | +| tst.ts:161:18:161:26 | [IndexExpr] colors[2] | semmle.label | [IndexExpr] colors[2] | +| tst.ts:161:25:161:25 | [Literal] 2 | semmle.label | [Literal] 2 | +| tst.ts:164:3:177:3 | [FunctionDeclStmt] functio ... "]; } | semmle.label | [FunctionDeclStmt] functio ... "]; } | +| tst.ts:164:12:164:29 | [VarDecl] stringPatternIndex | semmle.label | [VarDecl] stringPatternIndex | +| tst.ts:164:33:177:3 | [BlockStmt] { i ... "]; } | semmle.label | [BlockStmt] { i ... "]; } | +| tst.ts:165:5:167:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | semmle.label | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | +| tst.ts:165:15:165:17 | [Identifier] Foo | semmle.label | [Identifier] Foo | +| tst.ts:166:7:166:37 | [FunctionExpr] [key: ` ... number; | semmle.label | [FunctionExpr] [key: ` ... number; | +| tst.ts:166:7:166:37 | [IndexSignature] [key: ` ... number; | semmle.label | [IndexSignature] [key: ` ... number; | +| tst.ts:166:8:166:10 | [SimpleParameter] key | semmle.label | [SimpleParameter] key | +| tst.ts:166:13:166:27 | [TemplateLiteralTypeExpr] `foo-${number}` | semmle.label | [TemplateLiteralTypeExpr] `foo-${number}` | +| tst.ts:166:14:166:17 | [LiteralTypeExpr] foo- | semmle.label | [LiteralTypeExpr] foo- | +| tst.ts:166:20:166:25 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | +| tst.ts:166:31:166:36 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | +| tst.ts:168:5:168:23 | [DeclStmt] var bla = ... | semmle.label | [DeclStmt] var bla = ... | +| tst.ts:168:9:168:11 | [VarDecl] bla | semmle.label | [VarDecl] bla | +| tst.ts:168:9:168:22 | [VariableDeclarator] bla : Foo = {} | semmle.label | [VariableDeclarator] bla : Foo = {} | +| tst.ts:168:15:168:17 | [LocalTypeAccess] Foo | semmle.label | [LocalTypeAccess] Foo | +| tst.ts:168:21:168:22 | [ObjectExpr] {} | semmle.label | [ObjectExpr] {} | +| tst.ts:169:5:169:29 | [DeclStmt] const bar = ... | semmle.label | [DeclStmt] const bar = ... | +| tst.ts:169:11:169:13 | [VarDecl] bar | semmle.label | [VarDecl] bar | +| tst.ts:169:11:169:28 | [VariableDeclarator] bar = bla[`foo-1`] | semmle.label | [VariableDeclarator] bar = bla[`foo-1`] | +| tst.ts:169:17:169:19 | [VarRef] bla | semmle.label | [VarRef] bla | +| tst.ts:169:17:169:28 | [IndexExpr] bla[`foo-1`] | semmle.label | [IndexExpr] bla[`foo-1`] | +| tst.ts:169:21:169:27 | [TemplateElement] `foo-1` | semmle.label | [TemplateElement] `foo-1` | +| tst.ts:169:21:169:27 | [TemplateLiteral] `foo-1` | semmle.label | [TemplateLiteral] `foo-1` | +| tst.ts:171:5:173:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | semmle.label | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | +| tst.ts:171:15:171:18 | [Identifier] Data | semmle.label | [Identifier] Data | +| tst.ts:172:7:172:42 | [FunctionExpr] [optNam ... oolean; | semmle.label | [FunctionExpr] [optNam ... oolean; | +| tst.ts:172:7:172:42 | [IndexSignature] [optNam ... oolean; | semmle.label | [IndexSignature] [optNam ... oolean; | +| tst.ts:172:8:172:14 | [SimpleParameter] optName | semmle.label | [SimpleParameter] optName | +| tst.ts:172:17:172:22 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | +| tst.ts:172:17:172:31 | [UnionTypeExpr] string \| symbol | semmle.label | [UnionTypeExpr] string \| symbol | +| tst.ts:172:26:172:31 | [KeywordTypeExpr] symbol | semmle.label | [KeywordTypeExpr] symbol | +| tst.ts:172:35:172:41 | [KeywordTypeExpr] boolean | semmle.label | [KeywordTypeExpr] boolean | +| tst.ts:175:5:175:26 | [DeclStmt] const data = ... | semmle.label | [DeclStmt] const data = ... | +| tst.ts:175:11:175:14 | [VarDecl] data | semmle.label | [VarDecl] data | +| tst.ts:175:11:175:25 | [VariableDeclarator] data: Data = {} | semmle.label | [VariableDeclarator] data: Data = {} | +| tst.ts:175:17:175:20 | [LocalTypeAccess] Data | semmle.label | [LocalTypeAccess] Data | +| tst.ts:175:24:175:25 | [ObjectExpr] {} | semmle.label | [ObjectExpr] {} | +| tst.ts:176:5:176:28 | [DeclStmt] const baz = ... | semmle.label | [DeclStmt] const baz = ... | +| tst.ts:176:11:176:13 | [VarDecl] baz | semmle.label | [VarDecl] baz | +| tst.ts:176:11:176:27 | [VariableDeclarator] baz = data["foo"] | semmle.label | [VariableDeclarator] baz = data["foo"] | +| tst.ts:176:17:176:20 | [VarRef] data | semmle.label | [VarRef] data | +| tst.ts:176:17:176:27 | [IndexExpr] data["foo"] | semmle.label | [IndexExpr] data["foo"] | +| tst.ts:176:22:176:26 | [Literal] "foo" | semmle.label | [Literal] "foo" | +| tst.ts:179:3:192:3 | [ClassDefinition,TypeDefinition] class F ... } | semmle.label | [ClassDefinition,TypeDefinition] class F ... } | +| tst.ts:179:9:179:11 | [VarDecl] Foo | semmle.label | [VarDecl] Foo | +| tst.ts:179:13:179:12 | [BlockStmt] {} | semmle.label | [BlockStmt] {} | +| tst.ts:179:13:179:12 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | semmle.label | [ClassInitializedMember,ConstructorDefinition] constructor() {} | +| tst.ts:179:13:179:12 | [FunctionExpr] () {} | semmle.label | [FunctionExpr] () {} | +| tst.ts:179:13:179:12 | [Label] constructor | semmle.label | [Label] constructor | +| tst.ts:180:5:180:22 | [ClassInitializedMember,FieldDeclaration] static #count = 0; | semmle.label | [ClassInitializedMember,FieldDeclaration] static #count = 0; | +| tst.ts:180:12:180:17 | [Label] #count | semmle.label | [Label] #count | +| tst.ts:180:21:180:21 | [Literal] 0 | semmle.label | [Literal] 0 | +| tst.ts:182:5:184:5 | [ClassInitializedMember,GetterMethodDefinition] get cou ... ; } | semmle.label | [ClassInitializedMember,GetterMethodDefinition] get cou ... ; } | +| tst.ts:182:5:184:5 | [FunctionExpr] get cou ... ; } | semmle.label | [FunctionExpr] get cou ... ; } | +| tst.ts:182:9:182:13 | [Label] count | semmle.label | [Label] count | +| tst.ts:182:17:184:5 | [BlockStmt] { ... ; } | semmle.label | [BlockStmt] { ... ; } | +| tst.ts:183:9:183:26 | [ReturnStmt] return Foo.#count; | semmle.label | [ReturnStmt] return Foo.#count; | +| tst.ts:183:16:183:18 | [VarRef] Foo | semmle.label | [VarRef] Foo | +| tst.ts:183:16:183:25 | [DotExpr] Foo.#count | semmle.label | [DotExpr] Foo.#count | +| tst.ts:183:20:183:25 | [Label] #count | semmle.label | [Label] #count | +| tst.ts:185:5:187:5 | [BlockStmt] static ... ; } | semmle.label | [BlockStmt] static ... ; } | +| tst.ts:185:5:187:5 | [ClassInitializedMember] static ... ; } | semmle.label | [ClassInitializedMember] static ... ; } | +| tst.ts:186:7:186:9 | [VarRef] Foo | semmle.label | [VarRef] Foo | +| tst.ts:186:7:186:16 | [DotExpr] Foo.#count | semmle.label | [DotExpr] Foo.#count | +| tst.ts:186:7:186:21 | [CompoundAssignExpr] Foo.#count += 3 | semmle.label | [CompoundAssignExpr] Foo.#count += 3 | +| tst.ts:186:7:186:22 | [ExprStmt] Foo.#count += 3; | semmle.label | [ExprStmt] Foo.#count += 3; | +| tst.ts:186:11:186:16 | [Label] #count | semmle.label | [Label] #count | +| tst.ts:186:21:186:21 | [Literal] 3 | semmle.label | [Literal] 3 | +| tst.ts:188:5:190:5 | [BlockStmt] static ... ; } | semmle.label | [BlockStmt] static ... ; } | +| tst.ts:188:5:190:5 | [ClassInitializedMember] static ... ; } | semmle.label | [ClassInitializedMember] static ... ; } | +| tst.ts:189:7:189:29 | [DeclStmt] var count = ... | semmle.label | [DeclStmt] var count = ... | +| tst.ts:189:11:189:15 | [VarDecl] count | semmle.label | [VarDecl] count | +| tst.ts:189:11:189:28 | [VariableDeclarator] count = Foo.#count | semmle.label | [VariableDeclarator] count = Foo.#count | +| tst.ts:189:19:189:21 | [VarRef] Foo | semmle.label | [VarRef] Foo | +| tst.ts:189:19:189:28 | [DotExpr] Foo.#count | semmle.label | [DotExpr] Foo.#count | +| tst.ts:189:23:189:28 | [Label] #count | semmle.label | [Label] #count | | type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | -| type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.order | 56 | +| type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.order | 57 | | type_alias.ts:1:6:1:6 | [Identifier] B | semmle.label | [Identifier] B | | type_alias.ts:1:10:1:16 | [KeywordTypeExpr] boolean | semmle.label | [KeywordTypeExpr] boolean | | type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.label | [DeclStmt] var b = ... | -| type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.order | 57 | +| type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.order | 58 | | type_alias.ts:3:5:3:5 | [VarDecl] b | semmle.label | [VarDecl] b | | type_alias.ts:3:5:3:8 | [VariableDeclarator] b: B | semmle.label | [VariableDeclarator] b: B | | type_alias.ts:3:8:3:8 | [LocalTypeAccess] B | semmle.label | [LocalTypeAccess] B | | type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | -| type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | semmle.order | 58 | +| type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | semmle.order | 59 | | type_alias.ts:5:6:5:17 | [Identifier] ValueOrArray | semmle.label | [Identifier] ValueOrArray | | type_alias.ts:5:19:5:19 | [Identifier] T | semmle.label | [Identifier] T | | type_alias.ts:5:19:5:19 | [TypeParameter] T | semmle.label | [TypeParameter] T | @@ -613,14 +812,14 @@ nodes | type_alias.ts:5:34:5:48 | [GenericTypeExpr] ValueOrArray | semmle.label | [GenericTypeExpr] ValueOrArray | | type_alias.ts:5:47:5:47 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T | | type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.label | [DeclStmt] var c = ... | -| type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.order | 59 | +| type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.order | 60 | | type_alias.ts:7:5:7:5 | [VarDecl] c | semmle.label | [VarDecl] c | | type_alias.ts:7:5:7:27 | [VariableDeclarator] c: Valu ... number> | semmle.label | [VariableDeclarator] c: Valu ... number> | | type_alias.ts:7:8:7:19 | [LocalTypeAccess] ValueOrArray | semmle.label | [LocalTypeAccess] ValueOrArray | | type_alias.ts:7:8:7:27 | [GenericTypeExpr] ValueOrArray | semmle.label | [GenericTypeExpr] ValueOrArray | | type_alias.ts:7:21:7:26 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | | type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | -| type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.order | 60 | +| type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.order | 61 | | type_alias.ts:9:6:9:9 | [Identifier] Json | semmle.label | [Identifier] Json | | type_alias.ts:10:5:15:12 | [UnionTypeExpr] \| strin ... Json[] | semmle.label | [UnionTypeExpr] \| strin ... Json[] | | type_alias.ts:10:7:10:12 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | @@ -636,12 +835,12 @@ nodes | type_alias.ts:15:7:15:10 | [LocalTypeAccess] Json | semmle.label | [LocalTypeAccess] Json | | type_alias.ts:15:7:15:12 | [ArrayTypeExpr] Json[] | semmle.label | [ArrayTypeExpr] Json[] | | type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.label | [DeclStmt] var json = ... | -| type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.order | 61 | +| type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.order | 62 | | type_alias.ts:17:5:17:8 | [VarDecl] json | semmle.label | [VarDecl] json | | type_alias.ts:17:5:17:14 | [VariableDeclarator] json: Json | semmle.label | [VariableDeclarator] json: Json | | type_alias.ts:17:11:17:14 | [LocalTypeAccess] Json | semmle.label | [LocalTypeAccess] Json | | type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | -| type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.order | 62 | +| type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.order | 63 | | type_alias.ts:19:6:19:16 | [Identifier] VirtualNode | semmle.label | [Identifier] VirtualNode | | type_alias.ts:20:5:21:56 | [UnionTypeExpr] \| strin ... Node[]] | semmle.label | [UnionTypeExpr] \| strin ... Node[]] | | type_alias.ts:20:7:20:12 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | @@ -657,7 +856,7 @@ nodes | type_alias.ts:21:43:21:53 | [LocalTypeAccess] VirtualNode | semmle.label | [LocalTypeAccess] VirtualNode | | type_alias.ts:21:43:21:55 | [ArrayTypeExpr] VirtualNode[] | semmle.label | [ArrayTypeExpr] VirtualNode[] | | type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.label | [DeclStmt] const myNode = ... | -| type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.order | 63 | +| type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.order | 64 | | type_alias.ts:23:7:23:12 | [VarDecl] myNode | semmle.label | [VarDecl] myNode | | type_alias.ts:23:7:27:5 | [VariableDeclarator] myNode: ... ] ] | semmle.label | [VariableDeclarator] myNode: ... ] ] | | type_alias.ts:23:15:23:25 | [LocalTypeAccess] VirtualNode | semmle.label | [LocalTypeAccess] VirtualNode | @@ -682,12 +881,12 @@ nodes | type_alias.ts:26:23:26:36 | [Literal] "second-child" | semmle.label | [Literal] "second-child" | | type_alias.ts:26:41:26:62 | [Literal] "I'm the second child" | semmle.label | [Literal] "I'm the second child" | | type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.label | [ImportDeclaration] import ... dummy"; | -| type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 64 | +| type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 65 | | type_definition_objects.ts:1:8:1:17 | [ImportSpecifier] * as dummy | semmle.label | [ImportSpecifier] * as dummy | | type_definition_objects.ts:1:13:1:17 | [VarDecl] dummy | semmle.label | [VarDecl] dummy | | type_definition_objects.ts:1:24:1:32 | [Literal] "./dummy" | semmle.label | [Literal] "./dummy" | | type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.label | [ExportDeclaration] export class C {} | -| type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.order | 65 | +| type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.order | 66 | | type_definition_objects.ts:3:8:3:17 | [ClassDefinition,TypeDefinition] class C {} | semmle.label | [ClassDefinition,TypeDefinition] class C {} | | type_definition_objects.ts:3:14:3:14 | [VarDecl] C | semmle.label | [VarDecl] C | | type_definition_objects.ts:3:16:3:15 | [BlockStmt] {} | semmle.label | [BlockStmt] {} | @@ -695,36 +894,36 @@ nodes | type_definition_objects.ts:3:16:3:15 | [FunctionExpr] () {} | semmle.label | [FunctionExpr] () {} | | type_definition_objects.ts:3:16:3:15 | [Label] constructor | semmle.label | [Label] constructor | | type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.label | [DeclStmt] let classObj = ... | -| type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.order | 66 | +| type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.order | 67 | | type_definition_objects.ts:4:5:4:12 | [VarDecl] classObj | semmle.label | [VarDecl] classObj | | type_definition_objects.ts:4:5:4:16 | [VariableDeclarator] classObj = C | semmle.label | [VariableDeclarator] classObj = C | | type_definition_objects.ts:4:16:4:16 | [VarRef] C | semmle.label | [VarRef] C | | type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.label | [ExportDeclaration] export enum E {} | -| type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.order | 67 | +| type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.order | 68 | | type_definition_objects.ts:6:8:6:16 | [EnumDeclaration,TypeDefinition] enum E {} | semmle.label | [EnumDeclaration,TypeDefinition] enum E {} | | type_definition_objects.ts:6:13:6:13 | [VarDecl] E | semmle.label | [VarDecl] E | | type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.label | [DeclStmt] let enumObj = ... | -| type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.order | 68 | +| type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.order | 69 | | type_definition_objects.ts:7:5:7:11 | [VarDecl] enumObj | semmle.label | [VarDecl] enumObj | | type_definition_objects.ts:7:5:7:15 | [VariableDeclarator] enumObj = E | semmle.label | [VariableDeclarator] enumObj = E | | type_definition_objects.ts:7:15:7:15 | [VarRef] E | semmle.label | [VarRef] E | | type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.label | [ExportDeclaration] export ... e N {;} | -| type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.order | 69 | +| type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.order | 70 | | type_definition_objects.ts:9:8:9:22 | [NamespaceDeclaration] namespace N {;} | semmle.label | [NamespaceDeclaration] namespace N {;} | | type_definition_objects.ts:9:18:9:18 | [VarDecl] N | semmle.label | [VarDecl] N | | type_definition_objects.ts:9:21:9:21 | [EmptyStmt] ; | semmle.label | [EmptyStmt] ; | | type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.label | [DeclStmt] let namespaceObj = ... | -| type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.order | 70 | +| type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.order | 71 | | type_definition_objects.ts:10:5:10:16 | [VarDecl] namespaceObj | semmle.label | [VarDecl] namespaceObj | | type_definition_objects.ts:10:5:10:20 | [VariableDeclarator] namespaceObj = N | semmle.label | [VariableDeclarator] namespaceObj = N | | type_definition_objects.ts:10:20:10:20 | [VarRef] N | semmle.label | [VarRef] N | | type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.label | [ImportDeclaration] import ... dummy"; | -| type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 71 | +| type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 72 | | type_definitions.ts:1:8:1:17 | [ImportSpecifier] * as dummy | semmle.label | [ImportSpecifier] * as dummy | | type_definitions.ts:1:13:1:17 | [VarDecl] dummy | semmle.label | [VarDecl] dummy | | type_definitions.ts:1:24:1:32 | [Literal] "./dummy" | semmle.label | [Literal] "./dummy" | | type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.label | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | -| type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.order | 72 | +| type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.order | 73 | | type_definitions.ts:3:11:3:11 | [Identifier] I | semmle.label | [Identifier] I | | type_definitions.ts:3:13:3:13 | [Identifier] S | semmle.label | [Identifier] S | | type_definitions.ts:3:13:3:13 | [TypeParameter] S | semmle.label | [TypeParameter] S | @@ -732,14 +931,14 @@ nodes | type_definitions.ts:4:3:4:7 | [FieldDeclaration] x: S; | semmle.label | [FieldDeclaration] x: S; | | type_definitions.ts:4:6:4:6 | [LocalTypeAccess] S | semmle.label | [LocalTypeAccess] S | | type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.label | [DeclStmt] let i = ... | -| type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.order | 73 | +| type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.order | 74 | | type_definitions.ts:6:5:6:5 | [VarDecl] i | semmle.label | [VarDecl] i | | type_definitions.ts:6:5:6:16 | [VariableDeclarator] i: I | semmle.label | [VariableDeclarator] i: I | | type_definitions.ts:6:8:6:8 | [LocalTypeAccess] I | semmle.label | [LocalTypeAccess] I | | type_definitions.ts:6:8:6:16 | [GenericTypeExpr] I | semmle.label | [GenericTypeExpr] I | | type_definitions.ts:6:10:6:15 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | | type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.label | [ClassDefinition,TypeDefinition] class C ... x: T } | -| type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.order | 74 | +| type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.order | 75 | | type_definitions.ts:8:7:8:7 | [VarDecl] C | semmle.label | [VarDecl] C | | type_definitions.ts:8:8:8:7 | [BlockStmt] {} | semmle.label | [BlockStmt] {} | | type_definitions.ts:8:8:8:7 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | semmle.label | [ClassInitializedMember,ConstructorDefinition] constructor() {} | @@ -751,14 +950,14 @@ nodes | type_definitions.ts:9:3:9:6 | [FieldDeclaration] x: T | semmle.label | [FieldDeclaration] x: T | | type_definitions.ts:9:6:9:6 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T | | type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.label | [DeclStmt] let c = ... | -| type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.order | 75 | +| type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.order | 76 | | type_definitions.ts:11:5:11:5 | [VarDecl] c | semmle.label | [VarDecl] c | | type_definitions.ts:11:5:11:16 | [VariableDeclarator] c: C | semmle.label | [VariableDeclarator] c: C | | type_definitions.ts:11:8:11:8 | [LocalTypeAccess] C | semmle.label | [LocalTypeAccess] C | | type_definitions.ts:11:8:11:16 | [GenericTypeExpr] C | semmle.label | [GenericTypeExpr] C | | type_definitions.ts:11:10:11:15 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | | type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.label | [EnumDeclaration,TypeDefinition] enum Co ... blue } | -| type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.order | 76 | +| type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.order | 77 | | type_definitions.ts:13:6:13:10 | [VarDecl] Color | semmle.label | [VarDecl] Color | | type_definitions.ts:14:3:14:5 | [EnumMember,TypeDefinition] red | semmle.label | [EnumMember,TypeDefinition] red | | type_definitions.ts:14:3:14:5 | [VarDecl] red | semmle.label | [VarDecl] red | @@ -767,29 +966,29 @@ nodes | type_definitions.ts:14:15:14:18 | [EnumMember,TypeDefinition] blue | semmle.label | [EnumMember,TypeDefinition] blue | | type_definitions.ts:14:15:14:18 | [VarDecl] blue | semmle.label | [VarDecl] blue | | type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.label | [DeclStmt] let color = ... | -| type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.order | 77 | +| type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.order | 78 | | type_definitions.ts:16:5:16:9 | [VarDecl] color | semmle.label | [VarDecl] color | | type_definitions.ts:16:5:16:16 | [VariableDeclarator] color: Color | semmle.label | [VariableDeclarator] color: Color | | type_definitions.ts:16:12:16:16 | [LocalTypeAccess] Color | semmle.label | [LocalTypeAccess] Color | | type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.label | [EnumDeclaration,TypeDefinition] enum En ... ember } | -| type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.order | 78 | +| type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.order | 79 | | type_definitions.ts:18:6:18:22 | [VarDecl] EnumWithOneMember | semmle.label | [VarDecl] EnumWithOneMember | | type_definitions.ts:18:26:18:31 | [EnumMember,TypeDefinition] member | semmle.label | [EnumMember,TypeDefinition] member | | type_definitions.ts:18:26:18:31 | [VarDecl] member | semmle.label | [VarDecl] member | | type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.label | [DeclStmt] let e = ... | -| type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.order | 79 | +| type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.order | 80 | | type_definitions.ts:19:5:19:5 | [VarDecl] e | semmle.label | [VarDecl] e | | type_definitions.ts:19:5:19:24 | [VariableDeclarator] e: EnumWithOneMember | semmle.label | [VariableDeclarator] e: EnumWithOneMember | | type_definitions.ts:19:8:19:24 | [LocalTypeAccess] EnumWithOneMember | semmle.label | [LocalTypeAccess] EnumWithOneMember | | type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | -| type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | semmle.order | 80 | +| type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | semmle.order | 81 | | type_definitions.ts:21:6:21:10 | [Identifier] Alias | semmle.label | [Identifier] Alias | | type_definitions.ts:21:12:21:12 | [Identifier] T | semmle.label | [Identifier] T | | type_definitions.ts:21:12:21:12 | [TypeParameter] T | semmle.label | [TypeParameter] T | | type_definitions.ts:21:17:21:17 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T | | type_definitions.ts:21:17:21:19 | [ArrayTypeExpr] T[] | semmle.label | [ArrayTypeExpr] T[] | | type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.label | [DeclStmt] let aliasForNumberArray = ... | -| type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.order | 81 | +| type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.order | 82 | | type_definitions.ts:22:5:22:23 | [VarDecl] aliasForNumberArray | semmle.label | [VarDecl] aliasForNumberArray | | type_definitions.ts:22:5:22:38 | [VariableDeclarator] aliasFo ... number> | semmle.label | [VariableDeclarator] aliasFo ... number> | | type_definitions.ts:22:26:22:30 | [LocalTypeAccess] Alias | semmle.label | [LocalTypeAccess] Alias | @@ -920,6 +1119,8 @@ edges | file://:0:0:0:0 | (Arguments) | tst.ts:86:27:86:31 | [VarRef] value | semmle.order | 0 | | file://:0:0:0:0 | (Arguments) | tst.ts:97:27:97:26 | [SpreadElement] ...args | semmle.label | 0 | | file://:0:0:0:0 | (Arguments) | tst.ts:97:27:97:26 | [SpreadElement] ...args | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | tst.ts:159:31:159:35 | [Literal] "red" | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | tst.ts:159:31:159:35 | [Literal] "red" | semmle.order | 0 | | file://:0:0:0:0 | (Parameters) | tst.ts:14:17:14:17 | [SimpleParameter] x | semmle.label | 0 | | file://:0:0:0:0 | (Parameters) | tst.ts:14:17:14:17 | [SimpleParameter] x | semmle.order | 0 | | file://:0:0:0:0 | (Parameters) | tst.ts:14:28:14:28 | [SimpleParameter] y | semmle.label | 1 | @@ -944,6 +1145,20 @@ edges | file://:0:0:0:0 | (Parameters) | tst.ts:97:27:97:26 | [SimpleParameter] args | semmle.order | 0 | | file://:0:0:0:0 | (Parameters) | tst.ts:104:16:104:16 | [SimpleParameter] s | semmle.label | 0 | | file://:0:0:0:0 | (Parameters) | tst.ts:104:16:104:16 | [SimpleParameter] s | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:133:16:133:18 | [SimpleParameter] arg | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:133:16:133:18 | [SimpleParameter] arg | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:144:17:144:21 | [SimpleParameter] shape | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:144:17:144:21 | [SimpleParameter] shape | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:153:8:153:10 | [SimpleParameter] sym | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:153:8:153:10 | [SimpleParameter] sym | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:154:8:154:10 | [SimpleParameter] key | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:154:8:154:10 | [SimpleParameter] key | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:155:8:155:10 | [SimpleParameter] num | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:155:8:155:10 | [SimpleParameter] num | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:166:8:166:10 | [SimpleParameter] key | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:166:8:166:10 | [SimpleParameter] key | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:172:8:172:14 | [SimpleParameter] optName | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:172:8:172:14 | [SimpleParameter] optName | semmle.order | 0 | | file://:0:0:0:0 | (Parameters) | type_alias.ts:14:10:14:17 | [SimpleParameter] property | semmle.label | 0 | | file://:0:0:0:0 | (Parameters) | type_alias.ts:14:10:14:17 | [SimpleParameter] property | semmle.order | 0 | | file://:0:0:0:0 | (Parameters) | type_alias.ts:21:19:21:21 | [SimpleParameter] key | semmle.label | 0 | @@ -1760,6 +1975,384 @@ edges | tst.ts:127:14:127:28 | [DotExpr] this.#someValue | tst.ts:127:14:127:17 | [ThisExpr] this | semmle.order | 1 | | tst.ts:127:14:127:28 | [DotExpr] this.#someValue | tst.ts:127:19:127:28 | [Label] #someValue | semmle.label | 2 | | tst.ts:127:14:127:28 | [DotExpr] this.#someValue | tst.ts:127:19:127:28 | [Label] #someValue | semmle.order | 2 | +| tst.ts:132:1:193:1 | [NamespaceDeclaration] module ... } } | tst.ts:132:8:132:11 | [VarDecl] TS44 | semmle.label | 1 | +| tst.ts:132:1:193:1 | [NamespaceDeclaration] module ... } } | tst.ts:132:8:132:11 | [VarDecl] TS44 | semmle.order | 1 | +| tst.ts:132:1:193:1 | [NamespaceDeclaration] module ... } } | tst.ts:133:3:138:3 | [FunctionDeclStmt] functio ... } } | semmle.label | 2 | +| tst.ts:132:1:193:1 | [NamespaceDeclaration] module ... } } | tst.ts:133:3:138:3 | [FunctionDeclStmt] functio ... } } | semmle.order | 2 | +| tst.ts:132:1:193:1 | [NamespaceDeclaration] module ... } } | tst.ts:140:3:142:47 | [TypeAliasDeclaration,TypeDefinition] type Sh ... mber }; | semmle.label | 3 | +| tst.ts:132:1:193:1 | [NamespaceDeclaration] module ... } } | tst.ts:140:3:142:47 | [TypeAliasDeclaration,TypeDefinition] type Sh ... mber }; | semmle.order | 3 | +| tst.ts:132:1:193:1 | [NamespaceDeclaration] module ... } } | tst.ts:144:3:149:3 | [FunctionDeclStmt] functio ... ; } } | semmle.label | 4 | +| tst.ts:132:1:193:1 | [NamespaceDeclaration] module ... } } | tst.ts:144:3:149:3 | [FunctionDeclStmt] functio ... ; } } | semmle.order | 4 | +| tst.ts:132:1:193:1 | [NamespaceDeclaration] module ... } } | tst.ts:151:3:162:3 | [FunctionDeclStmt] functio ... 2]; } | semmle.label | 5 | +| tst.ts:132:1:193:1 | [NamespaceDeclaration] module ... } } | tst.ts:151:3:162:3 | [FunctionDeclStmt] functio ... 2]; } | semmle.order | 5 | +| tst.ts:132:1:193:1 | [NamespaceDeclaration] module ... } } | tst.ts:164:3:177:3 | [FunctionDeclStmt] functio ... "]; } | semmle.label | 6 | +| tst.ts:132:1:193:1 | [NamespaceDeclaration] module ... } } | tst.ts:164:3:177:3 | [FunctionDeclStmt] functio ... "]; } | semmle.order | 6 | +| tst.ts:132:1:193:1 | [NamespaceDeclaration] module ... } } | tst.ts:179:3:192:3 | [ClassDefinition,TypeDefinition] class F ... } | semmle.label | 7 | +| tst.ts:132:1:193:1 | [NamespaceDeclaration] module ... } } | tst.ts:179:3:192:3 | [ClassDefinition,TypeDefinition] class F ... } | semmle.order | 7 | +| tst.ts:133:3:138:3 | [FunctionDeclStmt] functio ... } } | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| tst.ts:133:3:138:3 | [FunctionDeclStmt] functio ... } } | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| tst.ts:133:3:138:3 | [FunctionDeclStmt] functio ... } } | tst.ts:133:12:133:14 | [VarDecl] foo | semmle.label | 0 | +| tst.ts:133:3:138:3 | [FunctionDeclStmt] functio ... } } | tst.ts:133:12:133:14 | [VarDecl] foo | semmle.order | 0 | +| tst.ts:133:3:138:3 | [FunctionDeclStmt] functio ... } } | tst.ts:133:30:138:3 | [BlockStmt] { c ... } } | semmle.label | 5 | +| tst.ts:133:3:138:3 | [FunctionDeclStmt] functio ... } } | tst.ts:133:30:138:3 | [BlockStmt] { c ... } } | semmle.order | 5 | +| tst.ts:133:16:133:18 | [SimpleParameter] arg | tst.ts:133:21:133:27 | [KeywordTypeExpr] unknown | semmle.label | 0 | +| tst.ts:133:16:133:18 | [SimpleParameter] arg | tst.ts:133:21:133:27 | [KeywordTypeExpr] unknown | semmle.order | 0 | +| tst.ts:133:30:138:3 | [BlockStmt] { c ... } } | tst.ts:134:5:134:48 | [DeclStmt] const argIsString = ... | semmle.label | 1 | +| tst.ts:133:30:138:3 | [BlockStmt] { c ... } } | tst.ts:134:5:134:48 | [DeclStmt] const argIsString = ... | semmle.order | 1 | +| tst.ts:133:30:138:3 | [BlockStmt] { c ... } } | tst.ts:135:5:137:5 | [IfStmt] if (arg ... ; } | semmle.label | 2 | +| tst.ts:133:30:138:3 | [BlockStmt] { c ... } } | tst.ts:135:5:137:5 | [IfStmt] if (arg ... ; } | semmle.order | 2 | +| tst.ts:134:5:134:48 | [DeclStmt] const argIsString = ... | tst.ts:134:11:134:47 | [VariableDeclarator] argIsSt ... string" | semmle.label | 1 | +| tst.ts:134:5:134:48 | [DeclStmt] const argIsString = ... | tst.ts:134:11:134:47 | [VariableDeclarator] argIsSt ... string" | semmle.order | 1 | +| tst.ts:134:11:134:47 | [VariableDeclarator] argIsSt ... string" | tst.ts:134:11:134:21 | [VarDecl] argIsString | semmle.label | 1 | +| tst.ts:134:11:134:47 | [VariableDeclarator] argIsSt ... string" | tst.ts:134:11:134:21 | [VarDecl] argIsString | semmle.order | 1 | +| tst.ts:134:11:134:47 | [VariableDeclarator] argIsSt ... string" | tst.ts:134:25:134:47 | [BinaryExpr] typeof ... string" | semmle.label | 2 | +| tst.ts:134:11:134:47 | [VariableDeclarator] argIsSt ... string" | tst.ts:134:25:134:47 | [BinaryExpr] typeof ... string" | semmle.order | 2 | +| tst.ts:134:25:134:34 | [UnaryExpr] typeof arg | tst.ts:134:32:134:34 | [VarRef] arg | semmle.label | 1 | +| tst.ts:134:25:134:34 | [UnaryExpr] typeof arg | tst.ts:134:32:134:34 | [VarRef] arg | semmle.order | 1 | +| tst.ts:134:25:134:47 | [BinaryExpr] typeof ... string" | tst.ts:134:25:134:34 | [UnaryExpr] typeof arg | semmle.label | 1 | +| tst.ts:134:25:134:47 | [BinaryExpr] typeof ... string" | tst.ts:134:25:134:34 | [UnaryExpr] typeof arg | semmle.order | 1 | +| tst.ts:134:25:134:47 | [BinaryExpr] typeof ... string" | tst.ts:134:40:134:47 | [Literal] "string" | semmle.label | 2 | +| tst.ts:134:25:134:47 | [BinaryExpr] typeof ... string" | tst.ts:134:40:134:47 | [Literal] "string" | semmle.order | 2 | +| tst.ts:135:5:137:5 | [IfStmt] if (arg ... ; } | tst.ts:135:9:135:19 | [VarRef] argIsString | semmle.label | 1 | +| tst.ts:135:5:137:5 | [IfStmt] if (arg ... ; } | tst.ts:135:9:135:19 | [VarRef] argIsString | semmle.order | 1 | +| tst.ts:135:5:137:5 | [IfStmt] if (arg ... ; } | tst.ts:135:22:137:5 | [BlockStmt] { ... ; } | semmle.label | 2 | +| tst.ts:135:5:137:5 | [IfStmt] if (arg ... ; } | tst.ts:135:22:137:5 | [BlockStmt] { ... ; } | semmle.order | 2 | +| tst.ts:135:22:137:5 | [BlockStmt] { ... ; } | tst.ts:136:9:136:40 | [DeclStmt] const upper = ... | semmle.label | 1 | +| tst.ts:135:22:137:5 | [BlockStmt] { ... ; } | tst.ts:136:9:136:40 | [DeclStmt] const upper = ... | semmle.order | 1 | +| tst.ts:136:9:136:40 | [DeclStmt] const upper = ... | tst.ts:136:15:136:39 | [VariableDeclarator] upper = ... rCase() | semmle.label | 1 | +| tst.ts:136:9:136:40 | [DeclStmt] const upper = ... | tst.ts:136:15:136:39 | [VariableDeclarator] upper = ... rCase() | semmle.order | 1 | +| tst.ts:136:15:136:39 | [VariableDeclarator] upper = ... rCase() | tst.ts:136:15:136:19 | [VarDecl] upper | semmle.label | 1 | +| tst.ts:136:15:136:39 | [VariableDeclarator] upper = ... rCase() | tst.ts:136:15:136:19 | [VarDecl] upper | semmle.order | 1 | +| tst.ts:136:15:136:39 | [VariableDeclarator] upper = ... rCase() | tst.ts:136:23:136:39 | [MethodCallExpr] arg.toUpperCase() | semmle.label | 2 | +| tst.ts:136:15:136:39 | [VariableDeclarator] upper = ... rCase() | tst.ts:136:23:136:39 | [MethodCallExpr] arg.toUpperCase() | semmle.order | 2 | +| tst.ts:136:23:136:37 | [DotExpr] arg.toUpperCase | tst.ts:136:23:136:25 | [VarRef] arg | semmle.label | 1 | +| tst.ts:136:23:136:37 | [DotExpr] arg.toUpperCase | tst.ts:136:23:136:25 | [VarRef] arg | semmle.order | 1 | +| tst.ts:136:23:136:37 | [DotExpr] arg.toUpperCase | tst.ts:136:27:136:37 | [Label] toUpperCase | semmle.label | 2 | +| tst.ts:136:23:136:37 | [DotExpr] arg.toUpperCase | tst.ts:136:27:136:37 | [Label] toUpperCase | semmle.order | 2 | +| tst.ts:136:23:136:39 | [MethodCallExpr] arg.toUpperCase() | tst.ts:136:23:136:37 | [DotExpr] arg.toUpperCase | semmle.label | 0 | +| tst.ts:136:23:136:39 | [MethodCallExpr] arg.toUpperCase() | tst.ts:136:23:136:37 | [DotExpr] arg.toUpperCase | semmle.order | 0 | +| tst.ts:140:3:142:47 | [TypeAliasDeclaration,TypeDefinition] type Sh ... mber }; | tst.ts:140:8:140:12 | [Identifier] Shape | semmle.label | 1 | +| tst.ts:140:3:142:47 | [TypeAliasDeclaration,TypeDefinition] type Sh ... mber }; | tst.ts:140:8:140:12 | [Identifier] Shape | semmle.order | 1 | +| tst.ts:140:3:142:47 | [TypeAliasDeclaration,TypeDefinition] type Sh ... mber }; | tst.ts:141:7:142:46 | [UnionTypeExpr] \| { kin ... umber } | semmle.label | 2 | +| tst.ts:140:3:142:47 | [TypeAliasDeclaration,TypeDefinition] type Sh ... mber }; | tst.ts:141:7:142:46 | [UnionTypeExpr] \| { kin ... umber } | semmle.order | 2 | +| tst.ts:141:7:142:46 | [UnionTypeExpr] \| { kin ... umber } | tst.ts:141:9:141:42 | [InterfaceTypeExpr] { kind: ... umber } | semmle.label | 1 | +| tst.ts:141:7:142:46 | [UnionTypeExpr] \| { kin ... umber } | tst.ts:141:9:141:42 | [InterfaceTypeExpr] { kind: ... umber } | semmle.order | 1 | +| tst.ts:141:7:142:46 | [UnionTypeExpr] \| { kin ... umber } | tst.ts:142:9:142:46 | [InterfaceTypeExpr] { kind: ... umber } | semmle.label | 2 | +| tst.ts:141:7:142:46 | [UnionTypeExpr] \| { kin ... umber } | tst.ts:142:9:142:46 | [InterfaceTypeExpr] { kind: ... umber } | semmle.order | 2 | +| tst.ts:141:9:141:42 | [InterfaceTypeExpr] { kind: ... umber } | tst.ts:141:11:141:25 | [FieldDeclaration] kind: "circle", | semmle.label | 1 | +| tst.ts:141:9:141:42 | [InterfaceTypeExpr] { kind: ... umber } | tst.ts:141:11:141:25 | [FieldDeclaration] kind: "circle", | semmle.order | 1 | +| tst.ts:141:9:141:42 | [InterfaceTypeExpr] { kind: ... umber } | tst.ts:141:27:141:40 | [FieldDeclaration] radius: number | semmle.label | 2 | +| tst.ts:141:9:141:42 | [InterfaceTypeExpr] { kind: ... umber } | tst.ts:141:27:141:40 | [FieldDeclaration] radius: number | semmle.order | 2 | +| tst.ts:141:11:141:25 | [FieldDeclaration] kind: "circle", | tst.ts:141:11:141:14 | [Label] kind | semmle.label | 1 | +| tst.ts:141:11:141:25 | [FieldDeclaration] kind: "circle", | tst.ts:141:11:141:14 | [Label] kind | semmle.order | 1 | +| tst.ts:141:11:141:25 | [FieldDeclaration] kind: "circle", | tst.ts:141:17:141:24 | [LiteralTypeExpr] "circle" | semmle.label | 2 | +| tst.ts:141:11:141:25 | [FieldDeclaration] kind: "circle", | tst.ts:141:17:141:24 | [LiteralTypeExpr] "circle" | semmle.order | 2 | +| tst.ts:141:27:141:40 | [FieldDeclaration] radius: number | tst.ts:141:27:141:32 | [Label] radius | semmle.label | 1 | +| tst.ts:141:27:141:40 | [FieldDeclaration] radius: number | tst.ts:141:27:141:32 | [Label] radius | semmle.order | 1 | +| tst.ts:141:27:141:40 | [FieldDeclaration] radius: number | tst.ts:141:35:141:40 | [KeywordTypeExpr] number | semmle.label | 2 | +| tst.ts:141:27:141:40 | [FieldDeclaration] radius: number | tst.ts:141:35:141:40 | [KeywordTypeExpr] number | semmle.order | 2 | +| tst.ts:142:9:142:46 | [InterfaceTypeExpr] { kind: ... umber } | tst.ts:142:11:142:25 | [FieldDeclaration] kind: "square", | semmle.label | 1 | +| tst.ts:142:9:142:46 | [InterfaceTypeExpr] { kind: ... umber } | tst.ts:142:11:142:25 | [FieldDeclaration] kind: "square", | semmle.order | 1 | +| tst.ts:142:9:142:46 | [InterfaceTypeExpr] { kind: ... umber } | tst.ts:142:27:142:44 | [FieldDeclaration] sideLength: number | semmle.label | 2 | +| tst.ts:142:9:142:46 | [InterfaceTypeExpr] { kind: ... umber } | tst.ts:142:27:142:44 | [FieldDeclaration] sideLength: number | semmle.order | 2 | +| tst.ts:142:11:142:25 | [FieldDeclaration] kind: "square", | tst.ts:142:11:142:14 | [Label] kind | semmle.label | 1 | +| tst.ts:142:11:142:25 | [FieldDeclaration] kind: "square", | tst.ts:142:11:142:14 | [Label] kind | semmle.order | 1 | +| tst.ts:142:11:142:25 | [FieldDeclaration] kind: "square", | tst.ts:142:17:142:24 | [LiteralTypeExpr] "square" | semmle.label | 2 | +| tst.ts:142:11:142:25 | [FieldDeclaration] kind: "square", | tst.ts:142:17:142:24 | [LiteralTypeExpr] "square" | semmle.order | 2 | +| tst.ts:142:27:142:44 | [FieldDeclaration] sideLength: number | tst.ts:142:27:142:36 | [Label] sideLength | semmle.label | 1 | +| tst.ts:142:27:142:44 | [FieldDeclaration] sideLength: number | tst.ts:142:27:142:36 | [Label] sideLength | semmle.order | 1 | +| tst.ts:142:27:142:44 | [FieldDeclaration] sideLength: number | tst.ts:142:39:142:44 | [KeywordTypeExpr] number | semmle.label | 2 | +| tst.ts:142:27:142:44 | [FieldDeclaration] sideLength: number | tst.ts:142:39:142:44 | [KeywordTypeExpr] number | semmle.order | 2 | +| tst.ts:144:3:149:3 | [FunctionDeclStmt] functio ... ; } } | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| tst.ts:144:3:149:3 | [FunctionDeclStmt] functio ... ; } } | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| tst.ts:144:3:149:3 | [FunctionDeclStmt] functio ... ; } } | tst.ts:144:12:144:15 | [VarDecl] side | semmle.label | 0 | +| tst.ts:144:3:149:3 | [FunctionDeclStmt] functio ... ; } } | tst.ts:144:12:144:15 | [VarDecl] side | semmle.order | 0 | +| tst.ts:144:3:149:3 | [FunctionDeclStmt] functio ... ; } } | tst.ts:144:32:144:37 | [KeywordTypeExpr] number | semmle.label | 4 | +| tst.ts:144:3:149:3 | [FunctionDeclStmt] functio ... ; } } | tst.ts:144:32:144:37 | [KeywordTypeExpr] number | semmle.order | 4 | +| tst.ts:144:3:149:3 | [FunctionDeclStmt] functio ... ; } } | tst.ts:144:39:149:3 | [BlockStmt] { ... ; } } | semmle.label | 5 | +| tst.ts:144:3:149:3 | [FunctionDeclStmt] functio ... ; } } | tst.ts:144:39:149:3 | [BlockStmt] { ... ; } } | semmle.order | 5 | +| tst.ts:144:17:144:21 | [SimpleParameter] shape | tst.ts:144:24:144:28 | [LocalTypeAccess] Shape | semmle.label | 0 | +| tst.ts:144:17:144:21 | [SimpleParameter] shape | tst.ts:144:24:144:28 | [LocalTypeAccess] Shape | semmle.order | 0 | +| tst.ts:144:39:149:3 | [BlockStmt] { ... ; } } | tst.ts:145:7:145:29 | [DeclStmt] const { ... shape; | semmle.label | 1 | +| tst.ts:144:39:149:3 | [BlockStmt] { ... ; } } | tst.ts:145:7:145:29 | [DeclStmt] const { ... shape; | semmle.order | 1 | +| tst.ts:144:39:149:3 | [BlockStmt] { ... ; } } | tst.ts:147:7:148:39 | [IfStmt] if (kin ... ngth; } | semmle.label | 2 | +| tst.ts:144:39:149:3 | [BlockStmt] { ... ; } } | tst.ts:147:7:148:39 | [IfStmt] if (kin ... ngth; } | semmle.order | 2 | +| tst.ts:145:7:145:29 | [DeclStmt] const { ... shape; | tst.ts:145:13:145:28 | [VariableDeclarator] { kind } = shape | semmle.label | 1 | +| tst.ts:145:7:145:29 | [DeclStmt] const { ... shape; | tst.ts:145:13:145:28 | [VariableDeclarator] { kind } = shape | semmle.order | 1 | +| tst.ts:145:13:145:20 | [ObjectPattern] { kind } | tst.ts:145:15:145:18 | [PropertyPattern] kind | semmle.label | 1 | +| tst.ts:145:13:145:20 | [ObjectPattern] { kind } | tst.ts:145:15:145:18 | [PropertyPattern] kind | semmle.order | 1 | +| tst.ts:145:13:145:28 | [VariableDeclarator] { kind } = shape | tst.ts:145:13:145:20 | [ObjectPattern] { kind } | semmle.label | 1 | +| tst.ts:145:13:145:28 | [VariableDeclarator] { kind } = shape | tst.ts:145:13:145:20 | [ObjectPattern] { kind } | semmle.order | 1 | +| tst.ts:145:13:145:28 | [VariableDeclarator] { kind } = shape | tst.ts:145:24:145:28 | [VarRef] shape | semmle.label | 2 | +| tst.ts:145:13:145:28 | [VariableDeclarator] { kind } = shape | tst.ts:145:24:145:28 | [VarRef] shape | semmle.order | 2 | +| tst.ts:145:15:145:18 | [PropertyPattern] kind | tst.ts:145:15:145:18 | [Label] kind | semmle.label | 1 | +| tst.ts:145:15:145:18 | [PropertyPattern] kind | tst.ts:145:15:145:18 | [Label] kind | semmle.order | 1 | +| tst.ts:145:15:145:18 | [PropertyPattern] kind | tst.ts:145:15:145:18 | [VarDecl] kind | semmle.label | 2 | +| tst.ts:145:15:145:18 | [PropertyPattern] kind | tst.ts:145:15:145:18 | [VarDecl] kind | semmle.order | 2 | +| tst.ts:147:7:148:39 | [IfStmt] if (kin ... ngth; } | tst.ts:147:11:147:27 | [BinaryExpr] kind === "circle" | semmle.label | 1 | +| tst.ts:147:7:148:39 | [IfStmt] if (kin ... ngth; } | tst.ts:147:11:147:27 | [BinaryExpr] kind === "circle" | semmle.order | 1 | +| tst.ts:147:7:148:39 | [IfStmt] if (kin ... ngth; } | tst.ts:147:30:147:52 | [BlockStmt] { retur ... adius;} | semmle.label | 2 | +| tst.ts:147:7:148:39 | [IfStmt] if (kin ... ngth; } | tst.ts:147:30:147:52 | [BlockStmt] { retur ... adius;} | semmle.order | 2 | +| tst.ts:147:7:148:39 | [IfStmt] if (kin ... ngth; } | tst.ts:148:12:148:39 | [BlockStmt] { retur ... ngth; } | semmle.label | 3 | +| tst.ts:147:7:148:39 | [IfStmt] if (kin ... ngth; } | tst.ts:148:12:148:39 | [BlockStmt] { retur ... ngth; } | semmle.order | 3 | +| tst.ts:147:11:147:27 | [BinaryExpr] kind === "circle" | tst.ts:147:11:147:14 | [VarRef] kind | semmle.label | 1 | +| tst.ts:147:11:147:27 | [BinaryExpr] kind === "circle" | tst.ts:147:11:147:14 | [VarRef] kind | semmle.order | 1 | +| tst.ts:147:11:147:27 | [BinaryExpr] kind === "circle" | tst.ts:147:20:147:27 | [Literal] "circle" | semmle.label | 2 | +| tst.ts:147:11:147:27 | [BinaryExpr] kind === "circle" | tst.ts:147:20:147:27 | [Literal] "circle" | semmle.order | 2 | +| tst.ts:147:30:147:52 | [BlockStmt] { retur ... adius;} | tst.ts:147:32:147:51 | [ReturnStmt] return shape.radius; | semmle.label | 1 | +| tst.ts:147:30:147:52 | [BlockStmt] { retur ... adius;} | tst.ts:147:32:147:51 | [ReturnStmt] return shape.radius; | semmle.order | 1 | +| tst.ts:147:32:147:51 | [ReturnStmt] return shape.radius; | tst.ts:147:39:147:50 | [DotExpr] shape.radius | semmle.label | 1 | +| tst.ts:147:32:147:51 | [ReturnStmt] return shape.radius; | tst.ts:147:39:147:50 | [DotExpr] shape.radius | semmle.order | 1 | +| tst.ts:147:39:147:50 | [DotExpr] shape.radius | tst.ts:147:39:147:43 | [VarRef] shape | semmle.label | 1 | +| tst.ts:147:39:147:50 | [DotExpr] shape.radius | tst.ts:147:39:147:43 | [VarRef] shape | semmle.order | 1 | +| tst.ts:147:39:147:50 | [DotExpr] shape.radius | tst.ts:147:45:147:50 | [Label] radius | semmle.label | 2 | +| tst.ts:147:39:147:50 | [DotExpr] shape.radius | tst.ts:147:45:147:50 | [Label] radius | semmle.order | 2 | +| tst.ts:148:12:148:39 | [BlockStmt] { retur ... ngth; } | tst.ts:148:14:148:37 | [ReturnStmt] return ... Length; | semmle.label | 1 | +| tst.ts:148:12:148:39 | [BlockStmt] { retur ... ngth; } | tst.ts:148:14:148:37 | [ReturnStmt] return ... Length; | semmle.order | 1 | +| tst.ts:148:14:148:37 | [ReturnStmt] return ... Length; | tst.ts:148:21:148:36 | [DotExpr] shape.sideLength | semmle.label | 1 | +| tst.ts:148:14:148:37 | [ReturnStmt] return ... Length; | tst.ts:148:21:148:36 | [DotExpr] shape.sideLength | semmle.order | 1 | +| tst.ts:148:21:148:36 | [DotExpr] shape.sideLength | tst.ts:148:21:148:25 | [VarRef] shape | semmle.label | 1 | +| tst.ts:148:21:148:36 | [DotExpr] shape.sideLength | tst.ts:148:21:148:25 | [VarRef] shape | semmle.order | 1 | +| tst.ts:148:21:148:36 | [DotExpr] shape.sideLength | tst.ts:148:27:148:36 | [Label] sideLength | semmle.label | 2 | +| tst.ts:148:21:148:36 | [DotExpr] shape.sideLength | tst.ts:148:27:148:36 | [Label] sideLength | semmle.order | 2 | +| tst.ts:151:3:162:3 | [FunctionDeclStmt] functio ... 2]; } | tst.ts:151:12:151:22 | [VarDecl] symbolIndex | semmle.label | 0 | +| tst.ts:151:3:162:3 | [FunctionDeclStmt] functio ... 2]; } | tst.ts:151:12:151:22 | [VarDecl] symbolIndex | semmle.order | 0 | +| tst.ts:151:3:162:3 | [FunctionDeclStmt] functio ... 2]; } | tst.ts:151:26:162:3 | [BlockStmt] { i ... 2]; } | semmle.label | 5 | +| tst.ts:151:3:162:3 | [FunctionDeclStmt] functio ... 2]; } | tst.ts:151:26:162:3 | [BlockStmt] { i ... 2]; } | semmle.order | 5 | +| tst.ts:151:26:162:3 | [BlockStmt] { i ... 2]; } | tst.ts:152:5:156:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | semmle.label | 1 | +| tst.ts:151:26:162:3 | [BlockStmt] { i ... 2]; } | tst.ts:152:5:156:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | semmle.order | 1 | +| tst.ts:151:26:162:3 | [BlockStmt] { i ... 2]; } | tst.ts:158:5:158:28 | [DeclStmt] let colors = ... | semmle.label | 2 | +| tst.ts:151:26:162:3 | [BlockStmt] { i ... 2]; } | tst.ts:158:5:158:28 | [DeclStmt] let colors = ... | semmle.order | 2 | +| tst.ts:151:26:162:3 | [BlockStmt] { i ... 2]; } | tst.ts:159:5:159:38 | [DeclStmt] const red = ... | semmle.label | 3 | +| tst.ts:151:26:162:3 | [BlockStmt] { i ... 2]; } | tst.ts:159:5:159:38 | [DeclStmt] const red = ... | semmle.order | 3 | +| tst.ts:151:26:162:3 | [BlockStmt] { i ... 2]; } | tst.ts:160:5:160:34 | [DeclStmt] const green = ... | semmle.label | 4 | +| tst.ts:151:26:162:3 | [BlockStmt] { i ... 2]; } | tst.ts:160:5:160:34 | [DeclStmt] const green = ... | semmle.order | 4 | +| tst.ts:151:26:162:3 | [BlockStmt] { i ... 2]; } | tst.ts:161:5:161:27 | [DeclStmt] const blue = ... | semmle.label | 5 | +| tst.ts:151:26:162:3 | [BlockStmt] { i ... 2]; } | tst.ts:161:5:161:27 | [DeclStmt] const blue = ... | semmle.order | 5 | +| tst.ts:152:5:156:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | tst.ts:152:15:152:20 | [Identifier] Colors | semmle.label | 1 | +| tst.ts:152:5:156:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | tst.ts:152:15:152:20 | [Identifier] Colors | semmle.order | 1 | +| tst.ts:152:5:156:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | tst.ts:153:7:153:28 | [IndexSignature] [sym: s ... number; | semmle.label | 2 | +| tst.ts:152:5:156:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | tst.ts:153:7:153:28 | [IndexSignature] [sym: s ... number; | semmle.order | 2 | +| tst.ts:152:5:156:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | tst.ts:154:7:154:28 | [IndexSignature] [key: s ... string; | semmle.label | 3 | +| tst.ts:152:5:156:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | tst.ts:154:7:154:28 | [IndexSignature] [key: s ... string; | semmle.order | 3 | +| tst.ts:152:5:156:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | tst.ts:155:7:155:29 | [IndexSignature] [num: n ... oolean; | semmle.label | 4 | +| tst.ts:152:5:156:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | tst.ts:155:7:155:29 | [IndexSignature] [num: n ... oolean; | semmle.order | 4 | +| tst.ts:153:7:153:28 | [FunctionExpr] [sym: s ... number; | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| tst.ts:153:7:153:28 | [FunctionExpr] [sym: s ... number; | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| tst.ts:153:7:153:28 | [FunctionExpr] [sym: s ... number; | tst.ts:153:22:153:27 | [KeywordTypeExpr] number | semmle.label | 4 | +| tst.ts:153:7:153:28 | [FunctionExpr] [sym: s ... number; | tst.ts:153:22:153:27 | [KeywordTypeExpr] number | semmle.order | 4 | +| tst.ts:153:7:153:28 | [IndexSignature] [sym: s ... number; | tst.ts:153:7:153:28 | [FunctionExpr] [sym: s ... number; | semmle.label | 1 | +| tst.ts:153:7:153:28 | [IndexSignature] [sym: s ... number; | tst.ts:153:7:153:28 | [FunctionExpr] [sym: s ... number; | semmle.order | 1 | +| tst.ts:153:8:153:10 | [SimpleParameter] sym | tst.ts:153:13:153:18 | [KeywordTypeExpr] symbol | semmle.label | 0 | +| tst.ts:153:8:153:10 | [SimpleParameter] sym | tst.ts:153:13:153:18 | [KeywordTypeExpr] symbol | semmle.order | 0 | +| tst.ts:154:7:154:28 | [FunctionExpr] [key: s ... string; | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| tst.ts:154:7:154:28 | [FunctionExpr] [key: s ... string; | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| tst.ts:154:7:154:28 | [FunctionExpr] [key: s ... string; | tst.ts:154:22:154:27 | [KeywordTypeExpr] string | semmle.label | 4 | +| tst.ts:154:7:154:28 | [FunctionExpr] [key: s ... string; | tst.ts:154:22:154:27 | [KeywordTypeExpr] string | semmle.order | 4 | +| tst.ts:154:7:154:28 | [IndexSignature] [key: s ... string; | tst.ts:154:7:154:28 | [FunctionExpr] [key: s ... string; | semmle.label | 1 | +| tst.ts:154:7:154:28 | [IndexSignature] [key: s ... string; | tst.ts:154:7:154:28 | [FunctionExpr] [key: s ... string; | semmle.order | 1 | +| tst.ts:154:8:154:10 | [SimpleParameter] key | tst.ts:154:13:154:18 | [KeywordTypeExpr] string | semmle.label | 0 | +| tst.ts:154:8:154:10 | [SimpleParameter] key | tst.ts:154:13:154:18 | [KeywordTypeExpr] string | semmle.order | 0 | +| tst.ts:155:7:155:29 | [FunctionExpr] [num: n ... oolean; | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| tst.ts:155:7:155:29 | [FunctionExpr] [num: n ... oolean; | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| tst.ts:155:7:155:29 | [FunctionExpr] [num: n ... oolean; | tst.ts:155:22:155:28 | [KeywordTypeExpr] boolean | semmle.label | 4 | +| tst.ts:155:7:155:29 | [FunctionExpr] [num: n ... oolean; | tst.ts:155:22:155:28 | [KeywordTypeExpr] boolean | semmle.order | 4 | +| tst.ts:155:7:155:29 | [IndexSignature] [num: n ... oolean; | tst.ts:155:7:155:29 | [FunctionExpr] [num: n ... oolean; | semmle.label | 1 | +| tst.ts:155:7:155:29 | [IndexSignature] [num: n ... oolean; | tst.ts:155:7:155:29 | [FunctionExpr] [num: n ... oolean; | semmle.order | 1 | +| tst.ts:155:8:155:10 | [SimpleParameter] num | tst.ts:155:13:155:18 | [KeywordTypeExpr] number | semmle.label | 0 | +| tst.ts:155:8:155:10 | [SimpleParameter] num | tst.ts:155:13:155:18 | [KeywordTypeExpr] number | semmle.order | 0 | +| tst.ts:158:5:158:28 | [DeclStmt] let colors = ... | tst.ts:158:9:158:27 | [VariableDeclarator] colors: Colors = {} | semmle.label | 1 | +| tst.ts:158:5:158:28 | [DeclStmt] let colors = ... | tst.ts:158:9:158:27 | [VariableDeclarator] colors: Colors = {} | semmle.order | 1 | +| tst.ts:158:9:158:27 | [VariableDeclarator] colors: Colors = {} | tst.ts:158:9:158:14 | [VarDecl] colors | semmle.label | 1 | +| tst.ts:158:9:158:27 | [VariableDeclarator] colors: Colors = {} | tst.ts:158:9:158:14 | [VarDecl] colors | semmle.order | 1 | +| tst.ts:158:9:158:27 | [VariableDeclarator] colors: Colors = {} | tst.ts:158:17:158:22 | [LocalTypeAccess] Colors | semmle.label | 2 | +| tst.ts:158:9:158:27 | [VariableDeclarator] colors: Colors = {} | tst.ts:158:17:158:22 | [LocalTypeAccess] Colors | semmle.order | 2 | +| tst.ts:158:9:158:27 | [VariableDeclarator] colors: Colors = {} | tst.ts:158:26:158:27 | [ObjectExpr] {} | semmle.label | 3 | +| tst.ts:158:9:158:27 | [VariableDeclarator] colors: Colors = {} | tst.ts:158:26:158:27 | [ObjectExpr] {} | semmle.order | 3 | +| tst.ts:159:5:159:38 | [DeclStmt] const red = ... | tst.ts:159:11:159:37 | [VariableDeclarator] red = c ... "red")] | semmle.label | 1 | +| tst.ts:159:5:159:38 | [DeclStmt] const red = ... | tst.ts:159:11:159:37 | [VariableDeclarator] red = c ... "red")] | semmle.order | 1 | +| tst.ts:159:11:159:37 | [VariableDeclarator] red = c ... "red")] | tst.ts:159:11:159:13 | [VarDecl] red | semmle.label | 1 | +| tst.ts:159:11:159:37 | [VariableDeclarator] red = c ... "red")] | tst.ts:159:11:159:13 | [VarDecl] red | semmle.order | 1 | +| tst.ts:159:11:159:37 | [VariableDeclarator] red = c ... "red")] | tst.ts:159:17:159:37 | [IndexExpr] colors[ ... "red")] | semmle.label | 2 | +| tst.ts:159:11:159:37 | [VariableDeclarator] red = c ... "red")] | tst.ts:159:17:159:37 | [IndexExpr] colors[ ... "red")] | semmle.order | 2 | +| tst.ts:159:17:159:37 | [IndexExpr] colors[ ... "red")] | tst.ts:159:17:159:22 | [VarRef] colors | semmle.label | 1 | +| tst.ts:159:17:159:37 | [IndexExpr] colors[ ... "red")] | tst.ts:159:17:159:22 | [VarRef] colors | semmle.order | 1 | +| tst.ts:159:17:159:37 | [IndexExpr] colors[ ... "red")] | tst.ts:159:24:159:36 | [CallExpr] Symbol("red") | semmle.label | 2 | +| tst.ts:159:17:159:37 | [IndexExpr] colors[ ... "red")] | tst.ts:159:24:159:36 | [CallExpr] Symbol("red") | semmle.order | 2 | +| tst.ts:159:24:159:36 | [CallExpr] Symbol("red") | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| tst.ts:159:24:159:36 | [CallExpr] Symbol("red") | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| tst.ts:159:24:159:36 | [CallExpr] Symbol("red") | tst.ts:159:24:159:29 | [VarRef] Symbol | semmle.label | 0 | +| tst.ts:159:24:159:36 | [CallExpr] Symbol("red") | tst.ts:159:24:159:29 | [VarRef] Symbol | semmle.order | 0 | +| tst.ts:160:5:160:34 | [DeclStmt] const green = ... | tst.ts:160:11:160:33 | [VariableDeclarator] green = ... green"] | semmle.label | 1 | +| tst.ts:160:5:160:34 | [DeclStmt] const green = ... | tst.ts:160:11:160:33 | [VariableDeclarator] green = ... green"] | semmle.order | 1 | +| tst.ts:160:11:160:33 | [VariableDeclarator] green = ... green"] | tst.ts:160:11:160:15 | [VarDecl] green | semmle.label | 1 | +| tst.ts:160:11:160:33 | [VariableDeclarator] green = ... green"] | tst.ts:160:11:160:15 | [VarDecl] green | semmle.order | 1 | +| tst.ts:160:11:160:33 | [VariableDeclarator] green = ... green"] | tst.ts:160:19:160:33 | [IndexExpr] colors["green"] | semmle.label | 2 | +| tst.ts:160:11:160:33 | [VariableDeclarator] green = ... green"] | tst.ts:160:19:160:33 | [IndexExpr] colors["green"] | semmle.order | 2 | +| tst.ts:160:19:160:33 | [IndexExpr] colors["green"] | tst.ts:160:19:160:24 | [VarRef] colors | semmle.label | 1 | +| tst.ts:160:19:160:33 | [IndexExpr] colors["green"] | tst.ts:160:19:160:24 | [VarRef] colors | semmle.order | 1 | +| tst.ts:160:19:160:33 | [IndexExpr] colors["green"] | tst.ts:160:26:160:32 | [Literal] "green" | semmle.label | 2 | +| tst.ts:160:19:160:33 | [IndexExpr] colors["green"] | tst.ts:160:26:160:32 | [Literal] "green" | semmle.order | 2 | +| tst.ts:161:5:161:27 | [DeclStmt] const blue = ... | tst.ts:161:11:161:26 | [VariableDeclarator] blue = colors[2] | semmle.label | 1 | +| tst.ts:161:5:161:27 | [DeclStmt] const blue = ... | tst.ts:161:11:161:26 | [VariableDeclarator] blue = colors[2] | semmle.order | 1 | +| tst.ts:161:11:161:26 | [VariableDeclarator] blue = colors[2] | tst.ts:161:11:161:14 | [VarDecl] blue | semmle.label | 1 | +| tst.ts:161:11:161:26 | [VariableDeclarator] blue = colors[2] | tst.ts:161:11:161:14 | [VarDecl] blue | semmle.order | 1 | +| tst.ts:161:11:161:26 | [VariableDeclarator] blue = colors[2] | tst.ts:161:18:161:26 | [IndexExpr] colors[2] | semmle.label | 2 | +| tst.ts:161:11:161:26 | [VariableDeclarator] blue = colors[2] | tst.ts:161:18:161:26 | [IndexExpr] colors[2] | semmle.order | 2 | +| tst.ts:161:18:161:26 | [IndexExpr] colors[2] | tst.ts:161:18:161:23 | [VarRef] colors | semmle.label | 1 | +| tst.ts:161:18:161:26 | [IndexExpr] colors[2] | tst.ts:161:18:161:23 | [VarRef] colors | semmle.order | 1 | +| tst.ts:161:18:161:26 | [IndexExpr] colors[2] | tst.ts:161:25:161:25 | [Literal] 2 | semmle.label | 2 | +| tst.ts:161:18:161:26 | [IndexExpr] colors[2] | tst.ts:161:25:161:25 | [Literal] 2 | semmle.order | 2 | +| tst.ts:164:3:177:3 | [FunctionDeclStmt] functio ... "]; } | tst.ts:164:12:164:29 | [VarDecl] stringPatternIndex | semmle.label | 0 | +| tst.ts:164:3:177:3 | [FunctionDeclStmt] functio ... "]; } | tst.ts:164:12:164:29 | [VarDecl] stringPatternIndex | semmle.order | 0 | +| tst.ts:164:3:177:3 | [FunctionDeclStmt] functio ... "]; } | tst.ts:164:33:177:3 | [BlockStmt] { i ... "]; } | semmle.label | 5 | +| tst.ts:164:3:177:3 | [FunctionDeclStmt] functio ... "]; } | tst.ts:164:33:177:3 | [BlockStmt] { i ... "]; } | semmle.order | 5 | +| tst.ts:164:33:177:3 | [BlockStmt] { i ... "]; } | tst.ts:165:5:167:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | semmle.label | 1 | +| tst.ts:164:33:177:3 | [BlockStmt] { i ... "]; } | tst.ts:165:5:167:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | semmle.order | 1 | +| tst.ts:164:33:177:3 | [BlockStmt] { i ... "]; } | tst.ts:168:5:168:23 | [DeclStmt] var bla = ... | semmle.label | 2 | +| tst.ts:164:33:177:3 | [BlockStmt] { i ... "]; } | tst.ts:168:5:168:23 | [DeclStmt] var bla = ... | semmle.order | 2 | +| tst.ts:164:33:177:3 | [BlockStmt] { i ... "]; } | tst.ts:169:5:169:29 | [DeclStmt] const bar = ... | semmle.label | 3 | +| tst.ts:164:33:177:3 | [BlockStmt] { i ... "]; } | tst.ts:169:5:169:29 | [DeclStmt] const bar = ... | semmle.order | 3 | +| tst.ts:164:33:177:3 | [BlockStmt] { i ... "]; } | tst.ts:171:5:173:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | semmle.label | 4 | +| tst.ts:164:33:177:3 | [BlockStmt] { i ... "]; } | tst.ts:171:5:173:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | semmle.order | 4 | +| tst.ts:164:33:177:3 | [BlockStmt] { i ... "]; } | tst.ts:175:5:175:26 | [DeclStmt] const data = ... | semmle.label | 5 | +| tst.ts:164:33:177:3 | [BlockStmt] { i ... "]; } | tst.ts:175:5:175:26 | [DeclStmt] const data = ... | semmle.order | 5 | +| tst.ts:164:33:177:3 | [BlockStmt] { i ... "]; } | tst.ts:176:5:176:28 | [DeclStmt] const baz = ... | semmle.label | 6 | +| tst.ts:164:33:177:3 | [BlockStmt] { i ... "]; } | tst.ts:176:5:176:28 | [DeclStmt] const baz = ... | semmle.order | 6 | +| tst.ts:165:5:167:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | tst.ts:165:15:165:17 | [Identifier] Foo | semmle.label | 1 | +| tst.ts:165:5:167:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | tst.ts:165:15:165:17 | [Identifier] Foo | semmle.order | 1 | +| tst.ts:165:5:167:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | tst.ts:166:7:166:37 | [IndexSignature] [key: ` ... number; | semmle.label | 2 | +| tst.ts:165:5:167:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | tst.ts:166:7:166:37 | [IndexSignature] [key: ` ... number; | semmle.order | 2 | +| tst.ts:166:7:166:37 | [FunctionExpr] [key: ` ... number; | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| tst.ts:166:7:166:37 | [FunctionExpr] [key: ` ... number; | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| tst.ts:166:7:166:37 | [FunctionExpr] [key: ` ... number; | tst.ts:166:31:166:36 | [KeywordTypeExpr] number | semmle.label | 4 | +| tst.ts:166:7:166:37 | [FunctionExpr] [key: ` ... number; | tst.ts:166:31:166:36 | [KeywordTypeExpr] number | semmle.order | 4 | +| tst.ts:166:7:166:37 | [IndexSignature] [key: ` ... number; | tst.ts:166:7:166:37 | [FunctionExpr] [key: ` ... number; | semmle.label | 1 | +| tst.ts:166:7:166:37 | [IndexSignature] [key: ` ... number; | tst.ts:166:7:166:37 | [FunctionExpr] [key: ` ... number; | semmle.order | 1 | +| tst.ts:166:8:166:10 | [SimpleParameter] key | tst.ts:166:13:166:27 | [TemplateLiteralTypeExpr] `foo-${number}` | semmle.label | 0 | +| tst.ts:166:8:166:10 | [SimpleParameter] key | tst.ts:166:13:166:27 | [TemplateLiteralTypeExpr] `foo-${number}` | semmle.order | 0 | +| tst.ts:166:13:166:27 | [TemplateLiteralTypeExpr] `foo-${number}` | tst.ts:166:14:166:17 | [LiteralTypeExpr] foo- | semmle.label | 1 | +| tst.ts:166:13:166:27 | [TemplateLiteralTypeExpr] `foo-${number}` | tst.ts:166:14:166:17 | [LiteralTypeExpr] foo- | semmle.order | 1 | +| tst.ts:166:13:166:27 | [TemplateLiteralTypeExpr] `foo-${number}` | tst.ts:166:20:166:25 | [KeywordTypeExpr] number | semmle.label | 2 | +| tst.ts:166:13:166:27 | [TemplateLiteralTypeExpr] `foo-${number}` | tst.ts:166:20:166:25 | [KeywordTypeExpr] number | semmle.order | 2 | +| tst.ts:168:5:168:23 | [DeclStmt] var bla = ... | tst.ts:168:9:168:22 | [VariableDeclarator] bla : Foo = {} | semmle.label | 1 | +| tst.ts:168:5:168:23 | [DeclStmt] var bla = ... | tst.ts:168:9:168:22 | [VariableDeclarator] bla : Foo = {} | semmle.order | 1 | +| tst.ts:168:9:168:22 | [VariableDeclarator] bla : Foo = {} | tst.ts:168:9:168:11 | [VarDecl] bla | semmle.label | 1 | +| tst.ts:168:9:168:22 | [VariableDeclarator] bla : Foo = {} | tst.ts:168:9:168:11 | [VarDecl] bla | semmle.order | 1 | +| tst.ts:168:9:168:22 | [VariableDeclarator] bla : Foo = {} | tst.ts:168:15:168:17 | [LocalTypeAccess] Foo | semmle.label | 2 | +| tst.ts:168:9:168:22 | [VariableDeclarator] bla : Foo = {} | tst.ts:168:15:168:17 | [LocalTypeAccess] Foo | semmle.order | 2 | +| tst.ts:168:9:168:22 | [VariableDeclarator] bla : Foo = {} | tst.ts:168:21:168:22 | [ObjectExpr] {} | semmle.label | 3 | +| tst.ts:168:9:168:22 | [VariableDeclarator] bla : Foo = {} | tst.ts:168:21:168:22 | [ObjectExpr] {} | semmle.order | 3 | +| tst.ts:169:5:169:29 | [DeclStmt] const bar = ... | tst.ts:169:11:169:28 | [VariableDeclarator] bar = bla[`foo-1`] | semmle.label | 1 | +| tst.ts:169:5:169:29 | [DeclStmt] const bar = ... | tst.ts:169:11:169:28 | [VariableDeclarator] bar = bla[`foo-1`] | semmle.order | 1 | +| tst.ts:169:11:169:28 | [VariableDeclarator] bar = bla[`foo-1`] | tst.ts:169:11:169:13 | [VarDecl] bar | semmle.label | 1 | +| tst.ts:169:11:169:28 | [VariableDeclarator] bar = bla[`foo-1`] | tst.ts:169:11:169:13 | [VarDecl] bar | semmle.order | 1 | +| tst.ts:169:11:169:28 | [VariableDeclarator] bar = bla[`foo-1`] | tst.ts:169:17:169:28 | [IndexExpr] bla[`foo-1`] | semmle.label | 2 | +| tst.ts:169:11:169:28 | [VariableDeclarator] bar = bla[`foo-1`] | tst.ts:169:17:169:28 | [IndexExpr] bla[`foo-1`] | semmle.order | 2 | +| tst.ts:169:17:169:28 | [IndexExpr] bla[`foo-1`] | tst.ts:169:17:169:19 | [VarRef] bla | semmle.label | 1 | +| tst.ts:169:17:169:28 | [IndexExpr] bla[`foo-1`] | tst.ts:169:17:169:19 | [VarRef] bla | semmle.order | 1 | +| tst.ts:169:17:169:28 | [IndexExpr] bla[`foo-1`] | tst.ts:169:21:169:27 | [TemplateLiteral] `foo-1` | semmle.label | 2 | +| tst.ts:169:17:169:28 | [IndexExpr] bla[`foo-1`] | tst.ts:169:21:169:27 | [TemplateLiteral] `foo-1` | semmle.order | 2 | +| tst.ts:169:21:169:27 | [TemplateLiteral] `foo-1` | tst.ts:169:21:169:27 | [TemplateElement] `foo-1` | semmle.label | 1 | +| tst.ts:169:21:169:27 | [TemplateLiteral] `foo-1` | tst.ts:169:21:169:27 | [TemplateElement] `foo-1` | semmle.order | 1 | +| tst.ts:171:5:173:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | tst.ts:171:15:171:18 | [Identifier] Data | semmle.label | 1 | +| tst.ts:171:5:173:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | tst.ts:171:15:171:18 | [Identifier] Data | semmle.order | 1 | +| tst.ts:171:5:173:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | tst.ts:172:7:172:42 | [IndexSignature] [optNam ... oolean; | semmle.label | 2 | +| tst.ts:171:5:173:5 | [InterfaceDeclaration,TypeDefinition] interfa ... ; } | tst.ts:172:7:172:42 | [IndexSignature] [optNam ... oolean; | semmle.order | 2 | +| tst.ts:172:7:172:42 | [FunctionExpr] [optNam ... oolean; | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| tst.ts:172:7:172:42 | [FunctionExpr] [optNam ... oolean; | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| tst.ts:172:7:172:42 | [FunctionExpr] [optNam ... oolean; | tst.ts:172:35:172:41 | [KeywordTypeExpr] boolean | semmle.label | 4 | +| tst.ts:172:7:172:42 | [FunctionExpr] [optNam ... oolean; | tst.ts:172:35:172:41 | [KeywordTypeExpr] boolean | semmle.order | 4 | +| tst.ts:172:7:172:42 | [IndexSignature] [optNam ... oolean; | tst.ts:172:7:172:42 | [FunctionExpr] [optNam ... oolean; | semmle.label | 1 | +| tst.ts:172:7:172:42 | [IndexSignature] [optNam ... oolean; | tst.ts:172:7:172:42 | [FunctionExpr] [optNam ... oolean; | semmle.order | 1 | +| tst.ts:172:8:172:14 | [SimpleParameter] optName | tst.ts:172:17:172:31 | [UnionTypeExpr] string \| symbol | semmle.label | 0 | +| tst.ts:172:8:172:14 | [SimpleParameter] optName | tst.ts:172:17:172:31 | [UnionTypeExpr] string \| symbol | semmle.order | 0 | +| tst.ts:172:17:172:31 | [UnionTypeExpr] string \| symbol | tst.ts:172:17:172:22 | [KeywordTypeExpr] string | semmle.label | 1 | +| tst.ts:172:17:172:31 | [UnionTypeExpr] string \| symbol | tst.ts:172:17:172:22 | [KeywordTypeExpr] string | semmle.order | 1 | +| tst.ts:172:17:172:31 | [UnionTypeExpr] string \| symbol | tst.ts:172:26:172:31 | [KeywordTypeExpr] symbol | semmle.label | 2 | +| tst.ts:172:17:172:31 | [UnionTypeExpr] string \| symbol | tst.ts:172:26:172:31 | [KeywordTypeExpr] symbol | semmle.order | 2 | +| tst.ts:175:5:175:26 | [DeclStmt] const data = ... | tst.ts:175:11:175:25 | [VariableDeclarator] data: Data = {} | semmle.label | 1 | +| tst.ts:175:5:175:26 | [DeclStmt] const data = ... | tst.ts:175:11:175:25 | [VariableDeclarator] data: Data = {} | semmle.order | 1 | +| tst.ts:175:11:175:25 | [VariableDeclarator] data: Data = {} | tst.ts:175:11:175:14 | [VarDecl] data | semmle.label | 1 | +| tst.ts:175:11:175:25 | [VariableDeclarator] data: Data = {} | tst.ts:175:11:175:14 | [VarDecl] data | semmle.order | 1 | +| tst.ts:175:11:175:25 | [VariableDeclarator] data: Data = {} | tst.ts:175:17:175:20 | [LocalTypeAccess] Data | semmle.label | 2 | +| tst.ts:175:11:175:25 | [VariableDeclarator] data: Data = {} | tst.ts:175:17:175:20 | [LocalTypeAccess] Data | semmle.order | 2 | +| tst.ts:175:11:175:25 | [VariableDeclarator] data: Data = {} | tst.ts:175:24:175:25 | [ObjectExpr] {} | semmle.label | 3 | +| tst.ts:175:11:175:25 | [VariableDeclarator] data: Data = {} | tst.ts:175:24:175:25 | [ObjectExpr] {} | semmle.order | 3 | +| tst.ts:176:5:176:28 | [DeclStmt] const baz = ... | tst.ts:176:11:176:27 | [VariableDeclarator] baz = data["foo"] | semmle.label | 1 | +| tst.ts:176:5:176:28 | [DeclStmt] const baz = ... | tst.ts:176:11:176:27 | [VariableDeclarator] baz = data["foo"] | semmle.order | 1 | +| tst.ts:176:11:176:27 | [VariableDeclarator] baz = data["foo"] | tst.ts:176:11:176:13 | [VarDecl] baz | semmle.label | 1 | +| tst.ts:176:11:176:27 | [VariableDeclarator] baz = data["foo"] | tst.ts:176:11:176:13 | [VarDecl] baz | semmle.order | 1 | +| tst.ts:176:11:176:27 | [VariableDeclarator] baz = data["foo"] | tst.ts:176:17:176:27 | [IndexExpr] data["foo"] | semmle.label | 2 | +| tst.ts:176:11:176:27 | [VariableDeclarator] baz = data["foo"] | tst.ts:176:17:176:27 | [IndexExpr] data["foo"] | semmle.order | 2 | +| tst.ts:176:17:176:27 | [IndexExpr] data["foo"] | tst.ts:176:17:176:20 | [VarRef] data | semmle.label | 1 | +| tst.ts:176:17:176:27 | [IndexExpr] data["foo"] | tst.ts:176:17:176:20 | [VarRef] data | semmle.order | 1 | +| tst.ts:176:17:176:27 | [IndexExpr] data["foo"] | tst.ts:176:22:176:26 | [Literal] "foo" | semmle.label | 2 | +| tst.ts:176:17:176:27 | [IndexExpr] data["foo"] | tst.ts:176:22:176:26 | [Literal] "foo" | semmle.order | 2 | +| tst.ts:179:3:192:3 | [ClassDefinition,TypeDefinition] class F ... } | tst.ts:179:9:179:11 | [VarDecl] Foo | semmle.label | 1 | +| tst.ts:179:3:192:3 | [ClassDefinition,TypeDefinition] class F ... } | tst.ts:179:9:179:11 | [VarDecl] Foo | semmle.order | 1 | +| tst.ts:179:3:192:3 | [ClassDefinition,TypeDefinition] class F ... } | tst.ts:179:13:179:12 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | semmle.label | 2 | +| tst.ts:179:3:192:3 | [ClassDefinition,TypeDefinition] class F ... } | tst.ts:179:13:179:12 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | semmle.order | 2 | +| tst.ts:179:3:192:3 | [ClassDefinition,TypeDefinition] class F ... } | tst.ts:180:5:180:22 | [ClassInitializedMember,FieldDeclaration] static #count = 0; | semmle.label | 3 | +| tst.ts:179:3:192:3 | [ClassDefinition,TypeDefinition] class F ... } | tst.ts:180:5:180:22 | [ClassInitializedMember,FieldDeclaration] static #count = 0; | semmle.order | 3 | +| tst.ts:179:3:192:3 | [ClassDefinition,TypeDefinition] class F ... } | tst.ts:182:5:184:5 | [ClassInitializedMember,GetterMethodDefinition] get cou ... ; } | semmle.label | 4 | +| tst.ts:179:3:192:3 | [ClassDefinition,TypeDefinition] class F ... } | tst.ts:182:5:184:5 | [ClassInitializedMember,GetterMethodDefinition] get cou ... ; } | semmle.order | 4 | +| tst.ts:179:3:192:3 | [ClassDefinition,TypeDefinition] class F ... } | tst.ts:185:5:187:5 | [ClassInitializedMember] static ... ; } | semmle.label | 5 | +| tst.ts:179:3:192:3 | [ClassDefinition,TypeDefinition] class F ... } | tst.ts:185:5:187:5 | [ClassInitializedMember] static ... ; } | semmle.order | 5 | +| tst.ts:179:3:192:3 | [ClassDefinition,TypeDefinition] class F ... } | tst.ts:188:5:190:5 | [ClassInitializedMember] static ... ; } | semmle.label | 6 | +| tst.ts:179:3:192:3 | [ClassDefinition,TypeDefinition] class F ... } | tst.ts:188:5:190:5 | [ClassInitializedMember] static ... ; } | semmle.order | 6 | +| tst.ts:179:13:179:12 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | tst.ts:179:13:179:12 | [FunctionExpr] () {} | semmle.label | 2 | +| tst.ts:179:13:179:12 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | tst.ts:179:13:179:12 | [FunctionExpr] () {} | semmle.order | 2 | +| tst.ts:179:13:179:12 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | tst.ts:179:13:179:12 | [Label] constructor | semmle.label | 1 | +| tst.ts:179:13:179:12 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | tst.ts:179:13:179:12 | [Label] constructor | semmle.order | 1 | +| tst.ts:179:13:179:12 | [FunctionExpr] () {} | tst.ts:179:13:179:12 | [BlockStmt] {} | semmle.label | 5 | +| tst.ts:179:13:179:12 | [FunctionExpr] () {} | tst.ts:179:13:179:12 | [BlockStmt] {} | semmle.order | 5 | +| tst.ts:180:5:180:22 | [ClassInitializedMember,FieldDeclaration] static #count = 0; | tst.ts:180:12:180:17 | [Label] #count | semmle.label | 1 | +| tst.ts:180:5:180:22 | [ClassInitializedMember,FieldDeclaration] static #count = 0; | tst.ts:180:12:180:17 | [Label] #count | semmle.order | 1 | +| tst.ts:180:5:180:22 | [ClassInitializedMember,FieldDeclaration] static #count = 0; | tst.ts:180:21:180:21 | [Literal] 0 | semmle.label | 2 | +| tst.ts:180:5:180:22 | [ClassInitializedMember,FieldDeclaration] static #count = 0; | tst.ts:180:21:180:21 | [Literal] 0 | semmle.order | 2 | +| tst.ts:182:5:184:5 | [ClassInitializedMember,GetterMethodDefinition] get cou ... ; } | tst.ts:182:5:184:5 | [FunctionExpr] get cou ... ; } | semmle.label | 1 | +| tst.ts:182:5:184:5 | [ClassInitializedMember,GetterMethodDefinition] get cou ... ; } | tst.ts:182:5:184:5 | [FunctionExpr] get cou ... ; } | semmle.order | 1 | +| tst.ts:182:5:184:5 | [ClassInitializedMember,GetterMethodDefinition] get cou ... ; } | tst.ts:182:9:182:13 | [Label] count | semmle.label | 2 | +| tst.ts:182:5:184:5 | [ClassInitializedMember,GetterMethodDefinition] get cou ... ; } | tst.ts:182:9:182:13 | [Label] count | semmle.order | 2 | +| tst.ts:182:5:184:5 | [FunctionExpr] get cou ... ; } | tst.ts:182:17:184:5 | [BlockStmt] { ... ; } | semmle.label | 5 | +| tst.ts:182:5:184:5 | [FunctionExpr] get cou ... ; } | tst.ts:182:17:184:5 | [BlockStmt] { ... ; } | semmle.order | 5 | +| tst.ts:182:17:184:5 | [BlockStmt] { ... ; } | tst.ts:183:9:183:26 | [ReturnStmt] return Foo.#count; | semmle.label | 1 | +| tst.ts:182:17:184:5 | [BlockStmt] { ... ; } | tst.ts:183:9:183:26 | [ReturnStmt] return Foo.#count; | semmle.order | 1 | +| tst.ts:183:9:183:26 | [ReturnStmt] return Foo.#count; | tst.ts:183:16:183:25 | [DotExpr] Foo.#count | semmle.label | 1 | +| tst.ts:183:9:183:26 | [ReturnStmt] return Foo.#count; | tst.ts:183:16:183:25 | [DotExpr] Foo.#count | semmle.order | 1 | +| tst.ts:183:16:183:25 | [DotExpr] Foo.#count | tst.ts:183:16:183:18 | [VarRef] Foo | semmle.label | 1 | +| tst.ts:183:16:183:25 | [DotExpr] Foo.#count | tst.ts:183:16:183:18 | [VarRef] Foo | semmle.order | 1 | +| tst.ts:183:16:183:25 | [DotExpr] Foo.#count | tst.ts:183:20:183:25 | [Label] #count | semmle.label | 2 | +| tst.ts:183:16:183:25 | [DotExpr] Foo.#count | tst.ts:183:20:183:25 | [Label] #count | semmle.order | 2 | +| tst.ts:185:5:187:5 | [BlockStmt] static ... ; } | tst.ts:186:7:186:22 | [ExprStmt] Foo.#count += 3; | semmle.label | 1 | +| tst.ts:185:5:187:5 | [BlockStmt] static ... ; } | tst.ts:186:7:186:22 | [ExprStmt] Foo.#count += 3; | semmle.order | 1 | +| tst.ts:185:5:187:5 | [ClassInitializedMember] static ... ; } | tst.ts:185:5:187:5 | [BlockStmt] static ... ; } | semmle.label | 1 | +| tst.ts:185:5:187:5 | [ClassInitializedMember] static ... ; } | tst.ts:185:5:187:5 | [BlockStmt] static ... ; } | semmle.order | 1 | +| tst.ts:186:7:186:16 | [DotExpr] Foo.#count | tst.ts:186:7:186:9 | [VarRef] Foo | semmle.label | 1 | +| tst.ts:186:7:186:16 | [DotExpr] Foo.#count | tst.ts:186:7:186:9 | [VarRef] Foo | semmle.order | 1 | +| tst.ts:186:7:186:16 | [DotExpr] Foo.#count | tst.ts:186:11:186:16 | [Label] #count | semmle.label | 2 | +| tst.ts:186:7:186:16 | [DotExpr] Foo.#count | tst.ts:186:11:186:16 | [Label] #count | semmle.order | 2 | +| tst.ts:186:7:186:21 | [CompoundAssignExpr] Foo.#count += 3 | tst.ts:186:7:186:16 | [DotExpr] Foo.#count | semmle.label | 1 | +| tst.ts:186:7:186:21 | [CompoundAssignExpr] Foo.#count += 3 | tst.ts:186:7:186:16 | [DotExpr] Foo.#count | semmle.order | 1 | +| tst.ts:186:7:186:21 | [CompoundAssignExpr] Foo.#count += 3 | tst.ts:186:21:186:21 | [Literal] 3 | semmle.label | 2 | +| tst.ts:186:7:186:21 | [CompoundAssignExpr] Foo.#count += 3 | tst.ts:186:21:186:21 | [Literal] 3 | semmle.order | 2 | +| tst.ts:186:7:186:22 | [ExprStmt] Foo.#count += 3; | tst.ts:186:7:186:21 | [CompoundAssignExpr] Foo.#count += 3 | semmle.label | 1 | +| tst.ts:186:7:186:22 | [ExprStmt] Foo.#count += 3; | tst.ts:186:7:186:21 | [CompoundAssignExpr] Foo.#count += 3 | semmle.order | 1 | +| tst.ts:188:5:190:5 | [BlockStmt] static ... ; } | tst.ts:189:7:189:29 | [DeclStmt] var count = ... | semmle.label | 1 | +| tst.ts:188:5:190:5 | [BlockStmt] static ... ; } | tst.ts:189:7:189:29 | [DeclStmt] var count = ... | semmle.order | 1 | +| tst.ts:188:5:190:5 | [ClassInitializedMember] static ... ; } | tst.ts:188:5:190:5 | [BlockStmt] static ... ; } | semmle.label | 1 | +| tst.ts:188:5:190:5 | [ClassInitializedMember] static ... ; } | tst.ts:188:5:190:5 | [BlockStmt] static ... ; } | semmle.order | 1 | +| tst.ts:189:7:189:29 | [DeclStmt] var count = ... | tst.ts:189:11:189:28 | [VariableDeclarator] count = Foo.#count | semmle.label | 1 | +| tst.ts:189:7:189:29 | [DeclStmt] var count = ... | tst.ts:189:11:189:28 | [VariableDeclarator] count = Foo.#count | semmle.order | 1 | +| tst.ts:189:11:189:28 | [VariableDeclarator] count = Foo.#count | tst.ts:189:11:189:15 | [VarDecl] count | semmle.label | 1 | +| tst.ts:189:11:189:28 | [VariableDeclarator] count = Foo.#count | tst.ts:189:11:189:15 | [VarDecl] count | semmle.order | 1 | +| tst.ts:189:11:189:28 | [VariableDeclarator] count = Foo.#count | tst.ts:189:19:189:28 | [DotExpr] Foo.#count | semmle.label | 2 | +| tst.ts:189:11:189:28 | [VariableDeclarator] count = Foo.#count | tst.ts:189:19:189:28 | [DotExpr] Foo.#count | semmle.order | 2 | +| tst.ts:189:19:189:28 | [DotExpr] Foo.#count | tst.ts:189:19:189:21 | [VarRef] Foo | semmle.label | 1 | +| tst.ts:189:19:189:28 | [DotExpr] Foo.#count | tst.ts:189:19:189:21 | [VarRef] Foo | semmle.order | 1 | +| tst.ts:189:19:189:28 | [DotExpr] Foo.#count | tst.ts:189:23:189:28 | [Label] #count | semmle.label | 2 | +| tst.ts:189:19:189:28 | [DotExpr] Foo.#count | tst.ts:189:23:189:28 | [Label] #count | semmle.order | 2 | | type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | type_alias.ts:1:6:1:6 | [Identifier] B | semmle.label | 1 | | type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | type_alias.ts:1:6:1:6 | [Identifier] B | semmle.order | 1 | | type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | type_alias.ts:1:10:1:16 | [KeywordTypeExpr] boolean | semmle.label | 2 | diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tests.expected b/javascript/ql/test/library-tests/TypeScript/Types/tests.expected index 187c0c7e6ce..1d398443dec 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/tests.expected +++ b/javascript/ql/test/library-tests/TypeScript/Types/tests.expected @@ -175,6 +175,91 @@ getExprType | tst.ts:126:7:126:22 | this.#someMethod | () => number | | tst.ts:126:7:126:24 | this.#someMethod() | number | | tst.ts:127:14:127:28 | this.#someValue | number | +| tst.ts:132:8:132:11 | TS44 | typeof TS44 in library-tests/TypeScript/Types/tst.ts | +| tst.ts:133:12:133:14 | foo | (arg: unknown) => void | +| tst.ts:133:16:133:18 | arg | unknown | +| tst.ts:134:11:134:21 | argIsString | boolean | +| tst.ts:134:25:134:34 | typeof arg | "string" \| "number" \| "bigint" \| "boolean" \| "s... | +| tst.ts:134:25:134:47 | typeof ... string" | boolean | +| tst.ts:134:32:134:34 | arg | unknown | +| tst.ts:134:40:134:47 | "string" | "string" | +| tst.ts:135:9:135:19 | argIsString | boolean | +| tst.ts:136:15:136:19 | upper | string | +| tst.ts:136:23:136:25 | arg | string | +| tst.ts:136:23:136:37 | arg.toUpperCase | () => string | +| tst.ts:136:23:136:39 | arg.toUpperCase() | string | +| tst.ts:136:27:136:37 | toUpperCase | () => string | +| tst.ts:141:11:141:14 | kind | "circle" | +| tst.ts:141:27:141:32 | radius | number | +| tst.ts:142:11:142:14 | kind | "square" | +| tst.ts:142:27:142:36 | sideLength | number | +| tst.ts:144:12:144:15 | side | (shape: Shape) => number | +| tst.ts:144:17:144:21 | shape | Shape | +| tst.ts:145:15:145:18 | kind | "circle" \| "square" | +| tst.ts:145:15:145:18 | kind | "circle" \| "square" | +| tst.ts:145:24:145:28 | shape | Shape | +| tst.ts:147:11:147:14 | kind | "circle" \| "square" | +| tst.ts:147:11:147:27 | kind === "circle" | boolean | +| tst.ts:147:20:147:27 | "circle" | "circle" | +| tst.ts:147:39:147:43 | shape | { kind: "circle"; radius: number; } | +| tst.ts:147:39:147:50 | shape.radius | number | +| tst.ts:147:45:147:50 | radius | number | +| tst.ts:148:21:148:25 | shape | { kind: "square"; sideLength: number; } | +| tst.ts:148:21:148:36 | shape.sideLength | number | +| tst.ts:148:27:148:36 | sideLength | number | +| tst.ts:151:12:151:22 | symbolIndex | () => void | +| tst.ts:153:7:153:28 | [sym: s ... number; | any | +| tst.ts:153:8:153:10 | sym | symbol | +| tst.ts:154:7:154:28 | [key: s ... string; | any | +| tst.ts:154:8:154:10 | key | string | +| tst.ts:155:7:155:29 | [num: n ... oolean; | any | +| tst.ts:155:8:155:10 | num | number | +| tst.ts:158:9:158:14 | colors | Colors | +| tst.ts:158:26:158:27 | {} | Colors | +| tst.ts:159:11:159:13 | red | number | +| tst.ts:159:17:159:22 | colors | Colors | +| tst.ts:159:17:159:37 | colors[ ... "red")] | number | +| tst.ts:159:24:159:29 | Symbol | SymbolConstructor | +| tst.ts:159:24:159:36 | Symbol("red") | symbol | +| tst.ts:159:31:159:35 | "red" | "red" | +| tst.ts:160:11:160:15 | green | string | +| tst.ts:160:19:160:24 | colors | Colors | +| tst.ts:160:19:160:33 | colors["green"] | string | +| tst.ts:160:26:160:32 | "green" | "green" | +| tst.ts:161:11:161:14 | blue | boolean | +| tst.ts:161:18:161:23 | colors | Colors | +| tst.ts:161:18:161:26 | colors[2] | boolean | +| tst.ts:161:25:161:25 | 2 | 2 | +| tst.ts:164:12:164:29 | stringPatternIndex | () => void | +| tst.ts:166:7:166:37 | [key: ` ... number; | any | +| tst.ts:168:9:168:11 | bla | Foo | +| tst.ts:168:21:168:22 | {} | Foo | +| tst.ts:169:11:169:13 | bar | number | +| tst.ts:169:17:169:19 | bla | Foo | +| tst.ts:169:17:169:28 | bla[`foo-1`] | number | +| tst.ts:169:21:169:27 | `foo-1` | "foo-1" | +| tst.ts:169:21:169:27 | `foo-1` | "foo-1" | +| tst.ts:172:7:172:42 | [optNam ... oolean; | any | +| tst.ts:172:8:172:14 | optName | string \| symbol | +| tst.ts:175:11:175:14 | data | Data | +| tst.ts:175:24:175:25 | {} | Data | +| tst.ts:176:11:176:13 | baz | boolean | +| tst.ts:176:17:176:20 | data | Data | +| tst.ts:176:17:176:27 | data["foo"] | boolean | +| tst.ts:176:22:176:26 | "foo" | "foo" | +| tst.ts:179:9:179:11 | Foo | Foo | +| tst.ts:180:21:180:21 | 0 | 0 | +| tst.ts:182:5:184:5 | get cou ... ;\\n } | number | +| tst.ts:182:9:182:13 | count | number | +| tst.ts:183:16:183:18 | Foo | typeof Foo in tst.ts:132 | +| tst.ts:183:16:183:25 | Foo.#count | number | +| tst.ts:186:7:186:9 | Foo | typeof Foo in tst.ts:132 | +| tst.ts:186:7:186:16 | Foo.#count | number | +| tst.ts:186:7:186:21 | Foo.#count += 3 | number | +| tst.ts:186:21:186:21 | 3 | 3 | +| tst.ts:189:11:189:15 | count | number | +| tst.ts:189:19:189:21 | Foo | typeof Foo in tst.ts:132 | +| tst.ts:189:19:189:28 | Foo.#count | number | | type_alias.ts:3:5:3:5 | b | boolean | | type_alias.ts:7:5:7:5 | c | ValueOrArray | | type_alias.ts:14:9:14:32 | [proper ... ]: Json | any | @@ -233,6 +318,11 @@ getTypeDefinitionType | tst.ts:91:3:95:3 | class S ... }\\n } | Super | | tst.ts:97:3:101:3 | class S ... }\\n } | Sub | | tst.ts:116:3:129:3 | class F ... }\\n } | Foo | +| tst.ts:140:3:142:47 | type Sh ... mber }; | Shape | +| tst.ts:152:5:156:5 | interfa ... ;\\n } | Colors | +| tst.ts:165:5:167:5 | interfa ... ;\\n } | Foo | +| tst.ts:171:5:173:5 | interfa ... ;\\n } | Data | +| tst.ts:179:3:192:3 | class F ... \\n } | Foo | | type_alias.ts:1:1:1:17 | type B = boolean; | boolean | | type_alias.ts:5:1:5:50 | type Va ... ay>; | ValueOrArray | | type_alias.ts:9:1:15:13 | type Js ... Json[]; | Json | @@ -369,6 +459,36 @@ getTypeExprType | tst.ts:111:29:111:32 | -2-3 | any | | tst.ts:117:20:117:25 | number | number | | tst.ts:121:23:121:28 | number | number | +| tst.ts:133:21:133:27 | unknown | unknown | +| tst.ts:140:8:140:12 | Shape | Shape | +| tst.ts:141:7:142:46 | \| { kin ... umber } | { kind: "circle"; radius: number; } \| { kind: "... | +| tst.ts:141:9:141:42 | { kind: ... umber } | { kind: "circle"; radius: number; } | +| tst.ts:141:17:141:24 | "circle" | "circle" | +| tst.ts:141:35:141:40 | number | number | +| tst.ts:142:9:142:46 | { kind: ... umber } | { kind: "square"; sideLength: number; } | +| tst.ts:142:17:142:24 | "square" | "square" | +| tst.ts:142:39:142:44 | number | number | +| tst.ts:144:24:144:28 | Shape | Shape | +| tst.ts:144:32:144:37 | number | number | +| tst.ts:152:15:152:20 | Colors | Colors | +| tst.ts:153:13:153:18 | symbol | symbol | +| tst.ts:153:22:153:27 | number | number | +| tst.ts:154:13:154:18 | string | string | +| tst.ts:154:22:154:27 | string | string | +| tst.ts:155:13:155:18 | number | number | +| tst.ts:155:22:155:28 | boolean | boolean | +| tst.ts:158:17:158:22 | Colors | Colors | +| tst.ts:165:15:165:17 | Foo | Foo | +| tst.ts:166:14:166:17 | foo- | any | +| tst.ts:166:20:166:25 | number | number | +| tst.ts:166:31:166:36 | number | number | +| tst.ts:168:15:168:17 | Foo | Foo | +| tst.ts:171:15:171:18 | Data | Data | +| tst.ts:172:17:172:22 | string | string | +| tst.ts:172:17:172:31 | string \| symbol | string \| symbol | +| tst.ts:172:26:172:31 | symbol | symbol | +| tst.ts:172:35:172:41 | boolean | boolean | +| tst.ts:175:17:175:20 | Data | Data | | type_alias.ts:1:6:1:6 | B | boolean | | type_alias.ts:1:10:1:16 | boolean | boolean | | type_alias.ts:3:8:3:8 | B | boolean | @@ -439,9 +559,13 @@ referenceDefinition | Color.blue | type_definitions.ts:14:15:14:18 | blue | | Color.green | type_definitions.ts:14:8:14:12 | green | | Color.red | type_definitions.ts:14:3:14:5 | red | +| Colors | tst.ts:152:5:156:5 | interfa ... ;\\n } | +| Data | tst.ts:171:5:173:5 | interfa ... ;\\n } | | E | type_definition_objects.ts:6:8:6:16 | enum E {} | | EnumWithOneMember | type_definitions.ts:18:26:18:31 | member | | Foo | tst.ts:116:3:129:3 | class F ... }\\n } | +| Foo | tst.ts:165:5:167:5 | interfa ... ;\\n } | +| Foo | tst.ts:179:3:192:3 | class F ... \\n } | | HasArea | tst.ts:58:1:60:1 | interfa ... mber;\\n} | | I | type_definitions.ts:3:1:5:1 | interfa ... x: S;\\n} | | I | type_definitions.ts:3:1:5:1 | interfa ... x: S;\\n} | @@ -449,6 +573,7 @@ referenceDefinition | MyUnion | tst.ts:65:1:65:54 | type My ... true}; | | MyUnion2 | tst.ts:68:1:68:49 | type My ... true}; | | NonAbstractDummy | tst.ts:54:1:56:1 | interfa ... mber;\\n} | +| Shape | tst.ts:140:3:142:47 | type Sh ... mber }; | | Sub | tst.ts:97:3:101:3 | class S ... }\\n } | | Super | tst.ts:91:3:95:3 | class S ... }\\n } | | Super | tst.ts:91:3:95:3 | class S ... }\\n } | @@ -490,6 +615,8 @@ unknownType | tst.ts:40:5:40:15 | unknownType | unknown | | tst.ts:47:8:47:8 | e | unknown | | tst.ts:48:14:48:14 | e | unknown | +| tst.ts:133:16:133:18 | arg | unknown | +| tst.ts:134:32:134:34 | arg | unknown | abstractSignature | (): HasArea | | new (): HasArea | @@ -498,9 +625,11 @@ unionIndex | 2 | 1 | 1 \| 2 | | "bigint" | 2 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | | "boolean" | 3 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | +| "circle" | 0 | "circle" \| "square" | | "function" | 7 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | | "number" | 1 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | | "object" | 6 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | +| "square" | 1 | "circle" \| "square" | | "string" | 0 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | | "symbol" | 4 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | | "undefined" | 5 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | @@ -524,7 +653,9 @@ unionIndex | string | 0 | string \| number \| boolean | | string | 0 | string \| number \| boolean \| { [property: string... | | string | 0 | string \| number \| true | +| string | 0 | string \| symbol | | string | 0 | string \| { [key: string]: any; } | +| symbol | 1 | string \| symbol | | true | 1 | boolean | | true | 2 | string \| number \| true | | true | 3 | string \| number \| boolean | @@ -532,8 +663,13 @@ unionIndex | { [key: string]: any; } | 1 | string \| { [key: string]: any; } | | { [key: string]: any; } | 2 | VirtualNode \| { [key: string]: any; } | | { [property: string]: Json; } | 4 | string \| number \| boolean \| { [property: string... | +| { kind: "circle"; radius: number; } | 0 | { kind: "circle"; radius: number; } \| { kind: "... | +| { kind: "square"; sideLength: number; } | 1 | { kind: "circle"; radius: number; } \| { kind: "... | | { myUnion: true; } | 0 | MyUnion \| { yetAnotherType: true; } | | { myUnion: true; } | 0 | { myUnion: true; } \| { stillMyUnion: true; } | | { stillMyUnion: true; } | 1 | MyUnion \| { yetAnotherType: true; } | | { stillMyUnion: true; } | 1 | { myUnion: true; } \| { stillMyUnion: true; } | | { yetAnotherType: true; } | 2 | MyUnion \| { yetAnotherType: true; } | +getAStaticInitializerBlock +| tst.ts:179:3:192:3 | class F ... \\n } | tst.ts:185:5:187:5 | static ... ;\\n } | +| tst.ts:179:3:192:3 | class F ... \\n } | tst.ts:188:5:190:5 | static ... ;\\n } | diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tests.ql b/javascript/ql/test/library-tests/TypeScript/Types/tests.ql index 0f31295ce50..dad3934113e 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/tests.ql +++ b/javascript/ql/test/library-tests/TypeScript/Types/tests.ql @@ -39,3 +39,7 @@ query predicate unknownType(Expr e, Type type) { query CallSignatureType abstractSignature() { result.isAbstract() } query UnionType unionIndex(Type element, int i) { result.getElementType(i) = element } + +query BlockStmt getAStaticInitializerBlock(ClassDefinition cls) { + result = cls.getAStaticInitializerBlock() +} diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tst.ts b/javascript/ql/test/library-tests/TypeScript/Types/tst.ts index 389770984fd..0db050b2f49 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/tst.ts +++ b/javascript/ql/test/library-tests/TypeScript/Types/tst.ts @@ -127,4 +127,67 @@ module TS43 { return this.#someValue; } } +} + +module TS44 { + function foo(arg: unknown) { + const argIsString = typeof arg === "string"; + if (argIsString) { + const upper = arg.toUpperCase(); + } + } + + type Shape = + | { kind: "circle", radius: number } + | { kind: "square", sideLength: number }; + + function side(shape: Shape): number { + const { kind } = shape; + + if (kind === "circle") { return shape.radius;} + else { return shape.sideLength; } + } + + function symbolIndex() { + interface Colors { + [sym: symbol]: number; + [key: string]: string; + [num: number]: boolean; + } + + let colors: Colors = {}; + const red = colors[Symbol("red")]; + const green = colors["green"]; + const blue = colors[2]; + } + + function stringPatternIndex() { + interface Foo { + [key: `foo-${number}`]: number; + } + var bla : Foo = {}; + const bar = bla[`foo-1`]; + + interface Data { + [optName: string | symbol]: boolean; + } + + const data: Data = {}; + const baz = data["foo"]; + } + + class Foo { + static #count = 0; + + get count() { + return Foo.#count; + } + static { + Foo.#count += 3; + } + static { + var count = Foo.#count; + } + + } } \ No newline at end of file diff --git a/javascript/ql/test/library-tests/TypeTracking/ClassStyle.expected b/javascript/ql/test/library-tests/TypeTracking/ClassStyle.expected index 1a04300fc3d..cf561c366f2 100644 --- a/javascript/ql/test/library-tests/TypeTracking/ClassStyle.expected +++ b/javascript/ql/test/library-tests/TypeTracking/ClassStyle.expected @@ -38,6 +38,9 @@ test_Connection | tst.js:112:10:112:14 | obj.x | | tst.js:114:1:114:28 | getX({ ... on() }) | | tst.js:114:11:114:25 | getConnection() | +| tst.js:118:12:118:26 | getConnection() | +| tst.js:120:21:120:24 | conn | +| tst.js:126:22:126:25 | conn | | tst_conflict.js:6:38:6:77 | api.cha ... ction() | test_DataCallback | client.js:3:28:3:34 | x => {} | diff --git a/javascript/ql/test/library-tests/TypeTracking/PredicateStyle.expected b/javascript/ql/test/library-tests/TypeTracking/PredicateStyle.expected index 61d1675e794..5aef5c84540 100644 --- a/javascript/ql/test/library-tests/TypeTracking/PredicateStyle.expected +++ b/javascript/ql/test/library-tests/TypeTracking/PredicateStyle.expected @@ -40,6 +40,9 @@ connection | type tracker without call steps | tst.js:108:8:108:22 | getConnection() | | type tracker without call steps | tst.js:114:1:114:28 | getX({ ... on() }) | | type tracker without call steps | tst.js:114:11:114:25 | getConnection() | +| type tracker without call steps | tst.js:118:12:118:26 | getConnection() | +| type tracker without call steps | tst.js:120:21:120:24 | conn | +| type tracker without call steps | tst.js:126:22:126:25 | conn | | type tracker without call steps | tst_conflict.js:6:38:6:77 | api.cha ... ction() | | type tracker without call steps with property MyApplication.namespace.connection | file://:0:0:0:0 | global access path | | type tracker without call steps with property conflict | tst.js:63:3:63:25 | MyAppli ... mespace | diff --git a/javascript/ql/test/library-tests/TypeTracking/tst.js b/javascript/ql/test/library-tests/TypeTracking/tst.js index 38817dbb57e..cd11eaae8e7 100644 --- a/javascript/ql/test/library-tests/TypeTracking/tst.js +++ b/javascript/ql/test/library-tests/TypeTracking/tst.js @@ -113,3 +113,15 @@ function getX(obj) { } getX({ x: getConnection() }); getX({ x: somethingElse() }); + +function makeConnectionAsync(callback) { + callback(getConnection()); +} +makeConnectionAsync(conn => {}); +makeConnectionAsync(); // suppress single-call precision gains + +function makeConnectionAsync2(callback) { + makeConnectionAsync(callback); +} +makeConnectionAsync2(conn => {}); +makeConnectionAsync2(); // suppress single-call precision gains diff --git a/javascript/ql/test/library-tests/literals/test.expected b/javascript/ql/test/library-tests/literals/test.expected new file mode 100644 index 00000000000..1f592fc7d77 --- /dev/null +++ b/javascript/ql/test/library-tests/literals/test.expected @@ -0,0 +1 @@ +| test.js:1:9:1:16 | "\\ud800" | \ufffd | "\\ud800" | \ufffd | test.js:1:9:1:16 | "\\ud800" | diff --git a/javascript/ql/test/library-tests/literals/test.js b/javascript/ql/test/library-tests/literals/test.js new file mode 100644 index 00000000000..2ba36a76199 --- /dev/null +++ b/javascript/ql/test/library-tests/literals/test.js @@ -0,0 +1 @@ +let s = "\ud800"; diff --git a/javascript/ql/test/library-tests/literals/test.ql b/javascript/ql/test/library-tests/literals/test.ql new file mode 100644 index 00000000000..9b1a172d530 --- /dev/null +++ b/javascript/ql/test/library-tests/literals/test.ql @@ -0,0 +1,5 @@ +import javascript + +from StringLiteral sl +where sl.getFile().getBaseName() = "test.js" +select sl, sl.getValue(), sl.getRawValue(), sl.getStringValue(), sl.getUnderlyingValue() diff --git a/javascript/ql/test/query-tests/Expressions/SelfAssignment/template.njk b/javascript/ql/test/query-tests/Expressions/SelfAssignment/template.njk new file mode 100644 index 00000000000..8319bb1e414 --- /dev/null +++ b/javascript/ql/test/query-tests/Expressions/SelfAssignment/template.njk @@ -0,0 +1,3 @@ +
    + {{ foo(x=x) }} +
    diff --git a/javascript/ql/test/query-tests/Performance/ReDoS/tst.js b/javascript/ql/test/query-tests/Performance/ReDoS/tst.js index c3521343111..1ab557520cb 100644 --- a/javascript/ql/test/query-tests/Performance/ReDoS/tst.js +++ b/javascript/ql/test/query-tests/Performance/ReDoS/tst.js @@ -304,10 +304,10 @@ var bad66 = /^ab(c+)+$/; // NOT GOOD var bad67 = /(\d(\s+)*){20}/; -// GOOD - but we spuriously conclude that a rejecting suffix exists. +// GOOD - but we spuriously conclude that a rejecting suffix exists. var good36 = /(([^/]|X)+)(\/[^]*)*$/; -// GOOD - but we spuriously conclude that a rejecting suffix exists. +// GOOD - but we spuriously conclude that a rejecting suffix exists. var good37 = /^((x([^Y]+)?)*(Y|$))/; // NOT GOOD @@ -331,7 +331,7 @@ var bad72 = /(c?a?)*b/; // NOT GOOD var bad73 = /(?:a|a?)+b/; -// NOT GOOD - but not detected. +// NOT GOOD - but not detected. var bad74 = /(a?b?)*$/; // NOT GOOD @@ -357,13 +357,13 @@ var good40 = /(a|b)+/; var good41 = /(?:[\s;,"'<>(){}|[\]@=+*]|:(?![/\\]))+/; // NOT GOOD -var bad83 = /^((?:a{|-)|\w\{)+X$/; -var bad84 = /^((?:a{0|-)|\w\{\d)+X$/; -var bad85 = /^((?:a{0,|-)|\w\{\d,)+X$/; -var bad86 = /^((?:a{0,2|-)|\w\{\d,\d)+X$/; +var bad83 = /^((?:a{|-)|\w\{)+X$/; +var bad84 = /^((?:a{0|-)|\w\{\d)+X$/; +var bad85 = /^((?:a{0,|-)|\w\{\d,)+X$/; +var bad86 = /^((?:a{0,2|-)|\w\{\d,\d)+X$/; -// GOOD: -var good42 = /^((?:a{0,2}|-)|\w\{\d,\d\})+X$/; +// GOOD: +var good42 = /^((?:a{0,2}|-)|\w\{\d,\d\})+X$/; // GOOD var good43 = /("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)/g; diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected index 199c3aacd3a..432aa42ab23 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected @@ -91,6 +91,20 @@ nodes | classnames.js:15:47:15:63 | clsx(window.name) | | classnames.js:15:52:15:62 | window.name | | classnames.js:15:52:15:62 | window.name | +| clipboard.ts:8:11:8:51 | html | +| clipboard.ts:8:18:8:51 | clipboa ... /html') | +| clipboard.ts:8:18:8:51 | clipboa ... /html') | +| clipboard.ts:15:25:15:28 | html | +| clipboard.ts:15:25:15:28 | html | +| clipboard.ts:24:23:24:58 | e.clipb ... /html') | +| clipboard.ts:24:23:24:58 | e.clipb ... /html') | +| clipboard.ts:24:23:24:58 | e.clipb ... /html') | +| clipboard.ts:29:19:29:54 | e.clipb ... /html') | +| clipboard.ts:29:19:29:54 | e.clipb ... /html') | +| clipboard.ts:29:19:29:54 | e.clipb ... /html') | +| clipboard.ts:33:19:33:68 | e.origi ... /html') | +| clipboard.ts:33:19:33:68 | e.origi ... /html') | +| clipboard.ts:33:19:33:68 | e.origi ... /html') | | d3.js:4:12:4:22 | window.name | | d3.js:4:12:4:22 | window.name | | d3.js:11:15:11:24 | getTaint() | @@ -857,6 +871,13 @@ edges | classnames.js:15:47:15:63 | clsx(window.name) | classnames.js:15:31:15:78 | `` | | classnames.js:15:52:15:62 | window.name | classnames.js:15:47:15:63 | clsx(window.name) | | classnames.js:15:52:15:62 | window.name | classnames.js:15:47:15:63 | clsx(window.name) | +| clipboard.ts:8:11:8:51 | html | clipboard.ts:15:25:15:28 | html | +| clipboard.ts:8:11:8:51 | html | clipboard.ts:15:25:15:28 | html | +| clipboard.ts:8:18:8:51 | clipboa ... /html') | clipboard.ts:8:11:8:51 | html | +| clipboard.ts:8:18:8:51 | clipboa ... /html') | clipboard.ts:8:11:8:51 | html | +| clipboard.ts:24:23:24:58 | e.clipb ... /html') | clipboard.ts:24:23:24:58 | e.clipb ... /html') | +| clipboard.ts:29:19:29:54 | e.clipb ... /html') | clipboard.ts:29:19:29:54 | e.clipb ... /html') | +| clipboard.ts:33:19:33:68 | e.origi ... /html') | clipboard.ts:33:19:33:68 | e.origi ... /html') | | d3.js:4:12:4:22 | window.name | d3.js:11:15:11:24 | getTaint() | | d3.js:4:12:4:22 | window.name | d3.js:11:15:11:24 | getTaint() | | d3.js:4:12:4:22 | window.name | d3.js:11:15:11:24 | getTaint() | @@ -1514,6 +1535,10 @@ edges | classnames.js:11:31:11:79 | `` | classnames.js:10:45:10:55 | window.name | classnames.js:11:31:11:79 | `` | Cross-site scripting vulnerability due to $@. | classnames.js:10:45:10:55 | window.name | user-provided value | | classnames.js:13:31:13:83 | `` | classnames.js:13:57:13:67 | window.name | classnames.js:13:31:13:83 | `` | Cross-site scripting vulnerability due to $@. | classnames.js:13:57:13:67 | window.name | user-provided value | | classnames.js:15:31:15:78 | `` | classnames.js:15:52:15:62 | window.name | classnames.js:15:31:15:78 | `` | Cross-site scripting vulnerability due to $@. | classnames.js:15:52:15:62 | window.name | user-provided value | +| clipboard.ts:15:25:15:28 | html | clipboard.ts:8:18:8:51 | clipboa ... /html') | clipboard.ts:15:25:15:28 | html | Cross-site scripting vulnerability due to $@. | clipboard.ts:8:18:8:51 | clipboa ... /html') | user-provided value | +| clipboard.ts:24:23:24:58 | e.clipb ... /html') | clipboard.ts:24:23:24:58 | e.clipb ... /html') | clipboard.ts:24:23:24:58 | e.clipb ... /html') | Cross-site scripting vulnerability due to $@. | clipboard.ts:24:23:24:58 | e.clipb ... /html') | user-provided value | +| clipboard.ts:29:19:29:54 | e.clipb ... /html') | clipboard.ts:29:19:29:54 | e.clipb ... /html') | clipboard.ts:29:19:29:54 | e.clipb ... /html') | Cross-site scripting vulnerability due to $@. | clipboard.ts:29:19:29:54 | e.clipb ... /html') | user-provided value | +| clipboard.ts:33:19:33:68 | e.origi ... /html') | clipboard.ts:33:19:33:68 | e.origi ... /html') | clipboard.ts:33:19:33:68 | e.origi ... /html') | Cross-site scripting vulnerability due to $@. | clipboard.ts:33:19:33:68 | e.origi ... /html') | user-provided value | | d3.js:11:15:11:24 | getTaint() | d3.js:4:12:4:22 | window.name | d3.js:11:15:11:24 | getTaint() | Cross-site scripting vulnerability due to $@. | d3.js:4:12:4:22 | window.name | user-provided value | | d3.js:12:20:12:29 | getTaint() | d3.js:4:12:4:22 | window.name | d3.js:12:20:12:29 | getTaint() | Cross-site scripting vulnerability due to $@. | d3.js:4:12:4:22 | window.name | user-provided value | | d3.js:14:20:14:29 | getTaint() | d3.js:4:12:4:22 | window.name | d3.js:14:20:14:29 | getTaint() | Cross-site scripting vulnerability due to $@. | d3.js:4:12:4:22 | window.name | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected index b54e7a231ec..278f00ecebd 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected @@ -91,6 +91,20 @@ nodes | classnames.js:15:47:15:63 | clsx(window.name) | | classnames.js:15:52:15:62 | window.name | | classnames.js:15:52:15:62 | window.name | +| clipboard.ts:8:11:8:51 | html | +| clipboard.ts:8:18:8:51 | clipboa ... /html') | +| clipboard.ts:8:18:8:51 | clipboa ... /html') | +| clipboard.ts:15:25:15:28 | html | +| clipboard.ts:15:25:15:28 | html | +| clipboard.ts:24:23:24:58 | e.clipb ... /html') | +| clipboard.ts:24:23:24:58 | e.clipb ... /html') | +| clipboard.ts:24:23:24:58 | e.clipb ... /html') | +| clipboard.ts:29:19:29:54 | e.clipb ... /html') | +| clipboard.ts:29:19:29:54 | e.clipb ... /html') | +| clipboard.ts:29:19:29:54 | e.clipb ... /html') | +| clipboard.ts:33:19:33:68 | e.origi ... /html') | +| clipboard.ts:33:19:33:68 | e.origi ... /html') | +| clipboard.ts:33:19:33:68 | e.origi ... /html') | | d3.js:4:12:4:22 | window.name | | d3.js:4:12:4:22 | window.name | | d3.js:11:15:11:24 | getTaint() | @@ -875,6 +889,13 @@ edges | classnames.js:15:47:15:63 | clsx(window.name) | classnames.js:15:31:15:78 | `` | | classnames.js:15:52:15:62 | window.name | classnames.js:15:47:15:63 | clsx(window.name) | | classnames.js:15:52:15:62 | window.name | classnames.js:15:47:15:63 | clsx(window.name) | +| clipboard.ts:8:11:8:51 | html | clipboard.ts:15:25:15:28 | html | +| clipboard.ts:8:11:8:51 | html | clipboard.ts:15:25:15:28 | html | +| clipboard.ts:8:18:8:51 | clipboa ... /html') | clipboard.ts:8:11:8:51 | html | +| clipboard.ts:8:18:8:51 | clipboa ... /html') | clipboard.ts:8:11:8:51 | html | +| clipboard.ts:24:23:24:58 | e.clipb ... /html') | clipboard.ts:24:23:24:58 | e.clipb ... /html') | +| clipboard.ts:29:19:29:54 | e.clipb ... /html') | clipboard.ts:29:19:29:54 | e.clipb ... /html') | +| clipboard.ts:33:19:33:68 | e.origi ... /html') | clipboard.ts:33:19:33:68 | e.origi ... /html') | | d3.js:4:12:4:22 | window.name | d3.js:11:15:11:24 | getTaint() | | d3.js:4:12:4:22 | window.name | d3.js:11:15:11:24 | getTaint() | | d3.js:4:12:4:22 | window.name | d3.js:11:15:11:24 | getTaint() | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/clipboard.ts b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/clipboard.ts new file mode 100644 index 00000000000..93eab788d06 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/clipboard.ts @@ -0,0 +1,34 @@ +$("#foo").on("paste", paste); + +function paste(e) { + const { clipboardData } = e.originalEvent; + if (!clipboardData) return; + + const text = clipboardData.getData('text/plain'); + const html = clipboardData.getData('text/html'); + if (!text && !html) return; + + e.preventDefault(); + + const div = document.createElement('div'); + if (html) { + div.innerHTML = html; // NOT OK + } else { + div.textContent = text; + } + document.body.append(div); +} + +export function install(el: HTMLElement): void { + el.addEventListener('paste', (e) => { + $("#id").html(e.clipboardData.getData('text/html')); // NOT OK + }) +} + +document.addEventListener('paste', (e) => { + $("#id").html(e.clipboardData.getData('text/html')); // NOT OK +}); + +$("#foo").bind('paste', (e) => { + $("#id").html(e.originalEvent.clipboardData.getData('text/html')); // NOT OK +}); \ No newline at end of file diff --git a/javascript/upgrades/9ca3692b65fd8d751431861d1a25c57f3e61d15b/old.dbscheme b/javascript/upgrades/9ca3692b65fd8d751431861d1a25c57f3e61d15b/old.dbscheme new file mode 100644 index 00000000000..9ca3692b65f --- /dev/null +++ b/javascript/upgrades/9ca3692b65fd8d751431861d1a25c57f3e61d15b/old.dbscheme @@ -0,0 +1,1226 @@ +/*** Standard fragments ***/ + +/** Files and folders **/ + +@location = @location_default; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref + ); + +@sourceline = @locatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref + ); + + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files(unique int id: @file, + varchar(900) name: string ref, + varchar(900) simple: string ref, + varchar(900) ext: string ref, + int fromSource: int ref); + +folders(unique int id: @folder, + varchar(900) name: string ref, + varchar(900) simple: string ref); + + +@container = @folder | @file ; + + +containerparent(int parent: @container ref, + unique int child: @container ref); + +/** Duplicate code **/ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity; + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/** External data **/ + +externalData( + int id : @externalDataElement, + varchar(900) path : string ref, + int column: int ref, + varchar(900) value : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + +/** Version control data **/ + +svnentries( + int id : @svnentry, + varchar(500) revision : string ref, + varchar(500) author : string ref, + date revisionDate : date ref, + int changeSize : int ref +); + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + varchar(500) action : string ref +); + +svnentrymsg( + int id : @svnentry ref, + varchar(500) message : string ref +); + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +); + + +/*** JavaScript-specific part ***/ + +filetype( + int file: @file ref, + string filetype: string ref +) + +// top-level code fragments +toplevels (unique int id: @toplevel, + int kind: int ref); + +is_externs (int toplevel: @toplevel ref); + +case @toplevel.kind of + 0 = @script +| 1 = @inline_script +| 2 = @event_handler +| 3 = @javascript_url +| 4 = @template_toplevel; + +is_module (int tl: @toplevel ref); +is_nodejs (int tl: @toplevel ref); +is_es2015_module (int tl: @toplevel ref); +is_closure_module (int tl: @toplevel ref); + +@xml_node_with_code = @xmlelement | @xmlattribute | @template_placeholder_tag; +toplevel_parent_xml_node( + unique int toplevel: @toplevel ref, + int xmlnode: @xml_node_with_code ref); + +xml_element_parent_expression( + unique int xmlnode: @xmlelement ref, + int expression: @expr ref, + int index: int ref); + +// statements +#keyset[parent, idx] +stmts (unique int id: @stmt, + int kind: int ref, + int parent: @stmt_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +stmt_containers (unique int stmt: @stmt ref, + int container: @stmt_container ref); + +jump_targets (unique int jump: @stmt ref, + int target: @stmt ref); + +@stmt_parent = @stmt | @toplevel | @function_expr | @arrow_function_expr; +@stmt_container = @toplevel | @function | @namespace_declaration | @external_module_declaration | @global_augmentation_declaration; + +case @stmt.kind of + 0 = @empty_stmt +| 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @labeled_stmt +| 5 = @break_stmt +| 6 = @continue_stmt +| 7 = @with_stmt +| 8 = @switch_stmt +| 9 = @return_stmt +| 10 = @throw_stmt +| 11 = @try_stmt +| 12 = @while_stmt +| 13 = @do_while_stmt +| 14 = @for_stmt +| 15 = @for_in_stmt +| 16 = @debugger_stmt +| 17 = @function_decl_stmt +| 18 = @var_decl_stmt +| 19 = @case +| 20 = @catch_clause +| 21 = @for_of_stmt +| 22 = @const_decl_stmt +| 23 = @let_stmt +| 24 = @legacy_let_stmt +| 25 = @for_each_stmt +| 26 = @class_decl_stmt +| 27 = @import_declaration +| 28 = @export_all_declaration +| 29 = @export_default_declaration +| 30 = @export_named_declaration +| 31 = @namespace_declaration +| 32 = @import_equals_declaration +| 33 = @export_assign_declaration +| 34 = @interface_declaration +| 35 = @type_alias_declaration +| 36 = @enum_declaration +| 37 = @external_module_declaration +| 38 = @export_as_namespace_declaration +| 39 = @global_augmentation_declaration +; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @let_stmt | @legacy_let_stmt; + +@export_declaration = @export_all_declaration | @export_default_declaration | @export_named_declaration; + +@namespace_definition = @namespace_declaration | @enum_declaration; +@type_definition = @class_definition | @interface_declaration | @enum_declaration | @type_alias_declaration | @enum_member; + +is_instantiated(unique int decl: @namespace_declaration ref); + +@declarable_node = @decl_stmt | @namespace_declaration | @class_decl_stmt | @function_decl_stmt | @enum_declaration | @external_module_declaration | @global_augmentation_declaration | @field; +has_declare_keyword(unique int stmt: @declarable_node ref); + +is_for_await_of(unique int forof: @for_of_stmt ref); + +// expressions +#keyset[parent, idx] +exprs (unique int id: @expr, + int kind: int ref, + int parent: @expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @expr_or_type ref); + +enclosing_stmt (unique int expr: @expr_or_type ref, + int stmt: @stmt ref); + +expr_containers (unique int expr: @expr_or_type ref, + int container: @stmt_container ref); + +array_size (unique int ae: @arraylike ref, + int sz: int ref); + +is_delegating (int yield: @yield_expr ref); + +@expr_or_stmt = @expr | @stmt; +@expr_or_type = @expr | @typeexpr; +@expr_parent = @expr_or_stmt | @property | @function_typeexpr; +@arraylike = @array_expr | @array_pattern; +@type_annotation = @typeexpr | @jsdoc_type_expr; +@node_in_stmt_container = @cfg_node | @type_annotation | @toplevel; + +case @expr.kind of + 0 = @label +| 1 = @null_literal +| 2 = @boolean_literal +| 3 = @number_literal +| 4 = @string_literal +| 5 = @regexp_literal +| 6 = @this_expr +| 7 = @array_expr +| 8 = @obj_expr +| 9 = @function_expr +| 10 = @seq_expr +| 11 = @conditional_expr +| 12 = @new_expr +| 13 = @call_expr +| 14 = @dot_expr +| 15 = @index_expr +| 16 = @neg_expr +| 17 = @plus_expr +| 18 = @log_not_expr +| 19 = @bit_not_expr +| 20 = @typeof_expr +| 21 = @void_expr +| 22 = @delete_expr +| 23 = @eq_expr +| 24 = @neq_expr +| 25 = @eqq_expr +| 26 = @neqq_expr +| 27 = @lt_expr +| 28 = @le_expr +| 29 = @gt_expr +| 30 = @ge_expr +| 31 = @lshift_expr +| 32 = @rshift_expr +| 33 = @urshift_expr +| 34 = @add_expr +| 35 = @sub_expr +| 36 = @mul_expr +| 37 = @div_expr +| 38 = @mod_expr +| 39 = @bitor_expr +| 40 = @xor_expr +| 41 = @bitand_expr +| 42 = @in_expr +| 43 = @instanceof_expr +| 44 = @logand_expr +| 45 = @logor_expr +| 47 = @assign_expr +| 48 = @assign_add_expr +| 49 = @assign_sub_expr +| 50 = @assign_mul_expr +| 51 = @assign_div_expr +| 52 = @assign_mod_expr +| 53 = @assign_lshift_expr +| 54 = @assign_rshift_expr +| 55 = @assign_urshift_expr +| 56 = @assign_or_expr +| 57 = @assign_xor_expr +| 58 = @assign_and_expr +| 59 = @preinc_expr +| 60 = @postinc_expr +| 61 = @predec_expr +| 62 = @postdec_expr +| 63 = @par_expr +| 64 = @var_declarator +| 65 = @arrow_function_expr +| 66 = @spread_element +| 67 = @array_pattern +| 68 = @object_pattern +| 69 = @yield_expr +| 70 = @tagged_template_expr +| 71 = @template_literal +| 72 = @template_element +| 73 = @array_comprehension_expr +| 74 = @generator_expr +| 75 = @for_in_comprehension_block +| 76 = @for_of_comprehension_block +| 77 = @legacy_letexpr +| 78 = @var_decl +| 79 = @proper_varaccess +| 80 = @class_expr +| 81 = @super_expr +| 82 = @newtarget_expr +| 83 = @named_import_specifier +| 84 = @import_default_specifier +| 85 = @import_namespace_specifier +| 86 = @named_export_specifier +| 87 = @exp_expr +| 88 = @assign_exp_expr +| 89 = @jsx_element +| 90 = @jsx_qualified_name +| 91 = @jsx_empty_expr +| 92 = @await_expr +| 93 = @function_sent_expr +| 94 = @decorator +| 95 = @export_default_specifier +| 96 = @export_namespace_specifier +| 97 = @bind_expr +| 98 = @external_module_reference +| 99 = @dynamic_import +| 100 = @expression_with_type_arguments +| 101 = @prefix_type_assertion +| 102 = @as_type_assertion +| 103 = @export_varaccess +| 104 = @decorator_list +| 105 = @non_null_assertion +| 106 = @bigint_literal +| 107 = @nullishcoalescing_expr +| 108 = @e4x_xml_anyname +| 109 = @e4x_xml_static_attribute_selector +| 110 = @e4x_xml_dynamic_attribute_selector +| 111 = @e4x_xml_filter_expression +| 112 = @e4x_xml_static_qualident +| 113 = @e4x_xml_dynamic_qualident +| 114 = @e4x_xml_dotdotexpr +| 115 = @import_meta_expr +| 116 = @assignlogandexpr +| 117 = @assignlogorexpr +| 118 = @assignnullishcoalescingexpr +| 119 = @template_pipe_ref +| 120 = @generated_code_expr +; + +@varaccess = @proper_varaccess | @export_varaccess; +@varref = @var_decl | @varaccess; + +@identifier = @label | @varref | @type_identifier; + +@literal = @null_literal | @boolean_literal | @number_literal | @string_literal | @regexp_literal | @bigint_literal; + +@propaccess = @dot_expr | @index_expr; + +@invokeexpr = @new_expr | @call_expr; + +@unaryexpr = @neg_expr | @plus_expr | @log_not_expr | @bit_not_expr | @typeof_expr | @void_expr | @delete_expr | @spread_element; + +@equality_test = @eq_expr | @neq_expr | @eqq_expr | @neqq_expr; + +@comparison = @equality_test | @lt_expr | @le_expr | @gt_expr | @ge_expr; + +@binaryexpr = @comparison | @lshift_expr | @rshift_expr | @urshift_expr | @add_expr | @sub_expr | @mul_expr | @div_expr | @mod_expr | @exp_expr | @bitor_expr | @xor_expr | @bitand_expr | @in_expr | @instanceof_expr | @logand_expr | @logor_expr | @nullishcoalescing_expr; + +@assignment = @assign_expr | @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr | @assign_mod_expr | @assign_exp_expr | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr | @assign_or_expr | @assign_xor_expr | @assign_and_expr | @assignlogandexpr | @assignlogorexpr | @assignnullishcoalescingexpr; + +@updateexpr = @preinc_expr | @postinc_expr | @predec_expr | @postdec_expr; + +@pattern = @varref | @array_pattern | @object_pattern; + +@comprehension_expr = @array_comprehension_expr | @generator_expr; + +@comprehension_block = @for_in_comprehension_block | @for_of_comprehension_block; + +@import_specifier = @named_import_specifier | @import_default_specifier | @import_namespace_specifier; + +@exportspecifier = @named_export_specifier | @export_default_specifier | @export_namespace_specifier; + +@import_or_export_declaration = @import_declaration | @export_declaration; + +@type_assertion = @as_type_assertion | @prefix_type_assertion; + +@class_definition = @class_decl_stmt | @class_expr; +@interface_definition = @interface_declaration | @interface_typeexpr; +@class_or_interface = @class_definition | @interface_definition; + +@lexical_decl = @var_decl | @type_decl; +@lexical_access = @varaccess | @local_type_access | @local_var_type_access | @local_namespace_access; +@lexical_ref = @lexical_decl | @lexical_access; + +@e4x_xml_attribute_selector = @e4x_xml_static_attribute_selector | @e4x_xml_dynamic_attribute_selector; +@e4x_xml_qualident = @e4x_xml_static_qualident | @e4x_xml_dynamic_qualident; + +expr_contains_template_tag_location( + int expr: @expr ref, + int location: @location ref +); + +@template_placeholder_tag_parent = @xmlelement | @xmlattribute | @file; + +template_placeholder_tag_info( + unique int node: @template_placeholder_tag, + int parentNode: @template_placeholder_tag_parent ref, + varchar(900) raw: string ref +); + +// scopes +scopes (unique int id: @scope, + int kind: int ref); + +case @scope.kind of + 0 = @global_scope +| 1 = @function_scope +| 2 = @catch_scope +| 3 = @module_scope +| 4 = @block_scope +| 5 = @for_scope +| 6 = @for_in_scope // for-of scopes work the same as for-in scopes +| 7 = @comprehension_block_scope +| 8 = @class_expr_scope +| 9 = @namespace_scope +| 10 = @class_decl_scope +| 11 = @interface_scope +| 12 = @type_alias_scope +| 13 = @mapped_type_scope +| 14 = @enum_scope +| 15 = @external_module_scope +| 16 = @conditional_type_scope; + +scopenodes (unique int node: @ast_node ref, + int scope: @scope ref); + +scopenesting (unique int inner: @scope ref, + int outer: @scope ref); + +// functions +@function = @function_decl_stmt | @function_expr | @arrow_function_expr; + +@parameterized = @function | @catch_clause; +@type_parameterized = @function | @class_or_interface | @type_alias_declaration | @mapped_typeexpr | @infer_typeexpr; + +is_generator (int fun: @function ref); +has_rest_parameter (int fun: @function ref); +is_async (int fun: @function ref); + +// variables and lexically scoped type names +#keyset[scope, name] +variables (unique int id: @variable, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_type_names (unique int id: @local_type_name, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_namespace_names (unique int id: @local_namespace_name, + varchar(900) name: string ref, + int scope: @scope ref); + +is_arguments_object (int id: @variable ref); + +@lexical_name = @variable | @local_type_name | @local_namespace_name; + +@bind_id = @varaccess | @local_var_type_access; +bind (unique int id: @bind_id ref, + int decl: @variable ref); + +decl (unique int id: @var_decl ref, + int decl: @variable ref); + +@typebind_id = @local_type_access | @export_varaccess; +typebind (unique int id: @typebind_id ref, + int decl: @local_type_name ref); + +@typedecl_id = @type_decl | @var_decl; +typedecl (unique int id: @typedecl_id ref, + int decl: @local_type_name ref); + +namespacedecl (unique int id: @var_decl ref, + int decl: @local_namespace_name ref); + +@namespacebind_id = @local_namespace_access | @export_varaccess; +namespacebind (unique int id: @namespacebind_id ref, + int decl: @local_namespace_name ref); + + +// properties in object literals, property patterns in object patterns, and method declarations in classes +#keyset[parent, index] +properties (unique int id: @property, + int parent: @property_parent ref, + int index: int ref, + int kind: int ref, + varchar(900) tostring: string ref); + +case @property.kind of + 0 = @value_property +| 1 = @property_getter +| 2 = @property_setter +| 3 = @jsx_attribute +| 4 = @function_call_signature +| 5 = @constructor_call_signature +| 6 = @index_signature +| 7 = @enum_member +| 8 = @proper_field +| 9 = @parameter_field +; + +@property_parent = @obj_expr | @object_pattern | @class_definition | @jsx_element | @interface_definition | @enum_declaration; +@property_accessor = @property_getter | @property_setter; +@call_signature = @function_call_signature | @constructor_call_signature; +@field = @proper_field | @parameter_field; +@field_or_vardeclarator = @field | @var_declarator; + +is_computed (int id: @property ref); +is_method (int id: @property ref); +is_static (int id: @property ref); +is_abstract_member (int id: @property ref); +is_const_enum (int id: @enum_declaration ref); +is_abstract_class (int id: @class_decl_stmt ref); + +has_public_keyword (int id: @property ref); +has_private_keyword (int id: @property ref); +has_protected_keyword (int id: @property ref); +has_readonly_keyword (int id: @property ref); +has_type_keyword (int id: @import_or_export_declaration ref); +is_optional_member (int id: @property ref); +has_definite_assignment_assertion (int id: @field_or_vardeclarator ref); +is_optional_parameter_declaration (unique int parameter: @pattern ref); + +#keyset[constructor, param_index] +parameter_fields( + unique int field: @parameter_field ref, + int constructor: @function_expr ref, + int param_index: int ref +); + +// types +#keyset[parent, idx] +typeexprs ( + unique int id: @typeexpr, + int kind: int ref, + int parent: @typeexpr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref +); + +case @typeexpr.kind of + 0 = @local_type_access +| 1 = @type_decl +| 2 = @keyword_typeexpr +| 3 = @string_literal_typeexpr +| 4 = @number_literal_typeexpr +| 5 = @boolean_literal_typeexpr +| 6 = @array_typeexpr +| 7 = @union_typeexpr +| 8 = @indexed_access_typeexpr +| 9 = @intersection_typeexpr +| 10 = @parenthesized_typeexpr +| 11 = @tuple_typeexpr +| 12 = @keyof_typeexpr +| 13 = @qualified_type_access +| 14 = @generic_typeexpr +| 15 = @type_label +| 16 = @typeof_typeexpr +| 17 = @local_var_type_access +| 18 = @qualified_var_type_access +| 19 = @this_var_type_access +| 20 = @predicate_typeexpr +| 21 = @interface_typeexpr +| 22 = @type_parameter +| 23 = @plain_function_typeexpr +| 24 = @constructor_typeexpr +| 25 = @local_namespace_access +| 26 = @qualified_namespace_access +| 27 = @mapped_typeexpr +| 28 = @conditional_typeexpr +| 29 = @infer_typeexpr +| 30 = @import_type_access +| 31 = @import_namespace_access +| 32 = @import_var_type_access +| 33 = @optional_typeexpr +| 34 = @rest_typeexpr +| 35 = @bigint_literal_typeexpr +| 36 = @readonly_typeexpr +| 37 = @template_literal_typeexpr +; + +@typeref = @typeaccess | @type_decl; +@type_identifier = @type_decl | @local_type_access | @type_label | @local_var_type_access | @local_namespace_access; +@typeexpr_parent = @expr | @stmt | @property | @typeexpr; +@literal_typeexpr = @string_literal_typeexpr | @number_literal_typeexpr | @boolean_literal_typeexpr | @bigint_literal_typeexpr; +@typeaccess = @local_type_access | @qualified_type_access | @import_type_access; +@vartypeaccess = @local_var_type_access | @qualified_var_type_access | @this_var_type_access | @import_var_type_access; +@namespace_access = @local_namespace_access | @qualified_namespace_access | @import_namespace_access; +@import_typeexpr = @import_type_access | @import_namespace_access | @import_var_type_access; + +@function_typeexpr = @plain_function_typeexpr | @constructor_typeexpr; + +// types +types ( + unique int id: @type, + int kind: int ref, + varchar(900) tostring: string ref +); + +#keyset[parent, idx] +type_child ( + int child: @type ref, + int parent: @type ref, + int idx: int ref +); + +case @type.kind of + 0 = @any_type +| 1 = @string_type +| 2 = @number_type +| 3 = @union_type +| 4 = @true_type +| 5 = @false_type +| 6 = @type_reference +| 7 = @object_type +| 8 = @canonical_type_variable_type +| 9 = @typeof_type +| 10 = @void_type +| 11 = @undefined_type +| 12 = @null_type +| 13 = @never_type +| 14 = @plain_symbol_type +| 15 = @unique_symbol_type +| 16 = @objectkeyword_type +| 17 = @intersection_type +| 18 = @tuple_type +| 19 = @lexical_type_variable_type +| 20 = @this_type +| 21 = @number_literal_type +| 22 = @string_literal_type +| 23 = @unknown_type +| 24 = @bigint_type +| 25 = @bigint_literal_type +; + +@boolean_literal_type = @true_type | @false_type; +@symbol_type = @plain_symbol_type | @unique_symbol_type; +@union_or_intersection_type = @union_type | @intersection_type; +@typevariable_type = @canonical_type_variable_type | @lexical_type_variable_type; + +has_asserts_keyword(int node: @predicate_typeexpr ref); + +@typed_ast_node = @expr | @typeexpr | @function; +ast_node_type( + unique int node: @typed_ast_node ref, + int typ: @type ref); + +declared_function_signature( + unique int node: @function ref, + int sig: @signature_type ref +); + +invoke_expr_signature( + unique int node: @invokeexpr ref, + int sig: @signature_type ref +); + +invoke_expr_overload_index( + unique int node: @invokeexpr ref, + int index: int ref +); + +symbols ( + unique int id: @symbol, + int kind: int ref, + varchar(900) name: string ref +); + +symbol_parent ( + unique int symbol: @symbol ref, + int parent: @symbol ref +); + +symbol_module ( + int symbol: @symbol ref, + varchar(900) moduleName: string ref +); + +symbol_global ( + int symbol: @symbol ref, + varchar(900) globalName: string ref +); + +case @symbol.kind of + 0 = @root_symbol +| 1 = @member_symbol +| 2 = @other_symbol +; + +@type_with_symbol = @type_reference | @typevariable_type | @typeof_type | @unique_symbol_type; +@ast_node_with_symbol = @type_definition | @namespace_definition | @toplevel | @typeaccess | @namespace_access | @var_decl | @function | @invokeexpr | @import_declaration | @external_module_reference; + +ast_node_symbol( + unique int node: @ast_node_with_symbol ref, + int symbol: @symbol ref); + +type_symbol( + unique int typ: @type_with_symbol ref, + int symbol: @symbol ref); + +#keyset[typ, name] +type_property( + int typ: @type ref, + varchar(900) name: string ref, + int propertyType: @type ref); + +type_alias( + unique int aliasType: @type ref, + int underlyingType: @type ref); + +@literal_type = @string_literal_type | @number_literal_type | @boolean_literal_type | @bigint_literal_type; +@type_with_literal_value = @string_literal_type | @number_literal_type | @bigint_literal_type; +type_literal_value( + unique int typ: @type_with_literal_value ref, + varchar(900) value: string ref); + +signature_types ( + unique int id: @signature_type, + int kind: int ref, + varchar(900) tostring: string ref, + int type_parameters: int ref, + int required_params: int ref +); + +is_abstract_signature( + unique int sig: @signature_type ref +); + +signature_rest_parameter( + unique int sig: @signature_type ref, + int rest_param_arra_type: @type ref +); + +case @signature_type.kind of + 0 = @function_signature_type +| 1 = @constructor_signature_type +; + +#keyset[typ, kind, index] +type_contains_signature ( + int typ: @type ref, + int kind: int ref, // constructor/call/index + int index: int ref, // ordering of overloaded signatures + int sig: @signature_type ref +); + +#keyset[parent, index] +signature_contains_type ( + int child: @type ref, + int parent: @signature_type ref, + int index: int ref +); + +#keyset[sig, index] +signature_parameter_name ( + int sig: @signature_type ref, + int index: int ref, + varchar(900) name: string ref +); + +number_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +string_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +base_type_names( + int typeName: @symbol ref, + int baseTypeName: @symbol ref +); + +self_types( + int typeName: @symbol ref, + int selfType: @type_reference ref +); + +tuple_type_min_length( + unique int typ: @type ref, + int minLength: int ref +); + +tuple_type_rest_index( + unique int typ: @type ref, + int index: int ref +); + +// comments +comments (unique int id: @comment, + int kind: int ref, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(900) tostring: string ref); + +case @comment.kind of + 0 = @slashslash_comment +| 1 = @slashstar_comment +| 2 = @doc_comment +| 3 = @html_comment_start +| 4 = @htmlcommentend; + +@html_comment = @html_comment_start | @htmlcommentend; +@line_comment = @slashslash_comment | @html_comment; +@block_comment = @slashstar_comment | @doc_comment; + +// source lines +lines (unique int id: @line, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(2) terminator: string ref); +indentation (int file: @file ref, + int lineno: int ref, + varchar(1) indentChar: string ref, + int indentDepth: int ref); + +// JavaScript parse errors +js_parse_errors (unique int id: @js_parse_error, + int toplevel: @toplevel ref, + varchar(900) message: string ref, + varchar(900) line: string ref); + +// regular expressions +#keyset[parent, idx] +regexpterm (unique int id: @regexpterm, + int kind: int ref, + int parent: @regexpparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +@regexpparent = @regexpterm | @regexp_literal | @string_literal; + +case @regexpterm.kind of + 0 = @regexp_alt +| 1 = @regexp_seq +| 2 = @regexp_caret +| 3 = @regexp_dollar +| 4 = @regexp_wordboundary +| 5 = @regexp_nonwordboundary +| 6 = @regexp_positive_lookahead +| 7 = @regexp_negative_lookahead +| 8 = @regexp_star +| 9 = @regexp_plus +| 10 = @regexp_opt +| 11 = @regexp_range +| 12 = @regexp_dot +| 13 = @regexp_group +| 14 = @regexp_normal_constant +| 15 = @regexp_hex_escape +| 16 = @regexp_unicode_escape +| 17 = @regexp_dec_escape +| 18 = @regexp_oct_escape +| 19 = @regexp_ctrl_escape +| 20 = @regexp_char_class_escape +| 21 = @regexp_id_escape +| 22 = @regexp_backref +| 23 = @regexp_char_class +| 24 = @regexp_char_range +| 25 = @regexp_positive_lookbehind +| 26 = @regexp_negative_lookbehind +| 27 = @regexp_unicode_property_escape; + +regexp_parse_errors (unique int id: @regexp_parse_error, + int regexp: @regexpterm ref, + varchar(900) message: string ref); + +@regexp_quantifier = @regexp_star | @regexp_plus | @regexp_opt | @regexp_range; +@regexp_escape = @regexp_char_escape | @regexp_char_class_escape | @regexp_unicode_property_escape; +@regexp_char_escape = @regexp_hex_escape | @regexp_unicode_escape | @regexp_dec_escape | @regexp_oct_escape | @regexp_ctrl_escape | @regexp_id_escape; +@regexp_constant = @regexp_normal_constant | @regexp_char_escape; +@regexp_lookahead = @regexp_positive_lookahead | @regexp_negative_lookahead; +@regexp_lookbehind = @regexp_positive_lookbehind | @regexp_negative_lookbehind; +@regexp_subpattern = @regexp_lookahead | @regexp_lookbehind; +@regexp_anchor = @regexp_dollar | @regexp_caret; + +is_greedy (int id: @regexp_quantifier ref); +range_quantifier_lower_bound (unique int id: @regexp_range ref, int lo: int ref); +range_quantifier_upper_bound (unique int id: @regexp_range ref, int hi: int ref); +is_capture (unique int id: @regexp_group ref, int number: int ref); +is_named_capture (unique int id: @regexp_group ref, string name: string ref); +is_inverted (int id: @regexp_char_class ref); +regexp_const_value (unique int id: @regexp_constant ref, varchar(1) value: string ref); +char_class_escape (unique int id: @regexp_char_class_escape ref, varchar(1) value: string ref); +backref (unique int id: @regexp_backref ref, int value: int ref); +named_backref (unique int id: @regexp_backref ref, string name: string ref); +unicode_property_escapename (unique int id: @regexp_unicode_property_escape ref, string name: string ref); +unicode_property_escapevalue (unique int id: @regexp_unicode_property_escape ref, string value: string ref); + +// tokens +#keyset[toplevel, idx] +tokeninfo (unique int id: @token, + int kind: int ref, + int toplevel: @toplevel ref, + int idx: int ref, + varchar(900) value: string ref); + +case @token.kind of + 0 = @token_eof +| 1 = @token_null_literal +| 2 = @token_boolean_literal +| 3 = @token_numeric_literal +| 4 = @token_string_literal +| 5 = @token_regular_expression +| 6 = @token_identifier +| 7 = @token_keyword +| 8 = @token_punctuator; + +// associate comments with the token immediately following them (which may be EOF) +next_token (int comment: @comment ref, int token: @token ref); + +// JSON +#keyset[parent, idx] +json (unique int id: @json_value, + int kind: int ref, + int parent: @json_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +json_literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @json_value ref); + +json_properties (int obj: @json_object ref, + varchar(900) property: string ref, + int value: @json_value ref); + +json_errors (unique int id: @json_parse_error, + varchar(900) message: string ref); + +json_locations(unique int locatable: @json_locatable ref, + int location: @location_default ref); + +case @json_value.kind of + 0 = @json_null +| 1 = @json_boolean +| 2 = @json_number +| 3 = @json_string +| 4 = @json_array +| 5 = @json_object; + +@json_parent = @json_object | @json_array | @file; + +@json_locatable = @json_value | @json_parse_error; + +// locations +@ast_node = @toplevel | @stmt | @expr | @property | @typeexpr; + +@locatable = @file + | @ast_node + | @comment + | @line + | @js_parse_error | @regexp_parse_error + | @regexpterm + | @json_locatable + | @token + | @cfg_node + | @jsdoc | @jsdoc_type_expr | @jsdoc_tag + | @yaml_locatable + | @xmllocatable + | @configLocatable + | @template_placeholder_tag; + +hasLocation (unique int locatable: @locatable ref, + int location: @location ref); + +// CFG +entry_cfg_node (unique int id: @entry_node, int container: @stmt_container ref); +exit_cfg_node (unique int id: @exit_node, int container: @stmt_container ref); +guard_node (unique int id: @guard_node, int kind: int ref, int test: @expr ref); +case @guard_node.kind of + 0 = @falsy_guard +| 1 = @truthy_guard; +@condition_guard = @falsy_guard | @truthy_guard; + +@synthetic_cfg_node = @entry_node | @exit_node | @guard_node; +@cfg_node = @synthetic_cfg_node | @expr_parent; + +successor (int pred: @cfg_node ref, int succ: @cfg_node ref); + +// JSDoc comments +jsdoc (unique int id: @jsdoc, varchar(900) description: string ref, int comment: @comment ref); +#keyset[parent, idx] +jsdoc_tags (unique int id: @jsdoc_tag, varchar(900) title: string ref, + int parent: @jsdoc ref, int idx: int ref, varchar(900) tostring: string ref); +jsdoc_tag_descriptions (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); +jsdoc_tag_names (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); + +#keyset[parent, idx] +jsdoc_type_exprs (unique int id: @jsdoc_type_expr, + int kind: int ref, + int parent: @jsdoc_type_expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); +case @jsdoc_type_expr.kind of + 0 = @jsdoc_any_type_expr +| 1 = @jsdoc_null_type_expr +| 2 = @jsdoc_undefined_type_expr +| 3 = @jsdoc_unknown_type_expr +| 4 = @jsdoc_void_type_expr +| 5 = @jsdoc_named_type_expr +| 6 = @jsdoc_applied_type_expr +| 7 = @jsdoc_nullable_type_expr +| 8 = @jsdoc_non_nullable_type_expr +| 9 = @jsdoc_record_type_expr +| 10 = @jsdoc_array_type_expr +| 11 = @jsdoc_union_type_expr +| 12 = @jsdoc_function_type_expr +| 13 = @jsdoc_optional_type_expr +| 14 = @jsdoc_rest_type_expr +; + +#keyset[id, idx] +jsdoc_record_field_name (int id: @jsdoc_record_type_expr ref, int idx: int ref, varchar(900) name: string ref); +jsdoc_prefix_qualifier (int id: @jsdoc_type_expr ref); +jsdoc_has_new_parameter (int fn: @jsdoc_function_type_expr ref); + +@jsdoc_type_expr_parent = @jsdoc_type_expr | @jsdoc_tag; + +jsdoc_errors (unique int id: @jsdoc_error, int tag: @jsdoc_tag ref, varchar(900) message: string ref, varchar(900) tostring: string ref); + +// YAML +#keyset[parent, idx] +yaml (unique int id: @yaml_node, + int kind: int ref, + int parent: @yaml_node_parent ref, + int idx: int ref, + varchar(900) tag: string ref, + varchar(900) tostring: string ref); + +case @yaml_node.kind of + 0 = @yaml_scalar_node +| 1 = @yaml_mapping_node +| 2 = @yaml_sequence_node +| 3 = @yaml_alias_node +; + +@yaml_collection_node = @yaml_mapping_node | @yaml_sequence_node; + +@yaml_node_parent = @yaml_collection_node | @file; + +yaml_anchors (unique int node: @yaml_node ref, + varchar(900) anchor: string ref); + +yaml_aliases (unique int alias: @yaml_alias_node ref, + varchar(900) target: string ref); + +yaml_scalars (unique int scalar: @yaml_scalar_node ref, + int style: int ref, + varchar(900) value: string ref); + +yaml_errors (unique int id: @yaml_error, + varchar(900) message: string ref); + +yaml_locations(unique int locatable: @yaml_locatable ref, + int location: @location_default ref); + +@yaml_locatable = @yaml_node | @yaml_error; + +/* XML Files */ + +xmlEncoding( + unique int id: @file ref, + varchar(900) encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +@dataflownode = @expr | @function_decl_stmt | @class_decl_stmt | @namespace_declaration | @enum_declaration | @property; + +@optionalchainable = @call_expr | @propaccess; + +isOptionalChaining(int id: @optionalchainable ref); + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +/** + * The time taken for the extraction of a file. + * This table contains non-deterministic content. + * + * The sum of the `time` column for each (`file`, `timerKind`) pair + * is the total time taken for extraction of `file`. The `extractionPhase` + * column provides a granular view of the extraction time of the file. + */ +extraction_time( + int file : @file ref, + // see `com.semmle.js.extractor.ExtractionMetrics.ExtractionPhase`. + int extractionPhase: int ref, + // 0 for the elapsed CPU time in nanoseconds, 1 for the elapsed wallclock time in nanoseconds + int timerKind: int ref, + float time: float ref +) + +/** + * Non-timing related data for the extraction of a single file. + * This table contains non-deterministic content. + */ +extraction_data( + int file : @file ref, + // the absolute path to the cache file + varchar(900) cacheFile: string ref, + boolean fromCache: boolean ref, + int length: int ref +) diff --git a/javascript/upgrades/9ca3692b65fd8d751431861d1a25c57f3e61d15b/semmlecode.javascript.dbscheme b/javascript/upgrades/9ca3692b65fd8d751431861d1a25c57f3e61d15b/semmlecode.javascript.dbscheme new file mode 100644 index 00000000000..e34b3e16dba --- /dev/null +++ b/javascript/upgrades/9ca3692b65fd8d751431861d1a25c57f3e61d15b/semmlecode.javascript.dbscheme @@ -0,0 +1,1216 @@ +/*** Standard fragments ***/ + +/** Files and folders **/ + +@location = @location_default; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref + ); + +@sourceline = @locatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref + ); + +files(unique int id: @file, + varchar(900) name: string ref); + +folders(unique int id: @folder, + varchar(900) name: string ref); + + +@container = @folder | @file ; + + +containerparent(int parent: @container ref, + unique int child: @container ref); + +/** Duplicate code **/ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity; + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/** External data **/ + +externalData( + int id : @externalDataElement, + varchar(900) path : string ref, + int column: int ref, + varchar(900) value : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + +/** Version control data **/ + +svnentries( + int id : @svnentry, + varchar(500) revision : string ref, + varchar(500) author : string ref, + date revisionDate : date ref, + int changeSize : int ref +); + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + varchar(500) action : string ref +); + +svnentrymsg( + int id : @svnentry ref, + varchar(500) message : string ref +); + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +); + + +/*** JavaScript-specific part ***/ + +filetype( + int file: @file ref, + string filetype: string ref +) + +// top-level code fragments +toplevels (unique int id: @toplevel, + int kind: int ref); + +is_externs (int toplevel: @toplevel ref); + +case @toplevel.kind of + 0 = @script +| 1 = @inline_script +| 2 = @event_handler +| 3 = @javascript_url +| 4 = @template_toplevel; + +is_module (int tl: @toplevel ref); +is_nodejs (int tl: @toplevel ref); +is_es2015_module (int tl: @toplevel ref); +is_closure_module (int tl: @toplevel ref); + +@xml_node_with_code = @xmlelement | @xmlattribute | @template_placeholder_tag; +toplevel_parent_xml_node( + unique int toplevel: @toplevel ref, + int xmlnode: @xml_node_with_code ref); + +xml_element_parent_expression( + unique int xmlnode: @xmlelement ref, + int expression: @expr ref, + int index: int ref); + +// statements +#keyset[parent, idx] +stmts (unique int id: @stmt, + int kind: int ref, + int parent: @stmt_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +stmt_containers (unique int stmt: @stmt ref, + int container: @stmt_container ref); + +jump_targets (unique int jump: @stmt ref, + int target: @stmt ref); + +@stmt_parent = @stmt | @toplevel | @function_expr | @arrow_function_expr; +@stmt_container = @toplevel | @function | @namespace_declaration | @external_module_declaration | @global_augmentation_declaration; + +case @stmt.kind of + 0 = @empty_stmt +| 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @labeled_stmt +| 5 = @break_stmt +| 6 = @continue_stmt +| 7 = @with_stmt +| 8 = @switch_stmt +| 9 = @return_stmt +| 10 = @throw_stmt +| 11 = @try_stmt +| 12 = @while_stmt +| 13 = @do_while_stmt +| 14 = @for_stmt +| 15 = @for_in_stmt +| 16 = @debugger_stmt +| 17 = @function_decl_stmt +| 18 = @var_decl_stmt +| 19 = @case +| 20 = @catch_clause +| 21 = @for_of_stmt +| 22 = @const_decl_stmt +| 23 = @let_stmt +| 24 = @legacy_let_stmt +| 25 = @for_each_stmt +| 26 = @class_decl_stmt +| 27 = @import_declaration +| 28 = @export_all_declaration +| 29 = @export_default_declaration +| 30 = @export_named_declaration +| 31 = @namespace_declaration +| 32 = @import_equals_declaration +| 33 = @export_assign_declaration +| 34 = @interface_declaration +| 35 = @type_alias_declaration +| 36 = @enum_declaration +| 37 = @external_module_declaration +| 38 = @export_as_namespace_declaration +| 39 = @global_augmentation_declaration +; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @let_stmt | @legacy_let_stmt; + +@export_declaration = @export_all_declaration | @export_default_declaration | @export_named_declaration; + +@namespace_definition = @namespace_declaration | @enum_declaration; +@type_definition = @class_definition | @interface_declaration | @enum_declaration | @type_alias_declaration | @enum_member; + +is_instantiated(unique int decl: @namespace_declaration ref); + +@declarable_node = @decl_stmt | @namespace_declaration | @class_decl_stmt | @function_decl_stmt | @enum_declaration | @external_module_declaration | @global_augmentation_declaration | @field; +has_declare_keyword(unique int stmt: @declarable_node ref); + +is_for_await_of(unique int forof: @for_of_stmt ref); + +// expressions +#keyset[parent, idx] +exprs (unique int id: @expr, + int kind: int ref, + int parent: @expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @expr_or_type ref); + +enclosing_stmt (unique int expr: @expr_or_type ref, + int stmt: @stmt ref); + +expr_containers (unique int expr: @expr_or_type ref, + int container: @stmt_container ref); + +array_size (unique int ae: @arraylike ref, + int sz: int ref); + +is_delegating (int yield: @yield_expr ref); + +@expr_or_stmt = @expr | @stmt; +@expr_or_type = @expr | @typeexpr; +@expr_parent = @expr_or_stmt | @property | @function_typeexpr; +@arraylike = @array_expr | @array_pattern; +@type_annotation = @typeexpr | @jsdoc_type_expr; +@node_in_stmt_container = @cfg_node | @type_annotation | @toplevel; + +case @expr.kind of + 0 = @label +| 1 = @null_literal +| 2 = @boolean_literal +| 3 = @number_literal +| 4 = @string_literal +| 5 = @regexp_literal +| 6 = @this_expr +| 7 = @array_expr +| 8 = @obj_expr +| 9 = @function_expr +| 10 = @seq_expr +| 11 = @conditional_expr +| 12 = @new_expr +| 13 = @call_expr +| 14 = @dot_expr +| 15 = @index_expr +| 16 = @neg_expr +| 17 = @plus_expr +| 18 = @log_not_expr +| 19 = @bit_not_expr +| 20 = @typeof_expr +| 21 = @void_expr +| 22 = @delete_expr +| 23 = @eq_expr +| 24 = @neq_expr +| 25 = @eqq_expr +| 26 = @neqq_expr +| 27 = @lt_expr +| 28 = @le_expr +| 29 = @gt_expr +| 30 = @ge_expr +| 31 = @lshift_expr +| 32 = @rshift_expr +| 33 = @urshift_expr +| 34 = @add_expr +| 35 = @sub_expr +| 36 = @mul_expr +| 37 = @div_expr +| 38 = @mod_expr +| 39 = @bitor_expr +| 40 = @xor_expr +| 41 = @bitand_expr +| 42 = @in_expr +| 43 = @instanceof_expr +| 44 = @logand_expr +| 45 = @logor_expr +| 47 = @assign_expr +| 48 = @assign_add_expr +| 49 = @assign_sub_expr +| 50 = @assign_mul_expr +| 51 = @assign_div_expr +| 52 = @assign_mod_expr +| 53 = @assign_lshift_expr +| 54 = @assign_rshift_expr +| 55 = @assign_urshift_expr +| 56 = @assign_or_expr +| 57 = @assign_xor_expr +| 58 = @assign_and_expr +| 59 = @preinc_expr +| 60 = @postinc_expr +| 61 = @predec_expr +| 62 = @postdec_expr +| 63 = @par_expr +| 64 = @var_declarator +| 65 = @arrow_function_expr +| 66 = @spread_element +| 67 = @array_pattern +| 68 = @object_pattern +| 69 = @yield_expr +| 70 = @tagged_template_expr +| 71 = @template_literal +| 72 = @template_element +| 73 = @array_comprehension_expr +| 74 = @generator_expr +| 75 = @for_in_comprehension_block +| 76 = @for_of_comprehension_block +| 77 = @legacy_letexpr +| 78 = @var_decl +| 79 = @proper_varaccess +| 80 = @class_expr +| 81 = @super_expr +| 82 = @newtarget_expr +| 83 = @named_import_specifier +| 84 = @import_default_specifier +| 85 = @import_namespace_specifier +| 86 = @named_export_specifier +| 87 = @exp_expr +| 88 = @assign_exp_expr +| 89 = @jsx_element +| 90 = @jsx_qualified_name +| 91 = @jsx_empty_expr +| 92 = @await_expr +| 93 = @function_sent_expr +| 94 = @decorator +| 95 = @export_default_specifier +| 96 = @export_namespace_specifier +| 97 = @bind_expr +| 98 = @external_module_reference +| 99 = @dynamic_import +| 100 = @expression_with_type_arguments +| 101 = @prefix_type_assertion +| 102 = @as_type_assertion +| 103 = @export_varaccess +| 104 = @decorator_list +| 105 = @non_null_assertion +| 106 = @bigint_literal +| 107 = @nullishcoalescing_expr +| 108 = @e4x_xml_anyname +| 109 = @e4x_xml_static_attribute_selector +| 110 = @e4x_xml_dynamic_attribute_selector +| 111 = @e4x_xml_filter_expression +| 112 = @e4x_xml_static_qualident +| 113 = @e4x_xml_dynamic_qualident +| 114 = @e4x_xml_dotdotexpr +| 115 = @import_meta_expr +| 116 = @assignlogandexpr +| 117 = @assignlogorexpr +| 118 = @assignnullishcoalescingexpr +| 119 = @template_pipe_ref +| 120 = @generated_code_expr +; + +@varaccess = @proper_varaccess | @export_varaccess; +@varref = @var_decl | @varaccess; + +@identifier = @label | @varref | @type_identifier; + +@literal = @null_literal | @boolean_literal | @number_literal | @string_literal | @regexp_literal | @bigint_literal; + +@propaccess = @dot_expr | @index_expr; + +@invokeexpr = @new_expr | @call_expr; + +@unaryexpr = @neg_expr | @plus_expr | @log_not_expr | @bit_not_expr | @typeof_expr | @void_expr | @delete_expr | @spread_element; + +@equality_test = @eq_expr | @neq_expr | @eqq_expr | @neqq_expr; + +@comparison = @equality_test | @lt_expr | @le_expr | @gt_expr | @ge_expr; + +@binaryexpr = @comparison | @lshift_expr | @rshift_expr | @urshift_expr | @add_expr | @sub_expr | @mul_expr | @div_expr | @mod_expr | @exp_expr | @bitor_expr | @xor_expr | @bitand_expr | @in_expr | @instanceof_expr | @logand_expr | @logor_expr | @nullishcoalescing_expr; + +@assignment = @assign_expr | @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr | @assign_mod_expr | @assign_exp_expr | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr | @assign_or_expr | @assign_xor_expr | @assign_and_expr | @assignlogandexpr | @assignlogorexpr | @assignnullishcoalescingexpr; + +@updateexpr = @preinc_expr | @postinc_expr | @predec_expr | @postdec_expr; + +@pattern = @varref | @array_pattern | @object_pattern; + +@comprehension_expr = @array_comprehension_expr | @generator_expr; + +@comprehension_block = @for_in_comprehension_block | @for_of_comprehension_block; + +@import_specifier = @named_import_specifier | @import_default_specifier | @import_namespace_specifier; + +@exportspecifier = @named_export_specifier | @export_default_specifier | @export_namespace_specifier; + +@import_or_export_declaration = @import_declaration | @export_declaration; + +@type_assertion = @as_type_assertion | @prefix_type_assertion; + +@class_definition = @class_decl_stmt | @class_expr; +@interface_definition = @interface_declaration | @interface_typeexpr; +@class_or_interface = @class_definition | @interface_definition; + +@lexical_decl = @var_decl | @type_decl; +@lexical_access = @varaccess | @local_type_access | @local_var_type_access | @local_namespace_access; +@lexical_ref = @lexical_decl | @lexical_access; + +@e4x_xml_attribute_selector = @e4x_xml_static_attribute_selector | @e4x_xml_dynamic_attribute_selector; +@e4x_xml_qualident = @e4x_xml_static_qualident | @e4x_xml_dynamic_qualident; + +expr_contains_template_tag_location( + int expr: @expr ref, + int location: @location ref +); + +@template_placeholder_tag_parent = @xmlelement | @xmlattribute | @file; + +template_placeholder_tag_info( + unique int node: @template_placeholder_tag, + int parentNode: @template_placeholder_tag_parent ref, + varchar(900) raw: string ref +); + +// scopes +scopes (unique int id: @scope, + int kind: int ref); + +case @scope.kind of + 0 = @global_scope +| 1 = @function_scope +| 2 = @catch_scope +| 3 = @module_scope +| 4 = @block_scope +| 5 = @for_scope +| 6 = @for_in_scope // for-of scopes work the same as for-in scopes +| 7 = @comprehension_block_scope +| 8 = @class_expr_scope +| 9 = @namespace_scope +| 10 = @class_decl_scope +| 11 = @interface_scope +| 12 = @type_alias_scope +| 13 = @mapped_type_scope +| 14 = @enum_scope +| 15 = @external_module_scope +| 16 = @conditional_type_scope; + +scopenodes (unique int node: @ast_node ref, + int scope: @scope ref); + +scopenesting (unique int inner: @scope ref, + int outer: @scope ref); + +// functions +@function = @function_decl_stmt | @function_expr | @arrow_function_expr; + +@parameterized = @function | @catch_clause; +@type_parameterized = @function | @class_or_interface | @type_alias_declaration | @mapped_typeexpr | @infer_typeexpr; + +is_generator (int fun: @function ref); +has_rest_parameter (int fun: @function ref); +is_async (int fun: @function ref); + +// variables and lexically scoped type names +#keyset[scope, name] +variables (unique int id: @variable, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_type_names (unique int id: @local_type_name, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_namespace_names (unique int id: @local_namespace_name, + varchar(900) name: string ref, + int scope: @scope ref); + +is_arguments_object (int id: @variable ref); + +@lexical_name = @variable | @local_type_name | @local_namespace_name; + +@bind_id = @varaccess | @local_var_type_access; +bind (unique int id: @bind_id ref, + int decl: @variable ref); + +decl (unique int id: @var_decl ref, + int decl: @variable ref); + +@typebind_id = @local_type_access | @export_varaccess; +typebind (unique int id: @typebind_id ref, + int decl: @local_type_name ref); + +@typedecl_id = @type_decl | @var_decl; +typedecl (unique int id: @typedecl_id ref, + int decl: @local_type_name ref); + +namespacedecl (unique int id: @var_decl ref, + int decl: @local_namespace_name ref); + +@namespacebind_id = @local_namespace_access | @export_varaccess; +namespacebind (unique int id: @namespacebind_id ref, + int decl: @local_namespace_name ref); + + +// properties in object literals, property patterns in object patterns, and method declarations in classes +#keyset[parent, index] +properties (unique int id: @property, + int parent: @property_parent ref, + int index: int ref, + int kind: int ref, + varchar(900) tostring: string ref); + +case @property.kind of + 0 = @value_property +| 1 = @property_getter +| 2 = @property_setter +| 3 = @jsx_attribute +| 4 = @function_call_signature +| 5 = @constructor_call_signature +| 6 = @index_signature +| 7 = @enum_member +| 8 = @proper_field +| 9 = @parameter_field +; + +@property_parent = @obj_expr | @object_pattern | @class_definition | @jsx_element | @interface_definition | @enum_declaration; +@property_accessor = @property_getter | @property_setter; +@call_signature = @function_call_signature | @constructor_call_signature; +@field = @proper_field | @parameter_field; +@field_or_vardeclarator = @field | @var_declarator; + +is_computed (int id: @property ref); +is_method (int id: @property ref); +is_static (int id: @property ref); +is_abstract_member (int id: @property ref); +is_const_enum (int id: @enum_declaration ref); +is_abstract_class (int id: @class_decl_stmt ref); + +has_public_keyword (int id: @property ref); +has_private_keyword (int id: @property ref); +has_protected_keyword (int id: @property ref); +has_readonly_keyword (int id: @property ref); +has_type_keyword (int id: @import_or_export_declaration ref); +is_optional_member (int id: @property ref); +has_definite_assignment_assertion (int id: @field_or_vardeclarator ref); +is_optional_parameter_declaration (unique int parameter: @pattern ref); + +#keyset[constructor, param_index] +parameter_fields( + unique int field: @parameter_field ref, + int constructor: @function_expr ref, + int param_index: int ref +); + +// types +#keyset[parent, idx] +typeexprs ( + unique int id: @typeexpr, + int kind: int ref, + int parent: @typeexpr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref +); + +case @typeexpr.kind of + 0 = @local_type_access +| 1 = @type_decl +| 2 = @keyword_typeexpr +| 3 = @string_literal_typeexpr +| 4 = @number_literal_typeexpr +| 5 = @boolean_literal_typeexpr +| 6 = @array_typeexpr +| 7 = @union_typeexpr +| 8 = @indexed_access_typeexpr +| 9 = @intersection_typeexpr +| 10 = @parenthesized_typeexpr +| 11 = @tuple_typeexpr +| 12 = @keyof_typeexpr +| 13 = @qualified_type_access +| 14 = @generic_typeexpr +| 15 = @type_label +| 16 = @typeof_typeexpr +| 17 = @local_var_type_access +| 18 = @qualified_var_type_access +| 19 = @this_var_type_access +| 20 = @predicate_typeexpr +| 21 = @interface_typeexpr +| 22 = @type_parameter +| 23 = @plain_function_typeexpr +| 24 = @constructor_typeexpr +| 25 = @local_namespace_access +| 26 = @qualified_namespace_access +| 27 = @mapped_typeexpr +| 28 = @conditional_typeexpr +| 29 = @infer_typeexpr +| 30 = @import_type_access +| 31 = @import_namespace_access +| 32 = @import_var_type_access +| 33 = @optional_typeexpr +| 34 = @rest_typeexpr +| 35 = @bigint_literal_typeexpr +| 36 = @readonly_typeexpr +| 37 = @template_literal_typeexpr +; + +@typeref = @typeaccess | @type_decl; +@type_identifier = @type_decl | @local_type_access | @type_label | @local_var_type_access | @local_namespace_access; +@typeexpr_parent = @expr | @stmt | @property | @typeexpr; +@literal_typeexpr = @string_literal_typeexpr | @number_literal_typeexpr | @boolean_literal_typeexpr | @bigint_literal_typeexpr; +@typeaccess = @local_type_access | @qualified_type_access | @import_type_access; +@vartypeaccess = @local_var_type_access | @qualified_var_type_access | @this_var_type_access | @import_var_type_access; +@namespace_access = @local_namespace_access | @qualified_namespace_access | @import_namespace_access; +@import_typeexpr = @import_type_access | @import_namespace_access | @import_var_type_access; + +@function_typeexpr = @plain_function_typeexpr | @constructor_typeexpr; + +// types +types ( + unique int id: @type, + int kind: int ref, + varchar(900) tostring: string ref +); + +#keyset[parent, idx] +type_child ( + int child: @type ref, + int parent: @type ref, + int idx: int ref +); + +case @type.kind of + 0 = @any_type +| 1 = @string_type +| 2 = @number_type +| 3 = @union_type +| 4 = @true_type +| 5 = @false_type +| 6 = @type_reference +| 7 = @object_type +| 8 = @canonical_type_variable_type +| 9 = @typeof_type +| 10 = @void_type +| 11 = @undefined_type +| 12 = @null_type +| 13 = @never_type +| 14 = @plain_symbol_type +| 15 = @unique_symbol_type +| 16 = @objectkeyword_type +| 17 = @intersection_type +| 18 = @tuple_type +| 19 = @lexical_type_variable_type +| 20 = @this_type +| 21 = @number_literal_type +| 22 = @string_literal_type +| 23 = @unknown_type +| 24 = @bigint_type +| 25 = @bigint_literal_type +; + +@boolean_literal_type = @true_type | @false_type; +@symbol_type = @plain_symbol_type | @unique_symbol_type; +@union_or_intersection_type = @union_type | @intersection_type; +@typevariable_type = @canonical_type_variable_type | @lexical_type_variable_type; + +has_asserts_keyword(int node: @predicate_typeexpr ref); + +@typed_ast_node = @expr | @typeexpr | @function; +ast_node_type( + unique int node: @typed_ast_node ref, + int typ: @type ref); + +declared_function_signature( + unique int node: @function ref, + int sig: @signature_type ref +); + +invoke_expr_signature( + unique int node: @invokeexpr ref, + int sig: @signature_type ref +); + +invoke_expr_overload_index( + unique int node: @invokeexpr ref, + int index: int ref +); + +symbols ( + unique int id: @symbol, + int kind: int ref, + varchar(900) name: string ref +); + +symbol_parent ( + unique int symbol: @symbol ref, + int parent: @symbol ref +); + +symbol_module ( + int symbol: @symbol ref, + varchar(900) moduleName: string ref +); + +symbol_global ( + int symbol: @symbol ref, + varchar(900) globalName: string ref +); + +case @symbol.kind of + 0 = @root_symbol +| 1 = @member_symbol +| 2 = @other_symbol +; + +@type_with_symbol = @type_reference | @typevariable_type | @typeof_type | @unique_symbol_type; +@ast_node_with_symbol = @type_definition | @namespace_definition | @toplevel | @typeaccess | @namespace_access | @var_decl | @function | @invokeexpr | @import_declaration | @external_module_reference; + +ast_node_symbol( + unique int node: @ast_node_with_symbol ref, + int symbol: @symbol ref); + +type_symbol( + unique int typ: @type_with_symbol ref, + int symbol: @symbol ref); + +#keyset[typ, name] +type_property( + int typ: @type ref, + varchar(900) name: string ref, + int propertyType: @type ref); + +type_alias( + unique int aliasType: @type ref, + int underlyingType: @type ref); + +@literal_type = @string_literal_type | @number_literal_type | @boolean_literal_type | @bigint_literal_type; +@type_with_literal_value = @string_literal_type | @number_literal_type | @bigint_literal_type; +type_literal_value( + unique int typ: @type_with_literal_value ref, + varchar(900) value: string ref); + +signature_types ( + unique int id: @signature_type, + int kind: int ref, + varchar(900) tostring: string ref, + int type_parameters: int ref, + int required_params: int ref +); + +is_abstract_signature( + unique int sig: @signature_type ref +); + +signature_rest_parameter( + unique int sig: @signature_type ref, + int rest_param_arra_type: @type ref +); + +case @signature_type.kind of + 0 = @function_signature_type +| 1 = @constructor_signature_type +; + +#keyset[typ, kind, index] +type_contains_signature ( + int typ: @type ref, + int kind: int ref, // constructor/call/index + int index: int ref, // ordering of overloaded signatures + int sig: @signature_type ref +); + +#keyset[parent, index] +signature_contains_type ( + int child: @type ref, + int parent: @signature_type ref, + int index: int ref +); + +#keyset[sig, index] +signature_parameter_name ( + int sig: @signature_type ref, + int index: int ref, + varchar(900) name: string ref +); + +number_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +string_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +base_type_names( + int typeName: @symbol ref, + int baseTypeName: @symbol ref +); + +self_types( + int typeName: @symbol ref, + int selfType: @type_reference ref +); + +tuple_type_min_length( + unique int typ: @type ref, + int minLength: int ref +); + +tuple_type_rest_index( + unique int typ: @type ref, + int index: int ref +); + +// comments +comments (unique int id: @comment, + int kind: int ref, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(900) tostring: string ref); + +case @comment.kind of + 0 = @slashslash_comment +| 1 = @slashstar_comment +| 2 = @doc_comment +| 3 = @html_comment_start +| 4 = @htmlcommentend; + +@html_comment = @html_comment_start | @htmlcommentend; +@line_comment = @slashslash_comment | @html_comment; +@block_comment = @slashstar_comment | @doc_comment; + +// source lines +lines (unique int id: @line, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(2) terminator: string ref); +indentation (int file: @file ref, + int lineno: int ref, + varchar(1) indentChar: string ref, + int indentDepth: int ref); + +// JavaScript parse errors +js_parse_errors (unique int id: @js_parse_error, + int toplevel: @toplevel ref, + varchar(900) message: string ref, + varchar(900) line: string ref); + +// regular expressions +#keyset[parent, idx] +regexpterm (unique int id: @regexpterm, + int kind: int ref, + int parent: @regexpparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +@regexpparent = @regexpterm | @regexp_literal | @string_literal; + +case @regexpterm.kind of + 0 = @regexp_alt +| 1 = @regexp_seq +| 2 = @regexp_caret +| 3 = @regexp_dollar +| 4 = @regexp_wordboundary +| 5 = @regexp_nonwordboundary +| 6 = @regexp_positive_lookahead +| 7 = @regexp_negative_lookahead +| 8 = @regexp_star +| 9 = @regexp_plus +| 10 = @regexp_opt +| 11 = @regexp_range +| 12 = @regexp_dot +| 13 = @regexp_group +| 14 = @regexp_normal_constant +| 15 = @regexp_hex_escape +| 16 = @regexp_unicode_escape +| 17 = @regexp_dec_escape +| 18 = @regexp_oct_escape +| 19 = @regexp_ctrl_escape +| 20 = @regexp_char_class_escape +| 21 = @regexp_id_escape +| 22 = @regexp_backref +| 23 = @regexp_char_class +| 24 = @regexp_char_range +| 25 = @regexp_positive_lookbehind +| 26 = @regexp_negative_lookbehind +| 27 = @regexp_unicode_property_escape; + +regexp_parse_errors (unique int id: @regexp_parse_error, + int regexp: @regexpterm ref, + varchar(900) message: string ref); + +@regexp_quantifier = @regexp_star | @regexp_plus | @regexp_opt | @regexp_range; +@regexp_escape = @regexp_char_escape | @regexp_char_class_escape | @regexp_unicode_property_escape; +@regexp_char_escape = @regexp_hex_escape | @regexp_unicode_escape | @regexp_dec_escape | @regexp_oct_escape | @regexp_ctrl_escape | @regexp_id_escape; +@regexp_constant = @regexp_normal_constant | @regexp_char_escape; +@regexp_lookahead = @regexp_positive_lookahead | @regexp_negative_lookahead; +@regexp_lookbehind = @regexp_positive_lookbehind | @regexp_negative_lookbehind; +@regexp_subpattern = @regexp_lookahead | @regexp_lookbehind; +@regexp_anchor = @regexp_dollar | @regexp_caret; + +is_greedy (int id: @regexp_quantifier ref); +range_quantifier_lower_bound (unique int id: @regexp_range ref, int lo: int ref); +range_quantifier_upper_bound (unique int id: @regexp_range ref, int hi: int ref); +is_capture (unique int id: @regexp_group ref, int number: int ref); +is_named_capture (unique int id: @regexp_group ref, string name: string ref); +is_inverted (int id: @regexp_char_class ref); +regexp_const_value (unique int id: @regexp_constant ref, varchar(1) value: string ref); +char_class_escape (unique int id: @regexp_char_class_escape ref, varchar(1) value: string ref); +backref (unique int id: @regexp_backref ref, int value: int ref); +named_backref (unique int id: @regexp_backref ref, string name: string ref); +unicode_property_escapename (unique int id: @regexp_unicode_property_escape ref, string name: string ref); +unicode_property_escapevalue (unique int id: @regexp_unicode_property_escape ref, string value: string ref); + +// tokens +#keyset[toplevel, idx] +tokeninfo (unique int id: @token, + int kind: int ref, + int toplevel: @toplevel ref, + int idx: int ref, + varchar(900) value: string ref); + +case @token.kind of + 0 = @token_eof +| 1 = @token_null_literal +| 2 = @token_boolean_literal +| 3 = @token_numeric_literal +| 4 = @token_string_literal +| 5 = @token_regular_expression +| 6 = @token_identifier +| 7 = @token_keyword +| 8 = @token_punctuator; + +// associate comments with the token immediately following them (which may be EOF) +next_token (int comment: @comment ref, int token: @token ref); + +// JSON +#keyset[parent, idx] +json (unique int id: @json_value, + int kind: int ref, + int parent: @json_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +json_literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @json_value ref); + +json_properties (int obj: @json_object ref, + varchar(900) property: string ref, + int value: @json_value ref); + +json_errors (unique int id: @json_parse_error, + varchar(900) message: string ref); + +json_locations(unique int locatable: @json_locatable ref, + int location: @location_default ref); + +case @json_value.kind of + 0 = @json_null +| 1 = @json_boolean +| 2 = @json_number +| 3 = @json_string +| 4 = @json_array +| 5 = @json_object; + +@json_parent = @json_object | @json_array | @file; + +@json_locatable = @json_value | @json_parse_error; + +// locations +@ast_node = @toplevel | @stmt | @expr | @property | @typeexpr; + +@locatable = @file + | @ast_node + | @comment + | @line + | @js_parse_error | @regexp_parse_error + | @regexpterm + | @json_locatable + | @token + | @cfg_node + | @jsdoc | @jsdoc_type_expr | @jsdoc_tag + | @yaml_locatable + | @xmllocatable + | @configLocatable + | @template_placeholder_tag; + +hasLocation (unique int locatable: @locatable ref, + int location: @location ref); + +// CFG +entry_cfg_node (unique int id: @entry_node, int container: @stmt_container ref); +exit_cfg_node (unique int id: @exit_node, int container: @stmt_container ref); +guard_node (unique int id: @guard_node, int kind: int ref, int test: @expr ref); +case @guard_node.kind of + 0 = @falsy_guard +| 1 = @truthy_guard; +@condition_guard = @falsy_guard | @truthy_guard; + +@synthetic_cfg_node = @entry_node | @exit_node | @guard_node; +@cfg_node = @synthetic_cfg_node | @expr_parent; + +successor (int pred: @cfg_node ref, int succ: @cfg_node ref); + +// JSDoc comments +jsdoc (unique int id: @jsdoc, varchar(900) description: string ref, int comment: @comment ref); +#keyset[parent, idx] +jsdoc_tags (unique int id: @jsdoc_tag, varchar(900) title: string ref, + int parent: @jsdoc ref, int idx: int ref, varchar(900) tostring: string ref); +jsdoc_tag_descriptions (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); +jsdoc_tag_names (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); + +#keyset[parent, idx] +jsdoc_type_exprs (unique int id: @jsdoc_type_expr, + int kind: int ref, + int parent: @jsdoc_type_expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); +case @jsdoc_type_expr.kind of + 0 = @jsdoc_any_type_expr +| 1 = @jsdoc_null_type_expr +| 2 = @jsdoc_undefined_type_expr +| 3 = @jsdoc_unknown_type_expr +| 4 = @jsdoc_void_type_expr +| 5 = @jsdoc_named_type_expr +| 6 = @jsdoc_applied_type_expr +| 7 = @jsdoc_nullable_type_expr +| 8 = @jsdoc_non_nullable_type_expr +| 9 = @jsdoc_record_type_expr +| 10 = @jsdoc_array_type_expr +| 11 = @jsdoc_union_type_expr +| 12 = @jsdoc_function_type_expr +| 13 = @jsdoc_optional_type_expr +| 14 = @jsdoc_rest_type_expr +; + +#keyset[id, idx] +jsdoc_record_field_name (int id: @jsdoc_record_type_expr ref, int idx: int ref, varchar(900) name: string ref); +jsdoc_prefix_qualifier (int id: @jsdoc_type_expr ref); +jsdoc_has_new_parameter (int fn: @jsdoc_function_type_expr ref); + +@jsdoc_type_expr_parent = @jsdoc_type_expr | @jsdoc_tag; + +jsdoc_errors (unique int id: @jsdoc_error, int tag: @jsdoc_tag ref, varchar(900) message: string ref, varchar(900) tostring: string ref); + +// YAML +#keyset[parent, idx] +yaml (unique int id: @yaml_node, + int kind: int ref, + int parent: @yaml_node_parent ref, + int idx: int ref, + varchar(900) tag: string ref, + varchar(900) tostring: string ref); + +case @yaml_node.kind of + 0 = @yaml_scalar_node +| 1 = @yaml_mapping_node +| 2 = @yaml_sequence_node +| 3 = @yaml_alias_node +; + +@yaml_collection_node = @yaml_mapping_node | @yaml_sequence_node; + +@yaml_node_parent = @yaml_collection_node | @file; + +yaml_anchors (unique int node: @yaml_node ref, + varchar(900) anchor: string ref); + +yaml_aliases (unique int alias: @yaml_alias_node ref, + varchar(900) target: string ref); + +yaml_scalars (unique int scalar: @yaml_scalar_node ref, + int style: int ref, + varchar(900) value: string ref); + +yaml_errors (unique int id: @yaml_error, + varchar(900) message: string ref); + +yaml_locations(unique int locatable: @yaml_locatable ref, + int location: @location_default ref); + +@yaml_locatable = @yaml_node | @yaml_error; + +/* XML Files */ + +xmlEncoding( + unique int id: @file ref, + varchar(900) encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +@dataflownode = @expr | @function_decl_stmt | @class_decl_stmt | @namespace_declaration | @enum_declaration | @property; + +@optionalchainable = @call_expr | @propaccess; + +isOptionalChaining(int id: @optionalchainable ref); + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +/** + * The time taken for the extraction of a file. + * This table contains non-deterministic content. + * + * The sum of the `time` column for each (`file`, `timerKind`) pair + * is the total time taken for extraction of `file`. The `extractionPhase` + * column provides a granular view of the extraction time of the file. + */ +extraction_time( + int file : @file ref, + // see `com.semmle.js.extractor.ExtractionMetrics.ExtractionPhase`. + int extractionPhase: int ref, + // 0 for the elapsed CPU time in nanoseconds, 1 for the elapsed wallclock time in nanoseconds + int timerKind: int ref, + float time: float ref +) + +/** + * Non-timing related data for the extraction of a single file. + * This table contains non-deterministic content. + */ +extraction_data( + int file : @file ref, + // the absolute path to the cache file + varchar(900) cacheFile: string ref, + boolean fromCache: boolean ref, + int length: int ref +) diff --git a/javascript/upgrades/9ca3692b65fd8d751431861d1a25c57f3e61d15b/upgrade.properties b/javascript/upgrades/9ca3692b65fd8d751431861d1a25c57f3e61d15b/upgrade.properties new file mode 100644 index 00000000000..a0c4ba602a1 --- /dev/null +++ b/javascript/upgrades/9ca3692b65fd8d751431861d1a25c57f3e61d15b/upgrade.properties @@ -0,0 +1,4 @@ +description: Removed unused column from the `folders` and `files` relations +compatibility: full +files.rel: reorder files.rel (int id, string name, string simple, string ext, int fromSource) id name +folders.rel: reorder folders.rel (int id, string name, string simple) id name \ No newline at end of file diff --git a/javascript/upgrades/e34b3e16dba5d11961119818c9beeff334f20a90/old.dbscheme b/javascript/upgrades/e34b3e16dba5d11961119818c9beeff334f20a90/old.dbscheme new file mode 100644 index 00000000000..e34b3e16dba --- /dev/null +++ b/javascript/upgrades/e34b3e16dba5d11961119818c9beeff334f20a90/old.dbscheme @@ -0,0 +1,1216 @@ +/*** Standard fragments ***/ + +/** Files and folders **/ + +@location = @location_default; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref + ); + +@sourceline = @locatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref + ); + +files(unique int id: @file, + varchar(900) name: string ref); + +folders(unique int id: @folder, + varchar(900) name: string ref); + + +@container = @folder | @file ; + + +containerparent(int parent: @container ref, + unique int child: @container ref); + +/** Duplicate code **/ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity; + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/** External data **/ + +externalData( + int id : @externalDataElement, + varchar(900) path : string ref, + int column: int ref, + varchar(900) value : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + +/** Version control data **/ + +svnentries( + int id : @svnentry, + varchar(500) revision : string ref, + varchar(500) author : string ref, + date revisionDate : date ref, + int changeSize : int ref +); + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + varchar(500) action : string ref +); + +svnentrymsg( + int id : @svnentry ref, + varchar(500) message : string ref +); + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +); + + +/*** JavaScript-specific part ***/ + +filetype( + int file: @file ref, + string filetype: string ref +) + +// top-level code fragments +toplevels (unique int id: @toplevel, + int kind: int ref); + +is_externs (int toplevel: @toplevel ref); + +case @toplevel.kind of + 0 = @script +| 1 = @inline_script +| 2 = @event_handler +| 3 = @javascript_url +| 4 = @template_toplevel; + +is_module (int tl: @toplevel ref); +is_nodejs (int tl: @toplevel ref); +is_es2015_module (int tl: @toplevel ref); +is_closure_module (int tl: @toplevel ref); + +@xml_node_with_code = @xmlelement | @xmlattribute | @template_placeholder_tag; +toplevel_parent_xml_node( + unique int toplevel: @toplevel ref, + int xmlnode: @xml_node_with_code ref); + +xml_element_parent_expression( + unique int xmlnode: @xmlelement ref, + int expression: @expr ref, + int index: int ref); + +// statements +#keyset[parent, idx] +stmts (unique int id: @stmt, + int kind: int ref, + int parent: @stmt_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +stmt_containers (unique int stmt: @stmt ref, + int container: @stmt_container ref); + +jump_targets (unique int jump: @stmt ref, + int target: @stmt ref); + +@stmt_parent = @stmt | @toplevel | @function_expr | @arrow_function_expr; +@stmt_container = @toplevel | @function | @namespace_declaration | @external_module_declaration | @global_augmentation_declaration; + +case @stmt.kind of + 0 = @empty_stmt +| 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @labeled_stmt +| 5 = @break_stmt +| 6 = @continue_stmt +| 7 = @with_stmt +| 8 = @switch_stmt +| 9 = @return_stmt +| 10 = @throw_stmt +| 11 = @try_stmt +| 12 = @while_stmt +| 13 = @do_while_stmt +| 14 = @for_stmt +| 15 = @for_in_stmt +| 16 = @debugger_stmt +| 17 = @function_decl_stmt +| 18 = @var_decl_stmt +| 19 = @case +| 20 = @catch_clause +| 21 = @for_of_stmt +| 22 = @const_decl_stmt +| 23 = @let_stmt +| 24 = @legacy_let_stmt +| 25 = @for_each_stmt +| 26 = @class_decl_stmt +| 27 = @import_declaration +| 28 = @export_all_declaration +| 29 = @export_default_declaration +| 30 = @export_named_declaration +| 31 = @namespace_declaration +| 32 = @import_equals_declaration +| 33 = @export_assign_declaration +| 34 = @interface_declaration +| 35 = @type_alias_declaration +| 36 = @enum_declaration +| 37 = @external_module_declaration +| 38 = @export_as_namespace_declaration +| 39 = @global_augmentation_declaration +; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @let_stmt | @legacy_let_stmt; + +@export_declaration = @export_all_declaration | @export_default_declaration | @export_named_declaration; + +@namespace_definition = @namespace_declaration | @enum_declaration; +@type_definition = @class_definition | @interface_declaration | @enum_declaration | @type_alias_declaration | @enum_member; + +is_instantiated(unique int decl: @namespace_declaration ref); + +@declarable_node = @decl_stmt | @namespace_declaration | @class_decl_stmt | @function_decl_stmt | @enum_declaration | @external_module_declaration | @global_augmentation_declaration | @field; +has_declare_keyword(unique int stmt: @declarable_node ref); + +is_for_await_of(unique int forof: @for_of_stmt ref); + +// expressions +#keyset[parent, idx] +exprs (unique int id: @expr, + int kind: int ref, + int parent: @expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @expr_or_type ref); + +enclosing_stmt (unique int expr: @expr_or_type ref, + int stmt: @stmt ref); + +expr_containers (unique int expr: @expr_or_type ref, + int container: @stmt_container ref); + +array_size (unique int ae: @arraylike ref, + int sz: int ref); + +is_delegating (int yield: @yield_expr ref); + +@expr_or_stmt = @expr | @stmt; +@expr_or_type = @expr | @typeexpr; +@expr_parent = @expr_or_stmt | @property | @function_typeexpr; +@arraylike = @array_expr | @array_pattern; +@type_annotation = @typeexpr | @jsdoc_type_expr; +@node_in_stmt_container = @cfg_node | @type_annotation | @toplevel; + +case @expr.kind of + 0 = @label +| 1 = @null_literal +| 2 = @boolean_literal +| 3 = @number_literal +| 4 = @string_literal +| 5 = @regexp_literal +| 6 = @this_expr +| 7 = @array_expr +| 8 = @obj_expr +| 9 = @function_expr +| 10 = @seq_expr +| 11 = @conditional_expr +| 12 = @new_expr +| 13 = @call_expr +| 14 = @dot_expr +| 15 = @index_expr +| 16 = @neg_expr +| 17 = @plus_expr +| 18 = @log_not_expr +| 19 = @bit_not_expr +| 20 = @typeof_expr +| 21 = @void_expr +| 22 = @delete_expr +| 23 = @eq_expr +| 24 = @neq_expr +| 25 = @eqq_expr +| 26 = @neqq_expr +| 27 = @lt_expr +| 28 = @le_expr +| 29 = @gt_expr +| 30 = @ge_expr +| 31 = @lshift_expr +| 32 = @rshift_expr +| 33 = @urshift_expr +| 34 = @add_expr +| 35 = @sub_expr +| 36 = @mul_expr +| 37 = @div_expr +| 38 = @mod_expr +| 39 = @bitor_expr +| 40 = @xor_expr +| 41 = @bitand_expr +| 42 = @in_expr +| 43 = @instanceof_expr +| 44 = @logand_expr +| 45 = @logor_expr +| 47 = @assign_expr +| 48 = @assign_add_expr +| 49 = @assign_sub_expr +| 50 = @assign_mul_expr +| 51 = @assign_div_expr +| 52 = @assign_mod_expr +| 53 = @assign_lshift_expr +| 54 = @assign_rshift_expr +| 55 = @assign_urshift_expr +| 56 = @assign_or_expr +| 57 = @assign_xor_expr +| 58 = @assign_and_expr +| 59 = @preinc_expr +| 60 = @postinc_expr +| 61 = @predec_expr +| 62 = @postdec_expr +| 63 = @par_expr +| 64 = @var_declarator +| 65 = @arrow_function_expr +| 66 = @spread_element +| 67 = @array_pattern +| 68 = @object_pattern +| 69 = @yield_expr +| 70 = @tagged_template_expr +| 71 = @template_literal +| 72 = @template_element +| 73 = @array_comprehension_expr +| 74 = @generator_expr +| 75 = @for_in_comprehension_block +| 76 = @for_of_comprehension_block +| 77 = @legacy_letexpr +| 78 = @var_decl +| 79 = @proper_varaccess +| 80 = @class_expr +| 81 = @super_expr +| 82 = @newtarget_expr +| 83 = @named_import_specifier +| 84 = @import_default_specifier +| 85 = @import_namespace_specifier +| 86 = @named_export_specifier +| 87 = @exp_expr +| 88 = @assign_exp_expr +| 89 = @jsx_element +| 90 = @jsx_qualified_name +| 91 = @jsx_empty_expr +| 92 = @await_expr +| 93 = @function_sent_expr +| 94 = @decorator +| 95 = @export_default_specifier +| 96 = @export_namespace_specifier +| 97 = @bind_expr +| 98 = @external_module_reference +| 99 = @dynamic_import +| 100 = @expression_with_type_arguments +| 101 = @prefix_type_assertion +| 102 = @as_type_assertion +| 103 = @export_varaccess +| 104 = @decorator_list +| 105 = @non_null_assertion +| 106 = @bigint_literal +| 107 = @nullishcoalescing_expr +| 108 = @e4x_xml_anyname +| 109 = @e4x_xml_static_attribute_selector +| 110 = @e4x_xml_dynamic_attribute_selector +| 111 = @e4x_xml_filter_expression +| 112 = @e4x_xml_static_qualident +| 113 = @e4x_xml_dynamic_qualident +| 114 = @e4x_xml_dotdotexpr +| 115 = @import_meta_expr +| 116 = @assignlogandexpr +| 117 = @assignlogorexpr +| 118 = @assignnullishcoalescingexpr +| 119 = @template_pipe_ref +| 120 = @generated_code_expr +; + +@varaccess = @proper_varaccess | @export_varaccess; +@varref = @var_decl | @varaccess; + +@identifier = @label | @varref | @type_identifier; + +@literal = @null_literal | @boolean_literal | @number_literal | @string_literal | @regexp_literal | @bigint_literal; + +@propaccess = @dot_expr | @index_expr; + +@invokeexpr = @new_expr | @call_expr; + +@unaryexpr = @neg_expr | @plus_expr | @log_not_expr | @bit_not_expr | @typeof_expr | @void_expr | @delete_expr | @spread_element; + +@equality_test = @eq_expr | @neq_expr | @eqq_expr | @neqq_expr; + +@comparison = @equality_test | @lt_expr | @le_expr | @gt_expr | @ge_expr; + +@binaryexpr = @comparison | @lshift_expr | @rshift_expr | @urshift_expr | @add_expr | @sub_expr | @mul_expr | @div_expr | @mod_expr | @exp_expr | @bitor_expr | @xor_expr | @bitand_expr | @in_expr | @instanceof_expr | @logand_expr | @logor_expr | @nullishcoalescing_expr; + +@assignment = @assign_expr | @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr | @assign_mod_expr | @assign_exp_expr | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr | @assign_or_expr | @assign_xor_expr | @assign_and_expr | @assignlogandexpr | @assignlogorexpr | @assignnullishcoalescingexpr; + +@updateexpr = @preinc_expr | @postinc_expr | @predec_expr | @postdec_expr; + +@pattern = @varref | @array_pattern | @object_pattern; + +@comprehension_expr = @array_comprehension_expr | @generator_expr; + +@comprehension_block = @for_in_comprehension_block | @for_of_comprehension_block; + +@import_specifier = @named_import_specifier | @import_default_specifier | @import_namespace_specifier; + +@exportspecifier = @named_export_specifier | @export_default_specifier | @export_namespace_specifier; + +@import_or_export_declaration = @import_declaration | @export_declaration; + +@type_assertion = @as_type_assertion | @prefix_type_assertion; + +@class_definition = @class_decl_stmt | @class_expr; +@interface_definition = @interface_declaration | @interface_typeexpr; +@class_or_interface = @class_definition | @interface_definition; + +@lexical_decl = @var_decl | @type_decl; +@lexical_access = @varaccess | @local_type_access | @local_var_type_access | @local_namespace_access; +@lexical_ref = @lexical_decl | @lexical_access; + +@e4x_xml_attribute_selector = @e4x_xml_static_attribute_selector | @e4x_xml_dynamic_attribute_selector; +@e4x_xml_qualident = @e4x_xml_static_qualident | @e4x_xml_dynamic_qualident; + +expr_contains_template_tag_location( + int expr: @expr ref, + int location: @location ref +); + +@template_placeholder_tag_parent = @xmlelement | @xmlattribute | @file; + +template_placeholder_tag_info( + unique int node: @template_placeholder_tag, + int parentNode: @template_placeholder_tag_parent ref, + varchar(900) raw: string ref +); + +// scopes +scopes (unique int id: @scope, + int kind: int ref); + +case @scope.kind of + 0 = @global_scope +| 1 = @function_scope +| 2 = @catch_scope +| 3 = @module_scope +| 4 = @block_scope +| 5 = @for_scope +| 6 = @for_in_scope // for-of scopes work the same as for-in scopes +| 7 = @comprehension_block_scope +| 8 = @class_expr_scope +| 9 = @namespace_scope +| 10 = @class_decl_scope +| 11 = @interface_scope +| 12 = @type_alias_scope +| 13 = @mapped_type_scope +| 14 = @enum_scope +| 15 = @external_module_scope +| 16 = @conditional_type_scope; + +scopenodes (unique int node: @ast_node ref, + int scope: @scope ref); + +scopenesting (unique int inner: @scope ref, + int outer: @scope ref); + +// functions +@function = @function_decl_stmt | @function_expr | @arrow_function_expr; + +@parameterized = @function | @catch_clause; +@type_parameterized = @function | @class_or_interface | @type_alias_declaration | @mapped_typeexpr | @infer_typeexpr; + +is_generator (int fun: @function ref); +has_rest_parameter (int fun: @function ref); +is_async (int fun: @function ref); + +// variables and lexically scoped type names +#keyset[scope, name] +variables (unique int id: @variable, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_type_names (unique int id: @local_type_name, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_namespace_names (unique int id: @local_namespace_name, + varchar(900) name: string ref, + int scope: @scope ref); + +is_arguments_object (int id: @variable ref); + +@lexical_name = @variable | @local_type_name | @local_namespace_name; + +@bind_id = @varaccess | @local_var_type_access; +bind (unique int id: @bind_id ref, + int decl: @variable ref); + +decl (unique int id: @var_decl ref, + int decl: @variable ref); + +@typebind_id = @local_type_access | @export_varaccess; +typebind (unique int id: @typebind_id ref, + int decl: @local_type_name ref); + +@typedecl_id = @type_decl | @var_decl; +typedecl (unique int id: @typedecl_id ref, + int decl: @local_type_name ref); + +namespacedecl (unique int id: @var_decl ref, + int decl: @local_namespace_name ref); + +@namespacebind_id = @local_namespace_access | @export_varaccess; +namespacebind (unique int id: @namespacebind_id ref, + int decl: @local_namespace_name ref); + + +// properties in object literals, property patterns in object patterns, and method declarations in classes +#keyset[parent, index] +properties (unique int id: @property, + int parent: @property_parent ref, + int index: int ref, + int kind: int ref, + varchar(900) tostring: string ref); + +case @property.kind of + 0 = @value_property +| 1 = @property_getter +| 2 = @property_setter +| 3 = @jsx_attribute +| 4 = @function_call_signature +| 5 = @constructor_call_signature +| 6 = @index_signature +| 7 = @enum_member +| 8 = @proper_field +| 9 = @parameter_field +; + +@property_parent = @obj_expr | @object_pattern | @class_definition | @jsx_element | @interface_definition | @enum_declaration; +@property_accessor = @property_getter | @property_setter; +@call_signature = @function_call_signature | @constructor_call_signature; +@field = @proper_field | @parameter_field; +@field_or_vardeclarator = @field | @var_declarator; + +is_computed (int id: @property ref); +is_method (int id: @property ref); +is_static (int id: @property ref); +is_abstract_member (int id: @property ref); +is_const_enum (int id: @enum_declaration ref); +is_abstract_class (int id: @class_decl_stmt ref); + +has_public_keyword (int id: @property ref); +has_private_keyword (int id: @property ref); +has_protected_keyword (int id: @property ref); +has_readonly_keyword (int id: @property ref); +has_type_keyword (int id: @import_or_export_declaration ref); +is_optional_member (int id: @property ref); +has_definite_assignment_assertion (int id: @field_or_vardeclarator ref); +is_optional_parameter_declaration (unique int parameter: @pattern ref); + +#keyset[constructor, param_index] +parameter_fields( + unique int field: @parameter_field ref, + int constructor: @function_expr ref, + int param_index: int ref +); + +// types +#keyset[parent, idx] +typeexprs ( + unique int id: @typeexpr, + int kind: int ref, + int parent: @typeexpr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref +); + +case @typeexpr.kind of + 0 = @local_type_access +| 1 = @type_decl +| 2 = @keyword_typeexpr +| 3 = @string_literal_typeexpr +| 4 = @number_literal_typeexpr +| 5 = @boolean_literal_typeexpr +| 6 = @array_typeexpr +| 7 = @union_typeexpr +| 8 = @indexed_access_typeexpr +| 9 = @intersection_typeexpr +| 10 = @parenthesized_typeexpr +| 11 = @tuple_typeexpr +| 12 = @keyof_typeexpr +| 13 = @qualified_type_access +| 14 = @generic_typeexpr +| 15 = @type_label +| 16 = @typeof_typeexpr +| 17 = @local_var_type_access +| 18 = @qualified_var_type_access +| 19 = @this_var_type_access +| 20 = @predicate_typeexpr +| 21 = @interface_typeexpr +| 22 = @type_parameter +| 23 = @plain_function_typeexpr +| 24 = @constructor_typeexpr +| 25 = @local_namespace_access +| 26 = @qualified_namespace_access +| 27 = @mapped_typeexpr +| 28 = @conditional_typeexpr +| 29 = @infer_typeexpr +| 30 = @import_type_access +| 31 = @import_namespace_access +| 32 = @import_var_type_access +| 33 = @optional_typeexpr +| 34 = @rest_typeexpr +| 35 = @bigint_literal_typeexpr +| 36 = @readonly_typeexpr +| 37 = @template_literal_typeexpr +; + +@typeref = @typeaccess | @type_decl; +@type_identifier = @type_decl | @local_type_access | @type_label | @local_var_type_access | @local_namespace_access; +@typeexpr_parent = @expr | @stmt | @property | @typeexpr; +@literal_typeexpr = @string_literal_typeexpr | @number_literal_typeexpr | @boolean_literal_typeexpr | @bigint_literal_typeexpr; +@typeaccess = @local_type_access | @qualified_type_access | @import_type_access; +@vartypeaccess = @local_var_type_access | @qualified_var_type_access | @this_var_type_access | @import_var_type_access; +@namespace_access = @local_namespace_access | @qualified_namespace_access | @import_namespace_access; +@import_typeexpr = @import_type_access | @import_namespace_access | @import_var_type_access; + +@function_typeexpr = @plain_function_typeexpr | @constructor_typeexpr; + +// types +types ( + unique int id: @type, + int kind: int ref, + varchar(900) tostring: string ref +); + +#keyset[parent, idx] +type_child ( + int child: @type ref, + int parent: @type ref, + int idx: int ref +); + +case @type.kind of + 0 = @any_type +| 1 = @string_type +| 2 = @number_type +| 3 = @union_type +| 4 = @true_type +| 5 = @false_type +| 6 = @type_reference +| 7 = @object_type +| 8 = @canonical_type_variable_type +| 9 = @typeof_type +| 10 = @void_type +| 11 = @undefined_type +| 12 = @null_type +| 13 = @never_type +| 14 = @plain_symbol_type +| 15 = @unique_symbol_type +| 16 = @objectkeyword_type +| 17 = @intersection_type +| 18 = @tuple_type +| 19 = @lexical_type_variable_type +| 20 = @this_type +| 21 = @number_literal_type +| 22 = @string_literal_type +| 23 = @unknown_type +| 24 = @bigint_type +| 25 = @bigint_literal_type +; + +@boolean_literal_type = @true_type | @false_type; +@symbol_type = @plain_symbol_type | @unique_symbol_type; +@union_or_intersection_type = @union_type | @intersection_type; +@typevariable_type = @canonical_type_variable_type | @lexical_type_variable_type; + +has_asserts_keyword(int node: @predicate_typeexpr ref); + +@typed_ast_node = @expr | @typeexpr | @function; +ast_node_type( + unique int node: @typed_ast_node ref, + int typ: @type ref); + +declared_function_signature( + unique int node: @function ref, + int sig: @signature_type ref +); + +invoke_expr_signature( + unique int node: @invokeexpr ref, + int sig: @signature_type ref +); + +invoke_expr_overload_index( + unique int node: @invokeexpr ref, + int index: int ref +); + +symbols ( + unique int id: @symbol, + int kind: int ref, + varchar(900) name: string ref +); + +symbol_parent ( + unique int symbol: @symbol ref, + int parent: @symbol ref +); + +symbol_module ( + int symbol: @symbol ref, + varchar(900) moduleName: string ref +); + +symbol_global ( + int symbol: @symbol ref, + varchar(900) globalName: string ref +); + +case @symbol.kind of + 0 = @root_symbol +| 1 = @member_symbol +| 2 = @other_symbol +; + +@type_with_symbol = @type_reference | @typevariable_type | @typeof_type | @unique_symbol_type; +@ast_node_with_symbol = @type_definition | @namespace_definition | @toplevel | @typeaccess | @namespace_access | @var_decl | @function | @invokeexpr | @import_declaration | @external_module_reference; + +ast_node_symbol( + unique int node: @ast_node_with_symbol ref, + int symbol: @symbol ref); + +type_symbol( + unique int typ: @type_with_symbol ref, + int symbol: @symbol ref); + +#keyset[typ, name] +type_property( + int typ: @type ref, + varchar(900) name: string ref, + int propertyType: @type ref); + +type_alias( + unique int aliasType: @type ref, + int underlyingType: @type ref); + +@literal_type = @string_literal_type | @number_literal_type | @boolean_literal_type | @bigint_literal_type; +@type_with_literal_value = @string_literal_type | @number_literal_type | @bigint_literal_type; +type_literal_value( + unique int typ: @type_with_literal_value ref, + varchar(900) value: string ref); + +signature_types ( + unique int id: @signature_type, + int kind: int ref, + varchar(900) tostring: string ref, + int type_parameters: int ref, + int required_params: int ref +); + +is_abstract_signature( + unique int sig: @signature_type ref +); + +signature_rest_parameter( + unique int sig: @signature_type ref, + int rest_param_arra_type: @type ref +); + +case @signature_type.kind of + 0 = @function_signature_type +| 1 = @constructor_signature_type +; + +#keyset[typ, kind, index] +type_contains_signature ( + int typ: @type ref, + int kind: int ref, // constructor/call/index + int index: int ref, // ordering of overloaded signatures + int sig: @signature_type ref +); + +#keyset[parent, index] +signature_contains_type ( + int child: @type ref, + int parent: @signature_type ref, + int index: int ref +); + +#keyset[sig, index] +signature_parameter_name ( + int sig: @signature_type ref, + int index: int ref, + varchar(900) name: string ref +); + +number_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +string_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +base_type_names( + int typeName: @symbol ref, + int baseTypeName: @symbol ref +); + +self_types( + int typeName: @symbol ref, + int selfType: @type_reference ref +); + +tuple_type_min_length( + unique int typ: @type ref, + int minLength: int ref +); + +tuple_type_rest_index( + unique int typ: @type ref, + int index: int ref +); + +// comments +comments (unique int id: @comment, + int kind: int ref, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(900) tostring: string ref); + +case @comment.kind of + 0 = @slashslash_comment +| 1 = @slashstar_comment +| 2 = @doc_comment +| 3 = @html_comment_start +| 4 = @htmlcommentend; + +@html_comment = @html_comment_start | @htmlcommentend; +@line_comment = @slashslash_comment | @html_comment; +@block_comment = @slashstar_comment | @doc_comment; + +// source lines +lines (unique int id: @line, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(2) terminator: string ref); +indentation (int file: @file ref, + int lineno: int ref, + varchar(1) indentChar: string ref, + int indentDepth: int ref); + +// JavaScript parse errors +js_parse_errors (unique int id: @js_parse_error, + int toplevel: @toplevel ref, + varchar(900) message: string ref, + varchar(900) line: string ref); + +// regular expressions +#keyset[parent, idx] +regexpterm (unique int id: @regexpterm, + int kind: int ref, + int parent: @regexpparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +@regexpparent = @regexpterm | @regexp_literal | @string_literal; + +case @regexpterm.kind of + 0 = @regexp_alt +| 1 = @regexp_seq +| 2 = @regexp_caret +| 3 = @regexp_dollar +| 4 = @regexp_wordboundary +| 5 = @regexp_nonwordboundary +| 6 = @regexp_positive_lookahead +| 7 = @regexp_negative_lookahead +| 8 = @regexp_star +| 9 = @regexp_plus +| 10 = @regexp_opt +| 11 = @regexp_range +| 12 = @regexp_dot +| 13 = @regexp_group +| 14 = @regexp_normal_constant +| 15 = @regexp_hex_escape +| 16 = @regexp_unicode_escape +| 17 = @regexp_dec_escape +| 18 = @regexp_oct_escape +| 19 = @regexp_ctrl_escape +| 20 = @regexp_char_class_escape +| 21 = @regexp_id_escape +| 22 = @regexp_backref +| 23 = @regexp_char_class +| 24 = @regexp_char_range +| 25 = @regexp_positive_lookbehind +| 26 = @regexp_negative_lookbehind +| 27 = @regexp_unicode_property_escape; + +regexp_parse_errors (unique int id: @regexp_parse_error, + int regexp: @regexpterm ref, + varchar(900) message: string ref); + +@regexp_quantifier = @regexp_star | @regexp_plus | @regexp_opt | @regexp_range; +@regexp_escape = @regexp_char_escape | @regexp_char_class_escape | @regexp_unicode_property_escape; +@regexp_char_escape = @regexp_hex_escape | @regexp_unicode_escape | @regexp_dec_escape | @regexp_oct_escape | @regexp_ctrl_escape | @regexp_id_escape; +@regexp_constant = @regexp_normal_constant | @regexp_char_escape; +@regexp_lookahead = @regexp_positive_lookahead | @regexp_negative_lookahead; +@regexp_lookbehind = @regexp_positive_lookbehind | @regexp_negative_lookbehind; +@regexp_subpattern = @regexp_lookahead | @regexp_lookbehind; +@regexp_anchor = @regexp_dollar | @regexp_caret; + +is_greedy (int id: @regexp_quantifier ref); +range_quantifier_lower_bound (unique int id: @regexp_range ref, int lo: int ref); +range_quantifier_upper_bound (unique int id: @regexp_range ref, int hi: int ref); +is_capture (unique int id: @regexp_group ref, int number: int ref); +is_named_capture (unique int id: @regexp_group ref, string name: string ref); +is_inverted (int id: @regexp_char_class ref); +regexp_const_value (unique int id: @regexp_constant ref, varchar(1) value: string ref); +char_class_escape (unique int id: @regexp_char_class_escape ref, varchar(1) value: string ref); +backref (unique int id: @regexp_backref ref, int value: int ref); +named_backref (unique int id: @regexp_backref ref, string name: string ref); +unicode_property_escapename (unique int id: @regexp_unicode_property_escape ref, string name: string ref); +unicode_property_escapevalue (unique int id: @regexp_unicode_property_escape ref, string value: string ref); + +// tokens +#keyset[toplevel, idx] +tokeninfo (unique int id: @token, + int kind: int ref, + int toplevel: @toplevel ref, + int idx: int ref, + varchar(900) value: string ref); + +case @token.kind of + 0 = @token_eof +| 1 = @token_null_literal +| 2 = @token_boolean_literal +| 3 = @token_numeric_literal +| 4 = @token_string_literal +| 5 = @token_regular_expression +| 6 = @token_identifier +| 7 = @token_keyword +| 8 = @token_punctuator; + +// associate comments with the token immediately following them (which may be EOF) +next_token (int comment: @comment ref, int token: @token ref); + +// JSON +#keyset[parent, idx] +json (unique int id: @json_value, + int kind: int ref, + int parent: @json_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +json_literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @json_value ref); + +json_properties (int obj: @json_object ref, + varchar(900) property: string ref, + int value: @json_value ref); + +json_errors (unique int id: @json_parse_error, + varchar(900) message: string ref); + +json_locations(unique int locatable: @json_locatable ref, + int location: @location_default ref); + +case @json_value.kind of + 0 = @json_null +| 1 = @json_boolean +| 2 = @json_number +| 3 = @json_string +| 4 = @json_array +| 5 = @json_object; + +@json_parent = @json_object | @json_array | @file; + +@json_locatable = @json_value | @json_parse_error; + +// locations +@ast_node = @toplevel | @stmt | @expr | @property | @typeexpr; + +@locatable = @file + | @ast_node + | @comment + | @line + | @js_parse_error | @regexp_parse_error + | @regexpterm + | @json_locatable + | @token + | @cfg_node + | @jsdoc | @jsdoc_type_expr | @jsdoc_tag + | @yaml_locatable + | @xmllocatable + | @configLocatable + | @template_placeholder_tag; + +hasLocation (unique int locatable: @locatable ref, + int location: @location ref); + +// CFG +entry_cfg_node (unique int id: @entry_node, int container: @stmt_container ref); +exit_cfg_node (unique int id: @exit_node, int container: @stmt_container ref); +guard_node (unique int id: @guard_node, int kind: int ref, int test: @expr ref); +case @guard_node.kind of + 0 = @falsy_guard +| 1 = @truthy_guard; +@condition_guard = @falsy_guard | @truthy_guard; + +@synthetic_cfg_node = @entry_node | @exit_node | @guard_node; +@cfg_node = @synthetic_cfg_node | @expr_parent; + +successor (int pred: @cfg_node ref, int succ: @cfg_node ref); + +// JSDoc comments +jsdoc (unique int id: @jsdoc, varchar(900) description: string ref, int comment: @comment ref); +#keyset[parent, idx] +jsdoc_tags (unique int id: @jsdoc_tag, varchar(900) title: string ref, + int parent: @jsdoc ref, int idx: int ref, varchar(900) tostring: string ref); +jsdoc_tag_descriptions (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); +jsdoc_tag_names (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); + +#keyset[parent, idx] +jsdoc_type_exprs (unique int id: @jsdoc_type_expr, + int kind: int ref, + int parent: @jsdoc_type_expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); +case @jsdoc_type_expr.kind of + 0 = @jsdoc_any_type_expr +| 1 = @jsdoc_null_type_expr +| 2 = @jsdoc_undefined_type_expr +| 3 = @jsdoc_unknown_type_expr +| 4 = @jsdoc_void_type_expr +| 5 = @jsdoc_named_type_expr +| 6 = @jsdoc_applied_type_expr +| 7 = @jsdoc_nullable_type_expr +| 8 = @jsdoc_non_nullable_type_expr +| 9 = @jsdoc_record_type_expr +| 10 = @jsdoc_array_type_expr +| 11 = @jsdoc_union_type_expr +| 12 = @jsdoc_function_type_expr +| 13 = @jsdoc_optional_type_expr +| 14 = @jsdoc_rest_type_expr +; + +#keyset[id, idx] +jsdoc_record_field_name (int id: @jsdoc_record_type_expr ref, int idx: int ref, varchar(900) name: string ref); +jsdoc_prefix_qualifier (int id: @jsdoc_type_expr ref); +jsdoc_has_new_parameter (int fn: @jsdoc_function_type_expr ref); + +@jsdoc_type_expr_parent = @jsdoc_type_expr | @jsdoc_tag; + +jsdoc_errors (unique int id: @jsdoc_error, int tag: @jsdoc_tag ref, varchar(900) message: string ref, varchar(900) tostring: string ref); + +// YAML +#keyset[parent, idx] +yaml (unique int id: @yaml_node, + int kind: int ref, + int parent: @yaml_node_parent ref, + int idx: int ref, + varchar(900) tag: string ref, + varchar(900) tostring: string ref); + +case @yaml_node.kind of + 0 = @yaml_scalar_node +| 1 = @yaml_mapping_node +| 2 = @yaml_sequence_node +| 3 = @yaml_alias_node +; + +@yaml_collection_node = @yaml_mapping_node | @yaml_sequence_node; + +@yaml_node_parent = @yaml_collection_node | @file; + +yaml_anchors (unique int node: @yaml_node ref, + varchar(900) anchor: string ref); + +yaml_aliases (unique int alias: @yaml_alias_node ref, + varchar(900) target: string ref); + +yaml_scalars (unique int scalar: @yaml_scalar_node ref, + int style: int ref, + varchar(900) value: string ref); + +yaml_errors (unique int id: @yaml_error, + varchar(900) message: string ref); + +yaml_locations(unique int locatable: @yaml_locatable ref, + int location: @location_default ref); + +@yaml_locatable = @yaml_node | @yaml_error; + +/* XML Files */ + +xmlEncoding( + unique int id: @file ref, + varchar(900) encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +@dataflownode = @expr | @function_decl_stmt | @class_decl_stmt | @namespace_declaration | @enum_declaration | @property; + +@optionalchainable = @call_expr | @propaccess; + +isOptionalChaining(int id: @optionalchainable ref); + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +/** + * The time taken for the extraction of a file. + * This table contains non-deterministic content. + * + * The sum of the `time` column for each (`file`, `timerKind`) pair + * is the total time taken for extraction of `file`. The `extractionPhase` + * column provides a granular view of the extraction time of the file. + */ +extraction_time( + int file : @file ref, + // see `com.semmle.js.extractor.ExtractionMetrics.ExtractionPhase`. + int extractionPhase: int ref, + // 0 for the elapsed CPU time in nanoseconds, 1 for the elapsed wallclock time in nanoseconds + int timerKind: int ref, + float time: float ref +) + +/** + * Non-timing related data for the extraction of a single file. + * This table contains non-deterministic content. + */ +extraction_data( + int file : @file ref, + // the absolute path to the cache file + varchar(900) cacheFile: string ref, + boolean fromCache: boolean ref, + int length: int ref +) diff --git a/javascript/upgrades/e34b3e16dba5d11961119818c9beeff334f20a90/semmlecode.javascript.dbscheme b/javascript/upgrades/e34b3e16dba5d11961119818c9beeff334f20a90/semmlecode.javascript.dbscheme new file mode 100644 index 00000000000..e54b35a8a12 --- /dev/null +++ b/javascript/upgrades/e34b3e16dba5d11961119818c9beeff334f20a90/semmlecode.javascript.dbscheme @@ -0,0 +1,1217 @@ +/*** Standard fragments ***/ + +/** Files and folders **/ + +@location = @location_default; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref + ); + +@sourceline = @locatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref + ); + +files(unique int id: @file, + varchar(900) name: string ref); + +folders(unique int id: @folder, + varchar(900) name: string ref); + + +@container = @folder | @file ; + + +containerparent(int parent: @container ref, + unique int child: @container ref); + +/** Duplicate code **/ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity; + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/** External data **/ + +externalData( + int id : @externalDataElement, + varchar(900) path : string ref, + int column: int ref, + varchar(900) value : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + +/** Version control data **/ + +svnentries( + int id : @svnentry, + varchar(500) revision : string ref, + varchar(500) author : string ref, + date revisionDate : date ref, + int changeSize : int ref +); + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + varchar(500) action : string ref +); + +svnentrymsg( + int id : @svnentry ref, + varchar(500) message : string ref +); + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +); + + +/*** JavaScript-specific part ***/ + +filetype( + int file: @file ref, + string filetype: string ref +) + +// top-level code fragments +toplevels (unique int id: @toplevel, + int kind: int ref); + +is_externs (int toplevel: @toplevel ref); + +case @toplevel.kind of + 0 = @script +| 1 = @inline_script +| 2 = @event_handler +| 3 = @javascript_url +| 4 = @template_toplevel; + +is_module (int tl: @toplevel ref); +is_nodejs (int tl: @toplevel ref); +is_es2015_module (int tl: @toplevel ref); +is_closure_module (int tl: @toplevel ref); + +@xml_node_with_code = @xmlelement | @xmlattribute | @template_placeholder_tag; +toplevel_parent_xml_node( + unique int toplevel: @toplevel ref, + int xmlnode: @xml_node_with_code ref); + +xml_element_parent_expression( + unique int xmlnode: @xmlelement ref, + int expression: @expr ref, + int index: int ref); + +// statements +#keyset[parent, idx] +stmts (unique int id: @stmt, + int kind: int ref, + int parent: @stmt_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +stmt_containers (unique int stmt: @stmt ref, + int container: @stmt_container ref); + +jump_targets (unique int jump: @stmt ref, + int target: @stmt ref); + +@stmt_parent = @stmt | @toplevel | @function_expr | @arrow_function_expr | @static_initializer; +@stmt_container = @toplevel | @function | @namespace_declaration | @external_module_declaration | @global_augmentation_declaration; + +case @stmt.kind of + 0 = @empty_stmt +| 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @labeled_stmt +| 5 = @break_stmt +| 6 = @continue_stmt +| 7 = @with_stmt +| 8 = @switch_stmt +| 9 = @return_stmt +| 10 = @throw_stmt +| 11 = @try_stmt +| 12 = @while_stmt +| 13 = @do_while_stmt +| 14 = @for_stmt +| 15 = @for_in_stmt +| 16 = @debugger_stmt +| 17 = @function_decl_stmt +| 18 = @var_decl_stmt +| 19 = @case +| 20 = @catch_clause +| 21 = @for_of_stmt +| 22 = @const_decl_stmt +| 23 = @let_stmt +| 24 = @legacy_let_stmt +| 25 = @for_each_stmt +| 26 = @class_decl_stmt +| 27 = @import_declaration +| 28 = @export_all_declaration +| 29 = @export_default_declaration +| 30 = @export_named_declaration +| 31 = @namespace_declaration +| 32 = @import_equals_declaration +| 33 = @export_assign_declaration +| 34 = @interface_declaration +| 35 = @type_alias_declaration +| 36 = @enum_declaration +| 37 = @external_module_declaration +| 38 = @export_as_namespace_declaration +| 39 = @global_augmentation_declaration +; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @let_stmt | @legacy_let_stmt; + +@export_declaration = @export_all_declaration | @export_default_declaration | @export_named_declaration; + +@namespace_definition = @namespace_declaration | @enum_declaration; +@type_definition = @class_definition | @interface_declaration | @enum_declaration | @type_alias_declaration | @enum_member; + +is_instantiated(unique int decl: @namespace_declaration ref); + +@declarable_node = @decl_stmt | @namespace_declaration | @class_decl_stmt | @function_decl_stmt | @enum_declaration | @external_module_declaration | @global_augmentation_declaration | @field; +has_declare_keyword(unique int stmt: @declarable_node ref); + +is_for_await_of(unique int forof: @for_of_stmt ref); + +// expressions +#keyset[parent, idx] +exprs (unique int id: @expr, + int kind: int ref, + int parent: @expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @expr_or_type ref); + +enclosing_stmt (unique int expr: @expr_or_type ref, + int stmt: @stmt ref); + +expr_containers (unique int expr: @expr_or_type ref, + int container: @stmt_container ref); + +array_size (unique int ae: @arraylike ref, + int sz: int ref); + +is_delegating (int yield: @yield_expr ref); + +@expr_or_stmt = @expr | @stmt; +@expr_or_type = @expr | @typeexpr; +@expr_parent = @expr_or_stmt | @property | @function_typeexpr; +@arraylike = @array_expr | @array_pattern; +@type_annotation = @typeexpr | @jsdoc_type_expr; +@node_in_stmt_container = @cfg_node | @type_annotation | @toplevel; + +case @expr.kind of + 0 = @label +| 1 = @null_literal +| 2 = @boolean_literal +| 3 = @number_literal +| 4 = @string_literal +| 5 = @regexp_literal +| 6 = @this_expr +| 7 = @array_expr +| 8 = @obj_expr +| 9 = @function_expr +| 10 = @seq_expr +| 11 = @conditional_expr +| 12 = @new_expr +| 13 = @call_expr +| 14 = @dot_expr +| 15 = @index_expr +| 16 = @neg_expr +| 17 = @plus_expr +| 18 = @log_not_expr +| 19 = @bit_not_expr +| 20 = @typeof_expr +| 21 = @void_expr +| 22 = @delete_expr +| 23 = @eq_expr +| 24 = @neq_expr +| 25 = @eqq_expr +| 26 = @neqq_expr +| 27 = @lt_expr +| 28 = @le_expr +| 29 = @gt_expr +| 30 = @ge_expr +| 31 = @lshift_expr +| 32 = @rshift_expr +| 33 = @urshift_expr +| 34 = @add_expr +| 35 = @sub_expr +| 36 = @mul_expr +| 37 = @div_expr +| 38 = @mod_expr +| 39 = @bitor_expr +| 40 = @xor_expr +| 41 = @bitand_expr +| 42 = @in_expr +| 43 = @instanceof_expr +| 44 = @logand_expr +| 45 = @logor_expr +| 47 = @assign_expr +| 48 = @assign_add_expr +| 49 = @assign_sub_expr +| 50 = @assign_mul_expr +| 51 = @assign_div_expr +| 52 = @assign_mod_expr +| 53 = @assign_lshift_expr +| 54 = @assign_rshift_expr +| 55 = @assign_urshift_expr +| 56 = @assign_or_expr +| 57 = @assign_xor_expr +| 58 = @assign_and_expr +| 59 = @preinc_expr +| 60 = @postinc_expr +| 61 = @predec_expr +| 62 = @postdec_expr +| 63 = @par_expr +| 64 = @var_declarator +| 65 = @arrow_function_expr +| 66 = @spread_element +| 67 = @array_pattern +| 68 = @object_pattern +| 69 = @yield_expr +| 70 = @tagged_template_expr +| 71 = @template_literal +| 72 = @template_element +| 73 = @array_comprehension_expr +| 74 = @generator_expr +| 75 = @for_in_comprehension_block +| 76 = @for_of_comprehension_block +| 77 = @legacy_letexpr +| 78 = @var_decl +| 79 = @proper_varaccess +| 80 = @class_expr +| 81 = @super_expr +| 82 = @newtarget_expr +| 83 = @named_import_specifier +| 84 = @import_default_specifier +| 85 = @import_namespace_specifier +| 86 = @named_export_specifier +| 87 = @exp_expr +| 88 = @assign_exp_expr +| 89 = @jsx_element +| 90 = @jsx_qualified_name +| 91 = @jsx_empty_expr +| 92 = @await_expr +| 93 = @function_sent_expr +| 94 = @decorator +| 95 = @export_default_specifier +| 96 = @export_namespace_specifier +| 97 = @bind_expr +| 98 = @external_module_reference +| 99 = @dynamic_import +| 100 = @expression_with_type_arguments +| 101 = @prefix_type_assertion +| 102 = @as_type_assertion +| 103 = @export_varaccess +| 104 = @decorator_list +| 105 = @non_null_assertion +| 106 = @bigint_literal +| 107 = @nullishcoalescing_expr +| 108 = @e4x_xml_anyname +| 109 = @e4x_xml_static_attribute_selector +| 110 = @e4x_xml_dynamic_attribute_selector +| 111 = @e4x_xml_filter_expression +| 112 = @e4x_xml_static_qualident +| 113 = @e4x_xml_dynamic_qualident +| 114 = @e4x_xml_dotdotexpr +| 115 = @import_meta_expr +| 116 = @assignlogandexpr +| 117 = @assignlogorexpr +| 118 = @assignnullishcoalescingexpr +| 119 = @template_pipe_ref +| 120 = @generated_code_expr +; + +@varaccess = @proper_varaccess | @export_varaccess; +@varref = @var_decl | @varaccess; + +@identifier = @label | @varref | @type_identifier; + +@literal = @null_literal | @boolean_literal | @number_literal | @string_literal | @regexp_literal | @bigint_literal; + +@propaccess = @dot_expr | @index_expr; + +@invokeexpr = @new_expr | @call_expr; + +@unaryexpr = @neg_expr | @plus_expr | @log_not_expr | @bit_not_expr | @typeof_expr | @void_expr | @delete_expr | @spread_element; + +@equality_test = @eq_expr | @neq_expr | @eqq_expr | @neqq_expr; + +@comparison = @equality_test | @lt_expr | @le_expr | @gt_expr | @ge_expr; + +@binaryexpr = @comparison | @lshift_expr | @rshift_expr | @urshift_expr | @add_expr | @sub_expr | @mul_expr | @div_expr | @mod_expr | @exp_expr | @bitor_expr | @xor_expr | @bitand_expr | @in_expr | @instanceof_expr | @logand_expr | @logor_expr | @nullishcoalescing_expr; + +@assignment = @assign_expr | @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr | @assign_mod_expr | @assign_exp_expr | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr | @assign_or_expr | @assign_xor_expr | @assign_and_expr | @assignlogandexpr | @assignlogorexpr | @assignnullishcoalescingexpr; + +@updateexpr = @preinc_expr | @postinc_expr | @predec_expr | @postdec_expr; + +@pattern = @varref | @array_pattern | @object_pattern; + +@comprehension_expr = @array_comprehension_expr | @generator_expr; + +@comprehension_block = @for_in_comprehension_block | @for_of_comprehension_block; + +@import_specifier = @named_import_specifier | @import_default_specifier | @import_namespace_specifier; + +@exportspecifier = @named_export_specifier | @export_default_specifier | @export_namespace_specifier; + +@import_or_export_declaration = @import_declaration | @export_declaration; + +@type_assertion = @as_type_assertion | @prefix_type_assertion; + +@class_definition = @class_decl_stmt | @class_expr; +@interface_definition = @interface_declaration | @interface_typeexpr; +@class_or_interface = @class_definition | @interface_definition; + +@lexical_decl = @var_decl | @type_decl; +@lexical_access = @varaccess | @local_type_access | @local_var_type_access | @local_namespace_access; +@lexical_ref = @lexical_decl | @lexical_access; + +@e4x_xml_attribute_selector = @e4x_xml_static_attribute_selector | @e4x_xml_dynamic_attribute_selector; +@e4x_xml_qualident = @e4x_xml_static_qualident | @e4x_xml_dynamic_qualident; + +expr_contains_template_tag_location( + int expr: @expr ref, + int location: @location ref +); + +@template_placeholder_tag_parent = @xmlelement | @xmlattribute | @file; + +template_placeholder_tag_info( + unique int node: @template_placeholder_tag, + int parentNode: @template_placeholder_tag_parent ref, + varchar(900) raw: string ref +); + +// scopes +scopes (unique int id: @scope, + int kind: int ref); + +case @scope.kind of + 0 = @global_scope +| 1 = @function_scope +| 2 = @catch_scope +| 3 = @module_scope +| 4 = @block_scope +| 5 = @for_scope +| 6 = @for_in_scope // for-of scopes work the same as for-in scopes +| 7 = @comprehension_block_scope +| 8 = @class_expr_scope +| 9 = @namespace_scope +| 10 = @class_decl_scope +| 11 = @interface_scope +| 12 = @type_alias_scope +| 13 = @mapped_type_scope +| 14 = @enum_scope +| 15 = @external_module_scope +| 16 = @conditional_type_scope; + +scopenodes (unique int node: @ast_node ref, + int scope: @scope ref); + +scopenesting (unique int inner: @scope ref, + int outer: @scope ref); + +// functions +@function = @function_decl_stmt | @function_expr | @arrow_function_expr; + +@parameterized = @function | @catch_clause; +@type_parameterized = @function | @class_or_interface | @type_alias_declaration | @mapped_typeexpr | @infer_typeexpr; + +is_generator (int fun: @function ref); +has_rest_parameter (int fun: @function ref); +is_async (int fun: @function ref); + +// variables and lexically scoped type names +#keyset[scope, name] +variables (unique int id: @variable, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_type_names (unique int id: @local_type_name, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_namespace_names (unique int id: @local_namespace_name, + varchar(900) name: string ref, + int scope: @scope ref); + +is_arguments_object (int id: @variable ref); + +@lexical_name = @variable | @local_type_name | @local_namespace_name; + +@bind_id = @varaccess | @local_var_type_access; +bind (unique int id: @bind_id ref, + int decl: @variable ref); + +decl (unique int id: @var_decl ref, + int decl: @variable ref); + +@typebind_id = @local_type_access | @export_varaccess; +typebind (unique int id: @typebind_id ref, + int decl: @local_type_name ref); + +@typedecl_id = @type_decl | @var_decl; +typedecl (unique int id: @typedecl_id ref, + int decl: @local_type_name ref); + +namespacedecl (unique int id: @var_decl ref, + int decl: @local_namespace_name ref); + +@namespacebind_id = @local_namespace_access | @export_varaccess; +namespacebind (unique int id: @namespacebind_id ref, + int decl: @local_namespace_name ref); + + +// properties in object literals, property patterns in object patterns, and method declarations in classes +#keyset[parent, index] +properties (unique int id: @property, + int parent: @property_parent ref, + int index: int ref, + int kind: int ref, + varchar(900) tostring: string ref); + +case @property.kind of + 0 = @value_property +| 1 = @property_getter +| 2 = @property_setter +| 3 = @jsx_attribute +| 4 = @function_call_signature +| 5 = @constructor_call_signature +| 6 = @index_signature +| 7 = @enum_member +| 8 = @proper_field +| 9 = @parameter_field +| 10 = @static_initializer +; + +@property_parent = @obj_expr | @object_pattern | @class_definition | @jsx_element | @interface_definition | @enum_declaration; +@property_accessor = @property_getter | @property_setter; +@call_signature = @function_call_signature | @constructor_call_signature; +@field = @proper_field | @parameter_field; +@field_or_vardeclarator = @field | @var_declarator; + +is_computed (int id: @property ref); +is_method (int id: @property ref); +is_static (int id: @property ref); +is_abstract_member (int id: @property ref); +is_const_enum (int id: @enum_declaration ref); +is_abstract_class (int id: @class_decl_stmt ref); + +has_public_keyword (int id: @property ref); +has_private_keyword (int id: @property ref); +has_protected_keyword (int id: @property ref); +has_readonly_keyword (int id: @property ref); +has_type_keyword (int id: @import_or_export_declaration ref); +is_optional_member (int id: @property ref); +has_definite_assignment_assertion (int id: @field_or_vardeclarator ref); +is_optional_parameter_declaration (unique int parameter: @pattern ref); + +#keyset[constructor, param_index] +parameter_fields( + unique int field: @parameter_field ref, + int constructor: @function_expr ref, + int param_index: int ref +); + +// types +#keyset[parent, idx] +typeexprs ( + unique int id: @typeexpr, + int kind: int ref, + int parent: @typeexpr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref +); + +case @typeexpr.kind of + 0 = @local_type_access +| 1 = @type_decl +| 2 = @keyword_typeexpr +| 3 = @string_literal_typeexpr +| 4 = @number_literal_typeexpr +| 5 = @boolean_literal_typeexpr +| 6 = @array_typeexpr +| 7 = @union_typeexpr +| 8 = @indexed_access_typeexpr +| 9 = @intersection_typeexpr +| 10 = @parenthesized_typeexpr +| 11 = @tuple_typeexpr +| 12 = @keyof_typeexpr +| 13 = @qualified_type_access +| 14 = @generic_typeexpr +| 15 = @type_label +| 16 = @typeof_typeexpr +| 17 = @local_var_type_access +| 18 = @qualified_var_type_access +| 19 = @this_var_type_access +| 20 = @predicate_typeexpr +| 21 = @interface_typeexpr +| 22 = @type_parameter +| 23 = @plain_function_typeexpr +| 24 = @constructor_typeexpr +| 25 = @local_namespace_access +| 26 = @qualified_namespace_access +| 27 = @mapped_typeexpr +| 28 = @conditional_typeexpr +| 29 = @infer_typeexpr +| 30 = @import_type_access +| 31 = @import_namespace_access +| 32 = @import_var_type_access +| 33 = @optional_typeexpr +| 34 = @rest_typeexpr +| 35 = @bigint_literal_typeexpr +| 36 = @readonly_typeexpr +| 37 = @template_literal_typeexpr +; + +@typeref = @typeaccess | @type_decl; +@type_identifier = @type_decl | @local_type_access | @type_label | @local_var_type_access | @local_namespace_access; +@typeexpr_parent = @expr | @stmt | @property | @typeexpr; +@literal_typeexpr = @string_literal_typeexpr | @number_literal_typeexpr | @boolean_literal_typeexpr | @bigint_literal_typeexpr; +@typeaccess = @local_type_access | @qualified_type_access | @import_type_access; +@vartypeaccess = @local_var_type_access | @qualified_var_type_access | @this_var_type_access | @import_var_type_access; +@namespace_access = @local_namespace_access | @qualified_namespace_access | @import_namespace_access; +@import_typeexpr = @import_type_access | @import_namespace_access | @import_var_type_access; + +@function_typeexpr = @plain_function_typeexpr | @constructor_typeexpr; + +// types +types ( + unique int id: @type, + int kind: int ref, + varchar(900) tostring: string ref +); + +#keyset[parent, idx] +type_child ( + int child: @type ref, + int parent: @type ref, + int idx: int ref +); + +case @type.kind of + 0 = @any_type +| 1 = @string_type +| 2 = @number_type +| 3 = @union_type +| 4 = @true_type +| 5 = @false_type +| 6 = @type_reference +| 7 = @object_type +| 8 = @canonical_type_variable_type +| 9 = @typeof_type +| 10 = @void_type +| 11 = @undefined_type +| 12 = @null_type +| 13 = @never_type +| 14 = @plain_symbol_type +| 15 = @unique_symbol_type +| 16 = @objectkeyword_type +| 17 = @intersection_type +| 18 = @tuple_type +| 19 = @lexical_type_variable_type +| 20 = @this_type +| 21 = @number_literal_type +| 22 = @string_literal_type +| 23 = @unknown_type +| 24 = @bigint_type +| 25 = @bigint_literal_type +; + +@boolean_literal_type = @true_type | @false_type; +@symbol_type = @plain_symbol_type | @unique_symbol_type; +@union_or_intersection_type = @union_type | @intersection_type; +@typevariable_type = @canonical_type_variable_type | @lexical_type_variable_type; + +has_asserts_keyword(int node: @predicate_typeexpr ref); + +@typed_ast_node = @expr | @typeexpr | @function; +ast_node_type( + unique int node: @typed_ast_node ref, + int typ: @type ref); + +declared_function_signature( + unique int node: @function ref, + int sig: @signature_type ref +); + +invoke_expr_signature( + unique int node: @invokeexpr ref, + int sig: @signature_type ref +); + +invoke_expr_overload_index( + unique int node: @invokeexpr ref, + int index: int ref +); + +symbols ( + unique int id: @symbol, + int kind: int ref, + varchar(900) name: string ref +); + +symbol_parent ( + unique int symbol: @symbol ref, + int parent: @symbol ref +); + +symbol_module ( + int symbol: @symbol ref, + varchar(900) moduleName: string ref +); + +symbol_global ( + int symbol: @symbol ref, + varchar(900) globalName: string ref +); + +case @symbol.kind of + 0 = @root_symbol +| 1 = @member_symbol +| 2 = @other_symbol +; + +@type_with_symbol = @type_reference | @typevariable_type | @typeof_type | @unique_symbol_type; +@ast_node_with_symbol = @type_definition | @namespace_definition | @toplevel | @typeaccess | @namespace_access | @var_decl | @function | @invokeexpr | @import_declaration | @external_module_reference; + +ast_node_symbol( + unique int node: @ast_node_with_symbol ref, + int symbol: @symbol ref); + +type_symbol( + unique int typ: @type_with_symbol ref, + int symbol: @symbol ref); + +#keyset[typ, name] +type_property( + int typ: @type ref, + varchar(900) name: string ref, + int propertyType: @type ref); + +type_alias( + unique int aliasType: @type ref, + int underlyingType: @type ref); + +@literal_type = @string_literal_type | @number_literal_type | @boolean_literal_type | @bigint_literal_type; +@type_with_literal_value = @string_literal_type | @number_literal_type | @bigint_literal_type; +type_literal_value( + unique int typ: @type_with_literal_value ref, + varchar(900) value: string ref); + +signature_types ( + unique int id: @signature_type, + int kind: int ref, + varchar(900) tostring: string ref, + int type_parameters: int ref, + int required_params: int ref +); + +is_abstract_signature( + unique int sig: @signature_type ref +); + +signature_rest_parameter( + unique int sig: @signature_type ref, + int rest_param_arra_type: @type ref +); + +case @signature_type.kind of + 0 = @function_signature_type +| 1 = @constructor_signature_type +; + +#keyset[typ, kind, index] +type_contains_signature ( + int typ: @type ref, + int kind: int ref, // constructor/call/index + int index: int ref, // ordering of overloaded signatures + int sig: @signature_type ref +); + +#keyset[parent, index] +signature_contains_type ( + int child: @type ref, + int parent: @signature_type ref, + int index: int ref +); + +#keyset[sig, index] +signature_parameter_name ( + int sig: @signature_type ref, + int index: int ref, + varchar(900) name: string ref +); + +number_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +string_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +base_type_names( + int typeName: @symbol ref, + int baseTypeName: @symbol ref +); + +self_types( + int typeName: @symbol ref, + int selfType: @type_reference ref +); + +tuple_type_min_length( + unique int typ: @type ref, + int minLength: int ref +); + +tuple_type_rest_index( + unique int typ: @type ref, + int index: int ref +); + +// comments +comments (unique int id: @comment, + int kind: int ref, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(900) tostring: string ref); + +case @comment.kind of + 0 = @slashslash_comment +| 1 = @slashstar_comment +| 2 = @doc_comment +| 3 = @html_comment_start +| 4 = @htmlcommentend; + +@html_comment = @html_comment_start | @htmlcommentend; +@line_comment = @slashslash_comment | @html_comment; +@block_comment = @slashstar_comment | @doc_comment; + +// source lines +lines (unique int id: @line, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(2) terminator: string ref); +indentation (int file: @file ref, + int lineno: int ref, + varchar(1) indentChar: string ref, + int indentDepth: int ref); + +// JavaScript parse errors +js_parse_errors (unique int id: @js_parse_error, + int toplevel: @toplevel ref, + varchar(900) message: string ref, + varchar(900) line: string ref); + +// regular expressions +#keyset[parent, idx] +regexpterm (unique int id: @regexpterm, + int kind: int ref, + int parent: @regexpparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +@regexpparent = @regexpterm | @regexp_literal | @string_literal; + +case @regexpterm.kind of + 0 = @regexp_alt +| 1 = @regexp_seq +| 2 = @regexp_caret +| 3 = @regexp_dollar +| 4 = @regexp_wordboundary +| 5 = @regexp_nonwordboundary +| 6 = @regexp_positive_lookahead +| 7 = @regexp_negative_lookahead +| 8 = @regexp_star +| 9 = @regexp_plus +| 10 = @regexp_opt +| 11 = @regexp_range +| 12 = @regexp_dot +| 13 = @regexp_group +| 14 = @regexp_normal_constant +| 15 = @regexp_hex_escape +| 16 = @regexp_unicode_escape +| 17 = @regexp_dec_escape +| 18 = @regexp_oct_escape +| 19 = @regexp_ctrl_escape +| 20 = @regexp_char_class_escape +| 21 = @regexp_id_escape +| 22 = @regexp_backref +| 23 = @regexp_char_class +| 24 = @regexp_char_range +| 25 = @regexp_positive_lookbehind +| 26 = @regexp_negative_lookbehind +| 27 = @regexp_unicode_property_escape; + +regexp_parse_errors (unique int id: @regexp_parse_error, + int regexp: @regexpterm ref, + varchar(900) message: string ref); + +@regexp_quantifier = @regexp_star | @regexp_plus | @regexp_opt | @regexp_range; +@regexp_escape = @regexp_char_escape | @regexp_char_class_escape | @regexp_unicode_property_escape; +@regexp_char_escape = @regexp_hex_escape | @regexp_unicode_escape | @regexp_dec_escape | @regexp_oct_escape | @regexp_ctrl_escape | @regexp_id_escape; +@regexp_constant = @regexp_normal_constant | @regexp_char_escape; +@regexp_lookahead = @regexp_positive_lookahead | @regexp_negative_lookahead; +@regexp_lookbehind = @regexp_positive_lookbehind | @regexp_negative_lookbehind; +@regexp_subpattern = @regexp_lookahead | @regexp_lookbehind; +@regexp_anchor = @regexp_dollar | @regexp_caret; + +is_greedy (int id: @regexp_quantifier ref); +range_quantifier_lower_bound (unique int id: @regexp_range ref, int lo: int ref); +range_quantifier_upper_bound (unique int id: @regexp_range ref, int hi: int ref); +is_capture (unique int id: @regexp_group ref, int number: int ref); +is_named_capture (unique int id: @regexp_group ref, string name: string ref); +is_inverted (int id: @regexp_char_class ref); +regexp_const_value (unique int id: @regexp_constant ref, varchar(1) value: string ref); +char_class_escape (unique int id: @regexp_char_class_escape ref, varchar(1) value: string ref); +backref (unique int id: @regexp_backref ref, int value: int ref); +named_backref (unique int id: @regexp_backref ref, string name: string ref); +unicode_property_escapename (unique int id: @regexp_unicode_property_escape ref, string name: string ref); +unicode_property_escapevalue (unique int id: @regexp_unicode_property_escape ref, string value: string ref); + +// tokens +#keyset[toplevel, idx] +tokeninfo (unique int id: @token, + int kind: int ref, + int toplevel: @toplevel ref, + int idx: int ref, + varchar(900) value: string ref); + +case @token.kind of + 0 = @token_eof +| 1 = @token_null_literal +| 2 = @token_boolean_literal +| 3 = @token_numeric_literal +| 4 = @token_string_literal +| 5 = @token_regular_expression +| 6 = @token_identifier +| 7 = @token_keyword +| 8 = @token_punctuator; + +// associate comments with the token immediately following them (which may be EOF) +next_token (int comment: @comment ref, int token: @token ref); + +// JSON +#keyset[parent, idx] +json (unique int id: @json_value, + int kind: int ref, + int parent: @json_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +json_literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @json_value ref); + +json_properties (int obj: @json_object ref, + varchar(900) property: string ref, + int value: @json_value ref); + +json_errors (unique int id: @json_parse_error, + varchar(900) message: string ref); + +json_locations(unique int locatable: @json_locatable ref, + int location: @location_default ref); + +case @json_value.kind of + 0 = @json_null +| 1 = @json_boolean +| 2 = @json_number +| 3 = @json_string +| 4 = @json_array +| 5 = @json_object; + +@json_parent = @json_object | @json_array | @file; + +@json_locatable = @json_value | @json_parse_error; + +// locations +@ast_node = @toplevel | @stmt | @expr | @property | @typeexpr; + +@locatable = @file + | @ast_node + | @comment + | @line + | @js_parse_error | @regexp_parse_error + | @regexpterm + | @json_locatable + | @token + | @cfg_node + | @jsdoc | @jsdoc_type_expr | @jsdoc_tag + | @yaml_locatable + | @xmllocatable + | @configLocatable + | @template_placeholder_tag; + +hasLocation (unique int locatable: @locatable ref, + int location: @location ref); + +// CFG +entry_cfg_node (unique int id: @entry_node, int container: @stmt_container ref); +exit_cfg_node (unique int id: @exit_node, int container: @stmt_container ref); +guard_node (unique int id: @guard_node, int kind: int ref, int test: @expr ref); +case @guard_node.kind of + 0 = @falsy_guard +| 1 = @truthy_guard; +@condition_guard = @falsy_guard | @truthy_guard; + +@synthetic_cfg_node = @entry_node | @exit_node | @guard_node; +@cfg_node = @synthetic_cfg_node | @expr_parent; + +successor (int pred: @cfg_node ref, int succ: @cfg_node ref); + +// JSDoc comments +jsdoc (unique int id: @jsdoc, varchar(900) description: string ref, int comment: @comment ref); +#keyset[parent, idx] +jsdoc_tags (unique int id: @jsdoc_tag, varchar(900) title: string ref, + int parent: @jsdoc ref, int idx: int ref, varchar(900) tostring: string ref); +jsdoc_tag_descriptions (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); +jsdoc_tag_names (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); + +#keyset[parent, idx] +jsdoc_type_exprs (unique int id: @jsdoc_type_expr, + int kind: int ref, + int parent: @jsdoc_type_expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); +case @jsdoc_type_expr.kind of + 0 = @jsdoc_any_type_expr +| 1 = @jsdoc_null_type_expr +| 2 = @jsdoc_undefined_type_expr +| 3 = @jsdoc_unknown_type_expr +| 4 = @jsdoc_void_type_expr +| 5 = @jsdoc_named_type_expr +| 6 = @jsdoc_applied_type_expr +| 7 = @jsdoc_nullable_type_expr +| 8 = @jsdoc_non_nullable_type_expr +| 9 = @jsdoc_record_type_expr +| 10 = @jsdoc_array_type_expr +| 11 = @jsdoc_union_type_expr +| 12 = @jsdoc_function_type_expr +| 13 = @jsdoc_optional_type_expr +| 14 = @jsdoc_rest_type_expr +; + +#keyset[id, idx] +jsdoc_record_field_name (int id: @jsdoc_record_type_expr ref, int idx: int ref, varchar(900) name: string ref); +jsdoc_prefix_qualifier (int id: @jsdoc_type_expr ref); +jsdoc_has_new_parameter (int fn: @jsdoc_function_type_expr ref); + +@jsdoc_type_expr_parent = @jsdoc_type_expr | @jsdoc_tag; + +jsdoc_errors (unique int id: @jsdoc_error, int tag: @jsdoc_tag ref, varchar(900) message: string ref, varchar(900) tostring: string ref); + +// YAML +#keyset[parent, idx] +yaml (unique int id: @yaml_node, + int kind: int ref, + int parent: @yaml_node_parent ref, + int idx: int ref, + varchar(900) tag: string ref, + varchar(900) tostring: string ref); + +case @yaml_node.kind of + 0 = @yaml_scalar_node +| 1 = @yaml_mapping_node +| 2 = @yaml_sequence_node +| 3 = @yaml_alias_node +; + +@yaml_collection_node = @yaml_mapping_node | @yaml_sequence_node; + +@yaml_node_parent = @yaml_collection_node | @file; + +yaml_anchors (unique int node: @yaml_node ref, + varchar(900) anchor: string ref); + +yaml_aliases (unique int alias: @yaml_alias_node ref, + varchar(900) target: string ref); + +yaml_scalars (unique int scalar: @yaml_scalar_node ref, + int style: int ref, + varchar(900) value: string ref); + +yaml_errors (unique int id: @yaml_error, + varchar(900) message: string ref); + +yaml_locations(unique int locatable: @yaml_locatable ref, + int location: @location_default ref); + +@yaml_locatable = @yaml_node | @yaml_error; + +/* XML Files */ + +xmlEncoding( + unique int id: @file ref, + varchar(900) encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +@dataflownode = @expr | @function_decl_stmt | @class_decl_stmt | @namespace_declaration | @enum_declaration | @property; + +@optionalchainable = @call_expr | @propaccess; + +isOptionalChaining(int id: @optionalchainable ref); + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +/** + * The time taken for the extraction of a file. + * This table contains non-deterministic content. + * + * The sum of the `time` column for each (`file`, `timerKind`) pair + * is the total time taken for extraction of `file`. The `extractionPhase` + * column provides a granular view of the extraction time of the file. + */ +extraction_time( + int file : @file ref, + // see `com.semmle.js.extractor.ExtractionMetrics.ExtractionPhase`. + int extractionPhase: int ref, + // 0 for the elapsed CPU time in nanoseconds, 1 for the elapsed wallclock time in nanoseconds + int timerKind: int ref, + float time: float ref +) + +/** + * Non-timing related data for the extraction of a single file. + * This table contains non-deterministic content. + */ +extraction_data( + int file : @file ref, + // the absolute path to the cache file + varchar(900) cacheFile: string ref, + boolean fromCache: boolean ref, + int length: int ref +) diff --git a/javascript/upgrades/e34b3e16dba5d11961119818c9beeff334f20a90/upgrade.properties b/javascript/upgrades/e34b3e16dba5d11961119818c9beeff334f20a90/upgrade.properties new file mode 100644 index 00000000000..736a282f9fa --- /dev/null +++ b/javascript/upgrades/e34b3e16dba5d11961119818c9beeff334f20a90/upgrade.properties @@ -0,0 +1,2 @@ +description: add @static_initializer property kind +compatibility: backwards diff --git a/misc/scripts/library-coverage/generate-timeseries.py b/misc/scripts/library-coverage/generate-timeseries.py index bfba9362ff2..49bade6ba03 100644 --- a/misc/scripts/library-coverage/generate-timeseries.py +++ b/misc/scripts/library-coverage/generate-timeseries.py @@ -41,14 +41,15 @@ class Git: return (parent_sha, parent_date) -def get_packages(lang, query, search_path): +def get_packages(config, search_path): try: - db = "empty_" + lang - ql_output = "output-" + lang + ".csv" + db = "empty_" + config.lang + ql_output = "output-" + config.lang + ".csv" if os.path.isdir(db): shutil.rmtree(db) - utils.create_empty_database(lang, ".java", db) - utils.run_codeql_query(query, db, ql_output, search_path) + utils.create_empty_database( + config.lang, config.ext, db, config.dbscheme) + utils.run_codeql_query(config.ql_path, db, ql_output, search_path) return pack.PackageCollection(ql_output) except: @@ -71,9 +72,9 @@ else: configs = [ utils.LanguageConfig( - "java", "Java", ".java", "java/ql/src/meta/frameworks/Coverage.ql"), + "java", "Java", ".java", "java/ql/src/meta/frameworks/Coverage.ql", ["java/ql/lib/config/semmlecode.dbscheme", "java/ql/src/config/semmlecode.dbscheme"]), utils.LanguageConfig( - "csharp", "C#", ".cs", "csharp/ql/src/meta/frameworks/Coverage.ql") + "csharp", "C#", ".cs", "csharp/ql/src/meta/frameworks/Coverage.ql", ["csharp/ql/lib/semmlecode.csharp.dbscheme", "csharp/ql/src/semmlecode.csharp.dbscheme"]) ] output_prefix = "framework-coverage-timeseries-" @@ -102,7 +103,8 @@ for lang in settings.languages: "file_total": file_total, "file_packages": file_packages, "csvwriter_total": csvwriter_total, - "csvwriter_packages": csvwriter_packages + "csvwriter_packages": csvwriter_packages, + "last_row": (None, None, None) } try: @@ -141,15 +143,20 @@ try: frameworks: fr.FrameworkCollection = language_utils[lang]["frameworks"] csvwriter_total = language_utils[lang]["csvwriter_total"] csvwriter_packages = language_utils[lang]["csvwriter_packages"] + last_row = language_utils[lang]["last_row"] - packages = get_packages(lang, config.ql_path, ".") + packages = get_packages(config, ".") - csvwriter_total.writerow([ - current_sha, - current_date, - packages.get_part_count("source"), - packages.get_part_count("sink"), - packages.get_part_count("summary")]) + new_row = (packages.get_part_count("source"), + packages.get_part_count("sink"), + packages.get_part_count("summary")) + + if last_row != new_row: + csvwriter_total.writerow([ + current_sha, + current_date, + new_row[0], new_row[1], new_row[2]]) + language_utils[lang]["last_row"] = new_row matched_packages = set() @@ -158,7 +165,7 @@ try: framework: fr.Framework = framework row = [current_sha, current_date, - framework.name, framework.package_pattern] + framework.name, ", ".join(sorted(framework.package_pattern.split(" ")))] sources = 0 sinks = 0 diff --git a/misc/scripts/library-coverage/utils.py b/misc/scripts/library-coverage/utils.py index b0a55b536d4..b016903cb3d 100644 --- a/misc/scripts/library-coverage/utils.py +++ b/misc/scripts/library-coverage/utils.py @@ -8,7 +8,16 @@ import sys def subprocess_run(cmd): """Runs a command through subprocess.run, with a few tweaks. Raises an Exception if exit code != 0.""" print(shlex.join(cmd)) - return subprocess.run(cmd, capture_output=True, text=True, env=os.environ.copy(), check=True) + try: + ret = subprocess.run(cmd, capture_output=True, + text=True, env=os.environ.copy(), check=True) + if (ret.stdout): + print(ret.stdout) + return ret + except subprocess.CalledProcessError as e: + if (e.stderr): + print(e.stderr) + raise e def subprocess_check_output(cmd): @@ -17,14 +26,23 @@ def subprocess_check_output(cmd): return subprocess.check_output(cmd, text=True, env=os.environ.copy()) -def create_empty_database(lang, extension, database): +def create_empty_database(lang, extension, database, dbscheme=None): """Creates an empty database for the given language.""" subprocess_run(["codeql", "database", "init", "--language=" + lang, "--source-root=/tmp/empty", "--allow-missing-source-root", database]) subprocess_run(["mkdir", "-p", database + "/src/tmp/empty"]) subprocess_run(["touch", database + "/src/tmp/empty/empty" + extension]) - subprocess_run(["codeql", "database", "finalize", - database, "--no-pre-finalize"]) + + finalize_cmd = ["codeql", "database", "finalize", + database, "--no-pre-finalize"] + if dbscheme is not None: + for scheme in dbscheme: + if os.path.exists(scheme): + finalize_cmd.append("--dbscheme") + finalize_cmd.append(scheme) + break + + subprocess_run(finalize_cmd) def run_codeql_query(query, database, output, search_path): @@ -38,11 +56,12 @@ def run_codeql_query(query, database, output, search_path): class LanguageConfig: - def __init__(self, lang, capitalized_lang, ext, ql_path): + def __init__(self, lang, capitalized_lang, ext, ql_path, dbscheme=None): self.lang = lang self.capitalized_lang = capitalized_lang self.ext = ext self.ql_path = ql_path + self.dbscheme = dbscheme def read_cwes(path): diff --git a/python/change-notes/2021-07-16-deprecate-importnode.md b/python/change-notes/2021-07-16-deprecate-importnode.md new file mode 100644 index 00000000000..4acd1243943 --- /dev/null +++ b/python/change-notes/2021-07-16-deprecate-importnode.md @@ -0,0 +1,4 @@ +lgtm,codescanning +* The `importNode` predicate from the data-flow library has been deprecated. In its place, we + recommend using the API graphs library, accessible via `import semmle.python.ApiGraphs`. + \ No newline at end of file diff --git a/python/change-notes/2021-08-30-port-modifying-default-query.md b/python/change-notes/2021-08-30-port-modifying-default-query.md new file mode 100644 index 00000000000..2fcd9a11ded --- /dev/null +++ b/python/change-notes/2021-08-30-port-modifying-default-query.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Updated _Modification of parameter with default_ (`py/modification-of-default-value`) query to use the new data flow library instead of the old taint tracking library and to remove the use of points-to analysis. You may see differences in the results found by the query, but overall this change should result in a more robust and accurate analysis. diff --git a/python/change-notes/2021-09-02-add-Flask-SQLAlchemy-modeling.md b/python/change-notes/2021-09-02-add-Flask-SQLAlchemy-modeling.md new file mode 100644 index 00000000000..82c7dce9cfd --- /dev/null +++ b/python/change-notes/2021-09-02-add-Flask-SQLAlchemy-modeling.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Added modeling of SQL execution in the `Flask-SQLAlchemy` PyPI package, resulting in additional sinks for the SQL Injection query (`py/sql-injection`). diff --git a/python/change-notes/2021-09-02-add-SQLAlchemy-modeling.md b/python/change-notes/2021-09-02-add-SQLAlchemy-modeling.md new file mode 100644 index 00000000000..9ba7a72614b --- /dev/null +++ b/python/change-notes/2021-09-02-add-SQLAlchemy-modeling.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Added modeling of SQL execution in the `SQLAlchemy` PyPI package, resulting in additional sinks for the SQL Injection query (`py/sql-injection`). This modeling was originally [submitted as a contribution by @mrthankyou](https://github.com/github/codeql/pull/5680). diff --git a/python/change-notes/2021-09-02-add-SQLAlchemyTextClauseInjection.md b/python/change-notes/2021-09-02-add-SQLAlchemyTextClauseInjection.md new file mode 100644 index 00000000000..fec1e75e9a8 --- /dev/null +++ b/python/change-notes/2021-09-02-add-SQLAlchemyTextClauseInjection.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Expanded the query _SQL query built from user-controlled sources_ (`py/sql-injection`) to alert if user-input is added to a TextClause from SQLAlchemy, since that can lead to SQL injection. diff --git a/python/change-notes/2021-09-08-add-flow-from-default-values.md b/python/change-notes/2021-09-08-add-flow-from-default-values.md new file mode 100644 index 00000000000..8a65028216c --- /dev/null +++ b/python/change-notes/2021-09-08-add-flow-from-default-values.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Function parameters with default values will now see flow from those values. diff --git a/python/ql/lib/semmle/python/ApiGraphs.qll b/python/ql/lib/semmle/python/ApiGraphs.qll index 96c1df9fa8a..19a287df63a 100644 --- a/python/ql/lib/semmle/python/ApiGraphs.qll +++ b/python/ql/lib/semmle/python/ApiGraphs.qll @@ -424,13 +424,8 @@ module API { * a value in the module `m`. */ private predicate possible_builtin_defined_in_module(string name, Module m) { - exists(NameNode n | - not exists(LocalVariable v | n.defines(v)) and - n.isStore() and - name = n.getId() and - name = getBuiltInName() and - m = n.getEnclosingModule() - ) + global_name_defined_in_module(name, m) and + name = getBuiltInName() } /** @@ -445,6 +440,51 @@ module API { m = n.getEnclosingModule() } + /** + * Holds if `n` is an access of a variable called `name` (which is _not_ the name of a + * built-in, and which is _not_ a global defined in the enclosing module) inside the scope `s`. + */ + private predicate name_possibly_defined_in_import_star(NameNode n, string name, Scope s) { + n.isLoad() and + name = n.getId() and + // Not already defined in an enclosing scope. + not exists(LocalVariable v | + v.getId() = name and v.getScope() = n.getScope().getEnclosingScope*() + ) and + not name = getBuiltInName() and + s = n.getScope().getEnclosingScope*() and + exists(potential_import_star_base(s)) and + not global_name_defined_in_module(name, n.getEnclosingModule()) + } + + /** Holds if a global variable called `name` is assigned a value in the module `m`. */ + private predicate global_name_defined_in_module(string name, Module m) { + exists(NameNode n | + not exists(LocalVariable v | n.defines(v)) and + n.isStore() and + name = n.getId() and + m = n.getEnclosingModule() + ) + } + + /** + * Gets the API graph node for all modules imported with `from ... import *` inside the scope `s`. + * + * For example, given + * + * `from foo.bar import *` + * + * this would be the API graph node with the path + * + * `moduleImport("foo").getMember("bar")` + */ + private TApiNode potential_import_star_base(Scope s) { + exists(DataFlow::Node ref | + ref.asCfgNode() = any(ImportStarNode n | n.getScope() = s).getModule() and + use(result, ref) + ) + } + /** * Holds if `ref` is a use of a node that should have an incoming edge from `base` labeled * `lbl` in the API graph. @@ -487,6 +527,15 @@ module API { // Built-ins, treated as members of the module `builtins` base = MkModuleImport("builtins") and lbl = Label::member(any(string name | ref = likely_builtin(name))) + or + // Unknown variables that may belong to a module imported with `import *` + exists(Scope s | + base = potential_import_star_base(s) and + lbl = + Label::member(any(string name | + name_possibly_defined_in_import_star(ref.asCfgNode(), name, s) + )) + ) } /** diff --git a/python/ql/lib/semmle/python/Files.qll b/python/ql/lib/semmle/python/Files.qll index 4fa94f46ac6..2fa1a733fc6 100644 --- a/python/ql/lib/semmle/python/Files.qll +++ b/python/ql/lib/semmle/python/Files.qll @@ -1,9 +1,7 @@ import python /** A file */ -class File extends Container { - File() { files(this, _, _, _, _) } - +class File extends Container, @file { /** DEPRECATED: Use `getAbsolutePath` instead. */ deprecated override string getName() { result = this.getAbsolutePath() } @@ -34,9 +32,7 @@ class File extends Container { } /** Gets a short name for this file (just the file name) */ - string getShortName() { - exists(string simple, string ext | files(this, _, simple, ext, _) | result = simple + ext) - } + string getShortName() { result = this.getBaseName() } private int lastLine() { result = max(int i | exists(Location l | l.getFile() = this and l.getEndLine() = i)) @@ -55,7 +51,7 @@ class File extends Container { ) } - override string getAbsolutePath() { files(this, result, _, _, _) } + override string getAbsolutePath() { files(this, result) } /** Gets the URL of this file. */ override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } @@ -118,15 +114,10 @@ private predicate occupied_line(File f, int n) { } /** A folder (directory) */ -class Folder extends Container { - Folder() { folders(this, _, _) } - +class Folder extends Container, @folder { /** DEPRECATED: Use `getAbsolutePath` instead. */ deprecated override string getName() { result = this.getAbsolutePath() } - /** DEPRECATED: Use `getBaseName` instead. */ - deprecated string getSimple() { folders(this, _, result) } - /** * Holds if this element is at the specified location. * The location spans column `startcolumn` of line `startline` to @@ -144,7 +135,7 @@ class Folder extends Container { endcolumn = 0 } - override string getAbsolutePath() { folders(this, result, _) } + override string getAbsolutePath() { folders(this, result) } /** Gets the URL of this folder. */ override string getURL() { result = "folder://" + this.getAbsolutePath() } diff --git a/python/ql/lib/semmle/python/Flow.qll b/python/ql/lib/semmle/python/Flow.qll index 83a89b053a7..beda3cef1c4 100755 --- a/python/ql/lib/semmle/python/Flow.qll +++ b/python/ql/lib/semmle/python/Flow.qll @@ -653,6 +653,8 @@ class DefinitionNode extends ControlFlowNode { DefinitionNode() { exists(Assign a | a.getATarget().getAFlowNode() = this) or + exists(AnnAssign a | a.getTarget().getAFlowNode() = this and exists(a.getValue())) + or exists(Alias a | a.getAsname().getAFlowNode() = this) or augstore(_, this) @@ -795,6 +797,9 @@ private AstNode assigned_value(Expr lhs) { /* lhs = result */ exists(Assign a | a.getATarget() = lhs and result = a.getValue()) or + /* lhs : annotation = result */ + exists(AnnAssign a | a.getTarget() = lhs and result = a.getValue()) + or /* import result as lhs */ exists(Alias a | a.getAsname() = lhs and result = a.getValue()) or diff --git a/python/ql/lib/semmle/python/Frameworks.qll b/python/ql/lib/semmle/python/Frameworks.qll index c6499e13508..b3ff235c3ee 100644 --- a/python/ql/lib/semmle/python/Frameworks.qll +++ b/python/ql/lib/semmle/python/Frameworks.qll @@ -13,6 +13,7 @@ private import semmle.python.frameworks.Dill private import semmle.python.frameworks.Django private import semmle.python.frameworks.Fabric private import semmle.python.frameworks.Flask +private import semmle.python.frameworks.FlaskSqlAlchemy private import semmle.python.frameworks.Idna private import semmle.python.frameworks.Invoke private import semmle.python.frameworks.Jmespath @@ -20,13 +21,14 @@ private import semmle.python.frameworks.MarkupSafe private import semmle.python.frameworks.Multidict private import semmle.python.frameworks.Mysql private import semmle.python.frameworks.MySQLdb +private import semmle.python.frameworks.Peewee private import semmle.python.frameworks.Psycopg2 private import semmle.python.frameworks.PyMySQL private import semmle.python.frameworks.Rsa private import semmle.python.frameworks.Simplejson +private import semmle.python.frameworks.SqlAlchemy private import semmle.python.frameworks.Stdlib private import semmle.python.frameworks.Tornado -private import semmle.python.frameworks.Peewee private import semmle.python.frameworks.Twisted private import semmle.python.frameworks.Ujson private import semmle.python.frameworks.Yaml diff --git a/python/ql/lib/semmle/python/Stmts.qll b/python/ql/lib/semmle/python/Stmts.qll index 0aa34c2a3fe..56612ef7283 100644 --- a/python/ql/lib/semmle/python/Stmts.qll +++ b/python/ql/lib/semmle/python/Stmts.qll @@ -153,6 +153,12 @@ class ExceptStmt extends ExceptStmt_ { override Stmt getASubStatement() { result = this.getAStmt() } override Stmt getLastStatement() { result = this.getBody().getLastItem().getLastStatement() } + + override Expr getType() { + result = super.getType() and not result instanceof Tuple + or + result = super.getType().(Tuple).getAnElt() + } } /** An assert statement, such as `assert a == b, "A is not equal to b"` */ diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll index 8597b5755f0..0c99a25ccc4 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -3639,9 +3643,10 @@ private module Subpaths { PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, apout) and + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, + unbindConf(arg.getConfiguration())) } /** @@ -3686,8 +3691,8 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | - arg.getASuccessor() = par and - arg.getASuccessor() = out and + pragma[only_bind_into](arg).getASuccessor() = par and + pragma[only_bind_into](arg).getASuccessor() = out and subpaths03(arg, p, ret, o, apout) and par.getNodeEx() = p and out.getNodeEx() = o and diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll index 8597b5755f0..0c99a25ccc4 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -3639,9 +3643,10 @@ private module Subpaths { PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, apout) and + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, + unbindConf(arg.getConfiguration())) } /** @@ -3686,8 +3691,8 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | - arg.getASuccessor() = par and - arg.getASuccessor() = out and + pragma[only_bind_into](arg).getASuccessor() = par and + pragma[only_bind_into](arg).getASuccessor() = out and subpaths03(arg, p, ret, o, apout) and par.getNodeEx() = p and out.getNodeEx() = o and diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll index 8597b5755f0..0c99a25ccc4 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -3639,9 +3643,10 @@ private module Subpaths { PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, apout) and + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, + unbindConf(arg.getConfiguration())) } /** @@ -3686,8 +3691,8 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | - arg.getASuccessor() = par and - arg.getASuccessor() = out and + pragma[only_bind_into](arg).getASuccessor() = par and + pragma[only_bind_into](arg).getASuccessor() = out and subpaths03(arg, p, ret, o, apout) and par.getNodeEx() = p and out.getNodeEx() = o and diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll index 8597b5755f0..0c99a25ccc4 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -3639,9 +3643,10 @@ private module Subpaths { PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, NodeEx out, AccessPath apout ) { - pathThroughCallable(arg, out, _, apout) and + pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and pathIntoCallable(arg, par, _, innercc, sc, _) and - paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration())) + paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, + unbindConf(arg.getConfiguration())) } /** @@ -3686,8 +3691,8 @@ private module Subpaths { */ predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) { exists(ParamNodeEx p, NodeEx o, AccessPath apout | - arg.getASuccessor() = par and - arg.getASuccessor() = out and + pragma[only_bind_into](arg).getASuccessor() = par and + pragma[only_bind_into](arg).getASuccessor() = out and subpaths03(arg, p, ret, o, apout) and par.getNodeEx() = p and out.getNodeEx() = o and diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll index 728f7b56c42..f588a25a176 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll @@ -786,13 +786,18 @@ private module Cached { } /** - * Holds if the call context `call` either improves virtual dispatch in - * `callable` or if it allows us to prune unreachable nodes in `callable`. + * Holds if the call context `call` improves virtual dispatch in `callable`. */ cached - predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + predicate recordDataFlowCallSiteDispatch(DataFlowCall call, DataFlowCallable callable) { reducedViableImplInCallContext(_, callable, call) - or + } + + /** + * Holds if the call context `call` allows us to prune unreachable nodes in `callable`. + */ + cached + predicate recordDataFlowCallSiteUnreachable(DataFlowCall call, DataFlowCallable callable) { exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call)) } @@ -846,6 +851,15 @@ private module Cached { TAccessPathFrontSome(AccessPathFront apf) } +/** + * Holds if the call context `call` either improves virtual dispatch in + * `callable` or if it allows us to prune unreachable nodes in `callable`. + */ +predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + recordDataFlowCallSiteDispatch(call, callable) or + recordDataFlowCallSiteUnreachable(call, callable) +} + /** * A `Node` at which a cast can occur such that the type should be checked. */ diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 074289b00fd..44c64234b75 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -869,6 +869,9 @@ predicate jumpStep(Node nodeFrom, Node nodeTo) { module_export(mv.getScope(), r.getAttributeName(), nodeFrom) and nodeTo = r ) + or + // Default value for parameter flows to that parameter + defaultValueFlowStep(nodeFrom, nodeTo) } /** @@ -1033,6 +1036,19 @@ predicate kwOverflowStoreStep(CfgNode nodeFrom, DictionaryElementContent c, Node ) } +predicate defaultValueFlowStep(CfgNode nodeFrom, CfgNode nodeTo) { + exists(Function f, Parameter p, ParameterDefinition def | + // `getArgByName` supports, unlike `getAnArg`, keyword-only parameters + p = f.getArgByName(_) and + nodeFrom.asExpr() = p.getDefault() and + // The following expresses + // nodeTo.(ParameterNode).getParameter() = p + // without non-monotonic recursion + def.getParameter() = p and + nodeTo.getNode() = def.getDefiningNode() + ) +} + /** * Holds if data can flow from `nodeFrom` to `nodeTo` via a read of content `c`. */ diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowUtil.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowUtil.qll index 174564db96b..9bdb7ede42c 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowUtil.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowUtil.qll @@ -18,6 +18,10 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) } /** + * DEPRECATED. Use the API graphs library (`semmle.python.ApiGraphs`) instead. + * + * For a drop-in replacement, use `API::moduleImport(name).getAUse()`. + * * Gets a `Node` that refers to the module referenced by `name`. * Note that for the statement `import pkg.mod`, the new variable introduced is `pkg` that is a * reference to the module `pkg`. @@ -37,7 +41,7 @@ predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) } * `mypkg/foo.py` but the variable `foo` containing `42` -- however, `import mypkg.foo` will always cause `mypkg.foo` * to refer to the module. */ -Node importNode(string name) { +deprecated Node importNode(string name) { exists(Variable var, Import imp, Alias alias | alias = imp.getAName() and alias.getAsname() = var.getAStore() and diff --git a/python/ql/lib/semmle/python/frameworks/FlaskSqlAlchemy.qll b/python/ql/lib/semmle/python/frameworks/FlaskSqlAlchemy.qll new file mode 100644 index 00000000000..08ba276e6ce --- /dev/null +++ b/python/ql/lib/semmle/python/frameworks/FlaskSqlAlchemy.qll @@ -0,0 +1,56 @@ +/** + * Provides classes modeling security-relevant aspects of the `Flask-SQLAlchemy` PyPI package + * (imported by `flask_sqlalchemy`). + * See + * - https://pypi.org/project/Flask-SQLAlchemy/ + * - https://flask-sqlalchemy.palletsprojects.com/en/2.x/ + */ + +private import python +private import semmle.python.dataflow.new.DataFlow +private import semmle.python.dataflow.new.TaintTracking +private import semmle.python.ApiGraphs +private import semmle.python.Concepts +private import semmle.python.frameworks.SqlAlchemy + +/** + * INTERNAL: Do not use. + * + * Provides models for the `Flask-SQLAlchemy` PyPI package (imported by `flask_sqlalchemy`). + * See + * - https://pypi.org/project/Flask-SQLAlchemy/ + * - https://flask-sqlalchemy.palletsprojects.com/en/2.x/ + */ +private module FlaskSqlAlchemy { + /** Gets an instance of `flask_sqlalchemy.SQLAlchemy` */ + private API::Node dbInstance() { + result = API::moduleImport("flask_sqlalchemy").getMember("SQLAlchemy").getReturn() + } + + /** A call to the `text` method on a DB. */ + private class DbTextCall extends SqlAlchemy::TextClause::TextClauseConstruction { + DbTextCall() { this = dbInstance().getMember("text").getACall() } + } + + /** Access on a DB resulting in an Engine */ + private class DbEngine extends SqlAlchemy::Engine::InstanceSource { + DbEngine() { + this = dbInstance().getMember("engine").getAUse() + or + this = dbInstance().getMember("get_engine").getACall() + } + } + + /** Access on a DB resulting in a Session */ + private class DbSession extends SqlAlchemy::Session::InstanceSource { + DbSession() { + this = dbInstance().getMember("session").getAUse() + or + this = dbInstance().getMember("create_session").getReturn().getACall() + or + this = dbInstance().getMember("create_session").getReturn().getMember("begin").getACall() + or + this = dbInstance().getMember("create_scoped_session").getACall() + } + } +} diff --git a/python/ql/lib/semmle/python/frameworks/SqlAlchemy.qll b/python/ql/lib/semmle/python/frameworks/SqlAlchemy.qll new file mode 100644 index 00000000000..a74d44573f7 --- /dev/null +++ b/python/ql/lib/semmle/python/frameworks/SqlAlchemy.qll @@ -0,0 +1,344 @@ +/** + * Provides classes modeling security-relevant aspects of the `SQLAlchemy` PyPI package. + * See + * - https://pypi.org/project/SQLAlchemy/ + * - https://docs.sqlalchemy.org/en/14/index.html + */ + +private import python +private import semmle.python.dataflow.new.DataFlow +private import semmle.python.dataflow.new.TaintTracking +private import semmle.python.ApiGraphs +private import semmle.python.Concepts +// This import is done like this to avoid importing the deprecated top-level things that +// would pollute the namespace +private import semmle.python.frameworks.PEP249::PEP249 as PEP249 + +/** + * INTERNAL: Do not use. + * + * Provides models for the `SQLAlchemy` PyPI package. + * See + * - https://pypi.org/project/SQLAlchemy/ + * - https://docs.sqlalchemy.org/en/14/index.html + */ +module SqlAlchemy { + /** + * Provides models for the `sqlalchemy.engine.Engine` and `sqlalchemy.future.Engine` classes. + * + * These are so similar that we model both in the same way. + * + * See + * - https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.Engine + * - https://docs.sqlalchemy.org/en/14/core/future.html#sqlalchemy.future.Engine + */ + module Engine { + /** Gets a reference to a SQLAlchemy Engine class. */ + private API::Node classRef() { + result = API::moduleImport("sqlalchemy").getMember("engine").getMember("Engine") + or + result = API::moduleImport("sqlalchemy").getMember("future").getMember("Engine") + } + + /** + * A source of instances of a SQLAlchemy Engine, extend this class to model new instances. + * + * This can include instantiations of the class, return values from function + * calls, or a special parameter that will be set when functions are called by an external + * library. + * + * Use the predicate `Engine::instance()` to get references to instances of a SQLAlchemy Engine. + */ + abstract class InstanceSource extends DataFlow::LocalSourceNode { } + + private class EngineConstruction extends InstanceSource, DataFlow::CallCfgNode { + EngineConstruction() { + this = classRef().getACall() + or + this = API::moduleImport("sqlalchemy").getMember("create_engine").getACall() + or + this = + API::moduleImport("sqlalchemy").getMember("future").getMember("create_engine").getACall() + or + this.(DataFlow::MethodCallNode).calls(instance(), "execution_options") + } + } + + /** Gets a reference to an instance of a SQLAlchemy Engine. */ + private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) { + t.start() and + result instanceof InstanceSource + or + exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t)) + } + + /** Gets a reference to an instance of a SQLAlchemy Engine. */ + DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) } + } + + /** + * Provides models for the `sqlalchemy.engine.base.Connection` and `sqlalchemy.future.Connection` classes. + * + * These are so similar that we model both in the same way. + * + * See + * - https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.Connection + * - https://docs.sqlalchemy.org/en/14/core/future.html#sqlalchemy.future.Connection + */ + module Connection { + /** Gets a reference to a SQLAlchemy Connection class. */ + private API::Node classRef() { + result = + API::moduleImport("sqlalchemy") + .getMember("engine") + .getMember("base") + .getMember("Connection") + or + result = API::moduleImport("sqlalchemy").getMember("future").getMember("Connection") + } + + /** + * A source of instances of a SQLAlchemy Connection, extend this class to model new instances. + * + * This can include instantiations of the class, return values from function + * calls, or a special parameter that will be set when functions are called by an external + * library. + * + * Use the predicate `Connection::instance()` to get references to instances of a SQLAlchemy Connection. + */ + abstract class InstanceSource extends DataFlow::LocalSourceNode { } + + private class ConnectionConstruction extends InstanceSource, DataFlow::CallCfgNode { + ConnectionConstruction() { + this = classRef().getACall() + or + this.(DataFlow::MethodCallNode).calls(Engine::instance(), ["begin", "connect"]) + or + this.(DataFlow::MethodCallNode).calls(instance(), "connect") + or + this.(DataFlow::MethodCallNode).calls(instance(), "execution_options") + } + } + + /** Gets a reference to an instance of a SQLAlchemy Connection. */ + private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) { + t.start() and + result instanceof InstanceSource + or + exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t)) + } + + /** Gets a reference to an instance of a SQLAlchemy Connection. */ + DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) } + } + + /** + * Provides models for the underlying DB-API Connection of a SQLAlchemy Connection. + * + * See https://docs.sqlalchemy.org/en/14/core/connections.html#dbapi-connections. + */ + module DBAPIConnection { + /** + * A source of instances of DB-API Connections, extend this class to model new instances. + * + * This can include instantiations of the class, return values from function + * calls, or a special parameter that will be set when functions are called by an external + * library. + * + * Use the predicate `DBAPIConnection::instance()` to get references to instances of DB-API Connections. + */ + abstract class InstanceSource extends DataFlow::LocalSourceNode { } + + private class DBAPIConnectionSources extends InstanceSource, PEP249::Connection::InstanceSource { + DBAPIConnectionSources() { + this.(DataFlow::MethodCallNode).calls(Engine::instance(), "raw_connection") + or + this.(DataFlow::AttrRead).accesses(Connection::instance(), "connection") + } + } + + /** Gets a reference to an instance of DB-API Connections. */ + private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) { + t.start() and + result instanceof InstanceSource + or + exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t)) + } + + /** Gets a reference to an instance of DB-API Connections. */ + DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) } + } + + /** + * Provides models for the `sqlalchemy.orm.Session` class + * + * See + * - https://docs.sqlalchemy.org/en/14/orm/session_api.html#sqlalchemy.orm.Session + * - https://docs.sqlalchemy.org/en/14/orm/session_basics.html + */ + module Session { + /** Gets a reference to the `sqlalchemy.orm.Session` class. */ + private API::Node classRef() { + result = API::moduleImport("sqlalchemy").getMember("orm").getMember("Session") + } + + /** + * A source of instances of `sqlalchemy.orm.Session`, extend this class to model new instances. + * + * This can include instantiations of the class, return values from function + * calls, or a special parameter that will be set when functions are called by an external + * library. + * + * Use the predicate `Session::instance()` to get references to instances of `sqlalchemy.orm.Session`. + */ + abstract class InstanceSource extends DataFlow::LocalSourceNode { } + + private class SessionConstruction extends InstanceSource, DataFlow::CallCfgNode { + SessionConstruction() { + this = classRef().getACall() + or + this = + API::moduleImport("sqlalchemy") + .getMember("orm") + .getMember("sessionmaker") + .getReturn() + .getACall() + or + this = + API::moduleImport("sqlalchemy") + .getMember("orm") + .getMember("sessionmaker") + .getReturn() + .getMember("begin") + .getACall() + } + } + + /** Gets a reference to an instance of `sqlalchemy.orm.Session`. */ + private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) { + t.start() and + result instanceof InstanceSource + or + exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t)) + } + + /** Gets a reference to an instance of `sqlalchemy.orm.Session`. */ + DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) } + } + + /** + * A call to `execute` on a SQLAlchemy Engine, Connection, or Session. + * See + * - https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.Engine.execute + * - https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.Connection.execute + * - https://docs.sqlalchemy.org/en/14/core/future.html#sqlalchemy.future.Connection.execute + * - https://docs.sqlalchemy.org/en/14/orm/session_api.html#sqlalchemy.orm.Session.execute + */ + private class SqlAlchemyExecuteCall extends DataFlow::MethodCallNode, SqlExecution::Range { + SqlAlchemyExecuteCall() { + this.calls(Engine::instance(), "execute") + or + this.calls(Connection::instance(), "execute") + or + this.calls(Session::instance(), "execute") + } + + override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("statement")] } + } + + /** + * A call to `exec_driver_sql` on a SQLAlchemy Connection. + * See + * - https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.Connection.exec_driver_sql + * - https://docs.sqlalchemy.org/en/14/core/future.html#sqlalchemy.future.Connection.exec_driver_sql + */ + private class SqlAlchemyExecDriverSqlCall extends DataFlow::MethodCallNode, SqlExecution::Range { + SqlAlchemyExecDriverSqlCall() { this.calls(Connection::instance(), "exec_driver_sql") } + + override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("statement")] } + } + + /** + * A call to `scalar` on a SQLAlchemy Engine, Connection, or Session. + * See + * - https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.Engine.scalar + * - https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.Connection.scalar + * - https://docs.sqlalchemy.org/en/14/core/future.html#sqlalchemy.future.Connection.scalar + * - https://docs.sqlalchemy.org/en/14/orm/session_api.html#sqlalchemy.orm.Session.scalar + */ + private class SqlAlchemyScalarCall extends DataFlow::MethodCallNode, SqlExecution::Range { + SqlAlchemyScalarCall() { + this.calls(Engine::instance(), "scalar") + or + this.calls(Connection::instance(), "scalar") + or + this.calls(Session::instance(), "scalar") + } + + override DataFlow::Node getSql() { + result in [this.getArg(0), this.getArgByName("statement"), this.getArgByName("object_")] + } + } + + /** + * Provides models for the `sqlalchemy.sql.expression.TextClause` class, + * which represents a textual SQL string directly. + * + * ```py + * session.query(For14).filter_by(description=sqlalchemy.text(f"'{user_input}'")).all() + * ``` + * + * Initially I wanted to add lots of additional taint steps for such that the normal + * SQL injection query would be able to find cases as the one above where an ORM query + * includes a TextClause that includes user-input directly... But that presented 2 + * problems: + * + * - which part of the query construction above should be marked as SQL to fit our + * `SqlExecution` concept. Nothing really fits this well, since all the SQL + * execution happens under the hood. + * - This would require a LOT of modeling for these additional taint steps, since + * there are many many constructs we would need to have models for. (see the 2 + * examples below) + * + * So instead we extended the SQL injection query to include TextClause construction + * as a sink. And so we don't highlight any parts of an ORM constructed query such as + * these as containing SQL, and don't need the additional taint steps either. + * + * See + * - https://docs.sqlalchemy.org/en/14/core/sqlelement.html#sqlalchemy.sql.expression.TextClause. + * - https://docs.sqlalchemy.org/en/14/core/sqlelement.html#sqlalchemy.sql.expression.text + */ + module TextClause { + /** + * A construction of a `sqlalchemy.sql.expression.TextClause`, which represents a + * textual SQL string directly. + */ + abstract class TextClauseConstruction extends DataFlow::CallCfgNode { + /** Gets the argument that specifies the SQL text. */ + DataFlow::Node getTextArg() { result in [this.getArg(0), this.getArgByName("text")] } + } + + /** `TextClause` constructions from the `sqlalchemy` package. */ + private class DefaultTextClauseConstruction extends TextClauseConstruction { + DefaultTextClauseConstruction() { + this = API::moduleImport("sqlalchemy").getMember("text").getACall() + or + this = API::moduleImport("sqlalchemy").getMember("sql").getMember("text").getACall() + or + this = + API::moduleImport("sqlalchemy") + .getMember("sql") + .getMember("expression") + .getMember("text") + .getACall() + or + this = + API::moduleImport("sqlalchemy") + .getMember("sql") + .getMember("expression") + .getMember("TextClause") + .getACall() + } + } + } +} diff --git a/python/ql/lib/semmle/python/regex.qll b/python/ql/lib/semmle/python/regex.qll index e57737bd6a2..883d2c3fbc4 100644 --- a/python/ql/lib/semmle/python/regex.qll +++ b/python/ql/lib/semmle/python/regex.qll @@ -773,15 +773,18 @@ abstract class RegexString extends Expr { * string is empty. */ predicate multiples(int start, int end, string lower, string upper) { - this.getChar(start) = "{" and - this.getChar(end - 1) = "}" and - exists(string inner | inner = this.getText().substring(start + 1, end - 1) | - inner.regexpMatch("[0-9]+") and + exists(string text, string match, string inner | + text = this.getText() and + end = start + match.length() and + inner = match.substring(1, match.length() - 1) + | + match = text.regexpFind("\\{[0-9]+\\}", _, start) and lower = inner and upper = lower or - inner.regexpMatch("[0-9]*,[0-9]*") and - exists(int commaIndex | commaIndex = inner.indexOf(",") | + match = text.regexpFind("\\{[0-9]*,[0-9]*\\}", _, start) and + exists(int commaIndex | + commaIndex = inner.indexOf(",") and lower = inner.prefix(commaIndex) and upper = inner.suffix(commaIndex + 1) ) diff --git a/python/ql/lib/semmle/python/security/dataflow/SqlInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/SqlInjectionCustomizations.qll index 186ebd3189d..c132878951f 100644 --- a/python/ql/lib/semmle/python/security/dataflow/SqlInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/SqlInjectionCustomizations.qll @@ -9,6 +9,7 @@ private import semmle.python.dataflow.new.DataFlow private import semmle.python.Concepts private import semmle.python.dataflow.new.RemoteFlowSources private import semmle.python.dataflow.new.BarrierGuards +private import semmle.python.frameworks.SqlAlchemy /** * Provides default sources, sinks and sanitizers for detecting @@ -48,6 +49,13 @@ module SqlInjection { SqlExecutionAsSink() { this = any(SqlExecution e).getSql() } } + /** + * The text argument of a SQLAlchemy TextClause construction, considered as a flow sink. + */ + class TextArgAsSink extends Sink { + TextArgAsSink() { this = any(SqlAlchemy::TextClause::TextClauseConstruction tcc).getTextArg() } + } + /** * A comparison with a constant string, considered as a sanitizer-guard. */ diff --git a/python/ql/lib/semmlecode.python.dbscheme b/python/ql/lib/semmlecode.python.dbscheme index 4f1806347d7..ff5327c074c 100644 --- a/python/ql/lib/semmlecode.python.dbscheme +++ b/python/ql/lib/semmlecode.python.dbscheme @@ -120,16 +120,11 @@ svnchurn( Python dbscheme ****************************/ -/* fromSource is ignored */ files(unique int id: @file, - varchar(900) name: string ref, - varchar(900) simple: string ref, - varchar(900) ext: string ref, - int fromSource: int ref); + varchar(900) name: string ref); folders(unique int id: @folder, - varchar(900) name: string ref, - varchar(900) simple: string ref); + varchar(900) name: string ref); @container = @folder | @file; diff --git a/python/ql/lib/semmlecode.python.dbscheme.stats b/python/ql/lib/semmlecode.python.dbscheme.stats index 99fa25b3817..31653bf41a9 100644 --- a/python/ql/lib/semmlecode.python.dbscheme.stats +++ b/python/ql/lib/semmlecode.python.dbscheme.stats @@ -4331,18 +4331,6 @@ name 3066 - -simple -1294 - - -ext -1 - - -fromSource -1 - @@ -4362,54 +4350,6 @@ -id -simple - - -12 - - -1 -2 -3066 - - - - - - -id -ext - - -12 - - -1 -2 -3066 - - - - - - -id -fromSource - - -12 - - -1 -2 -3066 - - - - - - name id @@ -4425,276 +4365,6 @@ - -name -simple - - -12 - - -1 -2 -3066 - - - - - - -name -ext - - -12 - - -1 -2 -3066 - - - - - - -name -fromSource - - -12 - - -1 -2 -3066 - - - - - - -simple -id - - -12 - - -1 -2 -1058 - - -2 -3 -132 - - -3 -38 -98 - - -47 -646 -6 - - - - - - -simple -name - - -12 - - -1 -2 -1058 - - -2 -3 -132 - - -3 -38 -98 - - -47 -646 -6 - - - - - - -simple -ext - - -12 - - -1 -2 -1294 - - - - - - -simple -fromSource - - -12 - - -1 -2 -1294 - - - - - - -ext -id - - -12 - - -3066 -3067 -1 - - - - - - -ext -name - - -12 - - -3066 -3067 -1 - - - - - - -ext -simple - - -12 - - -1294 -1295 -1 - - - - - - -ext -fromSource - - -12 - - -1 -2 -1 - - - - - - -fromSource -id - - -12 - - -3066 -3067 -1 - - - - - - -fromSource -name - - -12 - - -3066 -3067 -1 - - - - - - -fromSource -simple - - -12 - - -1294 -1295 -1 - - - - - - -fromSource -ext - - -12 - - -1 -2 -1 - - - - - @@ -4709,10 +4379,6 @@ name 686 - -simple -538 - @@ -4732,22 +4398,6 @@ -id -simple - - -12 - - -1 -2 -686 - - - - - - name id @@ -4763,74 +4413,6 @@ - -name -simple - - -12 - - -1 -2 -686 - - - - - - -simple -id - - -12 - - -1 -2 -481 - - -2 -4 -45 - - -4 -27 -12 - - - - - - -simple -name - - -12 - - -1 -2 -481 - - -2 -4 -45 - - -4 -27 -12 - - - - - diff --git a/python/ql/src/Functions/ModificationOfParameterWithDefault.ql b/python/ql/src/Functions/ModificationOfParameterWithDefault.ql index 03edc35fa17..9ff89d30e3f 100644 --- a/python/ql/src/Functions/ModificationOfParameterWithDefault.ql +++ b/python/ql/src/Functions/ModificationOfParameterWithDefault.ql @@ -12,88 +12,12 @@ */ import python -import semmle.python.security.Paths +import semmle.python.functions.ModificationOfParameterWithDefault +import DataFlow::PathGraph -predicate safe_method(string name) { - name = "count" or - name = "index" or - name = "copy" or - name = "get" or - name = "has_key" or - name = "items" or - name = "keys" or - name = "values" or - name = "iteritems" or - name = "iterkeys" or - name = "itervalues" or - name = "__contains__" or - name = "__getitem__" or - name = "__getattribute__" -} - -/** Gets the truthiness (non emptyness) of the default of `p` if that value is mutable */ -private boolean mutableDefaultValue(Parameter p) { - exists(Dict d | p.getDefault() = d | - exists(d.getAKey()) and result = true - or - not exists(d.getAKey()) and result = false - ) - or - exists(List l | p.getDefault() = l | - exists(l.getAnElt()) and result = true - or - not exists(l.getAnElt()) and result = false - ) -} - -class NonEmptyMutableValue extends TaintKind { - NonEmptyMutableValue() { this = "non-empty mutable value" } -} - -class EmptyMutableValue extends TaintKind { - EmptyMutableValue() { this = "empty mutable value" } - - override boolean booleanValue() { result = false } -} - -class MutableDefaultValue extends TaintSource { - boolean nonEmpty; - - MutableDefaultValue() { nonEmpty = mutableDefaultValue(this.(NameNode).getNode()) } - - override string toString() { result = "mutable default value" } - - override predicate isSourceOf(TaintKind kind) { - nonEmpty = false and kind instanceof EmptyMutableValue - or - nonEmpty = true and kind instanceof NonEmptyMutableValue - } -} - -private ClassValue mutable_class() { - result = Value::named("list") or - result = Value::named("dict") -} - -class Mutation extends TaintSink { - Mutation() { - exists(AugAssign a | a.getTarget().getAFlowNode() = this) - or - exists(Call c, Attribute a | c.getFunc() = a | - a.getObject().getAFlowNode() = this and - not safe_method(a.getName()) and - this.(ControlFlowNode).pointsTo().getClass() = mutable_class() - ) - } - - override predicate sinks(TaintKind kind) { - kind instanceof EmptyMutableValue - or - kind instanceof NonEmptyMutableValue - } -} - -from TaintedPathSource src, TaintedPathSink sink -where src.flowsTo(sink) -select sink.getSink(), src, sink, "$@ flows to here and is mutated.", src.getSource(), +from + ModificationOfParameterWithDefault::Configuration config, DataFlow::PathNode source, + DataFlow::PathNode sink +where config.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "$@ flows to here and is mutated.", source.getNode(), "Default value" diff --git a/python/ql/src/Security/CWE-089/SqlInjection.qhelp b/python/ql/src/Security/CWE-089/SqlInjection.qhelp index 63941706e84..05ef88a66e9 100644 --- a/python/ql/src/Security/CWE-089/SqlInjection.qhelp +++ b/python/ql/src/Security/CWE-089/SqlInjection.qhelp @@ -9,6 +9,13 @@ If a database query (such as a SQL or NoSQL query) is built from user-provided data without sufficient sanitization, a user may be able to run malicious database queries.

    + +

    +This also includes using the TextClause class in the +SQLAlchemy PyPI package, +which is used to represent a literal SQL fragment and is inserted directly into the +final SQL when used in a query built using the ORM. +

    @@ -52,5 +59,6 @@ vulnerable to SQL injection attacks. In this example, if username w
  • Wikipedia: SQL injection.
  • OWASP: SQL Injection Prevention Cheat Sheet.
  • +
  • SQLAlchemy documentation for TextClause.
  • diff --git a/python/ql/src/Statements/ModificationOfLocals.ql b/python/ql/src/Statements/ModificationOfLocals.ql index 1a76c38c52e..5a87d60edf2 100644 --- a/python/ql/src/Statements/ModificationOfLocals.ql +++ b/python/ql/src/Statements/ModificationOfLocals.ql @@ -30,5 +30,11 @@ predicate modification_of_locals(ControlFlowNode f) { } from AstNode a, ControlFlowNode f -where modification_of_locals(f) and a = f.getNode() +where + modification_of_locals(f) and + a = f.getNode() and + // in module level scope `locals() == globals()` + // see https://docs.python.org/3/library/functions.html#locals + // FP report in https://github.com/github/codeql/issues/6674 + not a.getScope() instanceof ModuleScope select a, "Modification of the locals() dictionary will have no effect on the local variables." diff --git a/python/ql/src/Variables/UnusedLocalVariable.ql b/python/ql/src/Variables/UnusedLocalVariable.ql index de83345f62d..e52c7fccaff 100644 --- a/python/ql/src/Variables/UnusedLocalVariable.ql +++ b/python/ql/src/Variables/UnusedLocalVariable.ql @@ -19,6 +19,7 @@ predicate unused_local(Name unused, LocalVariable v) { def.getVariable() = v and def.isUnused() and not exists(def.getARedef()) and + not exists(annotation_without_assignment(v)) and def.isRelevant() and not v = any(Nonlocal n).getAVariable() and not exists(def.getNode().getParentNode().(FunctionDef).getDefinedFunction().getADecorator()) and @@ -26,6 +27,17 @@ predicate unused_local(Name unused, LocalVariable v) { ) } +/** + * Gets any annotation of the local variable `v` that does not also reassign its value. + * + * TODO: This predicate should not be needed. Rather, annotated "assignments" that do not actually + * assign a value should not result in the creation of an SSA variable (which then goes unused). + */ +private AnnAssign annotation_without_assignment(LocalVariable v) { + result.getTarget() = v.getAStore() and + not exists(result.getValue()) +} + from Name unused, LocalVariable v where unused_local(unused, v) and diff --git a/python/ql/src/experimental/Security/CWE-522/LDAPInsecureAuth.qhelp b/python/ql/src/experimental/Security/CWE-522/LDAPInsecureAuth.qhelp new file mode 100644 index 00000000000..9033697fd59 --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-522/LDAPInsecureAuth.qhelp @@ -0,0 +1,23 @@ + + + + +

    Failing to ensure the utilization of SSL in an LDAP connection can cause the entire communication +to be sent in cleartext making it easier for an attacker to intercept it.

    +
    + + +

    Always set use_SSL to True, call start_tls_s() or set a proper option flag (ldap.OPT_X_TLS_XXXXXX).

    +
    + + +

    This example shows both good and bad ways to deal with this issue under Python 3.

    + +

    The first one sets use_SSL to true as a keyword argument whereas the second one fails to provide a value for it, so +the default one is used (False).

    + +
    + +
    diff --git a/python/ql/src/experimental/Security/CWE-522/LDAPInsecureAuth.ql b/python/ql/src/experimental/Security/CWE-522/LDAPInsecureAuth.ql new file mode 100644 index 00000000000..9f99527a3e3 --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-522/LDAPInsecureAuth.ql @@ -0,0 +1,21 @@ +/** + * @name Python Insecure LDAP Authentication + * @description Python LDAP Insecure LDAP Authentication + * @kind path-problem + * @problem.severity error + * @id py/insecure-ldap-auth + * @tags experimental + * security + * external/cwe/cwe-522 + * external/cwe/cwe-523 + */ + +// determine precision above +import python +import DataFlow::PathGraph +import experimental.semmle.python.security.LDAPInsecureAuth + +from LDAPInsecureAuthConfig config, DataFlow::PathNode source, DataFlow::PathNode sink +where config.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "$@ is authenticated insecurely.", sink.getNode(), + "This LDAP host" diff --git a/python/ql/src/experimental/Security/CWE-522/examples/LDAPInsecureAuth.py b/python/ql/src/experimental/Security/CWE-522/examples/LDAPInsecureAuth.py new file mode 100644 index 00000000000..051ca07b0dc --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-522/examples/LDAPInsecureAuth.py @@ -0,0 +1,20 @@ +from ldap3 import Server, Connection, ALL +from flask import request, Flask + +app = Flask(__name__) + + +@app.route("/good") +def good(): + srv = Server(host, port, use_ssl=True) + conn = Connection(srv, dn, password) + conn.search(dn, search_filter) + return conn.response + + +@app.route("/bad") +def bad(): + srv = Server(host, port) + conn = Connection(srv, dn, password) + conn.search(dn, search_filter) + return conn.response diff --git a/python/ql/src/experimental/Security/CWE-643/xpath.qhelp b/python/ql/src/experimental/Security/CWE-643/XpathInjection.qhelp similarity index 100% rename from python/ql/src/experimental/Security/CWE-643/xpath.qhelp rename to python/ql/src/experimental/Security/CWE-643/XpathInjection.qhelp diff --git a/python/ql/src/experimental/Security/CWE-643/XpathInjection.ql b/python/ql/src/experimental/Security/CWE-643/XpathInjection.ql new file mode 100644 index 00000000000..67b4741f610 --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-643/XpathInjection.ql @@ -0,0 +1,33 @@ +/** + * @name XPath query built from user-controlled sources + * @description Building a XPath query from user-controlled sources is vulnerable to insertion of + * malicious Xpath code by the user. + * @kind path-problem + * @problem.severity error + * @precision high + * @id py/xpath-injection + * @tags security + * external/cwe/cwe-643 + */ + +private import python +private import semmle.python.Concepts +private import semmle.python.dataflow.new.TaintTracking +private import semmle.python.Concepts +private import semmle.python.ApiGraphs +private import semmle.python.dataflow.new.RemoteFlowSources +private import semmle.python.dataflow.new.BarrierGuards +import XpathInjection::XpathInjection +import DataFlow::PathGraph + +class XpathInjectionConfiguration extends TaintTracking::Configuration { + XpathInjectionConfiguration() { this = "PathNotNormalizedConfiguration" } + + override predicate isSource(DataFlow::Node source) { source instanceof Source } + + override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } +} + +from XpathInjectionConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink +where config.hasFlowPath(source, sink) +select sink, source, sink, "This Xpath query depends on $@.", source, "a user-provided value" diff --git a/python/ql/src/experimental/Security/CWE-643/XpathInjection.qll b/python/ql/src/experimental/Security/CWE-643/XpathInjection.qll new file mode 100644 index 00000000000..e0a0815666a --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-643/XpathInjection.qll @@ -0,0 +1,35 @@ +/** + * Provides a taint-tracking configuration for detecting "Xpath Injection" vulnerabilities. + * + * Note, for performance reasons: only import this file if + * `XpathInjection::Configuration` is needed, otherwise + * `XpathInjectionCustomizations` should be imported instead. + */ + +private import python +import semmle.python.dataflow.new.DataFlow +import semmle.python.dataflow.new.TaintTracking + +/** + * Provides a taint-tracking configuration for detecting "Xpath Injection" vulnerabilities. + */ +module XpathInjection { + import XpathInjectionCustomizations::XpathInjection + + /** + * A taint-tracking configuration for detecting "Xpath Injection" vulnerabilities. + */ + class Configuration extends TaintTracking::Configuration { + Configuration() { this = "Xpath Injection" } + + override predicate isSource(DataFlow::Node source) { source instanceof Source } + + override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } + + override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { + guard instanceof SanitizerGuard + } + } +} diff --git a/python/ql/src/experimental/Security/CWE-643/XpathInjectionCustomizations.qll b/python/ql/src/experimental/Security/CWE-643/XpathInjectionCustomizations.qll new file mode 100644 index 00000000000..4a939253636 --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-643/XpathInjectionCustomizations.qll @@ -0,0 +1,105 @@ +/** + * Provides class and predicates to track external data that + * may represent malicious xpath query objects. + * + * This module is intended to be imported into a taint-tracking query. + */ + +private import python +private import semmle.python.Concepts +private import semmle.python.dataflow.new.TaintTracking +private import semmle.python.Concepts +private import semmle.python.ApiGraphs +private import semmle.python.dataflow.new.RemoteFlowSources +private import semmle.python.dataflow.new.BarrierGuards + +/** Models Xpath Injection related classes and functions */ +module XpathInjection { + /** + * A data flow source for "XPath injection" vulnerabilities. + */ + abstract class Source extends DataFlow::Node { } + + /** + * A data flow sink for "XPath injection" vulnerabilities. + */ + abstract class Sink extends DataFlow::Node { } + + /** + * A sanitizer for "XPath injection" vulnerabilities. + */ + abstract class Sanitizer extends DataFlow::Node { } + + /** + * A sanitizer guard for "XPath injection" vulnerabilities. + */ + abstract class SanitizerGuard extends DataFlow::BarrierGuard { } + + /** + * A source of remote user input, considered as a flow source. + */ + class RemoteFlowSourceAsSource extends Source, RemoteFlowSource { } + + /** Returns an API node referring to `lxml.etree` */ + API::Node etree() { result = API::moduleImport("lxml").getMember("etree") } + + /** Returns an API node referring to `lxml.etree` */ + API::Node etreeFromString() { result = etree().getMember("fromstring") } + + /** Returns an API node referring to `lxml.etree.parse` */ + API::Node etreeParse() { result = etree().getMember("parse") } + + /** Returns an API node referring to `lxml.etree.parse` */ + API::Node libxml2parseFile() { result = API::moduleImport("libxml2").getMember("parseFile") } + + /** + * A Sink representing an argument to `etree.XPath` or `etree.ETXPath` call. + * + * from lxml import etree + * root = etree.XML("") + * find_text = etree.XPath("`sink`") + * find_text = etree.ETXPath("`sink`") + */ + private class EtreeXpathArgument extends Sink { + EtreeXpathArgument() { this = etree().getMember(["XPath", "ETXPath"]).getACall().getArg(0) } + } + + /** + * A Sink representing an argument to the `etree.XPath` call. + * + * from lxml import etree + * root = etree.fromstring(file(XML_DB).read(), XMLParser()) + * find_text = root.xpath("`sink`") + */ + private class EtreeFromstringXpathArgument extends Sink { + EtreeFromstringXpathArgument() { + this = etreeFromString().getReturn().getMember("xpath").getACall().getArg(0) + } + } + + /** + * A Sink representing an argument to the `xpath` call to a parsed xml document. + * + * from lxml import etree + * from io import StringIO + * f = StringIO('') + * tree = etree.parse(f) + * r = tree.xpath('`sink`') + */ + private class ParseXpathArgument extends Sink { + ParseXpathArgument() { this = etreeParse().getReturn().getMember("xpath").getACall().getArg(0) } + } + + /** + * A Sink representing an argument to the `xpathEval` call to a parsed libxml2 document. + * + * import libxml2 + * tree = libxml2.parseFile("file.xml") + * r = tree.xpathEval('`sink`') + */ + private class ParseFileXpathEvalArgument extends Sink { + ParseFileXpathEvalArgument() { + this = libxml2parseFile().getReturn().getMember("xpathEval").getACall().getArg(0) + } + } +} diff --git a/python/ql/src/experimental/Security/CWE-643/xpath.ql b/python/ql/src/experimental/Security/CWE-643/xpath.ql deleted file mode 100644 index 15720c408ee..00000000000 --- a/python/ql/src/experimental/Security/CWE-643/xpath.ql +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @name XPath query built from user-controlled sources - * @description Building a XPath query from user-controlled sources is vulnerable to insertion of - * malicious Xpath code by the user. - * @kind path-problem - * @problem.severity error - * @precision high - * @id py/xpath-injection - * @tags security - * external/cwe/cwe-643 - */ - -import python -import semmle.python.security.Paths -import semmle.python.security.strings.Untrusted -/* Sources */ -import semmle.python.web.HttpRequest -/* Sinks */ -import experimental.semmle.python.security.injection.Xpath - -class XpathInjectionConfiguration extends TaintTracking::Configuration { - XpathInjectionConfiguration() { this = "Xpath injection configuration" } - - override predicate isSource(TaintTracking::Source source) { - source instanceof HttpRequestTaintSource - } - - override predicate isSink(TaintTracking::Sink sink) { - sink instanceof XpathInjection::XpathInjectionSink - } -} - -from XpathInjectionConfiguration config, TaintedPathSource src, TaintedPathSink sink -where config.hasFlowPath(src, sink) -select sink.getSink(), src, sink, "This Xpath query depends on $@.", src.getSource(), - "a user-provided value" diff --git a/python/ql/src/experimental/semmle/python/Concepts.qll b/python/ql/src/experimental/semmle/python/Concepts.qll index f87caa88497..18e0a114b59 100644 --- a/python/ql/src/experimental/semmle/python/Concepts.qll +++ b/python/ql/src/experimental/semmle/python/Concepts.qll @@ -156,10 +156,20 @@ module LDAPBind { * extend `LDAPBind` instead. */ abstract class Range extends DataFlow::Node { + /** + * Gets the argument containing the binding host. + */ + abstract DataFlow::Node getHost(); + /** * Gets the argument containing the binding expression. */ abstract DataFlow::Node getPassword(); + + /** + * Holds if the binding process use SSL. + */ + abstract predicate useSSL(); } } @@ -174,7 +184,20 @@ class LDAPBind extends DataFlow::Node { LDAPBind() { this = range } + /** + * Gets the argument containing the binding host. + */ + DataFlow::Node getHost() { result = range.getHost() } + + /** + * Gets the argument containing the binding expression. + */ DataFlow::Node getPassword() { result = range.getPassword() } + + /** + * Holds if the binding process use SSL. + */ + predicate useSSL() { range.useSSL() } } /** Provides classes for modeling SQL sanitization libraries. */ diff --git a/python/ql/src/experimental/semmle/python/frameworks/LDAP.qll b/python/ql/src/experimental/semmle/python/frameworks/LDAP.qll index 83b1accafc1..9286129cf6e 100644 --- a/python/ql/src/experimental/semmle/python/frameworks/LDAP.qll +++ b/python/ql/src/experimental/semmle/python/frameworks/LDAP.qll @@ -88,6 +88,11 @@ private module LDAP { result.(DataFlow::AttrRead).getAttributeName() instanceof LDAP2BindMethods } + /**List of SSL-demanding options */ + private class LDAPSSLOptions extends DataFlow::Node { + LDAPSSLOptions() { this = ldap().getMember("OPT_X_TLS_" + ["DEMAND", "HARD"]).getAUse() } + } + /** * A class to find `ldap` methods binding a connection. * @@ -99,6 +104,44 @@ private module LDAP { override DataFlow::Node getPassword() { result in [this.getArg(1), this.getArgByName("cred")] } + + override DataFlow::Node getHost() { + exists(DataFlow::CallCfgNode initialize | + this.getFunction().(DataFlow::AttrRead).getObject().getALocalSource() = initialize and + initialize = ldapInitialize().getACall() and + result = initialize.getArg(0) + ) + } + + override predicate useSSL() { + // use initialize to correlate `this` and so avoid FP in several instances + exists(DataFlow::CallCfgNode initialize | + // ldap.set_option(ldap.OPT_X_TLS_%s) + ldap().getMember("set_option").getACall().getArg(_) instanceof LDAPSSLOptions + or + this.getFunction().(DataFlow::AttrRead).getObject().getALocalSource() = initialize and + initialize = ldapInitialize().getACall() and + ( + // ldap_connection.start_tls_s() + // see https://www.python-ldap.org/en/python-ldap-3.3.0/reference/ldap.html#ldap.LDAPObject.start_tls_s + exists(DataFlow::MethodCallNode startTLS | + startTLS.getObject().getALocalSource() = initialize and + startTLS.getMethodName() = "start_tls_s" + ) + or + // ldap_connection.set_option(ldap.OPT_X_TLS_%s, True) + exists(DataFlow::CallCfgNode setOption | + setOption.getFunction().(DataFlow::AttrRead).getObject().getALocalSource() = + initialize and + setOption.getFunction().(DataFlow::AttrRead).getAttributeName() = "set_option" and + setOption.getArg(0) instanceof LDAPSSLOptions and + not DataFlow::exprNode(any(False falseExpr)) + .(DataFlow::LocalSourceNode) + .flowsTo(setOption.getArg(1)) + ) + ) + ) + } } /** @@ -166,6 +209,31 @@ private module LDAP { override DataFlow::Node getPassword() { result in [this.getArg(2), this.getArgByName("password")] } + + override DataFlow::Node getHost() { + exists(DataFlow::CallCfgNode serverCall | + serverCall = ldap3Server().getACall() and + this.getArg(0).getALocalSource() = serverCall and + result = serverCall.getArg(0) + ) + } + + override predicate useSSL() { + exists(DataFlow::CallCfgNode serverCall | + serverCall = ldap3Server().getACall() and + this.getArg(0).getALocalSource() = serverCall and + DataFlow::exprNode(any(True trueExpr)) + .(DataFlow::LocalSourceNode) + .flowsTo([serverCall.getArg(2), serverCall.getArgByName("use_ssl")]) + ) + or + // ldap_connection.start_tls_s() + // see https://www.python-ldap.org/en/python-ldap-3.3.0/reference/ldap.html#ldap.LDAPObject.start_tls_s + exists(DataFlow::MethodCallNode startTLS | + startTLS.getMethodName() = "start_tls_s" and + startTLS.getObject().getALocalSource() = this + ) + } } /** diff --git a/python/ql/src/experimental/semmle/python/frameworks/SqlAlchemy.qll b/python/ql/src/experimental/semmle/python/frameworks/SqlAlchemy.qll deleted file mode 100644 index 00d550d9844..00000000000 --- a/python/ql/src/experimental/semmle/python/frameworks/SqlAlchemy.qll +++ /dev/null @@ -1,148 +0,0 @@ -/** - * Provides classes modeling security-relevant aspects of the 'SqlAlchemy' package. - * See https://pypi.org/project/SQLAlchemy/. - */ - -private import python -private import semmle.python.dataflow.new.DataFlow -private import semmle.python.dataflow.new.TaintTracking -private import semmle.python.ApiGraphs -private import semmle.python.Concepts -private import experimental.semmle.python.Concepts - -private module SqlAlchemy { - /** - * Returns an instantization of a SqlAlchemy Session object. - * See https://docs.sqlalchemy.org/en/14/orm/session_api.html#sqlalchemy.orm.Session and - * https://docs.sqlalchemy.org/en/14/orm/session_api.html#sqlalchemy.orm.sessionmaker - */ - private API::Node getSqlAlchemySessionInstance() { - result = API::moduleImport("sqlalchemy.orm").getMember("Session").getReturn() or - result = API::moduleImport("sqlalchemy.orm").getMember("sessionmaker").getReturn().getReturn() - } - - /** - * Returns an instantization of a SqlAlchemy Engine object. - * See https://docs.sqlalchemy.org/en/14/core/engines.html#sqlalchemy.create_engine - */ - private API::Node getSqlAlchemyEngineInstance() { - result = API::moduleImport("sqlalchemy").getMember("create_engine").getReturn() - } - - /** - * Returns an instantization of a SqlAlchemy Query object. - * See https://docs.sqlalchemy.org/en/14/orm/query.html?highlight=query#sqlalchemy.orm.Query - */ - private API::Node getSqlAlchemyQueryInstance() { - result = getSqlAlchemySessionInstance().getMember("query").getReturn() - } - - /** - * A call to `execute` meant to execute an SQL expression - * See the following links: - * - https://docs.sqlalchemy.org/en/14/core/connections.html?highlight=execute#sqlalchemy.engine.Connection.execute - * - https://docs.sqlalchemy.org/en/14/core/connections.html?highlight=execute#sqlalchemy.engine.Engine.execute - * - https://docs.sqlalchemy.org/en/14/orm/session_api.html?highlight=execute#sqlalchemy.orm.Session.execute - */ - private class SqlAlchemyExecuteCall extends DataFlow::CallCfgNode, SqlExecution::Range { - SqlAlchemyExecuteCall() { - // new way - this = getSqlAlchemySessionInstance().getMember("execute").getACall() or - this = - getSqlAlchemyEngineInstance() - .getMember(["connect", "begin"]) - .getReturn() - .getMember("execute") - .getACall() - } - - override DataFlow::Node getSql() { result = this.getArg(0) } - } - - /** - * A call to `scalar` meant to execute an SQL expression - * See https://docs.sqlalchemy.org/en/14/orm/session_api.html#sqlalchemy.orm.Session.scalar and - * https://docs.sqlalchemy.org/en/14/core/connections.html?highlight=scalar#sqlalchemy.engine.Engine.scalar - */ - private class SqlAlchemyScalarCall extends DataFlow::CallCfgNode, SqlExecution::Range { - SqlAlchemyScalarCall() { - this = - [getSqlAlchemySessionInstance(), getSqlAlchemyEngineInstance()] - .getMember("scalar") - .getACall() - } - - override DataFlow::Node getSql() { result = this.getArg(0) } - } - - /** - * A call on a Query object - * See https://docs.sqlalchemy.org/en/14/orm/query.html?highlight=query#sqlalchemy.orm.Query - */ - private class SqlAlchemyQueryCall extends DataFlow::CallCfgNode, SqlExecution::Range { - SqlAlchemyQueryCall() { - this = - getSqlAlchemyQueryInstance() - .getMember(any(SqlAlchemyVulnerableMethodNames methodName)) - .getACall() - } - - override DataFlow::Node getSql() { result = this.getArg(0) } - } - - /** - * This class represents a list of methods vulnerable to sql injection. - * - * See https://github.com/jty-team/codeql/pull/2#issue-611592361 - */ - private class SqlAlchemyVulnerableMethodNames extends string { - SqlAlchemyVulnerableMethodNames() { this in ["filter", "filter_by", "group_by", "order_by"] } - } - - /** - * Additional taint-steps for `sqlalchemy.text()` - * - * See https://docs.sqlalchemy.org/en/14/core/sqlelement.html#sqlalchemy.sql.expression.text - * See https://docs.sqlalchemy.org/en/14/core/sqlelement.html#sqlalchemy.sql.expression.TextClause - */ - class SqlAlchemyTextAdditionalTaintSteps extends TaintTracking::AdditionalTaintStep { - override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - exists(DataFlow::CallCfgNode call | - ( - call = API::moduleImport("sqlalchemy").getMember("text").getACall() - or - call = API::moduleImport("sqlalchemy").getMember("sql").getMember("text").getACall() - or - call = - API::moduleImport("sqlalchemy") - .getMember("sql") - .getMember("expression") - .getMember("text") - .getACall() - or - call = - API::moduleImport("sqlalchemy") - .getMember("sql") - .getMember("expression") - .getMember("TextClause") - .getACall() - ) and - nodeFrom in [call.getArg(0), call.getArgByName("text")] and - nodeTo = call - ) - } - } - - /** - * Gets a reference to `sqlescapy.sqlescape`. - * - * See https://pypi.org/project/sqlescapy/ - */ - class SQLEscapySanitizerCall extends DataFlow::CallCfgNode, SQLEscape::Range { - SQLEscapySanitizerCall() { - this = API::moduleImport("sqlescapy").getMember("sqlescape").getACall() - } - - override DataFlow::Node getAnInput() { result = this.getArg(0) } - } -} diff --git a/python/ql/src/experimental/semmle/python/security/LDAPInsecureAuth.qll b/python/ql/src/experimental/semmle/python/security/LDAPInsecureAuth.qll new file mode 100644 index 00000000000..442a21de30f --- /dev/null +++ b/python/ql/src/experimental/semmle/python/security/LDAPInsecureAuth.qll @@ -0,0 +1,106 @@ +/** + * Provides a taint-tracking configuration for detecting LDAP injection vulnerabilities + */ + +import python +import semmle.python.dataflow.new.DataFlow +import semmle.python.dataflow.new.TaintTracking +import semmle.python.dataflow.new.RemoteFlowSources +import experimental.semmle.python.Concepts + +string getFullHostRegex() { result = "(?i)ldap://.+" } + +string getSchemaRegex() { result = "(?i)ldap(://)?" } + +string getPrivateHostRegex() { + result = + "(?i)localhost(?:[:/?#].*)?|127\\.0\\.0\\.1(?:[:/?#].*)?|10(?:\\.[0-9]+){3}(?:[:/?#].*)?|172\\.16(?:\\.[0-9]+){2}(?:[:/?#].*)?|192.168(?:\\.[0-9]+){2}(?:[:/?#].*)?|\\[?0:0:0:0:0:0:0:1\\]?(?:[:/?#].*)?|\\[?::1\\]?(?:[:/?#].*)?" +} + +// "ldap://somethingon.theinternet.com" +class LDAPFullHost extends StrConst { + LDAPFullHost() { + exists(string s | + s = this.getText() and + s.regexpMatch(getFullHostRegex()) and + // check what comes after the `ldap://` prefix + not s.substring(7, s.length()).regexpMatch(getPrivateHostRegex()) + ) + } +} + +class LDAPSchema extends StrConst { + LDAPSchema() { this.getText().regexpMatch(getSchemaRegex()) } +} + +class LDAPPrivateHost extends StrConst { + LDAPPrivateHost() { this.getText().regexpMatch(getPrivateHostRegex()) } +} + +predicate concatAndCompareAgainstFullHostRegex(LDAPSchema schema, StrConst host) { + not host instanceof LDAPPrivateHost and + (schema.getText() + host.getText()).regexpMatch(getFullHostRegex()) +} + +// "ldap://" + "somethingon.theinternet.com" +class LDAPBothStrings extends BinaryExpr { + LDAPBothStrings() { concatAndCompareAgainstFullHostRegex(this.getLeft(), this.getRight()) } +} + +// schema + host +class LDAPBothVar extends BinaryExpr { + LDAPBothVar() { + exists(SsaVariable schemaVar, SsaVariable hostVar | + this.getLeft() = schemaVar.getVariable().getALoad() and // getAUse is incompatible with Expr + this.getRight() = hostVar.getVariable().getALoad() and + concatAndCompareAgainstFullHostRegex(schemaVar + .getDefinition() + .getImmediateDominator() + .getNode(), hostVar.getDefinition().getImmediateDominator().getNode()) + ) + } +} + +// schema + "somethingon.theinternet.com" +class LDAPVarString extends BinaryExpr { + LDAPVarString() { + exists(SsaVariable schemaVar | + this.getLeft() = schemaVar.getVariable().getALoad() and + concatAndCompareAgainstFullHostRegex(schemaVar + .getDefinition() + .getImmediateDominator() + .getNode(), this.getRight()) + ) + } +} + +// "ldap://" + host +class LDAPStringVar extends BinaryExpr { + LDAPStringVar() { + exists(SsaVariable hostVar | + this.getRight() = hostVar.getVariable().getALoad() and + concatAndCompareAgainstFullHostRegex(this.getLeft(), + hostVar.getDefinition().getImmediateDominator().getNode()) + ) + } +} + +/** + * A taint-tracking configuration for detecting LDAP insecure authentications. + */ +class LDAPInsecureAuthConfig extends TaintTracking::Configuration { + LDAPInsecureAuthConfig() { this = "LDAPInsecureAuthConfig" } + + override predicate isSource(DataFlow::Node source) { + source instanceof RemoteFlowSource or + source.asExpr() instanceof LDAPFullHost or + source.asExpr() instanceof LDAPBothStrings or + source.asExpr() instanceof LDAPBothVar or + source.asExpr() instanceof LDAPVarString or + source.asExpr() instanceof LDAPStringVar + } + + override predicate isSink(DataFlow::Node sink) { + exists(LDAPBind ldapBind | not ldapBind.useSSL() and sink = ldapBind.getHost()) + } +} diff --git a/python/ql/src/experimental/semmle/python/security/injection/Xpath.qll b/python/ql/src/experimental/semmle/python/security/injection/Xpath.qll deleted file mode 100644 index fa5c7647f1f..00000000000 --- a/python/ql/src/experimental/semmle/python/security/injection/Xpath.qll +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Provides class and predicates to track external data that - * may represent malicious xpath query objects. - * - * This module is intended to be imported into a taint-tracking query - * to extend `TaintKind` and `TaintSink`. - */ - -import python -import semmle.python.dataflow.TaintTracking -import semmle.python.web.HttpRequest - -/** Models Xpath Injection related classes and functions */ -module XpathInjection { - /** Returns a class value which refers to `lxml.etree` */ - Value etree() { result = Value::named("lxml.etree") } - - /** Returns a class value which refers to `lxml.etree` */ - Value libxml2parseFile() { result = Value::named("libxml2.parseFile") } - - /** A generic taint sink that is vulnerable to Xpath injection. */ - abstract class XpathInjectionSink extends TaintSink { } - - /** - * A Sink representing an argument to the `etree.XPath` call. - * - * from lxml import etree - * root = etree.XML("") - * find_text = etree.XPath("`sink`") - */ - private class EtreeXpathArgument extends XpathInjectionSink { - override string toString() { result = "lxml.etree.XPath" } - - EtreeXpathArgument() { - exists(CallNode call | call.getFunction().(AttrNode).getObject("XPath").pointsTo(etree()) | - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - } - - /** - * A Sink representing an argument to the `etree.EtXpath` call. - * - * from lxml import etree - * root = etree.XML("") - * find_text = etree.EtXPath("`sink`") - */ - private class EtreeETXpathArgument extends XpathInjectionSink { - override string toString() { result = "lxml.etree.ETXpath" } - - EtreeETXpathArgument() { - exists(CallNode call | call.getFunction().(AttrNode).getObject("ETXPath").pointsTo(etree()) | - call.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - } - - /** - * A Sink representing an argument to the `xpath` call to a parsed xml document. - * - * from lxml import etree - * from io import StringIO - * f = StringIO('') - * tree = etree.parse(f) - * r = tree.xpath('`sink`') - */ - private class ParseXpathArgument extends XpathInjectionSink { - override string toString() { result = "lxml.etree.parse.xpath" } - - ParseXpathArgument() { - exists( - CallNode parseCall, CallNode xpathCall, ControlFlowNode obj, Variable var, AssignStmt assign - | - parseCall.getFunction().(AttrNode).getObject("parse").pointsTo(etree()) and - assign.getValue().(Call).getAFlowNode() = parseCall and - xpathCall.getFunction().(AttrNode).getObject("xpath") = obj and - var.getAUse() = obj and - assign.getATarget() = var.getAStore() and - xpathCall.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - } - - /** - * A Sink representing an argument to the `xpathEval` call to a parsed libxml2 document. - * - * import libxml2 - * tree = libxml2.parseFile("file.xml") - * r = tree.xpathEval('`sink`') - */ - private class ParseFileXpathEvalArgument extends XpathInjectionSink { - override string toString() { result = "libxml2.parseFile.xpathEval" } - - ParseFileXpathEvalArgument() { - exists( - CallNode parseCall, CallNode xpathCall, ControlFlowNode obj, Variable var, AssignStmt assign - | - parseCall.getFunction().(AttrNode).pointsTo(libxml2parseFile()) and - assign.getValue().(Call).getAFlowNode() = parseCall and - xpathCall.getFunction().(AttrNode).getObject("xpathEval") = obj and - var.getAUse() = obj and - assign.getATarget() = var.getAStore() and - xpathCall.getArg(0) = this - ) - } - - override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind } - } -} diff --git a/python/ql/src/semmle/python/functions/ModificationOfParameterWithDefault.qll b/python/ql/src/semmle/python/functions/ModificationOfParameterWithDefault.qll new file mode 100644 index 00000000000..24103a33ace --- /dev/null +++ b/python/ql/src/semmle/python/functions/ModificationOfParameterWithDefault.qll @@ -0,0 +1,46 @@ +/** + * Provides a data-flow configuration for detecting modifications of a parameters default value. + * + * Note, for performance reasons: only import this file if + * `ModificationOfParameterWithDefault::Configuration` is needed, otherwise + * `ModificationOfParameterWithDefaultCustomizations` should be imported instead. + */ + +private import python +import semmle.python.dataflow.new.DataFlow + +/** + * Provides a data-flow configuration for detecting modifications of a parameters default value. + */ +module ModificationOfParameterWithDefault { + import ModificationOfParameterWithDefaultCustomizations::ModificationOfParameterWithDefault + + /** + * A data-flow configuration for detecting modifications of a parameters default value. + */ + class Configuration extends DataFlow::Configuration { + /** Record whether the default value being tracked is non-empty. */ + boolean nonEmptyDefault; + + Configuration() { + nonEmptyDefault in [true, false] and + this = "ModificationOfParameterWithDefault:" + nonEmptyDefault.toString() + } + + override predicate isSource(DataFlow::Node source) { + source.(Source).isNonEmpty() = nonEmptyDefault + } + + override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + override predicate isBarrier(DataFlow::Node node) { + // if we are tracking a non-empty default, then it is ok to modify empty values, + // so our tracking ends at those. + nonEmptyDefault = true and node instanceof MustBeEmpty + or + // if we are tracking a empty default, then it is ok to modify non-empty values, + // so our tracking ends at those. + nonEmptyDefault = false and node instanceof MustBeNonEmpty + } + } +} diff --git a/python/ql/src/semmle/python/functions/ModificationOfParameterWithDefaultCustomizations.qll b/python/ql/src/semmle/python/functions/ModificationOfParameterWithDefaultCustomizations.qll new file mode 100644 index 00000000000..6abb3f80085 --- /dev/null +++ b/python/ql/src/semmle/python/functions/ModificationOfParameterWithDefaultCustomizations.qll @@ -0,0 +1,190 @@ +/** + * Provides default sources, sinks and sanitizers for detecting + * modifications of a parameters default value, as well as extension points for adding your own. + */ + +private import python +private import semmle.python.dataflow.new.DataFlow +private import semmle.python.dataflow.new.BarrierGuards + +/** + * Provides default sources, sinks and sanitizers for detecting + * "command injection" + * vulnerabilities, as well as extension points for adding your own. + */ +module ModificationOfParameterWithDefault { + /** + * A data flow source for detecting modifications of a parameters default value, + * that is a default value for some parameter. + */ + abstract class Source extends DataFlow::Node { + /** Result is true if the default value is non-empty for this source and false if not. */ + abstract boolean isNonEmpty(); + } + + /** + * A data flow sink for detecting modifications of a parameters default value, + * that is a node representing a modification. + */ + abstract class Sink extends DataFlow::Node { } + + /** + * A sanitizer for detecting modifications of a parameters default value + * should determine if the node (which is perhaps about to be modified) + * can be the default value or not. + * + * In this query we do not track the default value exactly, but rather wheter + * it is empty or not (see `Source`). + * + * This is the extension point for determining that a node must be empty and + * therefor is allowed to be modified if the tracked default value is non-empty. + */ + abstract class MustBeEmpty extends DataFlow::Node { } + + /** + * A sanitizer for detecting modifications of a parameters default value + * should determine if the node (which is perhaps about to be modified) + * can be the default value or not. + * + * In this query we do not track the default value exactly, but rather wheter + * it is empty or not (see `Source`). + * + * This is the extension point for determining that a node must be non-empty + * and therefor is allowed to be modified if the tracked default value is empty. + */ + abstract class MustBeNonEmpty extends DataFlow::Node { } + + /** Gets the truthiness (non emptyness) of the default of `p` if that value is mutable */ + private boolean mutableDefaultValue(Parameter p) { + exists(Dict d | p.getDefault() = d | + exists(d.getAKey()) and result = true + or + not exists(d.getAKey()) and result = false + ) + or + exists(List l | p.getDefault() = l | + exists(l.getAnElt()) and result = true + or + not exists(l.getAnElt()) and result = false + ) + } + + /** + * A mutable default value for a parameter, considered as a flow source. + */ + class MutableDefaultValue extends Source { + boolean nonEmpty; + + MutableDefaultValue() { nonEmpty = mutableDefaultValue(this.asCfgNode().(NameNode).getNode()) } + + override boolean isNonEmpty() { result = nonEmpty } + } + + /** + * A name of a list function that modifies the list. + * See https://docs.python.org/3/tutorial/datastructures.html#more-on-lists + */ + string list_modifying_method() { + result in ["append", "extend", "insert", "remove", "pop", "clear", "sort", "reverse"] + } + + /** + * A name of a dict function that modifies the dict. + * See https://docs.python.org/3/library/stdtypes.html#dict + */ + string dict_modifying_method() { result in ["clear", "pop", "popitem", "setdefault", "update"] } + + /** + * A mutation of the default value is a flow sink. + * + * Syntactic constructs that modify a list are: + * - s[i] = x + * - s[i:j] = t + * - del s[i:j] + * - s[i:j:k] = t + * - del s[i:j:k] + * - s += t + * - s *= n + * See https://docs.python.org/3/library/stdtypes.html#mutable-sequence-types + * + * Syntactic constructs that modify a dictionary are: + * - d[key] = value + * - del d[key] + * - d |= other + * See https://docs.python.org/3/library/stdtypes.html#dict + * + * These are all covered by: + * - assignment to a subscript (includes slices) + * - deletion of a subscript + * - augmented assignment to the value + */ + class Mutation extends Sink { + Mutation() { + // assignment to a subscript (includes slices) + exists(DefinitionNode d | d.(SubscriptNode).getObject() = this.asCfgNode()) + or + // deletion of a subscript + exists(DeletionNode d | d.getTarget().(SubscriptNode).getObject() = this.asCfgNode()) + or + // augmented assignment to the value + exists(AugAssign a | a.getTarget().getAFlowNode() = this.asCfgNode()) + or + // modifying function call + exists(DataFlow::CallCfgNode c, DataFlow::AttrRead a | c.getFunction() = a | + a.getObject() = this and + a.getAttributeName() in [list_modifying_method(), dict_modifying_method()] + ) + } + } + + // This to reimplement some of the functionality of the DataFlow::BarrierGuard + private import semmle.python.essa.SsaCompute + + /** + * A data-flow node that is known to be either truthy or falsey. + * + * It handles the cases `if x` and `if not x`. + * + * For example, in the following code, `this` will be the `x` that is printed, + * which we will know is truthy: + * + * ```py + * if x: + * print(x) + * ``` + */ + private class MustBe extends DataFlow::Node { + boolean truthy; + + MustBe() { + exists(DataFlow::GuardNode guard, NameNode guarded, boolean branch | + // case: if x + guard = guarded and + branch = truthy + or + // case: if not x + guard.(UnaryExprNode).getNode().getOp() instanceof Not and + guarded = guard.(UnaryExprNode).getOperand() and + branch = truthy.booleanNot() + | + // guard controls this + guard.controlsBlock(this.asCfgNode().getBasicBlock(), branch) and + // there is a definition tying the guarded value to this + exists(EssaDefinition def | + AdjacentUses::useOfDef(def, this.asCfgNode()) and + AdjacentUses::useOfDef(def, guarded) + ) + ) + } + } + + /** Simple guard detecting truthy values. */ + private class MustBeTruthy extends MustBe, MustBeNonEmpty { + MustBeTruthy() { truthy = true } + } + + /** Simple guard detecting falsey values. */ + private class MustBeFalsey extends MustBe, MustBeEmpty { + MustBeFalsey() { truthy = false } + } +} diff --git a/python/ql/test/experimental/dataflow/import-helper/dataflow-consistency.expected b/python/ql/test/experimental/dataflow/ApiGraphs/dataflow-consistency.expected similarity index 100% rename from python/ql/test/experimental/dataflow/import-helper/dataflow-consistency.expected rename to python/ql/test/experimental/dataflow/ApiGraphs/dataflow-consistency.expected diff --git a/python/ql/test/experimental/dataflow/import-helper/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/ApiGraphs/dataflow-consistency.ql similarity index 100% rename from python/ql/test/experimental/dataflow/import-helper/dataflow-consistency.ql rename to python/ql/test/experimental/dataflow/ApiGraphs/dataflow-consistency.ql diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/test.py b/python/ql/test/experimental/dataflow/ApiGraphs/test.py index f4988e41a0f..084ada0e801 100644 --- a/python/ql/test/experimental/dataflow/ApiGraphs/test.py +++ b/python/ql/test/experimental/dataflow/ApiGraphs/test.py @@ -74,12 +74,6 @@ def f(): change_foo() sink(foo) #$ use=moduleImport("danger").getMember("SOURCE") -# Star imports - -from unknown import * #$ use=moduleImport("unknown") - -hello() #$ MISSING: use=moduleImport("unknown").getMember("hello").getReturn() - # Subclasses diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/test_import_star.py b/python/ql/test/experimental/dataflow/ApiGraphs/test_import_star.py new file mode 100644 index 00000000000..7b2934357be --- /dev/null +++ b/python/ql/test/experimental/dataflow/ApiGraphs/test_import_star.py @@ -0,0 +1,36 @@ +# Star imports + +from unknown import * #$ use=moduleImport("unknown") + +# Currently missing, as we do not consider `hello` to be a `LocalSourceNode`, since it has flow +# going into it from its corresponding `GlobalSsaVariable`. +hello() #$ MISSING: use=moduleImport("unknown").getMember("hello").getReturn() + +# We don't want our analysis to think that either `non_module_member` or `outer_bar` can +# come from `from unknown import *` +non_module_member + +outer_bar = 5 +outer_bar + +def foo(): + world() #$ use=moduleImport("unknown").getMember("world").getReturn() + bar = 5 + bar + non_module_member + print(bar) #$ use=moduleImport("builtins").getMember("print").getReturn() + +def quux(): + global non_module_member + non_module_member = 5 + +def func1(): + var() #$ use=moduleImport("unknown").getMember("var").getReturn() + def func2(): + var = "FOO" + +def func3(): + var2 = print #$ use=moduleImport("builtins").getMember("print") + def func4(): + var2() #$ MISSING: use=moduleImport("builtins").getMember("print").getReturn() + func4() diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/test_import_star2.py b/python/ql/test/experimental/dataflow/ApiGraphs/test_import_star2.py new file mode 100644 index 00000000000..a73f1f43548 --- /dev/null +++ b/python/ql/test/experimental/dataflow/ApiGraphs/test_import_star2.py @@ -0,0 +1,15 @@ +# Star imports in local scope + +hello2() + +def foo(): + from unknown2 import * #$ use=moduleImport("unknown2") + world2() #$ use=moduleImport("unknown2").getMember("world2").getReturn() + bar2 = 5 + bar2 + non_module_member2 + print(bar2) #$ use=moduleImport("builtins").getMember("print").getReturn() + +def quux2(): + global non_module_member2 + non_module_member2 = 5 diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index cbbac6c0d68..94a9e512313 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -66,9 +66,9 @@ def argument_passing( b, /, c, - d=arg4, + d=arg4, #$ arg4 func=argument_passing *, - e=arg5, + e=arg5, #$ arg5 func=argument_passing f, **g, ): @@ -120,7 +120,7 @@ def test_multiple_kw_args(): with_multiple_kw_args(**{"b": arg2}, **{"c": arg3}, **{"a": arg1}) #$ arg1 arg2 arg3 func=with_multiple_kw_args -def with_default_arguments(a=arg1, b=arg2, c=arg3): # Need a mechanism to test default arguments +def with_default_arguments(a=arg1, b=arg2, c=arg3): #$ arg1 arg2 arg3 func=with_default_arguments SINK1(a) SINK2(b) SINK3(c) diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRouting1.expected b/python/ql/test/experimental/dataflow/coverage/argumentRouting1.expected index 14db3123c37..1f00190c5c7 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRouting1.expected +++ b/python/ql/test/experimental/dataflow/coverage/argumentRouting1.expected @@ -14,6 +14,8 @@ edges | argumentPassing.py:120:59:120:69 | ControlFlowNode for Dict [Dictionary element at key a] | argumentPassing.py:120:5:120:70 | KwUnpacked a | | argumentPassing.py:120:65:120:68 | ControlFlowNode for arg1 | argumentPassing.py:120:59:120:69 | ControlFlowNode for Dict [Dictionary element at key a] | | argumentPassing.py:123:28:123:28 | ControlFlowNode for a | argumentPassing.py:124:11:124:11 | ControlFlowNode for a | +| argumentPassing.py:123:28:123:28 | ControlFlowNode for a | argumentPassing.py:124:11:124:11 | ControlFlowNode for a | +| argumentPassing.py:123:30:123:33 | ControlFlowNode for arg1 | argumentPassing.py:123:28:123:28 | ControlFlowNode for a | | argumentPassing.py:132:28:132:31 | ControlFlowNode for arg1 | argumentPassing.py:123:28:123:28 | ControlFlowNode for a | | argumentPassing.py:138:22:138:24 | ControlFlowNode for foo | argumentPassing.py:139:11:139:13 | ControlFlowNode for foo | | argumentPassing.py:160:46:160:49 | ControlFlowNode for arg1 | argumentPassing.py:138:22:138:24 | ControlFlowNode for foo | @@ -102,6 +104,8 @@ nodes | argumentPassing.py:120:59:120:69 | ControlFlowNode for Dict [Dictionary element at key a] | semmle.label | ControlFlowNode for Dict [Dictionary element at key a] | | argumentPassing.py:120:65:120:68 | ControlFlowNode for arg1 | semmle.label | ControlFlowNode for arg1 | | argumentPassing.py:123:28:123:28 | ControlFlowNode for a | semmle.label | ControlFlowNode for a | +| argumentPassing.py:123:28:123:28 | ControlFlowNode for a | semmle.label | ControlFlowNode for a | +| argumentPassing.py:123:30:123:33 | ControlFlowNode for arg1 | semmle.label | ControlFlowNode for arg1 | | argumentPassing.py:124:11:124:11 | ControlFlowNode for a | semmle.label | ControlFlowNode for a | | argumentPassing.py:132:28:132:31 | ControlFlowNode for arg1 | semmle.label | ControlFlowNode for arg1 | | argumentPassing.py:138:22:138:24 | ControlFlowNode for foo | semmle.label | ControlFlowNode for foo | @@ -207,6 +211,7 @@ subpaths | argumentPassing.py:118:27:118:30 | ControlFlowNode for arg1 | argumentPassing.py:118:27:118:30 | ControlFlowNode for arg1 | argumentPassing.py:110:11:110:11 | ControlFlowNode for a | Flow found | | argumentPassing.py:119:27:119:30 | ControlFlowNode for arg1 | argumentPassing.py:119:27:119:30 | ControlFlowNode for arg1 | argumentPassing.py:110:11:110:11 | ControlFlowNode for a | Flow found | | argumentPassing.py:120:65:120:68 | ControlFlowNode for arg1 | argumentPassing.py:120:65:120:68 | ControlFlowNode for arg1 | argumentPassing.py:110:11:110:11 | ControlFlowNode for a | Flow found | +| argumentPassing.py:123:30:123:33 | ControlFlowNode for arg1 | argumentPassing.py:123:30:123:33 | ControlFlowNode for arg1 | argumentPassing.py:124:11:124:11 | ControlFlowNode for a | Flow found | | argumentPassing.py:132:28:132:31 | ControlFlowNode for arg1 | argumentPassing.py:132:28:132:31 | ControlFlowNode for arg1 | argumentPassing.py:124:11:124:11 | ControlFlowNode for a | Flow found | | argumentPassing.py:160:46:160:49 | ControlFlowNode for arg1 | argumentPassing.py:160:46:160:49 | ControlFlowNode for arg1 | argumentPassing.py:139:11:139:13 | ControlFlowNode for foo | Flow found | | argumentPassing.py:168:14:168:17 | ControlFlowNode for arg1 | argumentPassing.py:168:14:168:17 | ControlFlowNode for arg1 | argumentPassing.py:166:15:166:15 | ControlFlowNode for a | Flow found | diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRouting2.expected b/python/ql/test/experimental/dataflow/coverage/argumentRouting2.expected index b9271056743..ed816d030be 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRouting2.expected +++ b/python/ql/test/experimental/dataflow/coverage/argumentRouting2.expected @@ -10,6 +10,8 @@ edges | argumentPassing.py:120:29:120:39 | ControlFlowNode for Dict [Dictionary element at key b] | argumentPassing.py:120:5:120:70 | KwUnpacked b | | argumentPassing.py:120:35:120:38 | ControlFlowNode for arg2 | argumentPassing.py:120:29:120:39 | ControlFlowNode for Dict [Dictionary element at key b] | | argumentPassing.py:123:36:123:36 | ControlFlowNode for b | argumentPassing.py:125:11:125:11 | ControlFlowNode for b | +| argumentPassing.py:123:36:123:36 | ControlFlowNode for b | argumentPassing.py:125:11:125:11 | ControlFlowNode for b | +| argumentPassing.py:123:38:123:41 | ControlFlowNode for arg2 | argumentPassing.py:123:36:123:36 | ControlFlowNode for b | | argumentPassing.py:133:30:133:33 | ControlFlowNode for arg2 | argumentPassing.py:123:36:123:36 | ControlFlowNode for b | | argumentPassing.py:138:29:138:34 | ControlFlowNode for kwargs [Dictionary element at key bar] | argumentPassing.py:140:20:140:25 | ControlFlowNode for kwargs [Dictionary element at key bar] | | argumentPassing.py:140:5:140:26 | KwUnpacked bar | argumentPassing.py:145:18:145:20 | ControlFlowNode for bar | @@ -64,6 +66,8 @@ nodes | argumentPassing.py:120:29:120:39 | ControlFlowNode for Dict [Dictionary element at key b] | semmle.label | ControlFlowNode for Dict [Dictionary element at key b] | | argumentPassing.py:120:35:120:38 | ControlFlowNode for arg2 | semmle.label | ControlFlowNode for arg2 | | argumentPassing.py:123:36:123:36 | ControlFlowNode for b | semmle.label | ControlFlowNode for b | +| argumentPassing.py:123:36:123:36 | ControlFlowNode for b | semmle.label | ControlFlowNode for b | +| argumentPassing.py:123:38:123:41 | ControlFlowNode for arg2 | semmle.label | ControlFlowNode for arg2 | | argumentPassing.py:125:11:125:11 | ControlFlowNode for b | semmle.label | ControlFlowNode for b | | argumentPassing.py:133:30:133:33 | ControlFlowNode for arg2 | semmle.label | ControlFlowNode for arg2 | | argumentPassing.py:138:29:138:34 | ControlFlowNode for kwargs [Dictionary element at key bar] | semmle.label | ControlFlowNode for kwargs [Dictionary element at key bar] | @@ -128,6 +132,7 @@ subpaths | argumentPassing.py:105:27:105:30 | ControlFlowNode for arg2 | argumentPassing.py:105:27:105:30 | ControlFlowNode for arg2 | argumentPassing.py:99:11:99:11 | ControlFlowNode for b | Flow found | | argumentPassing.py:117:29:117:32 | ControlFlowNode for arg2 | argumentPassing.py:117:29:117:32 | ControlFlowNode for arg2 | argumentPassing.py:111:11:111:11 | ControlFlowNode for b | Flow found | | argumentPassing.py:120:35:120:38 | ControlFlowNode for arg2 | argumentPassing.py:120:35:120:38 | ControlFlowNode for arg2 | argumentPassing.py:111:11:111:11 | ControlFlowNode for b | Flow found | +| argumentPassing.py:123:38:123:41 | ControlFlowNode for arg2 | argumentPassing.py:123:38:123:41 | ControlFlowNode for arg2 | argumentPassing.py:125:11:125:11 | ControlFlowNode for b | Flow found | | argumentPassing.py:133:30:133:33 | ControlFlowNode for arg2 | argumentPassing.py:133:30:133:33 | ControlFlowNode for arg2 | argumentPassing.py:125:11:125:11 | ControlFlowNode for b | Flow found | | argumentPassing.py:160:36:160:39 | ControlFlowNode for arg2 | argumentPassing.py:160:36:160:39 | ControlFlowNode for arg2 | argumentPassing.py:146:11:146:13 | ControlFlowNode for bar | Flow found | | classes.py:565:18:565:21 | ControlFlowNode for arg2 | classes.py:565:18:565:21 | ControlFlowNode for arg2 | classes.py:556:15:556:17 | ControlFlowNode for key | Flow found | diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRouting3.expected b/python/ql/test/experimental/dataflow/coverage/argumentRouting3.expected index 31f76f9cc7b..12f5d39ddbd 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRouting3.expected +++ b/python/ql/test/experimental/dataflow/coverage/argumentRouting3.expected @@ -10,6 +10,8 @@ edges | argumentPassing.py:120:44:120:54 | ControlFlowNode for Dict [Dictionary element at key c] | argumentPassing.py:120:5:120:70 | KwUnpacked c | | argumentPassing.py:120:50:120:53 | ControlFlowNode for arg3 | argumentPassing.py:120:44:120:54 | ControlFlowNode for Dict [Dictionary element at key c] | | argumentPassing.py:123:44:123:44 | ControlFlowNode for c | argumentPassing.py:126:11:126:11 | ControlFlowNode for c | +| argumentPassing.py:123:44:123:44 | ControlFlowNode for c | argumentPassing.py:126:11:126:11 | ControlFlowNode for c | +| argumentPassing.py:123:46:123:49 | ControlFlowNode for arg3 | argumentPassing.py:123:44:123:44 | ControlFlowNode for c | | argumentPassing.py:134:5:134:41 | KwUnpacked c | argumentPassing.py:123:44:123:44 | ControlFlowNode for c | | argumentPassing.py:134:30:134:40 | ControlFlowNode for Dict [Dictionary element at key c] | argumentPassing.py:134:5:134:41 | KwUnpacked c | | argumentPassing.py:134:36:134:39 | ControlFlowNode for arg3 | argumentPassing.py:134:30:134:40 | ControlFlowNode for Dict [Dictionary element at key c] | @@ -37,6 +39,8 @@ nodes | argumentPassing.py:120:44:120:54 | ControlFlowNode for Dict [Dictionary element at key c] | semmle.label | ControlFlowNode for Dict [Dictionary element at key c] | | argumentPassing.py:120:50:120:53 | ControlFlowNode for arg3 | semmle.label | ControlFlowNode for arg3 | | argumentPassing.py:123:44:123:44 | ControlFlowNode for c | semmle.label | ControlFlowNode for c | +| argumentPassing.py:123:44:123:44 | ControlFlowNode for c | semmle.label | ControlFlowNode for c | +| argumentPassing.py:123:46:123:49 | ControlFlowNode for arg3 | semmle.label | ControlFlowNode for arg3 | | argumentPassing.py:126:11:126:11 | ControlFlowNode for c | semmle.label | ControlFlowNode for c | | argumentPassing.py:134:5:134:41 | KwUnpacked c | semmle.label | KwUnpacked c | | argumentPassing.py:134:30:134:40 | ControlFlowNode for Dict [Dictionary element at key c] | semmle.label | ControlFlowNode for Dict [Dictionary element at key c] | @@ -59,6 +63,7 @@ subpaths | argumentPassing.py:117:37:117:40 | ControlFlowNode for arg3 | argumentPassing.py:117:37:117:40 | ControlFlowNode for arg3 | argumentPassing.py:112:11:112:11 | ControlFlowNode for c | Flow found | | argumentPassing.py:119:41:119:44 | ControlFlowNode for arg3 | argumentPassing.py:119:41:119:44 | ControlFlowNode for arg3 | argumentPassing.py:112:11:112:11 | ControlFlowNode for c | Flow found | | argumentPassing.py:120:50:120:53 | ControlFlowNode for arg3 | argumentPassing.py:120:50:120:53 | ControlFlowNode for arg3 | argumentPassing.py:112:11:112:11 | ControlFlowNode for c | Flow found | +| argumentPassing.py:123:46:123:49 | ControlFlowNode for arg3 | argumentPassing.py:123:46:123:49 | ControlFlowNode for arg3 | argumentPassing.py:126:11:126:11 | ControlFlowNode for c | Flow found | | argumentPassing.py:134:36:134:39 | ControlFlowNode for arg3 | argumentPassing.py:134:36:134:39 | ControlFlowNode for arg3 | argumentPassing.py:126:11:126:11 | ControlFlowNode for c | Flow found | | argumentPassing.py:160:26:160:29 | ControlFlowNode for arg3 | argumentPassing.py:160:26:160:29 | ControlFlowNode for arg3 | argumentPassing.py:155:11:155:13 | ControlFlowNode for baz | Flow found | | classes.py:581:26:581:29 | ControlFlowNode for arg3 | classes.py:581:26:581:29 | ControlFlowNode for arg3 | classes.py:571:15:571:19 | ControlFlowNode for value | Flow found | diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRouting4.expected b/python/ql/test/experimental/dataflow/coverage/argumentRouting4.expected index e217064d1df..23432180c79 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRouting4.expected +++ b/python/ql/test/experimental/dataflow/coverage/argumentRouting4.expected @@ -1,4 +1,10 @@ edges +| argumentPassing.py:69:5:69:5 | ControlFlowNode for d | argumentPassing.py:78:11:78:11 | ControlFlowNode for d | +| argumentPassing.py:69:7:69:10 | ControlFlowNode for arg4 | argumentPassing.py:69:5:69:5 | ControlFlowNode for d | nodes +| argumentPassing.py:69:5:69:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| argumentPassing.py:69:7:69:10 | ControlFlowNode for arg4 | semmle.label | ControlFlowNode for arg4 | +| argumentPassing.py:78:11:78:11 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | subpaths #select +| argumentPassing.py:69:7:69:10 | ControlFlowNode for arg4 | argumentPassing.py:69:7:69:10 | ControlFlowNode for arg4 | argumentPassing.py:78:11:78:11 | ControlFlowNode for d | Flow found | diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRouting5.expected b/python/ql/test/experimental/dataflow/coverage/argumentRouting5.expected index e217064d1df..dea4556c307 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRouting5.expected +++ b/python/ql/test/experimental/dataflow/coverage/argumentRouting5.expected @@ -1,4 +1,10 @@ edges +| argumentPassing.py:71:5:71:5 | ControlFlowNode for e | argumentPassing.py:79:11:79:11 | ControlFlowNode for e | +| argumentPassing.py:71:7:71:10 | ControlFlowNode for arg5 | argumentPassing.py:71:5:71:5 | ControlFlowNode for e | nodes +| argumentPassing.py:71:5:71:5 | ControlFlowNode for e | semmle.label | ControlFlowNode for e | +| argumentPassing.py:71:7:71:10 | ControlFlowNode for arg5 | semmle.label | ControlFlowNode for arg5 | +| argumentPassing.py:79:11:79:11 | ControlFlowNode for e | semmle.label | ControlFlowNode for e | subpaths #select +| argumentPassing.py:71:7:71:10 | ControlFlowNode for arg5 | argumentPassing.py:71:7:71:10 | ControlFlowNode for arg5 | argumentPassing.py:79:11:79:11 | ControlFlowNode for e | Flow found | diff --git a/python/ql/test/experimental/dataflow/coverage/dataflow.expected b/python/ql/test/experimental/dataflow/coverage/dataflow.expected index 6099e76645e..68cd9dc50ee 100644 --- a/python/ql/test/experimental/dataflow/coverage/dataflow.expected +++ b/python/ql/test/experimental/dataflow/coverage/dataflow.expected @@ -379,6 +379,12 @@ edges | test.py:686:43:686:48 | ControlFlowNode for SOURCE | test.py:686:3:686:52 | PosOverflowNode for iterate_star_args() [Tuple element at index 0] | | test.py:686:51:686:51 | ControlFlowNode for s | test.py:686:3:686:52 | PosOverflowNode for iterate_star_args() [Tuple element at index 1] | | test.py:757:16:757:21 | ControlFlowNode for SOURCE | test.py:760:10:760:36 | ControlFlowNode for return_from_inner_scope() | +| test.py:795:35:795:35 | ControlFlowNode for x | test.py:796:10:796:10 | ControlFlowNode for x | +| test.py:795:37:795:42 | ControlFlowNode for SOURCE | test.py:795:35:795:35 | ControlFlowNode for x | +| test.py:795:48:795:48 | ControlFlowNode for y | test.py:797:10:797:10 | ControlFlowNode for y | +| test.py:795:50:795:55 | ControlFlowNode for SOURCE | test.py:795:48:795:48 | ControlFlowNode for y | +| test.py:795:61:795:61 | ControlFlowNode for z | test.py:798:10:798:10 | ControlFlowNode for z | +| test.py:795:63:795:68 | ControlFlowNode for SOURCE | test.py:795:61:795:61 | ControlFlowNode for z | nodes | datamodel.py:35:7:35:7 | ControlFlowNode for a | semmle.label | ControlFlowNode for a | | datamodel.py:36:10:36:10 | ControlFlowNode for a | semmle.label | ControlFlowNode for a | @@ -818,6 +824,15 @@ nodes | test.py:686:51:686:51 | ControlFlowNode for s | semmle.label | ControlFlowNode for s | | test.py:757:16:757:21 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | | test.py:760:10:760:36 | ControlFlowNode for return_from_inner_scope() | semmle.label | ControlFlowNode for return_from_inner_scope() | +| test.py:795:35:795:35 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| test.py:795:37:795:42 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:795:48:795:48 | ControlFlowNode for y | semmle.label | ControlFlowNode for y | +| test.py:795:50:795:55 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:795:61:795:61 | ControlFlowNode for z | semmle.label | ControlFlowNode for z | +| test.py:795:63:795:68 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:796:10:796:10 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| test.py:797:10:797:10 | ControlFlowNode for y | semmle.label | ControlFlowNode for y | +| test.py:798:10:798:10 | ControlFlowNode for z | semmle.label | ControlFlowNode for z | subpaths | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:35:7:35:7 | ControlFlowNode for a | datamodel.py:36:10:36:10 | ControlFlowNode for a | datamodel.py:38:6:38:17 | ControlFlowNode for f() | | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:44:22:44:22 | ControlFlowNode for x | datamodel.py:46:16:46:16 | ControlFlowNode for x | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | @@ -942,3 +957,6 @@ subpaths | test.py:680:10:680:12 | ControlFlowNode for arg | test.py:685:7:685:12 | ControlFlowNode for SOURCE | test.py:680:10:680:12 | ControlFlowNode for arg | Flow found | | test.py:680:10:680:12 | ControlFlowNode for arg | test.py:686:43:686:48 | ControlFlowNode for SOURCE | test.py:680:10:680:12 | ControlFlowNode for arg | Flow found | | test.py:760:10:760:36 | ControlFlowNode for return_from_inner_scope() | test.py:757:16:757:21 | ControlFlowNode for SOURCE | test.py:760:10:760:36 | ControlFlowNode for return_from_inner_scope() | Flow found | +| test.py:796:10:796:10 | ControlFlowNode for x | test.py:795:37:795:42 | ControlFlowNode for SOURCE | test.py:796:10:796:10 | ControlFlowNode for x | Flow found | +| test.py:797:10:797:10 | ControlFlowNode for y | test.py:795:50:795:55 | ControlFlowNode for SOURCE | test.py:797:10:797:10 | ControlFlowNode for y | Flow found | +| test.py:798:10:798:10 | ControlFlowNode for z | test.py:795:63:795:68 | ControlFlowNode for SOURCE | test.py:798:10:798:10 | ControlFlowNode for z | Flow found | diff --git a/python/ql/test/experimental/dataflow/coverage/test.py b/python/ql/test/experimental/dataflow/coverage/test.py index c7d5f063eb9..906ece07952 100644 --- a/python/ql/test/experimental/dataflow/coverage/test.py +++ b/python/ql/test/experimental/dataflow/coverage/test.py @@ -793,6 +793,6 @@ def test_reverse_read_subscript_cls(): @expects(3) def test_with_default_param_value(x=SOURCE, /, y=SOURCE, *, z=SOURCE): - SINK(x) #$ MISSING:flow="SOURCE, l:-1 -> x" - SINK(y) #$ MISSING:flow="SOURCE, l:-2 -> y" - SINK(z) #$ MISSING:flow="SOURCE, l:-3 -> z" + SINK(x) #$ flow="SOURCE, l:-1 -> x" + SINK(y) #$ flow="SOURCE, l:-2 -> y" + SINK(z) #$ flow="SOURCE, l:-3 -> z" diff --git a/python/ql/test/experimental/dataflow/import-helper/ImportHelper.expected b/python/ql/test/experimental/dataflow/import-helper/ImportHelper.expected deleted file mode 100644 index 11608b04ab8..00000000000 --- a/python/ql/test/experimental/dataflow/import-helper/ImportHelper.expected +++ /dev/null @@ -1,23 +0,0 @@ -| test1.py:1:8:1:12 | ControlFlowNode for ImportExpr | mypkg | -| test2.py:1:6:1:10 | ControlFlowNode for ImportExpr | mypkg | -| test2.py:1:6:1:10 | ControlFlowNode for ImportExpr | mypkg | -| test2.py:1:19:1:21 | ControlFlowNode for ImportMember | mypkg.foo | -| test2.py:1:24:1:26 | ControlFlowNode for ImportMember | mypkg.bar | -| test3.py:1:8:1:16 | ControlFlowNode for ImportExpr | mypkg | -| test3.py:2:8:2:16 | ControlFlowNode for ImportExpr | mypkg | -| test4.py:1:8:1:16 | ControlFlowNode for ImportExpr | mypkg.foo | -| test4.py:2:8:2:16 | ControlFlowNode for ImportExpr | mypkg.bar | -| test5.py:1:8:1:12 | ControlFlowNode for ImportExpr | mypkg | -| test5.py:9:6:9:10 | ControlFlowNode for ImportExpr | mypkg | -| test5.py:9:19:9:29 | ControlFlowNode for ImportMember | mypkg.bar | -| test6.py:1:8:1:12 | ControlFlowNode for ImportExpr | mypkg | -| test6.py:5:8:5:16 | ControlFlowNode for ImportExpr | mypkg | -| test7.py:1:6:1:10 | ControlFlowNode for ImportExpr | mypkg | -| test7.py:1:19:1:21 | ControlFlowNode for ImportMember | mypkg.foo | -| test7.py:5:8:5:16 | ControlFlowNode for ImportExpr | mypkg | -| test7.py:9:6:9:10 | ControlFlowNode for ImportExpr | mypkg | -| test7.py:9:19:9:21 | ControlFlowNode for ImportMember | mypkg.foo | -| test_deep.py:1:6:1:21 | ControlFlowNode for ImportExpr | start.middle.end | -| test_deep.py:1:6:1:21 | ControlFlowNode for ImportExpr | start.middle.end | -| test_deep.py:1:30:1:32 | ControlFlowNode for ImportMember | start.middle.end.foo | -| test_deep.py:1:35:1:37 | ControlFlowNode for ImportMember | start.middle.end.bar | diff --git a/python/ql/test/experimental/dataflow/import-helper/ImportHelper.ql b/python/ql/test/experimental/dataflow/import-helper/ImportHelper.ql deleted file mode 100644 index 0af7d88d87d..00000000000 --- a/python/ql/test/experimental/dataflow/import-helper/ImportHelper.ql +++ /dev/null @@ -1,4 +0,0 @@ -import python -import semmle.python.dataflow.new.DataFlow - -query predicate importNode(DataFlow::Node res, string name) { res = DataFlow::importNode(name) } diff --git a/python/ql/test/experimental/dataflow/import-helper/README.md b/python/ql/test/experimental/dataflow/import-helper/README.md deleted file mode 100644 index bcee9b620db..00000000000 --- a/python/ql/test/experimental/dataflow/import-helper/README.md +++ /dev/null @@ -1 +0,0 @@ -Small tests that explore difference between `import mypkg.foo` and `from mypkg import foo`. diff --git a/python/ql/test/experimental/dataflow/import-helper/mypkg/__init__.py b/python/ql/test/experimental/dataflow/import-helper/mypkg/__init__.py deleted file mode 100644 index c84a9b135a3..00000000000 --- a/python/ql/test/experimental/dataflow/import-helper/mypkg/__init__.py +++ /dev/null @@ -1 +0,0 @@ -foo = 42 diff --git a/python/ql/test/experimental/dataflow/import-helper/mypkg/bar.py b/python/ql/test/experimental/dataflow/import-helper/mypkg/bar.py deleted file mode 100644 index 2ae28399f5f..00000000000 --- a/python/ql/test/experimental/dataflow/import-helper/mypkg/bar.py +++ /dev/null @@ -1 +0,0 @@ -pass diff --git a/python/ql/test/experimental/dataflow/import-helper/mypkg/foo.py b/python/ql/test/experimental/dataflow/import-helper/mypkg/foo.py deleted file mode 100644 index 2ae28399f5f..00000000000 --- a/python/ql/test/experimental/dataflow/import-helper/mypkg/foo.py +++ /dev/null @@ -1 +0,0 @@ -pass diff --git a/python/ql/test/experimental/dataflow/import-helper/test1.py b/python/ql/test/experimental/dataflow/import-helper/test1.py deleted file mode 100644 index fa4d1464942..00000000000 --- a/python/ql/test/experimental/dataflow/import-helper/test1.py +++ /dev/null @@ -1,6 +0,0 @@ -import mypkg -print(mypkg.foo) # 42 -try: - print(mypkg.bar) -except AttributeError as e: - print(e) # module 'mypkg' has no attribute 'bar' diff --git a/python/ql/test/experimental/dataflow/import-helper/test2.py b/python/ql/test/experimental/dataflow/import-helper/test2.py deleted file mode 100644 index a706d61fd0c..00000000000 --- a/python/ql/test/experimental/dataflow/import-helper/test2.py +++ /dev/null @@ -1,3 +0,0 @@ -from mypkg import foo, bar -print(foo) -print(bar) diff --git a/python/ql/test/experimental/dataflow/import-helper/test3.py b/python/ql/test/experimental/dataflow/import-helper/test3.py deleted file mode 100644 index 4fc602432c2..00000000000 --- a/python/ql/test/experimental/dataflow/import-helper/test3.py +++ /dev/null @@ -1,4 +0,0 @@ -import mypkg.foo -import mypkg.bar -print(mypkg.foo) # " + +# also has engine/session instantiated + +raw_sql = "SELECT 'Foo'" + +conn = db.engine.connect() +result = conn.execute(raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("Foo",)] + +conn = db.get_engine().connect() +result = conn.execute(raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("Foo",)] + +result = db.session.execute(raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("Foo",)] + +Session = db.create_session(options={}) +session = Session() +result = session.execute(raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("Foo",)] + +Session = db.create_session(options={}) +with Session.begin() as session: + result = session.execute(raw_sql) # $ getSql=raw_sql + assert result.fetchall() == [("Foo",)] + +result = db.create_scoped_session().execute(raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("Foo",)] + + +# text +t = db.text("foo") +assert isinstance(t, sqlalchemy.sql.expression.TextClause) + +t = db.text(text="foo") +assert isinstance(t, sqlalchemy.sql.expression.TextClause) diff --git a/python/ql/test/library-tests/frameworks/sqlalchemy/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/sqlalchemy/ConceptsTest.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/frameworks/sqlalchemy/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/sqlalchemy/ConceptsTest.ql new file mode 100644 index 00000000000..b557a0bccb6 --- /dev/null +++ b/python/ql/test/library-tests/frameworks/sqlalchemy/ConceptsTest.ql @@ -0,0 +1,2 @@ +import python +import experimental.meta.ConceptsTest diff --git a/python/ql/test/library-tests/frameworks/sqlalchemy/InlineTaintTest.expected b/python/ql/test/library-tests/frameworks/sqlalchemy/InlineTaintTest.expected new file mode 100644 index 00000000000..79d760d87f4 --- /dev/null +++ b/python/ql/test/library-tests/frameworks/sqlalchemy/InlineTaintTest.expected @@ -0,0 +1,3 @@ +argumentToEnsureNotTaintedNotMarkedAsSpurious +untaintedArgumentToEnsureTaintedNotMarkedAsMissing +failures diff --git a/python/ql/test/library-tests/frameworks/sqlalchemy/InlineTaintTest.ql b/python/ql/test/library-tests/frameworks/sqlalchemy/InlineTaintTest.ql new file mode 100644 index 00000000000..027ad8667be --- /dev/null +++ b/python/ql/test/library-tests/frameworks/sqlalchemy/InlineTaintTest.ql @@ -0,0 +1 @@ +import experimental.meta.InlineTaintTest diff --git a/python/ql/test/experimental/library-tests/frameworks/sqlalchemy/SqlExecution.py b/python/ql/test/library-tests/frameworks/sqlalchemy/SqlExecution.py similarity index 86% rename from python/ql/test/experimental/library-tests/frameworks/sqlalchemy/SqlExecution.py rename to python/ql/test/library-tests/frameworks/sqlalchemy/SqlExecution.py index 7731e80e534..a7c9af9da32 100644 --- a/python/ql/test/experimental/library-tests/frameworks/sqlalchemy/SqlExecution.py +++ b/python/ql/test/library-tests/frameworks/sqlalchemy/SqlExecution.py @@ -47,10 +47,10 @@ with engine.begin() as connection: # Injection requiring the text() taint-step t = text("some sql") -session.query(User).filter(t) # $ getSql=t -session.query(User).group_by(User.id).having(t) # $ getSql=User.id MISSING: getSql=t -session.query(User).group_by(t).first() # $ getSql=t -session.query(User).order_by(t).first() # $ getSql=t +session.query(User).filter(t) +session.query(User).group_by(User.id).having(t) +session.query(User).group_by(t).first() +session.query(User).order_by(t).first() query = select(User).where(User.name == t) # $ MISSING: getSql=t with engine.connect() as conn: diff --git a/python/ql/test/library-tests/frameworks/sqlalchemy/new_tests.py b/python/ql/test/library-tests/frameworks/sqlalchemy/new_tests.py new file mode 100644 index 00000000000..9726e08f6bc --- /dev/null +++ b/python/ql/test/library-tests/frameworks/sqlalchemy/new_tests.py @@ -0,0 +1,388 @@ +import sqlalchemy +import sqlalchemy.orm + +# SQLAlchemy is slowly migrating to a 2.0 version, and as part of 1.4 release have a 2.0 +# style (forwards compatible) API that _can_ be adopted. So these tests are marked with +# either v1.4 or v2.0, such that we cover both. + +raw_sql = "select 'FOO'" +text_sql = sqlalchemy.text(raw_sql) + +Base = sqlalchemy.orm.declarative_base() + +# ============================================================================== +# v1.4 +# ============================================================================== + +print("v1.4") + +# Engine see https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.Engine + +engine = sqlalchemy.create_engine("sqlite+pysqlite:///:memory:", echo=True) + +result = engine.execute(raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("FOO",)] +result = engine.execute(statement=raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("FOO",)] +result = engine.execute(text_sql) # $ getSql=text_sql +assert result.fetchall() == [("FOO",)] + +scalar_result = engine.scalar(raw_sql) # $ getSql=raw_sql +assert scalar_result == "FOO" +scalar_result = engine.scalar(statement=raw_sql) # $ getSql=raw_sql +assert scalar_result == "FOO" + +# engine with custom execution options +# see https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.Engine.execution_options +engine_with_custom_exe_opts = engine.execution_options(foo=42) +result = engine_with_custom_exe_opts.execute(raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("FOO",)] + +even_more_opts = engine_with_custom_exe_opts.execution_options(bar=43) +result = even_more_opts.execute(raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("FOO",)] + +# Connection see https://docs.sqlalchemy.org/en/14/core/connections.html#sqlalchemy.engine.Connection +conn = engine.connect() +conn: sqlalchemy.engine.base.Connection + +result = conn.execute(raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("FOO",)] +result = conn.execute(statement=raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("FOO",)] + +result = conn.execute(text_sql) # $ getSql=text_sql +assert result.fetchall() == [("FOO",)] +result = conn.execute(statement=text_sql) # $ getSql=text_sql +assert result.fetchall() == [("FOO",)] + +# scalar +scalar_result = conn.scalar(raw_sql) # $ getSql=raw_sql +assert scalar_result == "FOO" +scalar_result = conn.scalar(object_=raw_sql) # $ getSql=raw_sql +assert scalar_result == "FOO" + +scalar_result = conn.scalar(text_sql) # $ getSql=text_sql +assert scalar_result == "FOO" +scalar_result = conn.scalar(object_=text_sql) # $ getSql=text_sql +assert scalar_result == "FOO" + + +# exec_driver_sql +result = conn.exec_driver_sql(raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("FOO",)] + +# construction by object +conn = sqlalchemy.engine.base.Connection(engine) +result = conn.execute(raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("FOO",)] + +# branched connection +branched_conn = conn.connect() +result = branched_conn.execute(text_sql) # $ getSql=text_sql +assert result.fetchall() == [("FOO",)] + +# raw connection +raw_conn = conn.connection +result = raw_conn.execute(raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("FOO",)] + +cursor = raw_conn.cursor() +cursor.execute(raw_sql) # $ getSql=raw_sql +assert cursor.fetchall() == [("FOO",)] +cursor.close() + +raw_conn = engine.raw_connection() +result = raw_conn.execute(raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("FOO",)] + +# connection with custom execution options +conn_with_custom_exe_opts = conn.execution_options(bar=1337) +result = conn_with_custom_exe_opts.execute(text_sql) # $ getSql=text_sql +assert result.fetchall() == [("FOO",)] + +# Session -- is what you use to work with the ORM layer +# see https://docs.sqlalchemy.org/en/14/orm/session_basics.html +# and https://docs.sqlalchemy.org/en/14/orm/session_api.html#sqlalchemy.orm.Session + +session = sqlalchemy.orm.Session(engine) + +result = session.execute(raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("FOO",)] +result = session.execute(statement=raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("FOO",)] + +result = session.execute(text_sql) # $ getSql=text_sql +assert result.fetchall() == [("FOO",)] +result = session.execute(statement=text_sql) # $ getSql=text_sql +assert result.fetchall() == [("FOO",)] + +# scalar +scalar_result = session.scalar(raw_sql) # $ getSql=raw_sql +assert scalar_result == "FOO" +scalar_result = session.scalar(statement=raw_sql) # $ getSql=raw_sql +assert scalar_result == "FOO" + +scalar_result = session.scalar(text_sql) # $ getSql=text_sql +assert scalar_result == "FOO" +scalar_result = session.scalar(statement=text_sql) # $ getSql=text_sql +assert scalar_result == "FOO" + +# other ways to construct a session +with sqlalchemy.orm.Session(engine) as session: + result = session.execute(raw_sql) # $ getSql=raw_sql + assert result.fetchall() == [("FOO",)] + +Session = sqlalchemy.orm.sessionmaker(engine) +session = Session() + +result = session.execute(raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("FOO",)] + +with Session() as session: + result = session.execute(raw_sql) # $ getSql=raw_sql + assert result.fetchall() == [("FOO",)] + +with Session.begin() as session: + result = session.execute(raw_sql) # $ getSql=raw_sql + assert result.fetchall() == [("FOO",)] + +# Querying (1.4) +# see https://docs.sqlalchemy.org/en/14/orm/session_basics.html#querying-1-x-style + +# to do so we first need a model + +class For14(Base): + __tablename__ = "for14" + + id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True) + description = sqlalchemy.Column(sqlalchemy.String) + +Base.metadata.create_all(engine) + +# add a test-entry +test_entry = For14(id=14, description="test") +session = sqlalchemy.orm.Session(engine) +session.add(test_entry) +session.commit() +assert session.query(For14).all()[0].id == 14 + +# and now we can do the actual querying + +text_foo = sqlalchemy.text("'FOO'") + +# filter_by is only vulnerable to injection if sqlalchemy.text is used, which is evident +# from the logs produced if this file is run +# that is, first filter_by results in the SQL +# +# SELECT for14.id AS for14_id, for14.description AS for14_description +# FROM for14 +# WHERE for14.description = ? +# +# which is then called with the argument `'FOO'` +# +# and the second filter_by results in the SQL +# +# SELECT for14.id AS for14_id, for14.description AS for14_description +# FROM for14 +# WHERE for14.description = 'FOO' +# +# which is then called without any arguments +assert session.query(For14).filter_by(description="'FOO'").all() == [] +query = session.query(For14).filter_by(description=text_foo) +assert query.all() == [] + +# Initially I wanted to add lots of additional taint steps such that the normal SQL +# injection query would find these cases where an ORM query includes a TextClause that +# includes user-input directly... But that presented 2 problems: +# +# - which part of the query construction above should be marked as SQL to fit our +# `SqlExecution` concept. Nothing really fits this well, since all the SQL execution +# happens under the hood. +# - This would require a LOT of modeling for these additional taint steps, since there +# are many many constructs we would need to have models for. (see the 2 examples below) +# +# So instead we extended the SQL injection query to include TextClause construction as a +# sink directly. + +# `filter` provides more general filtering +# see https://docs.sqlalchemy.org/en/14/orm/tutorial.html#common-filter-operators +# and https://docs.sqlalchemy.org/en/14/orm/query.html#sqlalchemy.orm.Query.filter +assert session.query(For14).filter(For14.description == "'FOO'").all() == [] +query = session.query(For14).filter(For14.description == text_foo) +assert query.all() == [] + +assert session.query(For14).filter(For14.description.like("'FOO'")).all() == [] +query = session.query(For14).filter(For14.description.like(text_foo)) +assert query.all() == [] + +# There are many other possibilities for ending up with SQL injection, including the +# following (not an exhaustive list): +# - `where` (alias for `filter`) +# - `group_by` +# - `having` +# - `order_by` +# - `join` +# - `outerjoin` + +# ============================================================================== +# v2.0 +# ============================================================================== +import sqlalchemy.future + +print("-"*80) +print("v2.0 style") + +# For Engine, see https://docs.sqlalchemy.org/en/14/core/future.html#sqlalchemy.future.Engine +engine = sqlalchemy.create_engine("sqlite+pysqlite:///:memory:", echo=True, future=True) +future_engine = sqlalchemy.future.create_engine("sqlite+pysqlite:///:memory:", echo=True) + +# in 2.0 you are not allowed to execute things directly on the engine +try: + engine.execute(raw_sql) # $ SPURIOUS: getSql=raw_sql + raise Exception("above not allowed in 2.0") +except NotImplementedError: + pass +try: + engine.execute(text_sql) # $ SPURIOUS: getSql=text_sql + raise Exception("above not allowed in 2.0") +except NotImplementedError: + pass + + +# `connect` returns a new Connection object. +# see https://docs.sqlalchemy.org/en/14/core/future.html#sqlalchemy.future.Connection +print("v2.0 engine.connect") +with engine.connect() as conn: + conn: sqlalchemy.future.Connection + + # in 2.0 you are not allowed to use raw strings like this: + try: + conn.execute(raw_sql) # $ SPURIOUS: getSql=raw_sql + raise Exception("above not allowed in 2.0") + except sqlalchemy.exc.ObjectNotExecutableError: + pass + + result = conn.execute(text_sql) # $ getSql=text_sql + assert result.fetchall() == [("FOO",)] + result = conn.execute(statement=text_sql) # $ getSql=text_sql + assert result.fetchall() == [("FOO",)] + + result = conn.exec_driver_sql(raw_sql) # $ getSql=raw_sql + assert result.fetchall() == [("FOO",)] + + raw_conn = conn.connection + result = raw_conn.execute(raw_sql) # $ getSql=raw_sql + assert result.fetchall() == [("FOO",)] + + # branching not allowed in 2.0 + try: + branched_conn = conn.connect() + raise Exception("above not allowed in 2.0") + except NotImplementedError: + pass + + # connection with custom execution options + conn_with_custom_exe_opts = conn.execution_options(bar=1337) + result = conn_with_custom_exe_opts.execute(text_sql) # $ getSql=text_sql + assert result.fetchall() == [("FOO",)] + + # `scalar` is shorthand helper + try: + conn.scalar(raw_sql) # $ SPURIOUS: getSql=raw_sql + except sqlalchemy.exc.ObjectNotExecutableError: + pass + scalar_result = conn.scalar(text_sql) # $ getSql=text_sql + assert scalar_result == "FOO" + scalar_result = conn.scalar(statement=text_sql) # $ getSql=text_sql + assert scalar_result == "FOO" + + # This is a contrived example + select = sqlalchemy.select(sqlalchemy.text("'BAR'")) + result = conn.execute(select) # $ getSql=select + assert result.fetchall() == [("BAR",)] + + # This is a contrived example + select = sqlalchemy.select(sqlalchemy.literal_column("'BAZ'")) + result = conn.execute(select) # $ getSql=select + assert result.fetchall() == [("BAZ",)] + +with future_engine.connect() as conn: + result = conn.execute(text_sql) # $ getSql=text_sql + assert result.fetchall() == [("FOO",)] + +# `begin` returns a new Connection object with a transaction begun. +print("v2.0 engine.begin") +with engine.begin() as conn: + result = conn.execute(text_sql) # $ getSql=text_sql + assert result.fetchall() == [("FOO",)] + +# construction by object +conn = sqlalchemy.future.Connection(engine) +result = conn.execute(text_sql) # $ getSql=text_sql +assert result.fetchall() == [("FOO",)] + +# raw_connection + +raw_conn = engine.raw_connection() +result = raw_conn.execute(raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("FOO",)] + +cursor = raw_conn.cursor() +cursor.execute(raw_sql) # $ getSql=raw_sql +assert cursor.fetchall() == [("FOO",)] +cursor.close() + +# Session (2.0) +session = sqlalchemy.orm.Session(engine, future=True) + +result = session.execute(raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("FOO",)] +result = session.execute(statement=raw_sql) # $ getSql=raw_sql +assert result.fetchall() == [("FOO",)] + +result = session.execute(text_sql) # $ getSql=text_sql +assert result.fetchall() == [("FOO",)] +result = session.execute(statement=text_sql) # $ getSql=text_sql +assert result.fetchall() == [("FOO",)] + +# scalar +scalar_result = session.scalar(raw_sql) # $ getSql=raw_sql +assert scalar_result == "FOO" +scalar_result = session.scalar(statement=raw_sql) # $ getSql=raw_sql +assert scalar_result == "FOO" + +scalar_result = session.scalar(text_sql) # $ getSql=text_sql +assert scalar_result == "FOO" +scalar_result = session.scalar(statement=text_sql) # $ getSql=text_sql +assert scalar_result == "FOO" + +# Querying (2.0) +# uses a slightly different style than 1.4 -- see note about not modeling +# ORM query construction as SQL execution at the 1.4 query tests. + +class For20(Base): + __tablename__ = "for20" + + id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True) + description = sqlalchemy.Column(sqlalchemy.String) + +For20.metadata.create_all(engine) + +# add a test-entry +test_entry = For20(id=20, description="test") +session = sqlalchemy.orm.Session(engine, future=True) +session.add(test_entry) +session.commit() +assert session.query(For20).all()[0].id == 20 + +# and now we can do the actual querying +# see https://docs.sqlalchemy.org/en/14/orm/session_basics.html#querying-2-0-style + +statement = sqlalchemy.select(For20) +result = session.execute(statement) # $ getSql=statement +assert result.scalars().all()[0].id == 20 + +statement = sqlalchemy.select(For20).where(For20.description == text_foo) +result = session.execute(statement) # $ getSql=statement +assert result.scalars().all() == [] diff --git a/python/ql/test/library-tests/frameworks/sqlalchemy/taint_test.py b/python/ql/test/library-tests/frameworks/sqlalchemy/taint_test.py new file mode 100644 index 00000000000..9e9764a411f --- /dev/null +++ b/python/ql/test/library-tests/frameworks/sqlalchemy/taint_test.py @@ -0,0 +1,28 @@ +import sqlalchemy + +ensure_tainted = ensure_not_tainted = print +TAINTED_STRING = "TAINTED_STRING" + +def test_taint(): + ts = TAINTED_STRING + + ensure_tainted(ts) # $ tainted + + t1 = sqlalchemy.text(ts) + t2 = sqlalchemy.text(text=ts) + t3 = sqlalchemy.sql.text(ts) + t4 = sqlalchemy.sql.text(text=ts) + t5 = sqlalchemy.sql.expression.text(ts) + t6 = sqlalchemy.sql.expression.text(text=ts) + t7 = sqlalchemy.sql.expression.TextClause(ts) + t8 = sqlalchemy.sql.expression.TextClause(text=ts) + + # Since we flag user-input to a TextClause with its' own query, we don't want to + # have a taint-step for it as that would lead to us also giving an alert for normal + # SQL-injection... and double alerting like this does not seem desireable. + ensure_not_tainted(t1, t2, t3, t4, t5, t6, t7, t8) + + for text in [t1, t2, t3, t4, t5, t6, t7, t8]: + assert isinstance(text, sqlalchemy.sql.expression.TextClause) + +test_taint() diff --git a/python/ql/test/library-tests/regexparser/redos.py b/python/ql/test/library-tests/regexparser/redos.py index 1ddee257e18..c8379bfcc0f 100644 --- a/python/ql/test/library-tests/regexparser/redos.py +++ b/python/ql/test/library-tests/regexparser/redos.py @@ -266,11 +266,11 @@ bad61 = re.compile(r'''(thisisagoddamnlongstringforstresstestingthequery|this\w+ # GOOD good27 = re.compile(r'''(thisisagoddamnlongstringforstresstestingthequery|imanotherbutunrelatedstringcomparedtotheotherstring)*-''') -# GOOD -good28 = re.compile(r'''foo([\uDC66\uDC67]|[\uDC68\uDC69])*foo''') +# GOOD (but false positive caused by the extractor converting all four unpaired surrogates to \uFFFD) +good28 = re.compile('''foo([\uDC66\uDC67]|[\uDC68\uDC69])*foo''') -# GOOD -good29 = re.compile(r'''foo((\uDC66|\uDC67)|(\uDC68|\uDC69))*foo''') +# GOOD (but false positive caused by the extractor converting all four unpaired surrogates to \uFFFD) +good29 = re.compile('''foo((\uDC66|\uDC67)|(\uDC68|\uDC69))*foo''') # NOT GOOD (but cannot currently construct a prefix) bad62 = re.compile(r'''a{2,3}(b+)+X''') diff --git a/python/ql/test/query-tests/Exceptions/generators/test.py b/python/ql/test/query-tests/Exceptions/generators/test.py index 7b7ef8c7fe2..e8b3f0b2b34 100644 --- a/python/ql/test/query-tests/Exceptions/generators/test.py +++ b/python/ql/test/query-tests/Exceptions/generators/test.py @@ -53,3 +53,12 @@ def ok5(seq): def ok6(seq): yield next(iter([]), default='foo') + +# Handling for multiple exception types, one of which is `StopIteration` +# Reported as a false positive in github/codeql#6227 +def ok7(seq, ctx): + try: + with ctx: + yield next(iter) + except (StopIteration, MemoryError): + return diff --git a/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/ModificationOfParameterWithDefault.expected b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/ModificationOfParameterWithDefault.expected new file mode 100644 index 00000000000..86daf9cb09e --- /dev/null +++ b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/ModificationOfParameterWithDefault.expected @@ -0,0 +1,108 @@ +edges +| test.py:2:12:2:12 | ControlFlowNode for l | test.py:3:5:3:5 | ControlFlowNode for l | +| test.py:7:11:7:11 | ControlFlowNode for l | test.py:8:5:8:5 | ControlFlowNode for l | +| test.py:12:14:12:14 | ControlFlowNode for l | test.py:13:9:13:9 | ControlFlowNode for l | +| test.py:17:15:17:15 | ControlFlowNode for l | test.py:18:5:18:5 | ControlFlowNode for l | +| test.py:22:15:22:15 | ControlFlowNode for l | test.py:23:5:23:5 | ControlFlowNode for l | +| test.py:27:12:27:12 | ControlFlowNode for l | test.py:28:5:28:5 | ControlFlowNode for l | +| test.py:38:13:38:13 | ControlFlowNode for l | test.py:39:5:39:5 | ControlFlowNode for l | +| test.py:43:14:43:14 | ControlFlowNode for l | test.py:44:13:44:13 | ControlFlowNode for l | +| test.py:44:13:44:13 | ControlFlowNode for l | test.py:38:13:38:13 | ControlFlowNode for l | +| test.py:48:14:48:14 | ControlFlowNode for l | test.py:49:5:49:5 | ControlFlowNode for l | +| test.py:53:10:53:10 | ControlFlowNode for d | test.py:54:5:54:5 | ControlFlowNode for d | +| test.py:58:19:58:19 | ControlFlowNode for d | test.py:59:5:59:5 | ControlFlowNode for d | +| test.py:63:28:63:28 | ControlFlowNode for d | test.py:64:5:64:5 | ControlFlowNode for d | +| test.py:67:14:67:14 | ControlFlowNode for d | test.py:68:5:68:5 | ControlFlowNode for d | +| test.py:72:19:72:19 | ControlFlowNode for d | test.py:73:14:73:14 | ControlFlowNode for d | +| test.py:73:14:73:14 | ControlFlowNode for d | test.py:67:14:67:14 | ControlFlowNode for d | +| test.py:77:17:77:17 | ControlFlowNode for d | test.py:78:5:78:5 | ControlFlowNode for d | +| test.py:82:26:82:26 | ControlFlowNode for d | test.py:83:5:83:5 | ControlFlowNode for d | +| test.py:87:35:87:35 | ControlFlowNode for d | test.py:88:5:88:5 | ControlFlowNode for d | +| test.py:91:21:91:21 | ControlFlowNode for d | test.py:92:5:92:5 | ControlFlowNode for d | +| test.py:96:26:96:26 | ControlFlowNode for d | test.py:97:21:97:21 | ControlFlowNode for d | +| test.py:97:21:97:21 | ControlFlowNode for d | test.py:91:21:91:21 | ControlFlowNode for d | +| test.py:108:14:108:14 | ControlFlowNode for d | test.py:109:9:109:9 | ControlFlowNode for d | +| test.py:113:20:113:20 | ControlFlowNode for d | test.py:115:5:115:5 | ControlFlowNode for d | +| test.py:119:29:119:29 | ControlFlowNode for d | test.py:121:5:121:5 | ControlFlowNode for d | +| test.py:124:15:124:15 | ControlFlowNode for l | test.py:128:9:128:9 | ControlFlowNode for l | +| test.py:131:23:131:23 | ControlFlowNode for l | test.py:135:9:135:9 | ControlFlowNode for l | +| test.py:138:15:138:15 | ControlFlowNode for l | test.py:140:9:140:9 | ControlFlowNode for l | +| test.py:145:23:145:23 | ControlFlowNode for l | test.py:147:9:147:9 | ControlFlowNode for l | +nodes +| test.py:2:12:2:12 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:3:5:3:5 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:7:11:7:11 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:8:5:8:5 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:12:14:12:14 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:13:9:13:9 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:17:15:17:15 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:18:5:18:5 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:22:15:22:15 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:23:5:23:5 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:27:12:27:12 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:28:5:28:5 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:38:13:38:13 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:39:5:39:5 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:43:14:43:14 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:44:13:44:13 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:48:14:48:14 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:49:5:49:5 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:53:10:53:10 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:54:5:54:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:58:19:58:19 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:59:5:59:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:63:28:63:28 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:64:5:64:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:67:14:67:14 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:68:5:68:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:72:19:72:19 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:73:14:73:14 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:77:17:77:17 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:78:5:78:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:82:26:82:26 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:83:5:83:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:87:35:87:35 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:88:5:88:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:91:21:91:21 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:92:5:92:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:96:26:96:26 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:97:21:97:21 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:108:14:108:14 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:109:9:109:9 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:113:20:113:20 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:115:5:115:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:119:29:119:29 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:121:5:121:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d | +| test.py:124:15:124:15 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:128:9:128:9 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:131:23:131:23 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:135:9:135:9 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:138:15:138:15 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:140:9:140:9 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:145:23:145:23 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +| test.py:147:9:147:9 | ControlFlowNode for l | semmle.label | ControlFlowNode for l | +subpaths +#select +| test.py:3:5:3:5 | ControlFlowNode for l | test.py:2:12:2:12 | ControlFlowNode for l | test.py:3:5:3:5 | ControlFlowNode for l | $@ flows to here and is mutated. | test.py:2:12:2:12 | ControlFlowNode for l | Default value | +| test.py:8:5:8:5 | ControlFlowNode for l | test.py:7:11:7:11 | ControlFlowNode for l | test.py:8:5:8:5 | ControlFlowNode for l | $@ flows to here and is mutated. | test.py:7:11:7:11 | ControlFlowNode for l | Default value | +| test.py:13:9:13:9 | ControlFlowNode for l | test.py:12:14:12:14 | ControlFlowNode for l | test.py:13:9:13:9 | ControlFlowNode for l | $@ flows to here and is mutated. | test.py:12:14:12:14 | ControlFlowNode for l | Default value | +| test.py:18:5:18:5 | ControlFlowNode for l | test.py:17:15:17:15 | ControlFlowNode for l | test.py:18:5:18:5 | ControlFlowNode for l | $@ flows to here and is mutated. | test.py:17:15:17:15 | ControlFlowNode for l | Default value | +| test.py:23:5:23:5 | ControlFlowNode for l | test.py:22:15:22:15 | ControlFlowNode for l | test.py:23:5:23:5 | ControlFlowNode for l | $@ flows to here and is mutated. | test.py:22:15:22:15 | ControlFlowNode for l | Default value | +| test.py:28:5:28:5 | ControlFlowNode for l | test.py:27:12:27:12 | ControlFlowNode for l | test.py:28:5:28:5 | ControlFlowNode for l | $@ flows to here and is mutated. | test.py:27:12:27:12 | ControlFlowNode for l | Default value | +| test.py:39:5:39:5 | ControlFlowNode for l | test.py:43:14:43:14 | ControlFlowNode for l | test.py:39:5:39:5 | ControlFlowNode for l | $@ flows to here and is mutated. | test.py:43:14:43:14 | ControlFlowNode for l | Default value | +| test.py:49:5:49:5 | ControlFlowNode for l | test.py:48:14:48:14 | ControlFlowNode for l | test.py:49:5:49:5 | ControlFlowNode for l | $@ flows to here and is mutated. | test.py:48:14:48:14 | ControlFlowNode for l | Default value | +| test.py:54:5:54:5 | ControlFlowNode for d | test.py:53:10:53:10 | ControlFlowNode for d | test.py:54:5:54:5 | ControlFlowNode for d | $@ flows to here and is mutated. | test.py:53:10:53:10 | ControlFlowNode for d | Default value | +| test.py:59:5:59:5 | ControlFlowNode for d | test.py:58:19:58:19 | ControlFlowNode for d | test.py:59:5:59:5 | ControlFlowNode for d | $@ flows to here and is mutated. | test.py:58:19:58:19 | ControlFlowNode for d | Default value | +| test.py:64:5:64:5 | ControlFlowNode for d | test.py:63:28:63:28 | ControlFlowNode for d | test.py:64:5:64:5 | ControlFlowNode for d | $@ flows to here and is mutated. | test.py:63:28:63:28 | ControlFlowNode for d | Default value | +| test.py:68:5:68:5 | ControlFlowNode for d | test.py:72:19:72:19 | ControlFlowNode for d | test.py:68:5:68:5 | ControlFlowNode for d | $@ flows to here and is mutated. | test.py:72:19:72:19 | ControlFlowNode for d | Default value | +| test.py:78:5:78:5 | ControlFlowNode for d | test.py:77:17:77:17 | ControlFlowNode for d | test.py:78:5:78:5 | ControlFlowNode for d | $@ flows to here and is mutated. | test.py:77:17:77:17 | ControlFlowNode for d | Default value | +| test.py:83:5:83:5 | ControlFlowNode for d | test.py:82:26:82:26 | ControlFlowNode for d | test.py:83:5:83:5 | ControlFlowNode for d | $@ flows to here and is mutated. | test.py:82:26:82:26 | ControlFlowNode for d | Default value | +| test.py:88:5:88:5 | ControlFlowNode for d | test.py:87:35:87:35 | ControlFlowNode for d | test.py:88:5:88:5 | ControlFlowNode for d | $@ flows to here and is mutated. | test.py:87:35:87:35 | ControlFlowNode for d | Default value | +| test.py:92:5:92:5 | ControlFlowNode for d | test.py:96:26:96:26 | ControlFlowNode for d | test.py:92:5:92:5 | ControlFlowNode for d | $@ flows to here and is mutated. | test.py:96:26:96:26 | ControlFlowNode for d | Default value | +| test.py:109:9:109:9 | ControlFlowNode for d | test.py:108:14:108:14 | ControlFlowNode for d | test.py:109:9:109:9 | ControlFlowNode for d | $@ flows to here and is mutated. | test.py:108:14:108:14 | ControlFlowNode for d | Default value | +| test.py:115:5:115:5 | ControlFlowNode for d | test.py:113:20:113:20 | ControlFlowNode for d | test.py:115:5:115:5 | ControlFlowNode for d | $@ flows to here and is mutated. | test.py:113:20:113:20 | ControlFlowNode for d | Default value | +| test.py:121:5:121:5 | ControlFlowNode for d | test.py:119:29:119:29 | ControlFlowNode for d | test.py:121:5:121:5 | ControlFlowNode for d | $@ flows to here and is mutated. | test.py:119:29:119:29 | ControlFlowNode for d | Default value | +| test.py:128:9:128:9 | ControlFlowNode for l | test.py:124:15:124:15 | ControlFlowNode for l | test.py:128:9:128:9 | ControlFlowNode for l | $@ flows to here and is mutated. | test.py:124:15:124:15 | ControlFlowNode for l | Default value | +| test.py:135:9:135:9 | ControlFlowNode for l | test.py:131:23:131:23 | ControlFlowNode for l | test.py:135:9:135:9 | ControlFlowNode for l | $@ flows to here and is mutated. | test.py:131:23:131:23 | ControlFlowNode for l | Default value | +| test.py:140:9:140:9 | ControlFlowNode for l | test.py:138:15:138:15 | ControlFlowNode for l | test.py:140:9:140:9 | ControlFlowNode for l | $@ flows to here and is mutated. | test.py:138:15:138:15 | ControlFlowNode for l | Default value | +| test.py:147:9:147:9 | ControlFlowNode for l | test.py:145:23:145:23 | ControlFlowNode for l | test.py:147:9:147:9 | ControlFlowNode for l | $@ flows to here and is mutated. | test.py:145:23:145:23 | ControlFlowNode for l | Default value | diff --git a/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/ModificationOfParameterWithDefault.qlref b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/ModificationOfParameterWithDefault.qlref new file mode 100644 index 00000000000..8c4044e8fee --- /dev/null +++ b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/ModificationOfParameterWithDefault.qlref @@ -0,0 +1 @@ +Functions/ModificationOfParameterWithDefault.ql diff --git a/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.expected b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.py b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.py new file mode 100644 index 00000000000..f1377f36e56 --- /dev/null +++ b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.py @@ -0,0 +1,150 @@ +# Not OK +def simple(l = [0]): + l[0] = 1 #$ modification=l + return l + +# Not OK +def slice(l = [0]): + l[0:1] = 1 #$ modification=l + return l + +# Not OK +def list_del(l = [0]): + del l[0] #$ modification=l + return l + +# Not OK +def append_op(l = []): + l += [1, 2, 3] #$ modification=l + return l + +# Not OK +def repeat_op(l = [0]): + l *= 3 #$ modification=l + return l + +# Not OK +def append(l = []): + l.append(1) #$ modification=l + return l + +# OK +def includes(l = []): + x = [0] + x.extend(l) + x.extend([1]) + return x + +def extends(l): + l.extend([1]) #$ modification=l + return l + +# Not OK +def deferred(l = []): + extends(l) + return l + +# Not OK +def nonempty(l = [5]): + l.append(1) #$ modification=l + return l + +# Not OK +def dict(d = {}): + d['a'] = 1 #$ modification=d + return d + +# Not OK +def dict_nonempty(d = {'a': 1}): + d['a'] = 2 #$ modification=d + return d + +# OK +def dict_nonempty_nochange(d = {'a': 1}): + d['a'] = 1 #$ SPURIOUS: modification=d + return d + +def modifies(d): + d['a'] = 1 #$ modification=d + return d + +# Not OK +def dict_deferred(d = {}): + modifies(d) + return d + +# Not OK +def dict_method(d = {}): + d.update({'a': 1}) #$ modification=d + return d + +# Not OK +def dict_method_nonempty(d = {'a': 1}): + d.update({'a': 2}) #$ modification=d + return d + +# OK +def dict_method_nonempty_nochange(d = {'a': 1}): + d.update({'a': 1}) #$ SPURIOUS:modification=d + return d + +def modifies_method(d): + d.update({'a': 1}) #$ modification=d + return d + +# Not OK +def dict_deferred_method(d = {}): + modifies_method(d) + return d + +# OK +def dict_includes(d = {}): + x = {} + x.update(d) + x.update({'a': 1}) + return x + +# Not OK +def dict_del(d = {'a': 1}): + del d['a'] #$ modification=d + return d + +# Not OK +def dict_update_op(d = {}): + x = {'a': 1} + d |= x #$ modification=d + return d + +# OK +def dict_update_op_nochange(d = {}): + x = {} + d |= x #$ SPURIOUS: modification=d + return d + +def sanitizer(l = []): + if l: + l.append(1) + else: + l.append(1) #$ modification=l + return l + +def sanitizer_negated(l = [1]): + if not l: + l.append(1) + else: + l.append(1) #$ modification=l + return l + +def sanitizer(l = []): + if not l: + l.append(1) #$ modification=l + else: + l.append(1) + return l + +def sanitizer_negated(l = [1]): + if l: + l.append(1) #$ modification=l + else: + l.append(1) + return l diff --git a/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.ql b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.ql new file mode 100644 index 00000000000..de516c7ec9b --- /dev/null +++ b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.ql @@ -0,0 +1,24 @@ +import python +import semmle.python.dataflow.new.DataFlow +import TestUtilities.InlineExpectationsTest +import semmle.python.functions.ModificationOfParameterWithDefault +private import semmle.python.dataflow.new.internal.PrintNode + +class ModificationOfParameterWithDefaultTest extends InlineExpectationsTest { + ModificationOfParameterWithDefaultTest() { this = "ModificationOfParameterWithDefaultTest" } + + override string getARelevantTag() { result = "modification" } + + predicate relevant_node(DataFlow::Node sink) { + exists(ModificationOfParameterWithDefault::Configuration cfg | cfg.hasFlowTo(sink)) + } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(DataFlow::Node n | relevant_node(n) | + n.getLocation() = location and + tag = "modification" and + value = prettyNode(n) and + element = n.toString() + ) + } +} diff --git a/python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.expected b/python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.expected index 08586d02c10..c32326d4942 100644 --- a/python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.expected +++ b/python/ql/test/query-tests/Functions/general/ModificationOfParameterWithDefault.expected @@ -1,24 +1,44 @@ edges -| functions_test.py:39:9:39:9 | empty mutable value | functions_test.py:40:5:40:5 | empty mutable value | -| functions_test.py:133:15:133:15 | empty mutable value | functions_test.py:134:5:134:5 | empty mutable value | -| functions_test.py:151:25:151:25 | empty mutable value | functions_test.py:152:5:152:5 | empty mutable value | -| functions_test.py:154:21:154:21 | empty mutable value | functions_test.py:155:5:155:5 | empty mutable value | -| functions_test.py:157:27:157:27 | empty mutable value | functions_test.py:158:25:158:25 | empty mutable value | -| functions_test.py:157:27:157:27 | empty mutable value | functions_test.py:159:21:159:21 | empty mutable value | -| functions_test.py:158:25:158:25 | empty mutable value | functions_test.py:151:25:151:25 | empty mutable value | -| functions_test.py:159:21:159:21 | empty mutable value | functions_test.py:154:21:154:21 | empty mutable value | -| functions_test.py:175:28:175:28 | non-empty mutable value | functions_test.py:179:9:179:9 | non-empty mutable value | -| functions_test.py:175:28:175:28 | non-empty mutable value | functions_test.py:181:9:181:9 | non-empty mutable value | -| functions_test.py:188:18:188:18 | non-empty mutable value | functions_test.py:189:28:189:28 | non-empty mutable value | -| functions_test.py:189:28:189:28 | non-empty mutable value | functions_test.py:175:28:175:28 | non-empty mutable value | -| functions_test.py:191:18:191:18 | non-empty mutable value | functions_test.py:192:28:192:28 | non-empty mutable value | -| functions_test.py:192:28:192:28 | non-empty mutable value | functions_test.py:175:28:175:28 | non-empty mutable value | +| functions_test.py:39:9:39:9 | ControlFlowNode for x | functions_test.py:40:5:40:5 | ControlFlowNode for x | +| functions_test.py:133:15:133:15 | ControlFlowNode for x | functions_test.py:134:5:134:5 | ControlFlowNode for x | +| functions_test.py:151:25:151:25 | ControlFlowNode for x | functions_test.py:152:5:152:5 | ControlFlowNode for x | +| functions_test.py:154:21:154:21 | ControlFlowNode for x | functions_test.py:155:5:155:5 | ControlFlowNode for x | +| functions_test.py:157:27:157:27 | ControlFlowNode for y | functions_test.py:158:25:158:25 | ControlFlowNode for y | +| functions_test.py:157:27:157:27 | ControlFlowNode for y | functions_test.py:159:21:159:21 | ControlFlowNode for y | +| functions_test.py:158:25:158:25 | ControlFlowNode for y | functions_test.py:151:25:151:25 | ControlFlowNode for x | +| functions_test.py:159:21:159:21 | ControlFlowNode for y | functions_test.py:154:21:154:21 | ControlFlowNode for x | +| functions_test.py:179:28:179:28 | ControlFlowNode for x | functions_test.py:183:9:183:9 | ControlFlowNode for x | +| functions_test.py:179:28:179:28 | ControlFlowNode for x | functions_test.py:185:9:185:9 | ControlFlowNode for x | +| functions_test.py:192:18:192:18 | ControlFlowNode for x | functions_test.py:193:28:193:28 | ControlFlowNode for x | +| functions_test.py:193:28:193:28 | ControlFlowNode for x | functions_test.py:179:28:179:28 | ControlFlowNode for x | +| functions_test.py:195:18:195:18 | ControlFlowNode for x | functions_test.py:196:28:196:28 | ControlFlowNode for x | +| functions_test.py:196:28:196:28 | ControlFlowNode for x | functions_test.py:179:28:179:28 | ControlFlowNode for x | +nodes +| functions_test.py:39:9:39:9 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| functions_test.py:40:5:40:5 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| functions_test.py:133:15:133:15 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| functions_test.py:134:5:134:5 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| functions_test.py:151:25:151:25 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| functions_test.py:152:5:152:5 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| functions_test.py:154:21:154:21 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| functions_test.py:155:5:155:5 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| functions_test.py:157:27:157:27 | ControlFlowNode for y | semmle.label | ControlFlowNode for y | +| functions_test.py:158:25:158:25 | ControlFlowNode for y | semmle.label | ControlFlowNode for y | +| functions_test.py:159:21:159:21 | ControlFlowNode for y | semmle.label | ControlFlowNode for y | +| functions_test.py:179:28:179:28 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| functions_test.py:183:9:183:9 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| functions_test.py:185:9:185:9 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| functions_test.py:192:18:192:18 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| functions_test.py:193:28:193:28 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| functions_test.py:195:18:195:18 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| functions_test.py:196:28:196:28 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +subpaths #select -| functions_test.py:40:5:40:5 | x | functions_test.py:39:9:39:9 | empty mutable value | functions_test.py:40:5:40:5 | empty mutable value | $@ flows to here and is mutated. | functions_test.py:39:9:39:9 | x | Default value | -| functions_test.py:134:5:134:5 | x | functions_test.py:133:15:133:15 | empty mutable value | functions_test.py:134:5:134:5 | empty mutable value | $@ flows to here and is mutated. | functions_test.py:133:15:133:15 | x | Default value | -| functions_test.py:152:5:152:5 | x | functions_test.py:157:27:157:27 | empty mutable value | functions_test.py:152:5:152:5 | empty mutable value | $@ flows to here and is mutated. | functions_test.py:157:27:157:27 | y | Default value | -| functions_test.py:155:5:155:5 | x | functions_test.py:157:27:157:27 | empty mutable value | functions_test.py:155:5:155:5 | empty mutable value | $@ flows to here and is mutated. | functions_test.py:157:27:157:27 | y | Default value | -| functions_test.py:179:9:179:9 | x | functions_test.py:188:18:188:18 | non-empty mutable value | functions_test.py:179:9:179:9 | non-empty mutable value | $@ flows to here and is mutated. | functions_test.py:188:18:188:18 | x | Default value | -| functions_test.py:179:9:179:9 | x | functions_test.py:191:18:191:18 | non-empty mutable value | functions_test.py:179:9:179:9 | non-empty mutable value | $@ flows to here and is mutated. | functions_test.py:191:18:191:18 | x | Default value | -| functions_test.py:181:9:181:9 | x | functions_test.py:188:18:188:18 | non-empty mutable value | functions_test.py:181:9:181:9 | non-empty mutable value | $@ flows to here and is mutated. | functions_test.py:188:18:188:18 | x | Default value | -| functions_test.py:181:9:181:9 | x | functions_test.py:191:18:191:18 | non-empty mutable value | functions_test.py:181:9:181:9 | non-empty mutable value | $@ flows to here and is mutated. | functions_test.py:191:18:191:18 | x | Default value | +| functions_test.py:40:5:40:5 | ControlFlowNode for x | functions_test.py:39:9:39:9 | ControlFlowNode for x | functions_test.py:40:5:40:5 | ControlFlowNode for x | $@ flows to here and is mutated. | functions_test.py:39:9:39:9 | ControlFlowNode for x | Default value | +| functions_test.py:134:5:134:5 | ControlFlowNode for x | functions_test.py:133:15:133:15 | ControlFlowNode for x | functions_test.py:134:5:134:5 | ControlFlowNode for x | $@ flows to here and is mutated. | functions_test.py:133:15:133:15 | ControlFlowNode for x | Default value | +| functions_test.py:152:5:152:5 | ControlFlowNode for x | functions_test.py:157:27:157:27 | ControlFlowNode for y | functions_test.py:152:5:152:5 | ControlFlowNode for x | $@ flows to here and is mutated. | functions_test.py:157:27:157:27 | ControlFlowNode for y | Default value | +| functions_test.py:155:5:155:5 | ControlFlowNode for x | functions_test.py:157:27:157:27 | ControlFlowNode for y | functions_test.py:155:5:155:5 | ControlFlowNode for x | $@ flows to here and is mutated. | functions_test.py:157:27:157:27 | ControlFlowNode for y | Default value | +| functions_test.py:183:9:183:9 | ControlFlowNode for x | functions_test.py:192:18:192:18 | ControlFlowNode for x | functions_test.py:183:9:183:9 | ControlFlowNode for x | $@ flows to here and is mutated. | functions_test.py:192:18:192:18 | ControlFlowNode for x | Default value | +| functions_test.py:183:9:183:9 | ControlFlowNode for x | functions_test.py:195:18:195:18 | ControlFlowNode for x | functions_test.py:183:9:183:9 | ControlFlowNode for x | $@ flows to here and is mutated. | functions_test.py:195:18:195:18 | ControlFlowNode for x | Default value | +| functions_test.py:185:9:185:9 | ControlFlowNode for x | functions_test.py:192:18:192:18 | ControlFlowNode for x | functions_test.py:185:9:185:9 | ControlFlowNode for x | $@ flows to here and is mutated. | functions_test.py:192:18:192:18 | ControlFlowNode for x | Default value | +| functions_test.py:185:9:185:9 | ControlFlowNode for x | functions_test.py:195:18:195:18 | ControlFlowNode for x | functions_test.py:185:9:185:9 | ControlFlowNode for x | $@ flows to here and is mutated. | functions_test.py:195:18:195:18 | ControlFlowNode for x | Default value | diff --git a/python/ql/test/query-tests/Functions/general/functions_test.py b/python/ql/test/query-tests/Functions/general/functions_test.py index 95e0923ea21..c47794fef28 100644 --- a/python/ql/test/query-tests/Functions/general/functions_test.py +++ b/python/ql/test/query-tests/Functions/general/functions_test.py @@ -163,11 +163,15 @@ def guarded_modification(z=[]): z.append(0) return z -def issue1143(expr, param=[]): - if not param: - return result - for i in param: - param.remove(i) # Mutation here +# This function causes a discrepancy between the +# Python 2 and 3 versions of the analysis. +# We comment it out until we have resoved the issue. +# +# def issue1143(expr, param=[]): +# if not param: +# return result +# for i in param: +# param.remove(i) # Mutation here # Type guarding of modification of parameter with default: diff --git a/python/ql/test/query-tests/Functions/general/options b/python/ql/test/query-tests/Functions/general/options new file mode 100644 index 00000000000..2032dd9e54c --- /dev/null +++ b/python/ql/test/query-tests/Functions/general/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=1 --dont-split-graph diff --git a/python/ql/test/query-tests/Security/CWE-089-SqlInjection/SqlInjection.expected b/python/ql/test/query-tests/Security/CWE-089-SqlInjection/SqlInjection.expected index 61c181ab754..ed4c3e3d313 100644 --- a/python/ql/test/query-tests/Security/CWE-089-SqlInjection/SqlInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-089-SqlInjection/SqlInjection.expected @@ -3,15 +3,52 @@ edges | sql_injection.py:14:15:14:22 | ControlFlowNode for username | sql_injection.py:24:38:24:95 | ControlFlowNode for BinaryExpr | | sql_injection.py:14:15:14:22 | ControlFlowNode for username | sql_injection.py:25:26:25:83 | ControlFlowNode for BinaryExpr | | sql_injection.py:14:15:14:22 | ControlFlowNode for username | sql_injection.py:26:28:26:85 | ControlFlowNode for BinaryExpr | +| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:27:28:27:87 | ControlFlowNode for Attribute() | +| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:31:50:31:72 | ControlFlowNode for Attribute() | +| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:41:26:41:33 | ControlFlowNode for username | +| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:42:31:42:38 | ControlFlowNode for username | +| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:43:30:43:37 | ControlFlowNode for username | +| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:44:35:44:42 | ControlFlowNode for username | +| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:45:41:45:48 | ControlFlowNode for username | +| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:46:46:46:53 | ControlFlowNode for username | +| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:47:47:47:54 | ControlFlowNode for username | +| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:48:52:48:59 | ControlFlowNode for username | +| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:50:18:50:25 | ControlFlowNode for username | +| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:51:24:51:31 | ControlFlowNode for username | nodes | sql_injection.py:14:15:14:22 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | | sql_injection.py:21:24:21:77 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | | sql_injection.py:24:38:24:95 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | | sql_injection.py:25:26:25:83 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | | sql_injection.py:26:28:26:85 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | +| sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | +| sqlalchemy_textclause.py:27:28:27:87 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| sqlalchemy_textclause.py:31:50:31:72 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| sqlalchemy_textclause.py:41:26:41:33 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | +| sqlalchemy_textclause.py:42:31:42:38 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | +| sqlalchemy_textclause.py:43:30:43:37 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | +| sqlalchemy_textclause.py:44:35:44:42 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | +| sqlalchemy_textclause.py:45:41:45:48 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | +| sqlalchemy_textclause.py:46:46:46:53 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | +| sqlalchemy_textclause.py:47:47:47:54 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | +| sqlalchemy_textclause.py:48:52:48:59 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | +| sqlalchemy_textclause.py:50:18:50:25 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | +| sqlalchemy_textclause.py:51:24:51:31 | ControlFlowNode for username | semmle.label | ControlFlowNode for username | subpaths #select | sql_injection.py:21:24:21:77 | ControlFlowNode for BinaryExpr | sql_injection.py:14:15:14:22 | ControlFlowNode for username | sql_injection.py:21:24:21:77 | ControlFlowNode for BinaryExpr | This SQL query depends on $@. | sql_injection.py:14:15:14:22 | ControlFlowNode for username | a user-provided value | | sql_injection.py:24:38:24:95 | ControlFlowNode for BinaryExpr | sql_injection.py:14:15:14:22 | ControlFlowNode for username | sql_injection.py:24:38:24:95 | ControlFlowNode for BinaryExpr | This SQL query depends on $@. | sql_injection.py:14:15:14:22 | ControlFlowNode for username | a user-provided value | | sql_injection.py:25:26:25:83 | ControlFlowNode for BinaryExpr | sql_injection.py:14:15:14:22 | ControlFlowNode for username | sql_injection.py:25:26:25:83 | ControlFlowNode for BinaryExpr | This SQL query depends on $@. | sql_injection.py:14:15:14:22 | ControlFlowNode for username | a user-provided value | | sql_injection.py:26:28:26:85 | ControlFlowNode for BinaryExpr | sql_injection.py:14:15:14:22 | ControlFlowNode for username | sql_injection.py:26:28:26:85 | ControlFlowNode for BinaryExpr | This SQL query depends on $@. | sql_injection.py:14:15:14:22 | ControlFlowNode for username | a user-provided value | +| sqlalchemy_textclause.py:27:28:27:87 | ControlFlowNode for Attribute() | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:27:28:27:87 | ControlFlowNode for Attribute() | This SQL query depends on $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | a user-provided value | +| sqlalchemy_textclause.py:31:50:31:72 | ControlFlowNode for Attribute() | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:31:50:31:72 | ControlFlowNode for Attribute() | This SQL query depends on $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | a user-provided value | +| sqlalchemy_textclause.py:41:26:41:33 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:41:26:41:33 | ControlFlowNode for username | This SQL query depends on $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | a user-provided value | +| sqlalchemy_textclause.py:42:31:42:38 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:42:31:42:38 | ControlFlowNode for username | This SQL query depends on $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | a user-provided value | +| sqlalchemy_textclause.py:43:30:43:37 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:43:30:43:37 | ControlFlowNode for username | This SQL query depends on $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | a user-provided value | +| sqlalchemy_textclause.py:44:35:44:42 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:44:35:44:42 | ControlFlowNode for username | This SQL query depends on $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | a user-provided value | +| sqlalchemy_textclause.py:45:41:45:48 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:45:41:45:48 | ControlFlowNode for username | This SQL query depends on $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | a user-provided value | +| sqlalchemy_textclause.py:46:46:46:53 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:46:46:46:53 | ControlFlowNode for username | This SQL query depends on $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | a user-provided value | +| sqlalchemy_textclause.py:47:47:47:54 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:47:47:47:54 | ControlFlowNode for username | This SQL query depends on $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | a user-provided value | +| sqlalchemy_textclause.py:48:52:48:59 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:48:52:48:59 | ControlFlowNode for username | This SQL query depends on $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | a user-provided value | +| sqlalchemy_textclause.py:50:18:50:25 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:50:18:50:25 | ControlFlowNode for username | This SQL query depends on $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | a user-provided value | +| sqlalchemy_textclause.py:51:24:51:31 | ControlFlowNode for username | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | sqlalchemy_textclause.py:51:24:51:31 | ControlFlowNode for username | This SQL query depends on $@. | sqlalchemy_textclause.py:23:15:23:22 | ControlFlowNode for username | a user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-089-SqlInjection/sqlalchemy_textclause.py b/python/ql/test/query-tests/Security/CWE-089-SqlInjection/sqlalchemy_textclause.py new file mode 100644 index 00000000000..a54d64517d4 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-089-SqlInjection/sqlalchemy_textclause.py @@ -0,0 +1,51 @@ +from flask import Flask, request +import sqlalchemy +import sqlalchemy.orm +from flask_sqlalchemy import SQLAlchemy + +app = Flask(__name__) +engine = sqlalchemy.create_engine(...) +Base = sqlalchemy.orm.declarative_base() + +app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite+pysqlite:///:memory:" +db = SQLAlchemy(app) + + + +class User(Base): + __tablename__ = "users" + + id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True) + username = sqlalchemy.Column(sqlalchemy.String) + + +@app.route("/users/") +def show_user(username): + session = sqlalchemy.orm.Session(engine) + + # BAD, normal SQL injection + stmt = sqlalchemy.text("SELECT * FROM users WHERE username = '{}'".format(username)) + results = session.execute(stmt).fetchall() + + # BAD, allows SQL injection + username_formatted_for_sql = sqlalchemy.text("'{}'".format(username)) + stmt = sqlalchemy.select(User).where(User.username == username_formatted_for_sql) + results = session.execute(stmt).scalars().all() + + # GOOD, does not allow for SQL injection + stmt = sqlalchemy.select(User).where(User.username == username) + results = session.execute(stmt).scalars().all() + + + # All of these should be flagged by query + t1 = sqlalchemy.text(username) + t2 = sqlalchemy.text(text=username) + t3 = sqlalchemy.sql.text(username) + t4 = sqlalchemy.sql.text(text=username) + t5 = sqlalchemy.sql.expression.text(username) + t6 = sqlalchemy.sql.expression.text(text=username) + t7 = sqlalchemy.sql.expression.TextClause(username) + t8 = sqlalchemy.sql.expression.TextClause(text=username) + + t9 = db.text(username) + t10 = db.text(text=username) diff --git a/python/ql/test/query-tests/Security/CWE-730-ReDoS/ReDoS.expected b/python/ql/test/query-tests/Security/CWE-730-ReDoS/ReDoS.expected index 21db78dd092..4356f13755d 100644 --- a/python/ql/test/query-tests/Security/CWE-730-ReDoS/ReDoS.expected +++ b/python/ql/test/query-tests/Security/CWE-730-ReDoS/ReDoS.expected @@ -65,6 +65,8 @@ | redos.py:259:24:259:126 | (.thisisagoddamnlongstringforstresstestingthequery\|\\sthisisagoddamnlongstringforstresstestingthequery)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of ' thisisagoddamnlongstringforstresstestingthequery'. | | redos.py:262:24:262:87 | (thisisagoddamnlongstringforstresstestingthequery\|this\\w+query)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'thisisagoddamnlongstringforstresstestingthequery'. | | redos.py:262:78:262:80 | \\w+ | This part of the regular expression may cause exponential backtracking on strings starting with 'this' and containing many repetitions of 'aquerythis'. | +| redos.py:268:28:268:39 | ([\ufffd\ufffd]\|[\ufffd\ufffd])* | This part of the regular expression may cause exponential backtracking on strings starting with 'foo' and containing many repetitions of '\ufffd'. | +| redos.py:271:28:271:41 | ((\ufffd\|\ufffd)\|(\ufffd\|\ufffd))* | This part of the regular expression may cause exponential backtracking on strings starting with 'foo' and containing many repetitions of '\ufffd'. | | redos.py:274:31:274:32 | b+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'b'. | | redos.py:277:48:277:50 | \\s* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '"" a='. | | redos.py:283:26:283:27 | a+ | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. | diff --git a/python/ql/test/query-tests/Security/CWE-730-ReDoS/redos.py b/python/ql/test/query-tests/Security/CWE-730-ReDoS/redos.py index 733c594a53a..99befe42f36 100644 --- a/python/ql/test/query-tests/Security/CWE-730-ReDoS/redos.py +++ b/python/ql/test/query-tests/Security/CWE-730-ReDoS/redos.py @@ -264,11 +264,11 @@ bad61 = re.compile(r'''(thisisagoddamnlongstringforstresstestingthequery|this\w+ # GOOD good27 = re.compile(r'''(thisisagoddamnlongstringforstresstestingthequery|imanotherbutunrelatedstringcomparedtotheotherstring)*-''') -# GOOD -good28 = re.compile(r'''foo([\uDC66\uDC67]|[\uDC68\uDC69])*foo''') +# GOOD (but false positive caused by the extractor converting all four unpaired surrogates to \uFFFD) +good28 = re.compile('''foo([\uDC66\uDC67]|[\uDC68\uDC69])*foo''') -# GOOD -good29 = re.compile(r'''foo((\uDC66|\uDC67)|(\uDC68|\uDC69))*foo''') +# GOOD (but false positive caused by the extractor converting all four unpaired surrogates to \uFFFD) +good29 = re.compile('''foo((\uDC66|\uDC67)|(\uDC68|\uDC69))*foo''') # NOT GOOD (but cannot currently construct a prefix) bad62 = re.compile(r'''a{2,3}(b+)+X''') diff --git a/python/ql/test/query-tests/Statements/general/C_StyleParentheses.expected b/python/ql/test/query-tests/Statements/general/C_StyleParentheses.expected index a7fa79d219a..44ae1710468 100644 --- a/python/ql/test/query-tests/Statements/general/C_StyleParentheses.expected +++ b/python/ql/test/query-tests/Statements/general/C_StyleParentheses.expected @@ -1,4 +1,4 @@ -| test.py:109:5:109:8 | cond | Parenthesized condition in 'if' statement. | -| test.py:112:8:112:11 | cond | Parenthesized condition in 'while' statement. | -| test.py:115:9:115:12 | test | Parenthesized test in 'assert' statement. | -| test.py:118:13:118:13 | x | Parenthesized value in 'return' statement. | +| test.py:115:5:115:8 | cond | Parenthesized condition in 'if' statement. | +| test.py:118:8:118:11 | cond | Parenthesized condition in 'while' statement. | +| test.py:121:9:121:12 | test | Parenthesized test in 'assert' statement. | +| test.py:124:13:124:13 | x | Parenthesized value in 'return' statement. | diff --git a/python/ql/test/query-tests/Statements/general/ShouldUseWithStatement.expected b/python/ql/test/query-tests/Statements/general/ShouldUseWithStatement.expected index 41a8723db03..d062717bbf2 100644 --- a/python/ql/test/query-tests/Statements/general/ShouldUseWithStatement.expected +++ b/python/ql/test/query-tests/Statements/general/ShouldUseWithStatement.expected @@ -1 +1 @@ -| test.py:162:9:162:17 | Attribute() | Instance of context-manager class $@ is closed in a finally block. Consider using 'with' statement. | test.py:145:1:145:17 | class CM | CM | +| test.py:168:9:168:17 | Attribute() | Instance of context-manager class $@ is closed in a finally block. Consider using 'with' statement. | test.py:151:1:151:17 | class CM | CM | diff --git a/python/ql/test/query-tests/Statements/general/test.py b/python/ql/test/query-tests/Statements/general/test.py index 0f23a0b1681..eee63fa89e8 100644 --- a/python/ql/test/query-tests/Statements/general/test.py +++ b/python/ql/test/query-tests/Statements/general/test.py @@ -18,7 +18,7 @@ def return_in_finally(seq, x): finally: return 1 return 0 - + #Break in loop in finally #This is OK def return_in_loop_in_finally(f, seq): @@ -27,7 +27,7 @@ def return_in_loop_in_finally(f, seq): finally: for i in seq: break - + #But this is not def return_in_loop_in_finally(f, seq): try: @@ -49,7 +49,7 @@ class NonIterator(object): for x in NonIterator(): do_something(x) - + #None in for loop def dodgy_iter(x): @@ -91,8 +91,8 @@ for z in D(): - - + + def modification_of_locals(): x = 0 locals()['x'] = 1 @@ -104,6 +104,12 @@ def modification_of_locals(): return x +globals()['foo'] = 42 # OK +# in module-level scope `locals() == globals()` +# FP report from https://github.com/github/codeql/issues/6674 +locals()['foo'] = 43 # technically OK + + #C-style things if (cond): @@ -128,7 +134,7 @@ class classproperty(object): return self.getter(instance_type) class WithClassProperty(object): - + @classproperty def x(self): return [0] @@ -143,13 +149,13 @@ for i in WithClassProperty.x: #Should use context mamager class CM(object): - + def __enter__(self): pass - + def __exit__(self, ex, cls, tb): pass - + def write(self, data): pass @@ -168,4 +174,3 @@ def assert_ok(seq): # False positive. ODASA-8042. Fixed in PR #2401. class false_positive: e = (x for x in []) - diff --git a/python/ql/test/query-tests/Variables/undefined/UninitializedLocal.py b/python/ql/test/query-tests/Variables/undefined/UninitializedLocal.py index f8a8d76ad15..26e109af5a2 100644 --- a/python/ql/test/query-tests/Variables/undefined/UninitializedLocal.py +++ b/python/ql/test/query-tests/Variables/undefined/UninitializedLocal.py @@ -288,3 +288,8 @@ def avoid_redundant_split(a): var = False if var: foo.bar() #foo is defined here. + +def type_annotation_fp(): + annotated : annotation = [1,2,3] + for x in annotated: + print(x) diff --git a/python/ql/test/query-tests/Variables/unused/UnusedLocalVariable.expected b/python/ql/test/query-tests/Variables/unused/UnusedLocalVariable.expected index 339a74432bc..a902cad04cb 100644 --- a/python/ql/test/query-tests/Variables/unused/UnusedLocalVariable.expected +++ b/python/ql/test/query-tests/Variables/unused/UnusedLocalVariable.expected @@ -1,4 +1,3 @@ -| type_annotation_fp.py:5:5:5:7 | foo | The value assigned to local variable 'foo' is never used. | | variables_test.py:29:5:29:5 | x | The value assigned to local variable 'x' is never used. | | variables_test.py:89:5:89:5 | a | The value assigned to local variable 'a' is never used. | | variables_test.py:89:7:89:7 | b | The value assigned to local variable 'b' is never used. | diff --git a/python/ql/test/query-tests/Variables/unused/type_annotation_fp.py b/python/ql/test/query-tests/Variables/unused/type_annotation_fp.py index 72293f232e5..4f10f6e333e 100644 --- a/python/ql/test/query-tests/Variables/unused/type_annotation_fp.py +++ b/python/ql/test/query-tests/Variables/unused/type_annotation_fp.py @@ -9,3 +9,8 @@ def type_annotation(x): else: foo : float do_other_stuff_with(foo) + +def type_annotation_fn(): + # False negative: the value of `bar` is never used, but this is masked by the presence of the type annotation. + bar = 5 + bar : int diff --git a/python/upgrades/4f1806347d7fafe2f78508da01c01e5aff5f7cbb/old.dbscheme b/python/upgrades/4f1806347d7fafe2f78508da01c01e5aff5f7cbb/old.dbscheme new file mode 100644 index 00000000000..4f1806347d7 --- /dev/null +++ b/python/upgrades/4f1806347d7fafe2f78508da01c01e5aff5f7cbb/old.dbscheme @@ -0,0 +1,999 @@ +/* + * This dbscheme is auto-generated by 'semmle/dbscheme_gen.py'. + * WARNING: Any modifications to this file will be lost. + * Relations can be changed by modifying master.py or + * by adding rules to dbscheme.template + */ + +/* This is a dummy line to alter the dbscheme, so we can make a database upgrade + * without actually changing any of the dbscheme predicates. It contains a date + * to allow for such updates in the future as well. + * + * 2020-07-02 + * + * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a + * previously seen state (matching a previously seen SHA), which would make the upgrade + * mechanism not work properly. + */ + + /* + * External artifacts + */ + +externalDefects( + unique int id : @externalDefect, + varchar(900) queryPath : string ref, + int location : @location ref, + varchar(900) message : string ref, + float severity : float ref +); + +externalMetrics( + unique int id : @externalMetric, + varchar(900) queryPath : string ref, + int location : @location ref, + float value : float ref +); + +externalData( + int id : @externalDataElement, + varchar(900) queryPath : string ref, + int column: int ref, + varchar(900) data : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + + +/* + * Duplicate code + */ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/* + * Line metrics + */ +py_codelines(int id : @py_scope ref, + int count : int ref); + +py_commentlines(int id : @py_scope ref, + int count : int ref); + +py_docstringlines(int id : @py_scope ref, + int count : int ref); + +py_alllines(int id : @py_scope ref, + int count : int ref); + +/* + * Version history + */ + +svnentries( + int id : @svnentry, + varchar(500) revision : string ref, + varchar(500) author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + varchar(500) action : string ref +) + +svnentrymsg( + int id : @svnentry ref, + varchar(500) message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/**************************** + Python dbscheme +****************************/ + +/* fromSource is ignored */ +files(unique int id: @file, + varchar(900) name: string ref, + varchar(900) simple: string ref, + varchar(900) ext: string ref, + int fromSource: int ref); + +folders(unique int id: @folder, + varchar(900) name: string ref, + varchar(900) simple: string ref); + +@container = @folder | @file; + +containerparent(int parent: @container ref, + unique int child: @container ref); + +@sourceline = @file | @py_Module | @xmllocatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref + ); + +@location = @location_ast | @location_default ; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +locations_ast(unique int id: @location_ast, + int module: @py_Module ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +file_contents(unique int file: @file ref, string contents: string ref); + +py_module_path(int module: @py_Module ref, int file: @container ref); + +variable(unique int id : @py_variable, + int scope : @py_scope ref, + varchar(1) name : string ref); + +py_line_lengths(unique int id : @py_line, + int file: @py_Module ref, + int line : int ref, + int length : int ref); + +py_extracted_version(int module : @py_Module ref, + varchar(1) version : string ref); + +/* AUTO GENERATED PART STARTS HERE */ + + +/* AnnAssign.location = 0, location */ +/* AnnAssign.value = 1, expr */ +/* AnnAssign.annotation = 2, expr */ +/* AnnAssign.target = 3, expr */ + +/* Assert.location = 0, location */ +/* Assert.test = 1, expr */ +/* Assert.msg = 2, expr */ + +/* Assign.location = 0, location */ +/* Assign.value = 1, expr */ +/* Assign.targets = 2, expr_list */ + +/* AssignExpr.location = 0, location */ +/* AssignExpr.parenthesised = 1, bool */ +/* AssignExpr.value = 2, expr */ +/* AssignExpr.target = 3, expr */ + +/* Attribute.location = 0, location */ +/* Attribute.parenthesised = 1, bool */ +/* Attribute.value = 2, expr */ +/* Attribute.attr = 3, str */ +/* Attribute.ctx = 4, expr_context */ + +/* AugAssign.location = 0, location */ +/* AugAssign.operation = 1, BinOp */ + +/* Await.location = 0, location */ +/* Await.parenthesised = 1, bool */ +/* Await.value = 2, expr */ + +/* BinaryExpr.location = 0, location */ +/* BinaryExpr.parenthesised = 1, bool */ +/* BinaryExpr.left = 2, expr */ +/* BinaryExpr.op = 3, operator */ +/* BinaryExpr.right = 4, expr */ +/* BinaryExpr = AugAssign */ + +/* BoolExpr.location = 0, location */ +/* BoolExpr.parenthesised = 1, bool */ +/* BoolExpr.op = 2, boolop */ +/* BoolExpr.values = 3, expr_list */ + +/* Break.location = 0, location */ + +/* Bytes.location = 0, location */ +/* Bytes.parenthesised = 1, bool */ +/* Bytes.s = 2, bytes */ +/* Bytes.prefix = 3, bytes */ +/* Bytes.implicitly_concatenated_parts = 4, StringPart_list */ + +/* Call.location = 0, location */ +/* Call.parenthesised = 1, bool */ +/* Call.func = 2, expr */ +/* Call.positional_args = 3, expr_list */ +/* Call.named_args = 4, dict_item_list */ + +/* Class.name = 0, str */ +/* Class.body = 1, stmt_list */ +/* Class = ClassExpr */ + +/* ClassExpr.location = 0, location */ +/* ClassExpr.parenthesised = 1, bool */ +/* ClassExpr.name = 2, str */ +/* ClassExpr.bases = 3, expr_list */ +/* ClassExpr.keywords = 4, dict_item_list */ +/* ClassExpr.inner_scope = 5, Class */ + +/* Compare.location = 0, location */ +/* Compare.parenthesised = 1, bool */ +/* Compare.left = 2, expr */ +/* Compare.ops = 3, cmpop_list */ +/* Compare.comparators = 4, expr_list */ + +/* Continue.location = 0, location */ + +/* Delete.location = 0, location */ +/* Delete.targets = 1, expr_list */ + +/* Dict.location = 0, location */ +/* Dict.parenthesised = 1, bool */ +/* Dict.items = 2, dict_item_list */ + +/* DictComp.location = 0, location */ +/* DictComp.parenthesised = 1, bool */ +/* DictComp.function = 2, Function */ +/* DictComp.iterable = 3, expr */ + +/* DictUnpacking.location = 0, location */ +/* DictUnpacking.value = 1, expr */ + +/* Ellipsis.location = 0, location */ +/* Ellipsis.parenthesised = 1, bool */ + +/* ExceptStmt.location = 0, location */ +/* ExceptStmt.type = 1, expr */ +/* ExceptStmt.name = 2, expr */ +/* ExceptStmt.body = 3, stmt_list */ + +/* Exec.location = 0, location */ +/* Exec.body = 1, expr */ +/* Exec.globals = 2, expr */ +/* Exec.locals = 3, expr */ + +/* ExprStmt.location = 0, location */ +/* ExprStmt.value = 1, expr */ + +/* Filter.location = 0, location */ +/* Filter.parenthesised = 1, bool */ +/* Filter.value = 2, expr */ +/* Filter.filter = 3, expr */ + +/* For.location = 0, location */ +/* For.target = 1, expr */ +/* For.iter = 2, expr */ +/* For.body = 3, stmt_list */ +/* For.orelse = 4, stmt_list */ +/* For.is_async = 5, bool */ + +/* FormattedValue.location = 0, location */ +/* FormattedValue.parenthesised = 1, bool */ +/* FormattedValue.value = 2, expr */ +/* FormattedValue.conversion = 3, str */ +/* FormattedValue.format_spec = 4, JoinedStr */ + +/* Function.name = 0, str */ +/* Function.args = 1, parameter_list */ +/* Function.vararg = 2, expr */ +/* Function.kwonlyargs = 3, expr_list */ +/* Function.kwarg = 4, expr */ +/* Function.body = 5, stmt_list */ +/* Function.is_async = 6, bool */ +/* Function = FunctionParent */ + +/* FunctionExpr.location = 0, location */ +/* FunctionExpr.parenthesised = 1, bool */ +/* FunctionExpr.name = 2, str */ +/* FunctionExpr.args = 3, arguments */ +/* FunctionExpr.returns = 4, expr */ +/* FunctionExpr.inner_scope = 5, Function */ + +/* GeneratorExp.location = 0, location */ +/* GeneratorExp.parenthesised = 1, bool */ +/* GeneratorExp.function = 2, Function */ +/* GeneratorExp.iterable = 3, expr */ + +/* Global.location = 0, location */ +/* Global.names = 1, str_list */ + +/* If.location = 0, location */ +/* If.test = 1, expr */ +/* If.body = 2, stmt_list */ +/* If.orelse = 3, stmt_list */ + +/* IfExp.location = 0, location */ +/* IfExp.parenthesised = 1, bool */ +/* IfExp.test = 2, expr */ +/* IfExp.body = 3, expr */ +/* IfExp.orelse = 4, expr */ + +/* Import.location = 0, location */ +/* Import.names = 1, alias_list */ + +/* ImportExpr.location = 0, location */ +/* ImportExpr.parenthesised = 1, bool */ +/* ImportExpr.level = 2, int */ +/* ImportExpr.name = 3, str */ +/* ImportExpr.top = 4, bool */ + +/* ImportStar.location = 0, location */ +/* ImportStar.module = 1, expr */ + +/* ImportMember.location = 0, location */ +/* ImportMember.parenthesised = 1, bool */ +/* ImportMember.module = 2, expr */ +/* ImportMember.name = 3, str */ + +/* Fstring.location = 0, location */ +/* Fstring.parenthesised = 1, bool */ +/* Fstring.values = 2, expr_list */ +/* Fstring = FormattedValue */ + +/* KeyValuePair.location = 0, location */ +/* KeyValuePair.value = 1, expr */ +/* KeyValuePair.key = 2, expr */ + +/* Lambda.location = 0, location */ +/* Lambda.parenthesised = 1, bool */ +/* Lambda.args = 2, arguments */ +/* Lambda.inner_scope = 3, Function */ + +/* List.location = 0, location */ +/* List.parenthesised = 1, bool */ +/* List.elts = 2, expr_list */ +/* List.ctx = 3, expr_context */ + +/* ListComp.location = 0, location */ +/* ListComp.parenthesised = 1, bool */ +/* ListComp.function = 2, Function */ +/* ListComp.iterable = 3, expr */ +/* ListComp.generators = 4, comprehension_list */ +/* ListComp.elt = 5, expr */ + +/* Module.name = 0, str */ +/* Module.hash = 1, str */ +/* Module.body = 2, stmt_list */ +/* Module.kind = 3, str */ + +/* Name.location = 0, location */ +/* Name.parenthesised = 1, bool */ +/* Name.variable = 2, variable */ +/* Name.ctx = 3, expr_context */ +/* Name = ParameterList */ + +/* Nonlocal.location = 0, location */ +/* Nonlocal.names = 1, str_list */ + +/* Num.location = 0, location */ +/* Num.parenthesised = 1, bool */ +/* Num.n = 2, number */ +/* Num.text = 3, number */ + +/* Pass.location = 0, location */ + +/* PlaceHolder.location = 0, location */ +/* PlaceHolder.parenthesised = 1, bool */ +/* PlaceHolder.variable = 2, variable */ +/* PlaceHolder.ctx = 3, expr_context */ + +/* Print.location = 0, location */ +/* Print.dest = 1, expr */ +/* Print.values = 2, expr_list */ +/* Print.nl = 3, bool */ + +/* Raise.location = 0, location */ +/* Raise.exc = 1, expr */ +/* Raise.cause = 2, expr */ +/* Raise.type = 3, expr */ +/* Raise.inst = 4, expr */ +/* Raise.tback = 5, expr */ + +/* Repr.location = 0, location */ +/* Repr.parenthesised = 1, bool */ +/* Repr.value = 2, expr */ + +/* Return.location = 0, location */ +/* Return.value = 1, expr */ + +/* Set.location = 0, location */ +/* Set.parenthesised = 1, bool */ +/* Set.elts = 2, expr_list */ + +/* SetComp.location = 0, location */ +/* SetComp.parenthesised = 1, bool */ +/* SetComp.function = 2, Function */ +/* SetComp.iterable = 3, expr */ + +/* Slice.location = 0, location */ +/* Slice.parenthesised = 1, bool */ +/* Slice.start = 2, expr */ +/* Slice.stop = 3, expr */ +/* Slice.step = 4, expr */ + +/* SpecialOperation.location = 0, location */ +/* SpecialOperation.parenthesised = 1, bool */ +/* SpecialOperation.name = 2, str */ +/* SpecialOperation.arguments = 3, expr_list */ + +/* Starred.location = 0, location */ +/* Starred.parenthesised = 1, bool */ +/* Starred.value = 2, expr */ +/* Starred.ctx = 3, expr_context */ + +/* Str.location = 0, location */ +/* Str.parenthesised = 1, bool */ +/* Str.s = 2, str */ +/* Str.prefix = 3, str */ +/* Str.implicitly_concatenated_parts = 4, StringPart_list */ + +/* StringPart.text = 0, str */ +/* StringPart.location = 1, location */ +/* StringPart = StringPartList */ +/* StringPartList = BytesOrStr */ + +/* Subscript.location = 0, location */ +/* Subscript.parenthesised = 1, bool */ +/* Subscript.value = 2, expr */ +/* Subscript.index = 3, expr */ +/* Subscript.ctx = 4, expr_context */ + +/* TemplateDottedNotation.location = 0, location */ +/* TemplateDottedNotation.parenthesised = 1, bool */ +/* TemplateDottedNotation.value = 2, expr */ +/* TemplateDottedNotation.attr = 3, str */ +/* TemplateDottedNotation.ctx = 4, expr_context */ + +/* TemplateWrite.location = 0, location */ +/* TemplateWrite.value = 1, expr */ + +/* Try.location = 0, location */ +/* Try.body = 1, stmt_list */ +/* Try.orelse = 2, stmt_list */ +/* Try.handlers = 3, stmt_list */ +/* Try.finalbody = 4, stmt_list */ + +/* Tuple.location = 0, location */ +/* Tuple.parenthesised = 1, bool */ +/* Tuple.elts = 2, expr_list */ +/* Tuple.ctx = 3, expr_context */ +/* Tuple = ParameterList */ + +/* UnaryExpr.location = 0, location */ +/* UnaryExpr.parenthesised = 1, bool */ +/* UnaryExpr.op = 2, unaryop */ +/* UnaryExpr.operand = 3, expr */ + +/* While.location = 0, location */ +/* While.test = 1, expr */ +/* While.body = 2, stmt_list */ +/* While.orelse = 3, stmt_list */ + +/* With.location = 0, location */ +/* With.context_expr = 1, expr */ +/* With.optional_vars = 2, expr */ +/* With.body = 3, stmt_list */ +/* With.is_async = 4, bool */ + +/* Yield.location = 0, location */ +/* Yield.parenthesised = 1, bool */ +/* Yield.value = 2, expr */ + +/* YieldFrom.location = 0, location */ +/* YieldFrom.parenthesised = 1, bool */ +/* YieldFrom.value = 2, expr */ + +/* Alias.value = 0, expr */ +/* Alias.asname = 1, expr */ +/* Alias = AliasList */ +/* AliasList = Import */ + +/* Arguments.kw_defaults = 0, expr_list */ +/* Arguments.defaults = 1, expr_list */ +/* Arguments.annotations = 2, expr_list */ +/* Arguments.varargannotation = 3, expr */ +/* Arguments.kwargannotation = 4, expr */ +/* Arguments.kw_annotations = 5, expr_list */ +/* Arguments = ArgumentsParent */ +/* boolean = BoolParent */ +/* Boolop = BoolExpr */ +/* string = Bytes */ +/* Cmpop = CmpopList */ +/* CmpopList = Compare */ + +/* Comprehension.location = 0, location */ +/* Comprehension.iter = 1, expr */ +/* Comprehension.target = 2, expr */ +/* Comprehension.ifs = 3, expr_list */ +/* Comprehension = ComprehensionList */ +/* ComprehensionList = ListComp */ +/* DictItem = DictItemList */ +/* DictItemList = DictItemListParent */ + +/* Expr.location = 0, location */ +/* Expr.parenthesised = 1, bool */ +/* Expr = ExprParent */ +/* ExprContext = ExprContextParent */ +/* ExprList = ExprListParent */ +/* int = ImportExpr */ + +/* Keyword.location = 0, location */ +/* Keyword.value = 1, expr */ +/* Keyword.arg = 2, str */ +/* Location = LocationParent */ +/* string = Num */ +/* Operator = BinaryExpr */ +/* ParameterList = Function */ + +/* Stmt.location = 0, location */ +/* Stmt = StmtList */ +/* StmtList = StmtListParent */ +/* string = StrParent */ +/* StringList = StrListParent */ +/* Unaryop = UnaryExpr */ +/* Variable = VariableParent */ +py_Classes(unique int id : @py_Class, + unique int parent : @py_ClassExpr ref); + +py_Functions(unique int id : @py_Function, + unique int parent : @py_Function_parent ref); + +py_Modules(unique int id : @py_Module); + +py_StringParts(unique int id : @py_StringPart, + int parent : @py_StringPart_list ref, + int idx : int ref); + +py_StringPart_lists(unique int id : @py_StringPart_list, + unique int parent : @py_Bytes_or_Str ref); + +py_aliases(unique int id : @py_alias, + int parent : @py_alias_list ref, + int idx : int ref); + +py_alias_lists(unique int id : @py_alias_list, + unique int parent : @py_Import ref); + +py_arguments(unique int id : @py_arguments, + unique int parent : @py_arguments_parent ref); + +py_bools(int parent : @py_bool_parent ref, + int idx : int ref); + +py_boolops(unique int id : @py_boolop, + int kind: int ref, + unique int parent : @py_BoolExpr ref); + +py_bytes(varchar(1) id : string ref, + int parent : @py_Bytes ref, + int idx : int ref); + +py_cmpops(unique int id : @py_cmpop, + int kind: int ref, + int parent : @py_cmpop_list ref, + int idx : int ref); + +py_cmpop_lists(unique int id : @py_cmpop_list, + unique int parent : @py_Compare ref); + +py_comprehensions(unique int id : @py_comprehension, + int parent : @py_comprehension_list ref, + int idx : int ref); + +py_comprehension_lists(unique int id : @py_comprehension_list, + unique int parent : @py_ListComp ref); + +py_dict_items(unique int id : @py_dict_item, + int kind: int ref, + int parent : @py_dict_item_list ref, + int idx : int ref); + +py_dict_item_lists(unique int id : @py_dict_item_list, + unique int parent : @py_dict_item_list_parent ref); + +py_exprs(unique int id : @py_expr, + int kind: int ref, + int parent : @py_expr_parent ref, + int idx : int ref); + +py_expr_contexts(unique int id : @py_expr_context, + int kind: int ref, + unique int parent : @py_expr_context_parent ref); + +py_expr_lists(unique int id : @py_expr_list, + int parent : @py_expr_list_parent ref, + int idx : int ref); + +py_ints(int id : int ref, + unique int parent : @py_ImportExpr ref); + +py_locations(unique int id : @location ref, + unique int parent : @py_location_parent ref); + +py_numbers(varchar(1) id : string ref, + int parent : @py_Num ref, + int idx : int ref); + +py_operators(unique int id : @py_operator, + int kind: int ref, + unique int parent : @py_BinaryExpr ref); + +py_parameter_lists(unique int id : @py_parameter_list, + unique int parent : @py_Function ref); + +py_stmts(unique int id : @py_stmt, + int kind: int ref, + int parent : @py_stmt_list ref, + int idx : int ref); + +py_stmt_lists(unique int id : @py_stmt_list, + int parent : @py_stmt_list_parent ref, + int idx : int ref); + +py_strs(varchar(1) id : string ref, + int parent : @py_str_parent ref, + int idx : int ref); + +py_str_lists(unique int id : @py_str_list, + unique int parent : @py_str_list_parent ref); + +py_unaryops(unique int id : @py_unaryop, + int kind: int ref, + unique int parent : @py_UnaryExpr ref); + +py_variables(int id : @py_variable ref, + unique int parent : @py_variable_parent ref); + +case @py_boolop.kind of + 0 = @py_And +| 1 = @py_Or; + +case @py_cmpop.kind of + 0 = @py_Eq +| 1 = @py_Gt +| 2 = @py_GtE +| 3 = @py_In +| 4 = @py_Is +| 5 = @py_IsNot +| 6 = @py_Lt +| 7 = @py_LtE +| 8 = @py_NotEq +| 9 = @py_NotIn; + +case @py_dict_item.kind of + 0 = @py_DictUnpacking +| 1 = @py_KeyValuePair +| 2 = @py_keyword; + +case @py_expr.kind of + 0 = @py_Attribute +| 1 = @py_BinaryExpr +| 2 = @py_BoolExpr +| 3 = @py_Bytes +| 4 = @py_Call +| 5 = @py_ClassExpr +| 6 = @py_Compare +| 7 = @py_Dict +| 8 = @py_DictComp +| 9 = @py_Ellipsis +| 10 = @py_FunctionExpr +| 11 = @py_GeneratorExp +| 12 = @py_IfExp +| 13 = @py_ImportExpr +| 14 = @py_ImportMember +| 15 = @py_Lambda +| 16 = @py_List +| 17 = @py_ListComp +| 18 = @py_Name +| 19 = @py_Num +| 20 = @py_Repr +| 21 = @py_Set +| 22 = @py_SetComp +| 23 = @py_Slice +| 24 = @py_Starred +| 25 = @py_Str +| 26 = @py_Subscript +| 27 = @py_Tuple +| 28 = @py_UnaryExpr +| 29 = @py_Yield +| 30 = @py_YieldFrom +| 31 = @py_TemplateDottedNotation +| 32 = @py_Filter +| 33 = @py_PlaceHolder +| 34 = @py_Await +| 35 = @py_Fstring +| 36 = @py_FormattedValue +| 37 = @py_AssignExpr +| 38 = @py_SpecialOperation; + +case @py_expr_context.kind of + 0 = @py_AugLoad +| 1 = @py_AugStore +| 2 = @py_Del +| 3 = @py_Load +| 4 = @py_Param +| 5 = @py_Store; + +case @py_operator.kind of + 0 = @py_Add +| 1 = @py_BitAnd +| 2 = @py_BitOr +| 3 = @py_BitXor +| 4 = @py_Div +| 5 = @py_FloorDiv +| 6 = @py_LShift +| 7 = @py_Mod +| 8 = @py_Mult +| 9 = @py_Pow +| 10 = @py_RShift +| 11 = @py_Sub +| 12 = @py_MatMult; + +case @py_stmt.kind of + 0 = @py_Assert +| 1 = @py_Assign +| 2 = @py_AugAssign +| 3 = @py_Break +| 4 = @py_Continue +| 5 = @py_Delete +| 6 = @py_ExceptStmt +| 7 = @py_Exec +| 8 = @py_Expr_stmt +| 9 = @py_For +| 10 = @py_Global +| 11 = @py_If +| 12 = @py_Import +| 13 = @py_ImportStar +| 14 = @py_Nonlocal +| 15 = @py_Pass +| 16 = @py_Print +| 17 = @py_Raise +| 18 = @py_Return +| 19 = @py_Try +| 20 = @py_While +| 21 = @py_With +| 22 = @py_TemplateWrite +| 23 = @py_AnnAssign; + +case @py_unaryop.kind of + 0 = @py_Invert +| 1 = @py_Not +| 2 = @py_UAdd +| 3 = @py_USub; + +@py_Bytes_or_Str = @py_Bytes | @py_Str; + +@py_Function_parent = @py_DictComp | @py_FunctionExpr | @py_GeneratorExp | @py_Lambda | @py_ListComp | @py_SetComp; + +@py_arguments_parent = @py_FunctionExpr | @py_Lambda; + +@py_ast_node = @py_Class | @py_Function | @py_Module | @py_StringPart | @py_comprehension | @py_dict_item | @py_expr | @py_stmt; + +@py_bool_parent = @py_For | @py_Function | @py_Print | @py_With | @py_expr; + +@py_dict_item_list_parent = @py_Call | @py_ClassExpr | @py_Dict; + +@py_expr_context_parent = @py_Attribute | @py_List | @py_Name | @py_PlaceHolder | @py_Starred | @py_Subscript | @py_TemplateDottedNotation | @py_Tuple; + +@py_expr_list_parent = @py_Assign | @py_BoolExpr | @py_Call | @py_ClassExpr | @py_Compare | @py_Delete | @py_Fstring | @py_Function | @py_List | @py_Print | @py_Set | @py_SpecialOperation | @py_Tuple | @py_arguments | @py_comprehension; + +@py_expr_or_stmt = @py_expr | @py_stmt; + +@py_expr_parent = @py_AnnAssign | @py_Assert | @py_Assign | @py_AssignExpr | @py_Attribute | @py_AugAssign | @py_Await | @py_BinaryExpr | @py_Call | @py_Compare | @py_DictComp | @py_DictUnpacking | @py_ExceptStmt | @py_Exec | @py_Expr_stmt | @py_Filter | @py_For | @py_FormattedValue | @py_Function | @py_FunctionExpr | @py_GeneratorExp | @py_If | @py_IfExp | @py_ImportMember | @py_ImportStar | @py_KeyValuePair | @py_ListComp | @py_Print | @py_Raise | @py_Repr | @py_Return | @py_SetComp | @py_Slice | @py_Starred | @py_Subscript | @py_TemplateDottedNotation | @py_TemplateWrite | @py_UnaryExpr | @py_While | @py_With | @py_Yield | @py_YieldFrom | @py_alias | @py_arguments | @py_comprehension | @py_expr_list | @py_keyword | @py_parameter_list; + +@py_location_parent = @py_DictUnpacking | @py_KeyValuePair | @py_StringPart | @py_comprehension | @py_expr | @py_keyword | @py_stmt; + +@py_parameter = @py_Name | @py_Tuple; + +@py_scope = @py_Class | @py_Function | @py_Module; + +@py_stmt_list_parent = @py_Class | @py_ExceptStmt | @py_For | @py_Function | @py_If | @py_Module | @py_Try | @py_While | @py_With; + +@py_str_list_parent = @py_Global | @py_Nonlocal; + +@py_str_parent = @py_Attribute | @py_Class | @py_ClassExpr | @py_FormattedValue | @py_Function | @py_FunctionExpr | @py_ImportExpr | @py_ImportMember | @py_Module | @py_SpecialOperation | @py_Str | @py_StringPart | @py_TemplateDottedNotation | @py_keyword | @py_str_list; + +@py_variable_parent = @py_Name | @py_PlaceHolder; + + +/* + * End of auto-generated part + */ + + + +/* Map relative names to absolute names for imports */ +py_absolute_names(int module : @py_Module ref, + varchar(1) relname : string ref, + varchar(1) absname : string ref); + +py_exports(int id : @py_Module ref, + varchar(1) name : string ref); + +/* Successor information */ +py_successors(int predecessor : @py_flow_node ref, + int successor : @py_flow_node ref); + +py_true_successors(int predecessor : @py_flow_node ref, + int successor : @py_flow_node ref); + +py_exception_successors(int predecessor : @py_flow_node ref, + int successor : @py_flow_node ref); + +py_false_successors(int predecessor : @py_flow_node ref, + int successor : @py_flow_node ref); + +py_flow_bb_node(unique int flownode : @py_flow_node, + int realnode : @py_ast_node ref, + int basicblock : @py_flow_node ref, + int index : int ref); + +py_scope_flow(int flow : @py_flow_node ref, + int scope : @py_scope ref, + int kind : int ref); + +py_idoms(unique int node : @py_flow_node ref, + int immediate_dominator : @py_flow_node ref); + +py_ssa_phi(int phi : @py_ssa_var ref, + int arg: @py_ssa_var ref); + +py_ssa_var(unique int id : @py_ssa_var, + int var : @py_variable ref); + +py_ssa_use(int node: @py_flow_node ref, + int var : @py_ssa_var ref); + +py_ssa_defn(unique int id : @py_ssa_var ref, + int node: @py_flow_node ref); + +@py_base_var = @py_variable | @py_ssa_var; + +py_scopes(unique int node : @py_expr_or_stmt ref, + int scope : @py_scope ref); + +py_scope_location(unique int id : @location ref, + unique int scope : @py_scope ref); + +py_flags_versioned(varchar(1) name : string ref, + varchar(1) value : string ref, + varchar(1) version : string ref); + +py_syntax_error_versioned(unique int id : @location ref, + varchar(1) message : string ref, + varchar(1) version : string ref); + +py_comments(unique int id : @py_comment, + varchar(1) text : string ref, + unique int location : @location ref); + +/* Type information support */ + +py_cobjects(unique int obj : @py_cobject); + +py_cobjecttypes(unique int obj : @py_cobject ref, + int typeof : @py_cobject ref); + +py_cobjectnames(unique int obj : @py_cobject ref, + varchar(1) name : string ref); + +/* Kind should be 0 for introspection, > 0 from source, as follows: + 1 from C extension source + */ +py_cobject_sources(int obj : @py_cobject ref, + int kind : int ref); + +py_cmembers_versioned(int object : @py_cobject ref, + varchar(1) name : string ref, + int member : @py_cobject ref, + varchar(1) version : string ref); + +py_citems(int object : @py_cobject ref, + int index : int ref, + int member : @py_cobject ref); + +ext_argtype(int funcid : @py_object ref, + int arg : int ref, + int typeid : @py_object ref); + +ext_rettype(int funcid : @py_object ref, + int typeid : @py_object ref); + +ext_proptype(int propid : @py_object ref, + int typeid : @py_object ref); + +ext_argreturn(int funcid : @py_object ref, + int arg : int ref); + +py_special_objects(unique int obj : @py_cobject ref, + unique varchar(1) name : string ref); + +py_decorated_object(int object : @py_object ref, + int level: int ref); + +@py_object = @py_cobject | @py_flow_node; + +@py_source_element = @py_ast_node | @container; + +/* XML Files */ + +xmlEncoding (unique int id: @file ref, varchar(900) encoding: string ref); + +xmlDTDs (unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref); + +xmlElements (unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs (unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs (int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref); + +xmlHasNs (int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments (unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars (unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations(int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; diff --git a/python/upgrades/4f1806347d7fafe2f78508da01c01e5aff5f7cbb/semmlecode.python.dbscheme b/python/upgrades/4f1806347d7fafe2f78508da01c01e5aff5f7cbb/semmlecode.python.dbscheme new file mode 100644 index 00000000000..ff5327c074c --- /dev/null +++ b/python/upgrades/4f1806347d7fafe2f78508da01c01e5aff5f7cbb/semmlecode.python.dbscheme @@ -0,0 +1,994 @@ +/* + * This dbscheme is auto-generated by 'semmle/dbscheme_gen.py'. + * WARNING: Any modifications to this file will be lost. + * Relations can be changed by modifying master.py or + * by adding rules to dbscheme.template + */ + +/* This is a dummy line to alter the dbscheme, so we can make a database upgrade + * without actually changing any of the dbscheme predicates. It contains a date + * to allow for such updates in the future as well. + * + * 2020-07-02 + * + * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a + * previously seen state (matching a previously seen SHA), which would make the upgrade + * mechanism not work properly. + */ + + /* + * External artifacts + */ + +externalDefects( + unique int id : @externalDefect, + varchar(900) queryPath : string ref, + int location : @location ref, + varchar(900) message : string ref, + float severity : float ref +); + +externalMetrics( + unique int id : @externalMetric, + varchar(900) queryPath : string ref, + int location : @location ref, + float value : float ref +); + +externalData( + int id : @externalDataElement, + varchar(900) queryPath : string ref, + int column: int ref, + varchar(900) data : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + + +/* + * Duplicate code + */ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/* + * Line metrics + */ +py_codelines(int id : @py_scope ref, + int count : int ref); + +py_commentlines(int id : @py_scope ref, + int count : int ref); + +py_docstringlines(int id : @py_scope ref, + int count : int ref); + +py_alllines(int id : @py_scope ref, + int count : int ref); + +/* + * Version history + */ + +svnentries( + int id : @svnentry, + varchar(500) revision : string ref, + varchar(500) author : string ref, + date revisionDate : date ref, + int changeSize : int ref +) + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + varchar(500) action : string ref +) + +svnentrymsg( + int id : @svnentry ref, + varchar(500) message : string ref +) + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +) + +/**************************** + Python dbscheme +****************************/ + +files(unique int id: @file, + varchar(900) name: string ref); + +folders(unique int id: @folder, + varchar(900) name: string ref); + +@container = @folder | @file; + +containerparent(int parent: @container ref, + unique int child: @container ref); + +@sourceline = @file | @py_Module | @xmllocatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref + ); + +@location = @location_ast | @location_default ; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +locations_ast(unique int id: @location_ast, + int module: @py_Module ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref); + +file_contents(unique int file: @file ref, string contents: string ref); + +py_module_path(int module: @py_Module ref, int file: @container ref); + +variable(unique int id : @py_variable, + int scope : @py_scope ref, + varchar(1) name : string ref); + +py_line_lengths(unique int id : @py_line, + int file: @py_Module ref, + int line : int ref, + int length : int ref); + +py_extracted_version(int module : @py_Module ref, + varchar(1) version : string ref); + +/* AUTO GENERATED PART STARTS HERE */ + + +/* AnnAssign.location = 0, location */ +/* AnnAssign.value = 1, expr */ +/* AnnAssign.annotation = 2, expr */ +/* AnnAssign.target = 3, expr */ + +/* Assert.location = 0, location */ +/* Assert.test = 1, expr */ +/* Assert.msg = 2, expr */ + +/* Assign.location = 0, location */ +/* Assign.value = 1, expr */ +/* Assign.targets = 2, expr_list */ + +/* AssignExpr.location = 0, location */ +/* AssignExpr.parenthesised = 1, bool */ +/* AssignExpr.value = 2, expr */ +/* AssignExpr.target = 3, expr */ + +/* Attribute.location = 0, location */ +/* Attribute.parenthesised = 1, bool */ +/* Attribute.value = 2, expr */ +/* Attribute.attr = 3, str */ +/* Attribute.ctx = 4, expr_context */ + +/* AugAssign.location = 0, location */ +/* AugAssign.operation = 1, BinOp */ + +/* Await.location = 0, location */ +/* Await.parenthesised = 1, bool */ +/* Await.value = 2, expr */ + +/* BinaryExpr.location = 0, location */ +/* BinaryExpr.parenthesised = 1, bool */ +/* BinaryExpr.left = 2, expr */ +/* BinaryExpr.op = 3, operator */ +/* BinaryExpr.right = 4, expr */ +/* BinaryExpr = AugAssign */ + +/* BoolExpr.location = 0, location */ +/* BoolExpr.parenthesised = 1, bool */ +/* BoolExpr.op = 2, boolop */ +/* BoolExpr.values = 3, expr_list */ + +/* Break.location = 0, location */ + +/* Bytes.location = 0, location */ +/* Bytes.parenthesised = 1, bool */ +/* Bytes.s = 2, bytes */ +/* Bytes.prefix = 3, bytes */ +/* Bytes.implicitly_concatenated_parts = 4, StringPart_list */ + +/* Call.location = 0, location */ +/* Call.parenthesised = 1, bool */ +/* Call.func = 2, expr */ +/* Call.positional_args = 3, expr_list */ +/* Call.named_args = 4, dict_item_list */ + +/* Class.name = 0, str */ +/* Class.body = 1, stmt_list */ +/* Class = ClassExpr */ + +/* ClassExpr.location = 0, location */ +/* ClassExpr.parenthesised = 1, bool */ +/* ClassExpr.name = 2, str */ +/* ClassExpr.bases = 3, expr_list */ +/* ClassExpr.keywords = 4, dict_item_list */ +/* ClassExpr.inner_scope = 5, Class */ + +/* Compare.location = 0, location */ +/* Compare.parenthesised = 1, bool */ +/* Compare.left = 2, expr */ +/* Compare.ops = 3, cmpop_list */ +/* Compare.comparators = 4, expr_list */ + +/* Continue.location = 0, location */ + +/* Delete.location = 0, location */ +/* Delete.targets = 1, expr_list */ + +/* Dict.location = 0, location */ +/* Dict.parenthesised = 1, bool */ +/* Dict.items = 2, dict_item_list */ + +/* DictComp.location = 0, location */ +/* DictComp.parenthesised = 1, bool */ +/* DictComp.function = 2, Function */ +/* DictComp.iterable = 3, expr */ + +/* DictUnpacking.location = 0, location */ +/* DictUnpacking.value = 1, expr */ + +/* Ellipsis.location = 0, location */ +/* Ellipsis.parenthesised = 1, bool */ + +/* ExceptStmt.location = 0, location */ +/* ExceptStmt.type = 1, expr */ +/* ExceptStmt.name = 2, expr */ +/* ExceptStmt.body = 3, stmt_list */ + +/* Exec.location = 0, location */ +/* Exec.body = 1, expr */ +/* Exec.globals = 2, expr */ +/* Exec.locals = 3, expr */ + +/* ExprStmt.location = 0, location */ +/* ExprStmt.value = 1, expr */ + +/* Filter.location = 0, location */ +/* Filter.parenthesised = 1, bool */ +/* Filter.value = 2, expr */ +/* Filter.filter = 3, expr */ + +/* For.location = 0, location */ +/* For.target = 1, expr */ +/* For.iter = 2, expr */ +/* For.body = 3, stmt_list */ +/* For.orelse = 4, stmt_list */ +/* For.is_async = 5, bool */ + +/* FormattedValue.location = 0, location */ +/* FormattedValue.parenthesised = 1, bool */ +/* FormattedValue.value = 2, expr */ +/* FormattedValue.conversion = 3, str */ +/* FormattedValue.format_spec = 4, JoinedStr */ + +/* Function.name = 0, str */ +/* Function.args = 1, parameter_list */ +/* Function.vararg = 2, expr */ +/* Function.kwonlyargs = 3, expr_list */ +/* Function.kwarg = 4, expr */ +/* Function.body = 5, stmt_list */ +/* Function.is_async = 6, bool */ +/* Function = FunctionParent */ + +/* FunctionExpr.location = 0, location */ +/* FunctionExpr.parenthesised = 1, bool */ +/* FunctionExpr.name = 2, str */ +/* FunctionExpr.args = 3, arguments */ +/* FunctionExpr.returns = 4, expr */ +/* FunctionExpr.inner_scope = 5, Function */ + +/* GeneratorExp.location = 0, location */ +/* GeneratorExp.parenthesised = 1, bool */ +/* GeneratorExp.function = 2, Function */ +/* GeneratorExp.iterable = 3, expr */ + +/* Global.location = 0, location */ +/* Global.names = 1, str_list */ + +/* If.location = 0, location */ +/* If.test = 1, expr */ +/* If.body = 2, stmt_list */ +/* If.orelse = 3, stmt_list */ + +/* IfExp.location = 0, location */ +/* IfExp.parenthesised = 1, bool */ +/* IfExp.test = 2, expr */ +/* IfExp.body = 3, expr */ +/* IfExp.orelse = 4, expr */ + +/* Import.location = 0, location */ +/* Import.names = 1, alias_list */ + +/* ImportExpr.location = 0, location */ +/* ImportExpr.parenthesised = 1, bool */ +/* ImportExpr.level = 2, int */ +/* ImportExpr.name = 3, str */ +/* ImportExpr.top = 4, bool */ + +/* ImportStar.location = 0, location */ +/* ImportStar.module = 1, expr */ + +/* ImportMember.location = 0, location */ +/* ImportMember.parenthesised = 1, bool */ +/* ImportMember.module = 2, expr */ +/* ImportMember.name = 3, str */ + +/* Fstring.location = 0, location */ +/* Fstring.parenthesised = 1, bool */ +/* Fstring.values = 2, expr_list */ +/* Fstring = FormattedValue */ + +/* KeyValuePair.location = 0, location */ +/* KeyValuePair.value = 1, expr */ +/* KeyValuePair.key = 2, expr */ + +/* Lambda.location = 0, location */ +/* Lambda.parenthesised = 1, bool */ +/* Lambda.args = 2, arguments */ +/* Lambda.inner_scope = 3, Function */ + +/* List.location = 0, location */ +/* List.parenthesised = 1, bool */ +/* List.elts = 2, expr_list */ +/* List.ctx = 3, expr_context */ + +/* ListComp.location = 0, location */ +/* ListComp.parenthesised = 1, bool */ +/* ListComp.function = 2, Function */ +/* ListComp.iterable = 3, expr */ +/* ListComp.generators = 4, comprehension_list */ +/* ListComp.elt = 5, expr */ + +/* Module.name = 0, str */ +/* Module.hash = 1, str */ +/* Module.body = 2, stmt_list */ +/* Module.kind = 3, str */ + +/* Name.location = 0, location */ +/* Name.parenthesised = 1, bool */ +/* Name.variable = 2, variable */ +/* Name.ctx = 3, expr_context */ +/* Name = ParameterList */ + +/* Nonlocal.location = 0, location */ +/* Nonlocal.names = 1, str_list */ + +/* Num.location = 0, location */ +/* Num.parenthesised = 1, bool */ +/* Num.n = 2, number */ +/* Num.text = 3, number */ + +/* Pass.location = 0, location */ + +/* PlaceHolder.location = 0, location */ +/* PlaceHolder.parenthesised = 1, bool */ +/* PlaceHolder.variable = 2, variable */ +/* PlaceHolder.ctx = 3, expr_context */ + +/* Print.location = 0, location */ +/* Print.dest = 1, expr */ +/* Print.values = 2, expr_list */ +/* Print.nl = 3, bool */ + +/* Raise.location = 0, location */ +/* Raise.exc = 1, expr */ +/* Raise.cause = 2, expr */ +/* Raise.type = 3, expr */ +/* Raise.inst = 4, expr */ +/* Raise.tback = 5, expr */ + +/* Repr.location = 0, location */ +/* Repr.parenthesised = 1, bool */ +/* Repr.value = 2, expr */ + +/* Return.location = 0, location */ +/* Return.value = 1, expr */ + +/* Set.location = 0, location */ +/* Set.parenthesised = 1, bool */ +/* Set.elts = 2, expr_list */ + +/* SetComp.location = 0, location */ +/* SetComp.parenthesised = 1, bool */ +/* SetComp.function = 2, Function */ +/* SetComp.iterable = 3, expr */ + +/* Slice.location = 0, location */ +/* Slice.parenthesised = 1, bool */ +/* Slice.start = 2, expr */ +/* Slice.stop = 3, expr */ +/* Slice.step = 4, expr */ + +/* SpecialOperation.location = 0, location */ +/* SpecialOperation.parenthesised = 1, bool */ +/* SpecialOperation.name = 2, str */ +/* SpecialOperation.arguments = 3, expr_list */ + +/* Starred.location = 0, location */ +/* Starred.parenthesised = 1, bool */ +/* Starred.value = 2, expr */ +/* Starred.ctx = 3, expr_context */ + +/* Str.location = 0, location */ +/* Str.parenthesised = 1, bool */ +/* Str.s = 2, str */ +/* Str.prefix = 3, str */ +/* Str.implicitly_concatenated_parts = 4, StringPart_list */ + +/* StringPart.text = 0, str */ +/* StringPart.location = 1, location */ +/* StringPart = StringPartList */ +/* StringPartList = BytesOrStr */ + +/* Subscript.location = 0, location */ +/* Subscript.parenthesised = 1, bool */ +/* Subscript.value = 2, expr */ +/* Subscript.index = 3, expr */ +/* Subscript.ctx = 4, expr_context */ + +/* TemplateDottedNotation.location = 0, location */ +/* TemplateDottedNotation.parenthesised = 1, bool */ +/* TemplateDottedNotation.value = 2, expr */ +/* TemplateDottedNotation.attr = 3, str */ +/* TemplateDottedNotation.ctx = 4, expr_context */ + +/* TemplateWrite.location = 0, location */ +/* TemplateWrite.value = 1, expr */ + +/* Try.location = 0, location */ +/* Try.body = 1, stmt_list */ +/* Try.orelse = 2, stmt_list */ +/* Try.handlers = 3, stmt_list */ +/* Try.finalbody = 4, stmt_list */ + +/* Tuple.location = 0, location */ +/* Tuple.parenthesised = 1, bool */ +/* Tuple.elts = 2, expr_list */ +/* Tuple.ctx = 3, expr_context */ +/* Tuple = ParameterList */ + +/* UnaryExpr.location = 0, location */ +/* UnaryExpr.parenthesised = 1, bool */ +/* UnaryExpr.op = 2, unaryop */ +/* UnaryExpr.operand = 3, expr */ + +/* While.location = 0, location */ +/* While.test = 1, expr */ +/* While.body = 2, stmt_list */ +/* While.orelse = 3, stmt_list */ + +/* With.location = 0, location */ +/* With.context_expr = 1, expr */ +/* With.optional_vars = 2, expr */ +/* With.body = 3, stmt_list */ +/* With.is_async = 4, bool */ + +/* Yield.location = 0, location */ +/* Yield.parenthesised = 1, bool */ +/* Yield.value = 2, expr */ + +/* YieldFrom.location = 0, location */ +/* YieldFrom.parenthesised = 1, bool */ +/* YieldFrom.value = 2, expr */ + +/* Alias.value = 0, expr */ +/* Alias.asname = 1, expr */ +/* Alias = AliasList */ +/* AliasList = Import */ + +/* Arguments.kw_defaults = 0, expr_list */ +/* Arguments.defaults = 1, expr_list */ +/* Arguments.annotations = 2, expr_list */ +/* Arguments.varargannotation = 3, expr */ +/* Arguments.kwargannotation = 4, expr */ +/* Arguments.kw_annotations = 5, expr_list */ +/* Arguments = ArgumentsParent */ +/* boolean = BoolParent */ +/* Boolop = BoolExpr */ +/* string = Bytes */ +/* Cmpop = CmpopList */ +/* CmpopList = Compare */ + +/* Comprehension.location = 0, location */ +/* Comprehension.iter = 1, expr */ +/* Comprehension.target = 2, expr */ +/* Comprehension.ifs = 3, expr_list */ +/* Comprehension = ComprehensionList */ +/* ComprehensionList = ListComp */ +/* DictItem = DictItemList */ +/* DictItemList = DictItemListParent */ + +/* Expr.location = 0, location */ +/* Expr.parenthesised = 1, bool */ +/* Expr = ExprParent */ +/* ExprContext = ExprContextParent */ +/* ExprList = ExprListParent */ +/* int = ImportExpr */ + +/* Keyword.location = 0, location */ +/* Keyword.value = 1, expr */ +/* Keyword.arg = 2, str */ +/* Location = LocationParent */ +/* string = Num */ +/* Operator = BinaryExpr */ +/* ParameterList = Function */ + +/* Stmt.location = 0, location */ +/* Stmt = StmtList */ +/* StmtList = StmtListParent */ +/* string = StrParent */ +/* StringList = StrListParent */ +/* Unaryop = UnaryExpr */ +/* Variable = VariableParent */ +py_Classes(unique int id : @py_Class, + unique int parent : @py_ClassExpr ref); + +py_Functions(unique int id : @py_Function, + unique int parent : @py_Function_parent ref); + +py_Modules(unique int id : @py_Module); + +py_StringParts(unique int id : @py_StringPart, + int parent : @py_StringPart_list ref, + int idx : int ref); + +py_StringPart_lists(unique int id : @py_StringPart_list, + unique int parent : @py_Bytes_or_Str ref); + +py_aliases(unique int id : @py_alias, + int parent : @py_alias_list ref, + int idx : int ref); + +py_alias_lists(unique int id : @py_alias_list, + unique int parent : @py_Import ref); + +py_arguments(unique int id : @py_arguments, + unique int parent : @py_arguments_parent ref); + +py_bools(int parent : @py_bool_parent ref, + int idx : int ref); + +py_boolops(unique int id : @py_boolop, + int kind: int ref, + unique int parent : @py_BoolExpr ref); + +py_bytes(varchar(1) id : string ref, + int parent : @py_Bytes ref, + int idx : int ref); + +py_cmpops(unique int id : @py_cmpop, + int kind: int ref, + int parent : @py_cmpop_list ref, + int idx : int ref); + +py_cmpop_lists(unique int id : @py_cmpop_list, + unique int parent : @py_Compare ref); + +py_comprehensions(unique int id : @py_comprehension, + int parent : @py_comprehension_list ref, + int idx : int ref); + +py_comprehension_lists(unique int id : @py_comprehension_list, + unique int parent : @py_ListComp ref); + +py_dict_items(unique int id : @py_dict_item, + int kind: int ref, + int parent : @py_dict_item_list ref, + int idx : int ref); + +py_dict_item_lists(unique int id : @py_dict_item_list, + unique int parent : @py_dict_item_list_parent ref); + +py_exprs(unique int id : @py_expr, + int kind: int ref, + int parent : @py_expr_parent ref, + int idx : int ref); + +py_expr_contexts(unique int id : @py_expr_context, + int kind: int ref, + unique int parent : @py_expr_context_parent ref); + +py_expr_lists(unique int id : @py_expr_list, + int parent : @py_expr_list_parent ref, + int idx : int ref); + +py_ints(int id : int ref, + unique int parent : @py_ImportExpr ref); + +py_locations(unique int id : @location ref, + unique int parent : @py_location_parent ref); + +py_numbers(varchar(1) id : string ref, + int parent : @py_Num ref, + int idx : int ref); + +py_operators(unique int id : @py_operator, + int kind: int ref, + unique int parent : @py_BinaryExpr ref); + +py_parameter_lists(unique int id : @py_parameter_list, + unique int parent : @py_Function ref); + +py_stmts(unique int id : @py_stmt, + int kind: int ref, + int parent : @py_stmt_list ref, + int idx : int ref); + +py_stmt_lists(unique int id : @py_stmt_list, + int parent : @py_stmt_list_parent ref, + int idx : int ref); + +py_strs(varchar(1) id : string ref, + int parent : @py_str_parent ref, + int idx : int ref); + +py_str_lists(unique int id : @py_str_list, + unique int parent : @py_str_list_parent ref); + +py_unaryops(unique int id : @py_unaryop, + int kind: int ref, + unique int parent : @py_UnaryExpr ref); + +py_variables(int id : @py_variable ref, + unique int parent : @py_variable_parent ref); + +case @py_boolop.kind of + 0 = @py_And +| 1 = @py_Or; + +case @py_cmpop.kind of + 0 = @py_Eq +| 1 = @py_Gt +| 2 = @py_GtE +| 3 = @py_In +| 4 = @py_Is +| 5 = @py_IsNot +| 6 = @py_Lt +| 7 = @py_LtE +| 8 = @py_NotEq +| 9 = @py_NotIn; + +case @py_dict_item.kind of + 0 = @py_DictUnpacking +| 1 = @py_KeyValuePair +| 2 = @py_keyword; + +case @py_expr.kind of + 0 = @py_Attribute +| 1 = @py_BinaryExpr +| 2 = @py_BoolExpr +| 3 = @py_Bytes +| 4 = @py_Call +| 5 = @py_ClassExpr +| 6 = @py_Compare +| 7 = @py_Dict +| 8 = @py_DictComp +| 9 = @py_Ellipsis +| 10 = @py_FunctionExpr +| 11 = @py_GeneratorExp +| 12 = @py_IfExp +| 13 = @py_ImportExpr +| 14 = @py_ImportMember +| 15 = @py_Lambda +| 16 = @py_List +| 17 = @py_ListComp +| 18 = @py_Name +| 19 = @py_Num +| 20 = @py_Repr +| 21 = @py_Set +| 22 = @py_SetComp +| 23 = @py_Slice +| 24 = @py_Starred +| 25 = @py_Str +| 26 = @py_Subscript +| 27 = @py_Tuple +| 28 = @py_UnaryExpr +| 29 = @py_Yield +| 30 = @py_YieldFrom +| 31 = @py_TemplateDottedNotation +| 32 = @py_Filter +| 33 = @py_PlaceHolder +| 34 = @py_Await +| 35 = @py_Fstring +| 36 = @py_FormattedValue +| 37 = @py_AssignExpr +| 38 = @py_SpecialOperation; + +case @py_expr_context.kind of + 0 = @py_AugLoad +| 1 = @py_AugStore +| 2 = @py_Del +| 3 = @py_Load +| 4 = @py_Param +| 5 = @py_Store; + +case @py_operator.kind of + 0 = @py_Add +| 1 = @py_BitAnd +| 2 = @py_BitOr +| 3 = @py_BitXor +| 4 = @py_Div +| 5 = @py_FloorDiv +| 6 = @py_LShift +| 7 = @py_Mod +| 8 = @py_Mult +| 9 = @py_Pow +| 10 = @py_RShift +| 11 = @py_Sub +| 12 = @py_MatMult; + +case @py_stmt.kind of + 0 = @py_Assert +| 1 = @py_Assign +| 2 = @py_AugAssign +| 3 = @py_Break +| 4 = @py_Continue +| 5 = @py_Delete +| 6 = @py_ExceptStmt +| 7 = @py_Exec +| 8 = @py_Expr_stmt +| 9 = @py_For +| 10 = @py_Global +| 11 = @py_If +| 12 = @py_Import +| 13 = @py_ImportStar +| 14 = @py_Nonlocal +| 15 = @py_Pass +| 16 = @py_Print +| 17 = @py_Raise +| 18 = @py_Return +| 19 = @py_Try +| 20 = @py_While +| 21 = @py_With +| 22 = @py_TemplateWrite +| 23 = @py_AnnAssign; + +case @py_unaryop.kind of + 0 = @py_Invert +| 1 = @py_Not +| 2 = @py_UAdd +| 3 = @py_USub; + +@py_Bytes_or_Str = @py_Bytes | @py_Str; + +@py_Function_parent = @py_DictComp | @py_FunctionExpr | @py_GeneratorExp | @py_Lambda | @py_ListComp | @py_SetComp; + +@py_arguments_parent = @py_FunctionExpr | @py_Lambda; + +@py_ast_node = @py_Class | @py_Function | @py_Module | @py_StringPart | @py_comprehension | @py_dict_item | @py_expr | @py_stmt; + +@py_bool_parent = @py_For | @py_Function | @py_Print | @py_With | @py_expr; + +@py_dict_item_list_parent = @py_Call | @py_ClassExpr | @py_Dict; + +@py_expr_context_parent = @py_Attribute | @py_List | @py_Name | @py_PlaceHolder | @py_Starred | @py_Subscript | @py_TemplateDottedNotation | @py_Tuple; + +@py_expr_list_parent = @py_Assign | @py_BoolExpr | @py_Call | @py_ClassExpr | @py_Compare | @py_Delete | @py_Fstring | @py_Function | @py_List | @py_Print | @py_Set | @py_SpecialOperation | @py_Tuple | @py_arguments | @py_comprehension; + +@py_expr_or_stmt = @py_expr | @py_stmt; + +@py_expr_parent = @py_AnnAssign | @py_Assert | @py_Assign | @py_AssignExpr | @py_Attribute | @py_AugAssign | @py_Await | @py_BinaryExpr | @py_Call | @py_Compare | @py_DictComp | @py_DictUnpacking | @py_ExceptStmt | @py_Exec | @py_Expr_stmt | @py_Filter | @py_For | @py_FormattedValue | @py_Function | @py_FunctionExpr | @py_GeneratorExp | @py_If | @py_IfExp | @py_ImportMember | @py_ImportStar | @py_KeyValuePair | @py_ListComp | @py_Print | @py_Raise | @py_Repr | @py_Return | @py_SetComp | @py_Slice | @py_Starred | @py_Subscript | @py_TemplateDottedNotation | @py_TemplateWrite | @py_UnaryExpr | @py_While | @py_With | @py_Yield | @py_YieldFrom | @py_alias | @py_arguments | @py_comprehension | @py_expr_list | @py_keyword | @py_parameter_list; + +@py_location_parent = @py_DictUnpacking | @py_KeyValuePair | @py_StringPart | @py_comprehension | @py_expr | @py_keyword | @py_stmt; + +@py_parameter = @py_Name | @py_Tuple; + +@py_scope = @py_Class | @py_Function | @py_Module; + +@py_stmt_list_parent = @py_Class | @py_ExceptStmt | @py_For | @py_Function | @py_If | @py_Module | @py_Try | @py_While | @py_With; + +@py_str_list_parent = @py_Global | @py_Nonlocal; + +@py_str_parent = @py_Attribute | @py_Class | @py_ClassExpr | @py_FormattedValue | @py_Function | @py_FunctionExpr | @py_ImportExpr | @py_ImportMember | @py_Module | @py_SpecialOperation | @py_Str | @py_StringPart | @py_TemplateDottedNotation | @py_keyword | @py_str_list; + +@py_variable_parent = @py_Name | @py_PlaceHolder; + + +/* + * End of auto-generated part + */ + + + +/* Map relative names to absolute names for imports */ +py_absolute_names(int module : @py_Module ref, + varchar(1) relname : string ref, + varchar(1) absname : string ref); + +py_exports(int id : @py_Module ref, + varchar(1) name : string ref); + +/* Successor information */ +py_successors(int predecessor : @py_flow_node ref, + int successor : @py_flow_node ref); + +py_true_successors(int predecessor : @py_flow_node ref, + int successor : @py_flow_node ref); + +py_exception_successors(int predecessor : @py_flow_node ref, + int successor : @py_flow_node ref); + +py_false_successors(int predecessor : @py_flow_node ref, + int successor : @py_flow_node ref); + +py_flow_bb_node(unique int flownode : @py_flow_node, + int realnode : @py_ast_node ref, + int basicblock : @py_flow_node ref, + int index : int ref); + +py_scope_flow(int flow : @py_flow_node ref, + int scope : @py_scope ref, + int kind : int ref); + +py_idoms(unique int node : @py_flow_node ref, + int immediate_dominator : @py_flow_node ref); + +py_ssa_phi(int phi : @py_ssa_var ref, + int arg: @py_ssa_var ref); + +py_ssa_var(unique int id : @py_ssa_var, + int var : @py_variable ref); + +py_ssa_use(int node: @py_flow_node ref, + int var : @py_ssa_var ref); + +py_ssa_defn(unique int id : @py_ssa_var ref, + int node: @py_flow_node ref); + +@py_base_var = @py_variable | @py_ssa_var; + +py_scopes(unique int node : @py_expr_or_stmt ref, + int scope : @py_scope ref); + +py_scope_location(unique int id : @location ref, + unique int scope : @py_scope ref); + +py_flags_versioned(varchar(1) name : string ref, + varchar(1) value : string ref, + varchar(1) version : string ref); + +py_syntax_error_versioned(unique int id : @location ref, + varchar(1) message : string ref, + varchar(1) version : string ref); + +py_comments(unique int id : @py_comment, + varchar(1) text : string ref, + unique int location : @location ref); + +/* Type information support */ + +py_cobjects(unique int obj : @py_cobject); + +py_cobjecttypes(unique int obj : @py_cobject ref, + int typeof : @py_cobject ref); + +py_cobjectnames(unique int obj : @py_cobject ref, + varchar(1) name : string ref); + +/* Kind should be 0 for introspection, > 0 from source, as follows: + 1 from C extension source + */ +py_cobject_sources(int obj : @py_cobject ref, + int kind : int ref); + +py_cmembers_versioned(int object : @py_cobject ref, + varchar(1) name : string ref, + int member : @py_cobject ref, + varchar(1) version : string ref); + +py_citems(int object : @py_cobject ref, + int index : int ref, + int member : @py_cobject ref); + +ext_argtype(int funcid : @py_object ref, + int arg : int ref, + int typeid : @py_object ref); + +ext_rettype(int funcid : @py_object ref, + int typeid : @py_object ref); + +ext_proptype(int propid : @py_object ref, + int typeid : @py_object ref); + +ext_argreturn(int funcid : @py_object ref, + int arg : int ref); + +py_special_objects(unique int obj : @py_cobject ref, + unique varchar(1) name : string ref); + +py_decorated_object(int object : @py_object ref, + int level: int ref); + +@py_object = @py_cobject | @py_flow_node; + +@py_source_element = @py_ast_node | @container; + +/* XML Files */ + +xmlEncoding (unique int id: @file ref, varchar(900) encoding: string ref); + +xmlDTDs (unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref); + +xmlElements (unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs (unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs (int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref); + +xmlHasNs (int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref); + +xmlComments (unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars (unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations(int xmlElement: @xmllocatable ref, + int location: @location_default ref); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; diff --git a/python/upgrades/4f1806347d7fafe2f78508da01c01e5aff5f7cbb/upgrade.properties b/python/upgrades/4f1806347d7fafe2f78508da01c01e5aff5f7cbb/upgrade.properties new file mode 100644 index 00000000000..a0c4ba602a1 --- /dev/null +++ b/python/upgrades/4f1806347d7fafe2f78508da01c01e5aff5f7cbb/upgrade.properties @@ -0,0 +1,4 @@ +description: Removed unused column from the `folders` and `files` relations +compatibility: full +files.rel: reorder files.rel (int id, string name, string simple, string ext, int fromSource) id name +folders.rel: reorder folders.rel (int id, string name, string simple) id name \ No newline at end of file