diff --git a/MODULE.bazel b/MODULE.bazel index d1ff8b0b8d2a..38f182d14bac 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -128,6 +128,7 @@ use_repo( "kotlin-compiler-1.9.20-Beta", "kotlin-compiler-2.0.0-RC1", "kotlin-compiler-2.0.20-Beta2", + "kotlin-compiler-2.1.0-Beta1", "kotlin-compiler-embeddable-1.5.0", "kotlin-compiler-embeddable-1.5.10", "kotlin-compiler-embeddable-1.5.20", @@ -141,6 +142,7 @@ use_repo( "kotlin-compiler-embeddable-1.9.20-Beta", "kotlin-compiler-embeddable-2.0.0-RC1", "kotlin-compiler-embeddable-2.0.20-Beta2", + "kotlin-compiler-embeddable-2.1.0-Beta1", "kotlin-stdlib-1.5.0", "kotlin-stdlib-1.5.10", "kotlin-stdlib-1.5.20", @@ -154,6 +156,7 @@ use_repo( "kotlin-stdlib-1.9.20-Beta", "kotlin-stdlib-2.0.0-RC1", "kotlin-stdlib-2.0.20-Beta2", + "kotlin-stdlib-2.1.0-Beta1", ) go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk") diff --git a/config/identical-files.json b/config/identical-files.json index d14052c12d83..1b48e4372bf5 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -57,10 +57,6 @@ "java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll", "csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll" ], - "Model as Data Generation Java/C# - CaptureModels": [ - "java/ql/src/utils/modelgenerator/internal/CaptureModels.qll", - "csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll" - ], "Sign Java/C#": [ "java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll", "csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll" @@ -355,5 +351,9 @@ "Python model summaries test extension": [ "python/ql/test/library-tests/dataflow/model-summaries/InlineTaintTest.ext.yml", "python/ql/test/library-tests/dataflow/model-summaries/NormalDataflowTest.ext.yml" + ], + "Diagnostics.qll": [ + "ruby/ql/lib/codeql/ruby/Diagnostics.qll", + "rust/ql/lib/codeql/rust/Diagnostics.qll" ] } diff --git a/cpp/ql/lib/semmle/code/cpp/Type.qll b/cpp/ql/lib/semmle/code/cpp/Type.qll index 16d589e99955..b67b6502afe2 100644 --- a/cpp/ql/lib/semmle/code/cpp/Type.qll +++ b/cpp/ql/lib/semmle/code/cpp/Type.qll @@ -39,8 +39,8 @@ class Type extends Locatable, @type { /** * Gets a specifier of this type, recursively looking through `typedef` and - * `decltype`. For example, in the context of `typedef const int *restrict - * t`, the type `volatile t` has specifiers `volatile` and `restrict` but not + * `decltype`. For example, in the context of `typedef const int *restrict t`, + * the type `volatile t` has specifiers `volatile` and `restrict` but not * `const` since the `const` is attached to the type being pointed to rather * than the pointer itself. */ diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl1.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl1.qll index 359fa71744b4..ce964917e970 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl1.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl1.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I 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 359fa71744b4..ce964917e970 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I 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 359fa71744b4..ce964917e970 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I 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 359fa71744b4..ce964917e970 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I 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 359fa71744b4..ce964917e970 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl1.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl1.qll index 359fa71744b4..ce964917e970 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl1.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl1.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I 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 359fa71744b4..ce964917e970 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 @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I 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 359fa71744b4..ce964917e970 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 @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I 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 359fa71744b4..ce964917e970 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 @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ProductFlow.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ProductFlow.qll index c2325593df26..0c474b0e75d0 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ProductFlow.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ProductFlow.qll @@ -546,7 +546,7 @@ module ProductFlow { Flow1::PathGraph::edges(pred1, succ1, _, _) and exists(ReturnKindExt returnKind | succ1.getNode() = returnKind.getAnOutNode(call) and - paramReturnNode(_, pred1.asParameterReturnNode(), _, returnKind) + returnKind = getParamReturnPosition(_, pred1.asParameterReturnNode()).getKind() ) } @@ -574,7 +574,7 @@ module ProductFlow { Flow2::PathGraph::edges(pred2, succ2, _, _) and exists(ReturnKindExt returnKind | succ2.getNode() = returnKind.getAnOutNode(call) and - paramReturnNode(_, pred2.asParameterReturnNode(), _, returnKind) + returnKind = getParamReturnPosition(_, pred2.asParameterReturnNode()).getKind() ) } diff --git a/cpp/ql/lib/semmle/code/cpp/security/InvalidPointerDereference/InvalidPointerToDereference.qll b/cpp/ql/lib/semmle/code/cpp/security/InvalidPointerDereference/InvalidPointerToDereference.qll index 90d7f04f7ca7..03369aacade3 100644 --- a/cpp/ql/lib/semmle/code/cpp/security/InvalidPointerDereference/InvalidPointerToDereference.qll +++ b/cpp/ql/lib/semmle/code/cpp/security/InvalidPointerDereference/InvalidPointerToDereference.qll @@ -160,6 +160,26 @@ private module InvalidPointerToDerefBarrier { } } +/** + * BEWARE: This configuration uses an unrestricted sink, so accessing its full + * flow computation or any stages beyond the first 2 will likely diverge. + * Stage 1 will still be fast and we use it to restrict the subsequent sink + * computation. + */ +private module InvalidPointerReachesConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { invalidPointerToDerefSource(_, _, source) } + + predicate isSink(DataFlow::Node sink) { any() } + + predicate isBarrier(DataFlow::Node node) { InvalidPointerToDerefConfig::isBarrier(node) } + + int fieldFlowBranchLimit() { result = invalidPointerToDereferenceFieldFlowBranchLimit() } +} + +private module InvalidPointerReachesFlow = DataFlow::Global; + +private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon + /** * A configuration to track flow from a pointer-arithmetic operation found * by `AllocToInvalidPointerConfig` to a dereference of the pointer. @@ -173,8 +193,13 @@ private module InvalidPointerToDerefConfig implements DataFlow::StateConfigSig { invalidPointerToDerefSource(_, pai, source) } - pragma[inline] - predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _, _, _) } + predicate isSink(DataFlow::Node sink) { + exists(DataFlowImplCommon::NodeEx n | + InvalidPointerReachesFlow::Stages::Stage1::sinkNode(n, _) and + n.asNode() = sink and + isInvalidPointerDerefSink(sink, _, _, _, _) + ) + } predicate isSink(DataFlow::Node sink, FlowState pai) { none() } diff --git a/cpp/ql/lib/semmle/code/cpp/security/flowafterfree/FlowAfterFree.qll b/cpp/ql/lib/semmle/code/cpp/security/flowafterfree/FlowAfterFree.qll index 1103ff93a1c2..e6a037a94314 100644 --- a/cpp/ql/lib/semmle/code/cpp/security/flowafterfree/FlowAfterFree.qll +++ b/cpp/ql/lib/semmle/code/cpp/security/flowafterfree/FlowAfterFree.qll @@ -72,7 +72,6 @@ module FlowFromFree { predicate isSource(DataFlow::Node node, FlowState state) { isFree(node, _, state, _) } - pragma[inline] predicate isSink(DataFlow::Node sink, FlowState state) { exists(Expr e, DataFlow::Node source, DeallocationExpr dealloc | P::isSink(sink, e) and diff --git a/csharp/ql/consistency-queries/CfgConsistency.ql b/csharp/ql/consistency-queries/CfgConsistency.ql index 9802ddff264b..3caf64f9aece 100644 --- a/csharp/ql/consistency-queries/CfgConsistency.ql +++ b/csharp/ql/consistency-queries/CfgConsistency.ql @@ -61,8 +61,3 @@ query predicate preBasicBlockConsistency(ControlFlowElement cfe1, ControlFlowEle bbIntraSuccInconsistency(cfe1, cfe2) and s = "intra succ inconsistency" } - -query predicate multipleToString(Node n, string s) { - s = strictconcat(n.toString(), ",") and - strictcount(n.toString()) > 1 -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl1.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl1.qll index 359fa71744b4..ce964917e970 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl1.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl1.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I 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 359fa71744b4..ce964917e970 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I 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 359fa71744b4..ce964917e970 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I 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 359fa71744b4..ce964917e970 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I 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 359fa71744b4..ce964917e970 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/Html.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/Html.qll index 6889d6c5b896..362a993e5321 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/Html.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/Html.qll @@ -56,10 +56,9 @@ class HtmlTextWriterSink extends HtmlSink { } /** - * An expression that is used as an argument to an HTML sink method on - * `AttributeCollection`. + * DEPRECATED: Attribute collections are no longer considered HTML sinks. */ -class AttributeCollectionSink extends HtmlSink { +deprecated class AttributeCollectionSink extends DataFlow::ExprNode { AttributeCollectionSink() { exists(SystemWebUIAttributeCollectionClass ac, Parameter p | p = ac.getAddMethod().getParameter(1) or diff --git a/csharp/ql/src/change-notes/2024-09-25-attribute-collection-sink.md b/csharp/ql/src/change-notes/2024-09-25-attribute-collection-sink.md new file mode 100644 index 000000000000..35e959f6f3db --- /dev/null +++ b/csharp/ql/src/change-notes/2024-09-25-attribute-collection-sink.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* C#: The indexer and `Add` method on `System.Web.UI.AttributeCollection` is no longer considered an HTML sink. diff --git a/csharp/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql index 5a653867572e..306ec34d31d0 100644 --- a/csharp/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql +++ b/csharp/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql @@ -9,5 +9,5 @@ import internal.CaptureModels from DataFlowSummaryTargetApi api, string flow -where flow = captureContentFlow(api) +where flow = ContentSensitive::captureFlow(api) select flow order by flow diff --git a/csharp/ql/src/utils/modelgenerator/CaptureNeutralModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureNeutralModels.ql index a601c2511e6d..7a53125e21c1 100644 --- a/csharp/ql/src/utils/modelgenerator/CaptureNeutralModels.ql +++ b/csharp/ql/src/utils/modelgenerator/CaptureNeutralModels.ql @@ -6,9 +6,7 @@ * @tags modelgenerator */ -import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl import internal.CaptureModels -import internal.CaptureSummaryFlowQuery from DataFlowSummaryTargetApi api, string noflow where noflow = captureNoFlow(api) diff --git a/csharp/ql/src/utils/modelgenerator/CaptureSummaryModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureSummaryModels.ql index da4d03fa9bb2..991e593474e2 100644 --- a/csharp/ql/src/utils/modelgenerator/CaptureSummaryModels.ql +++ b/csharp/ql/src/utils/modelgenerator/CaptureSummaryModels.ql @@ -6,9 +6,7 @@ * @tags modelgenerator */ -import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl import internal.CaptureModels -import internal.CaptureSummaryFlowQuery from DataFlowSummaryTargetApi api, string flow where flow = captureFlow(api) diff --git a/csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll b/csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll index ab5de0d01979..7c0aed91b6b8 100644 --- a/csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll +++ b/csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll @@ -1,635 +1,351 @@ -/** - * Provides classes and predicates related to capturing summary, source, - * and sink models of the Standard or a 3rd party library. - */ - -private import CaptureModelsSpecific -private import CaptureModelsPrinting - -/** - * A node from which flow can return to the caller. This is either a regular - * `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter. - */ -private class ReturnNodeExt extends DataFlow::Node { - private DataFlowImplCommon::ReturnKindExt kind; - - ReturnNodeExt() { - kind = DataFlowImplCommon::getValueReturnPosition(this).getKind() or - kind = DataFlowImplCommon::getParamReturnPosition(this, _).getKind() +private import csharp as CS +private import semmle.code.csharp.commons.Util as Util +private import semmle.code.csharp.commons.Collections as Collections +private import semmle.code.csharp.commons.QualifiedName as QualifiedName +private import semmle.code.csharp.dataflow.internal.DataFlowDispatch +private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl +private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate as TaintTrackingPrivate +private import semmle.code.csharp.dataflow.internal.ExternalFlow as ExternalFlow +private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon +private import semmle.code.csharp.dataflow.internal.DataFlowImplSpecific +private import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate +private import semmle.code.csharp.dataflow.internal.TaintTrackingImplSpecific +private import semmle.code.csharp.frameworks.system.linq.Expressions +private import semmle.code.csharp.frameworks.System +private import semmle.code.csharp.Location +private import codeql.mad.modelgenerator.internal.ModelGeneratorImpl + +module ModelGeneratorInput implements ModelGeneratorInputSig { + class Type = CS::Type; + + class Parameter = CS::Parameter; + + class Callable = CS::Callable; + + class NodeExtended extends CS::DataFlow::Node { + Callable getAsExprEnclosingCallable() { result = this.asExpr().getEnclosingCallable() } } /** - * Gets the kind of the return node. + * Holds if any of the parameters of `api` are `System.Func<>`. */ - DataFlowImplCommon::ReturnKindExt getKind() { result = kind } -} + private predicate isHigherOrder(Callable api) { + exists(Type t | t = api.getAParameter().getType().getUnboundDeclaration() | + t instanceof SystemLinqExpressions::DelegateExtType + ) + } -bindingset[c] -private signature string printCallableParamSig(Callable c, ParameterPosition p); + private predicate irrelevantAccessor(CS::Accessor a) { + a.getDeclaration().(CS::Property).isReadWrite() + } -private module PrintReturnNodeExt { - string getOutput(ReturnNodeExt node) { - node.getKind() instanceof DataFlowImplCommon::ValueReturnKind and - result = "ReturnValue" + private predicate isUninterestingForModels(Callable api) { + api.getDeclaringType().getNamespace().getFullName() = "" + or + api instanceof CS::ConversionOperator + or + api instanceof Util::MainMethod or - exists(ParameterPosition pos | - pos = node.getKind().(DataFlowImplCommon::ParamUpdateReturnKind).getPosition() and - result = printCallableParam(returnNodeEnclosingCallable(node), pos) + api instanceof CS::Destructor + or + api instanceof CS::AnonymousFunctionExpr + or + api.(CS::Constructor).isParameterless() + or + exists(Type decl | decl = api.getDeclaringType() | + decl instanceof SystemObjectClass or + decl instanceof SystemValueTypeClass ) + or + // Disregard properties that have both a get and a set accessor, + // which implicitly means auto implemented properties. + irrelevantAccessor(api) } -} - -string getOutput(ReturnNodeExt node) { - result = PrintReturnNodeExt::getOutput(node) -} -string getContentOutput(ReturnNodeExt node) { - result = PrintReturnNodeExt::getOutput(node) -} - -class DataFlowSummaryTargetApi extends SummaryTargetApi { - DataFlowSummaryTargetApi() { not isUninterestingForDataFlowModels(this) } -} - -class DataFlowSourceTargetApi = SourceTargetApi; - -class DataFlowSinkTargetApi = SinkTargetApi; - -private module ModelPrintingInput implements ModelPrintingSig { - class SummaryApi = DataFlowSummaryTargetApi; - - class SourceOrSinkApi = SourceOrSinkTargetApi; + private predicate relevant(Callable api) { + [api.(CS::Modifiable), api.(CS::Accessor).getDeclaration()].isEffectivelyPublic() and + api.fromSource() and + api.isUnboundDeclaration() and + not isUninterestingForModels(api) + } - string getProvenance() { result = "df-generated" } -} + private Callable getARelevantOverrideeOrImplementee(Overridable m) { + m.overridesOrImplements(result) and relevant(result) + } -module Printing = ModelPrinting; + /** + * Gets the super implementation of `api` if it is relevant. + * If such a super implementation does not exist, returns `api` if it is relevant. + */ + private Callable liftedImpl(Callable api) { + ( + result = getARelevantOverrideeOrImplementee(api) + or + result = api and relevant(api) + ) and + not exists(getARelevantOverrideeOrImplementee(result)) + } -/** - * Holds if `c` is a relevant content kind, where the underlying type is relevant. - */ -private predicate isRelevantTypeInContent(DataFlow::ContentSet c) { - isRelevantType(getUnderlyingContentType(c)) -} + private predicate hasManualSummaryModel(Callable api) { + api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()) or + api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel()) + } -/** - * Holds if data can flow from `node1` to `node2` either via a read or a write of an intermediate field `f`. - */ -private predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2) { - exists(DataFlow::ContentSet f | - DataFlowPrivate::readStep(node1, f, node2) and - // Partially restrict the content types used for intermediate steps. - (not exists(getUnderlyingContentType(f)) or isRelevantTypeInContent(f)) - ) - or - exists(DataFlow::ContentSet f | DataFlowPrivate::storeStep(node1, f, node2) | containerContent(f)) -} + private predicate hasManualSourceModel(Callable api) { + api = any(ExternalFlow::SourceCallable sc | sc.hasManualModel()) or + api = any(FlowSummaryImpl::Public::NeutralSourceCallable sc | sc.hasManualModel()) + } -/** - * Holds if content `c` is either a field, a synthetic field or language specific - * content of a relevant type or a container like content. - */ -pragma[nomagic] -private predicate isRelevantContent0(DataFlow::ContentSet c) { - isRelevantTypeInContent(c) or - containerContent(c) -} + private predicate hasManualSinkModel(Callable api) { + api = any(ExternalFlow::SinkCallable sc | sc.hasManualModel()) or + api = any(FlowSummaryImpl::Public::NeutralSinkCallable sc | sc.hasManualModel()) + } -/** - * Gets the MaD string representation of the parameter node `p`. - */ -string parameterNodeAsInput(DataFlow::ParameterNode p) { - result = parameterAccess(p.asParameter()) - or - result = qualifierString() and p instanceof InstanceParameterNode -} + predicate isUninterestingForDataFlowModels(Callable api) { isHigherOrder(api) } -/** - * Gets the MaD string representation of the parameter `p` - * when used in content flow. - */ -string parameterNodeAsContentInput(DataFlow::ParameterNode p) { - result = parameterContentAccess(p.asParameter()) - or - result = qualifierString() and p instanceof InstanceParameterNode -} + class SourceOrSinkTargetApi extends Callable { + SourceOrSinkTargetApi() { relevant(this) } + } -/** - * Gets the MaD input string representation of `source`. - */ -string asInputArgument(DataFlow::Node source) { result = asInputArgumentSpecific(source) } - -/** - * Gets the summary model of `api`, if it follows the `fluent` programming pattern (returns `this`). - */ -string captureQualifierFlow(DataFlowSummaryTargetApi api) { - exists(ReturnNodeExt ret | - api = returnNodeEnclosingCallable(ret) and - isOwnInstanceAccessNode(ret) - ) and - result = Printing::asLiftedValueModel(api, qualifierString(), "ReturnValue") -} + class SinkTargetApi extends SourceOrSinkTargetApi { + SinkTargetApi() { not hasManualSinkModel(this) } + } -private int accessPathLimit0() { result = 2 } + class SourceTargetApi extends SourceOrSinkTargetApi { + SourceTargetApi() { + not hasManualSourceModel(this) and + // Do not generate source models for overridable callables + // as virtual dispatch implies that too many methods + // will be considered sources. + not this.(Overridable).overridesOrImplements(_) + } + } -private newtype TTaintState = - TTaintRead(int n) { n in [0 .. accessPathLimit0()] } or - TTaintStore(int n) { n in [1 .. accessPathLimit0()] } + class SummaryTargetApi extends Callable { + private Callable lift; -abstract private class TaintState extends TTaintState { - abstract string toString(); -} + SummaryTargetApi() { + lift = liftedImpl(this) and + not hasManualSummaryModel(lift) + } -/** - * A FlowState representing a tainted read. - */ -private class TaintRead extends TaintState, TTaintRead { - private int step; + Callable lift() { result = lift } - TaintRead() { this = TTaintRead(step) } + predicate isRelevant() { relevant(this) } + } /** - * Gets the flow state step number. + * Holds if `t` is a type that is generally used for bulk data in collection types. + * Eg. char[] is roughly equivalent to string and thus a highly + * relevant type for model generation. */ - int getStep() { result = step } - - override string toString() { result = "TaintRead(" + step + ")" } -} + private predicate isPrimitiveTypeUsedForBulkData(CS::Type t) { + t instanceof CS::ByteType or + t instanceof CS::CharType + } -/** - * A FlowState representing a tainted write. - */ -private class TaintStore extends TaintState, TTaintStore { - private int step; + /** + * Holds if the collection type `ct` is irrelevant for model generation. + * Collection types where the type of the elements are + * (1) unknown - are considered relevant. + * (2) known - at least one the child types should be relevant (a non-simple type + * or a type used for bulk data) + */ + private predicate irrelevantCollectionType(CS::Type ct) { + Collections::isCollectionType(ct) and + forex(CS::Type child | child = ct.getAChild() | + child instanceof CS::SimpleType and + not isPrimitiveTypeUsedForBulkData(child) + ) + } - TaintStore() { this = TTaintStore(step) } + predicate isRelevantType(CS::Type t) { + not t instanceof CS::SimpleType and + not t instanceof CS::Enum and + not t instanceof SystemDateTimeStruct and + not t instanceof SystemTypeClass and + not irrelevantCollectionType(t) + } /** - * Gets the flow state step number. + * Gets the underlying type of the content `c`. */ - int getStep() { result = step } - - override string toString() { result = "TaintStore(" + step + ")" } -} + private CS::Type getUnderlyingContType(DataFlow::Content c) { + result = c.(DataFlow::FieldContent).getField().getType() or + result = c.(DataFlow::SyntheticFieldContent).getField().getType() + } -/** - * A data-flow configuration for tracking flow through APIs. - * The sources are the parameters of an API and the sinks are the return values (excluding `this`) and parameters. - * - * This can be used to generate Flow summaries for APIs from parameter to return. - */ -module PropagateFlowConfig implements DataFlow::StateConfigSig { - class FlowState = TaintState; - - predicate isSource(DataFlow::Node source, FlowState state) { - source instanceof DataFlow::ParameterNode and - source.getEnclosingCallable() instanceof DataFlowSummaryTargetApi and - state.(TaintRead).getStep() = 0 - } - - predicate isSink(DataFlow::Node sink, FlowState state) { - sink instanceof ReturnNodeExt and - not isOwnInstanceAccessNode(sink) and - not exists(captureQualifierFlow(sink.asExpr().getEnclosingCallable())) and - (state instanceof TaintRead or state instanceof TaintStore) - } - - predicate isAdditionalFlowStep( - DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2 - ) { - exists(DataFlow::ContentSet c | - DataFlowImplCommon::store(node1, c.getAStoreContent(), node2, _, _) and - isRelevantContent0(c) and - ( - state1 instanceof TaintRead and state2.(TaintStore).getStep() = 1 - or - state1.(TaintStore).getStep() + 1 = state2.(TaintStore).getStep() - ) + Type getUnderlyingContentType(DataFlow::ContentSet c) { + exists(DataFlow::Content cont | + c.isSingleton(cont) and + result = getUnderlyingContType(cont) ) or - exists(DataFlow::ContentSet c | - DataFlowPrivate::readStep(node1, c, node2) and - isRelevantContent0(c) and - state1.(TaintRead).getStep() + 1 = state2.(TaintRead).getStep() + exists(CS::Property p | + c.isProperty(p) and + result = p.getType() ) } - predicate isBarrier(DataFlow::Node n) { - exists(Type t | t = n.getType() and not isRelevantType(t)) - } + string qualifierString() { result = "Argument[this]" } - DataFlow::FlowFeature getAFeature() { - result instanceof DataFlow::FeatureEqualSourceSinkCallContext + string parameterAccess(CS::Parameter p) { + if Collections::isCollectionType(p.getType()) + then result = "Argument[" + p.getPosition() + "].Element" + else result = "Argument[" + p.getPosition() + "]" } -} -module PropagateFlow = TaintTracking::GlobalWithState; - -/** - * Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter. - */ -string captureThroughFlow0( - DataFlowSummaryTargetApi api, DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt -) { - exists(string input, string output | - p.getEnclosingCallable() = api and - returnNodeExt.(DataFlow::Node).getEnclosingCallable() = api and - input = parameterNodeAsInput(p) and - output = getOutput(returnNodeExt) and - input != output and - result = Printing::asLiftedTaintModel(api, input, output) - ) -} + string parameterContentAccess(CS::Parameter p) { result = "Argument[" + p.getPosition() + "]" } -/** - * Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter. - */ -string captureThroughFlow(DataFlowSummaryTargetApi api) { - exists(DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt | - PropagateFlow::flow(p, returnNodeExt) and - result = captureThroughFlow0(api, p, returnNodeExt) - ) -} + class InstanceParameterNode = DataFlowPrivate::InstanceParameterNode; -private module PropagateContentFlowConfig implements ContentDataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { - source instanceof DataFlow::ParameterNode and - source.getEnclosingCallable() instanceof DataFlowSummaryTargetApi - } + private signature string parameterAccessSig(Parameter p); - predicate isSink(DataFlow::Node sink) { - sink instanceof ReturnNodeExt and - sink.getEnclosingCallable() instanceof DataFlowSummaryTargetApi + private module ParamReturnNodeAsOutput { + bindingset[c] + string paramReturnNodeAsOutput(CS::Callable c, ParameterPosition pos) { + result = getParamAccess(c.getParameter(pos.getPosition())) + or + pos.isThisParameter() and + result = qualifierString() + } } - predicate isAdditionalFlowStep = isAdditionalContentFlowStep/2; - - predicate isBarrier(DataFlow::Node n) { - exists(Type t | t = n.getType() and not isRelevantType(t)) + bindingset[c] + string paramReturnNodeAsOutput(CS::Callable c, ParameterPosition pos) { + result = ParamReturnNodeAsOutput::paramReturnNodeAsOutput(c, pos) } - int accessPathLimit() { result = 2 } - - predicate isRelevantContent(DataFlow::ContentSet s) { isRelevantContent0(s) } - - DataFlow::FlowFeature getAFeature() { - result instanceof DataFlow::FeatureEqualSourceSinkCallContext + bindingset[c] + string paramReturnNodeAsContentOutput(Callable c, ParameterPosition pos) { + result = ParamReturnNodeAsOutput::paramReturnNodeAsOutput(c, pos) } -} - -private module PropagateContentFlow = ContentDataFlow::Global; -private string getContent(PropagateContentFlow::AccessPath ap, int i) { - exists(ContentSet head, PropagateContentFlow::AccessPath tail | - head = ap.getHead() and - tail = ap.getTail() - | - i = 0 and - result = "." + printContent(head) - or - i > 0 and result = getContent(tail, i - 1) - ) -} - -/** - * Gets the MaD string representation of a store step access path. - */ -private string printStoreAccessPath(PropagateContentFlow::AccessPath ap) { - result = concat(int i | | getContent(ap, i), "" order by i) -} - -/** - * Gets the MaD string representation of a read step access path. - */ -private string printReadAccessPath(PropagateContentFlow::AccessPath ap) { - result = concat(int i | | getContent(ap, i), "" order by i desc) -} - -/** - * Holds if the access path `ap` contains a field or synthetic field access. - */ -private predicate mentionsField(PropagateContentFlow::AccessPath ap) { - exists(ContentSet head, PropagateContentFlow::AccessPath tail | - head = ap.getHead() and - tail = ap.getTail() - | - mentionsField(tail) or isField(head) - ) -} - -private predicate apiFlow( - DataFlowSummaryTargetApi api, DataFlow::ParameterNode p, PropagateContentFlow::AccessPath reads, - ReturnNodeExt returnNodeExt, PropagateContentFlow::AccessPath stores, boolean preservesValue -) { - PropagateContentFlow::flow(p, reads, returnNodeExt, stores, preservesValue) and - returnNodeExt.getEnclosingCallable() = api and - p.getEnclosingCallable() = api -} - -/** - * A class of APIs relevant for modeling using content flow. - * The following heuristic is applied: - * Content flow is only relevant for an API, if - * #content flow <= 2 * #parameters + 3 - * If an API produces more content flow, it is likely that - * 1. Types are not sufficiently constrained leading to a combinatorial - * explosion in dispatch and thus in the generated summaries. - * 2. It is a reasonable approximation to use the non-content based flow - * detection instead, as reads and stores would use a significant - * part of an objects internal state. - */ -private class ContentDataFlowSummaryTargetApi extends DataFlowSummaryTargetApi { - ContentDataFlowSummaryTargetApi() { - count(string input, string output | - exists( - DataFlow::ParameterNode p, PropagateContentFlow::AccessPath reads, - ReturnNodeExt returnNodeExt, PropagateContentFlow::AccessPath stores - | - apiFlow(this, p, reads, returnNodeExt, stores, _) and - input = parameterNodeAsContentInput(p) + printReadAccessPath(reads) and - output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores) - ) - ) <= 2 * this.getNumberOfParameters() + 3 + Callable returnNodeEnclosingCallable(DataFlow::Node ret) { + result = DataFlowImplCommon::getNodeEnclosingCallable(ret).asCallable(_) } -} -pragma[nomagic] -private predicate apiContentFlow( - ContentDataFlowSummaryTargetApi api, DataFlow::ParameterNode p, - PropagateContentFlow::AccessPath reads, ReturnNodeExt returnNodeExt, - PropagateContentFlow::AccessPath stores, boolean preservesValue -) { - PropagateContentFlow::flow(p, reads, returnNodeExt, stores, preservesValue) and - returnNodeExt.getEnclosingCallable() = api and - p.getEnclosingCallable() = api -} - -/** - * Holds if any of the content sets in `path` translates into a synthetic field. - */ -private predicate hasSyntheticContent(PropagateContentFlow::AccessPath path) { - exists(PropagateContentFlow::AccessPath tail, ContentSet head | - head = path.getHead() and - tail = path.getTail() - | - exists(getSyntheticName(head)) or - hasSyntheticContent(tail) - ) -} + predicate isOwnInstanceAccessNode(DataFlowPrivate::ReturnNode node) { + node.asExpr() instanceof CS::ThisAccess + } -/** - * A module containing predicates for validating access paths containing content sets - * that translates into synthetic fields, when used for generated summary models. - */ -private module AccessPathSyntheticValidation { - /** - * Holds if there exists an API that has content flow from `read` (on type `t1`) - * to `store` (on type `t2`). - */ - private predicate step( - Type t1, PropagateContentFlow::AccessPath read, Type t2, PropagateContentFlow::AccessPath store - ) { - exists(DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt | - p.getType() = t1 and - returnNodeExt.getType() = t2 and - apiContentFlow(_, p, read, returnNodeExt, store, _) + private predicate isRelevantMemberAccess(DataFlow::Node node) { + exists(CS::MemberAccess access | access = node.asExpr() | + access.hasThisQualifier() and + access.getTarget().isEffectivelyPublic() and + ( + access instanceof CS::FieldAccess + or + access.getTarget().(CS::Property).getSetter().isPublic() + ) ) } - /** - * Holds if there exists an API that has content flow from `read` (on type `t1`) - * to `store` (on type `t2`), where `read` does not have synthetic content and `store` does. - * - * Step A -> Synth. - */ - private predicate synthPathEntry( - Type t1, PropagateContentFlow::AccessPath read, Type t2, PropagateContentFlow::AccessPath store - ) { - not hasSyntheticContent(read) and - hasSyntheticContent(store) and - step(t1, read, t2, store) - } + predicate sinkModelSanitizer(DataFlow::Node node) { none() } - /** - * Holds if there exists an API that has content flow from `read` (on type `t1`) - * to `store` (on type `t2`), where `read` has synthetic content - * and `store` does not. - * - * Step Synth -> A. - */ - private predicate synthPathExit( - Type t1, PropagateContentFlow::AccessPath read, Type t2, PropagateContentFlow::AccessPath store - ) { - hasSyntheticContent(read) and - not hasSyntheticContent(store) and - step(t1, read, t2, store) + predicate apiSource(DataFlow::Node source) { + isRelevantMemberAccess(source) or source instanceof DataFlow::ParameterNode } - /** - * Holds if there exists a path of steps from `read` to an exit. - * - * read ->* Synth -> A - */ - private predicate reachesSynthExit(Type t, PropagateContentFlow::AccessPath read) { - synthPathExit(t, read, _, _) - or - hasSyntheticContent(read) and - exists(PropagateContentFlow::AccessPath mid, Type midType | - hasSyntheticContent(mid) and - step(t, read, midType, mid) and - reachesSynthExit(midType, mid.reverse()) + private predicate uniquelyCalls(DataFlowCallable dc1, DataFlowCallable dc2) { + exists(DataFlowCall call | + dc1 = call.getEnclosingCallable() and + dc2 = unique(DataFlowCallable dc0 | dc0 = viableCallable(call) | dc0) ) } - /** - * Holds if there exists a path of steps from an entry to `store`. - * - * A -> Synth ->* store - */ - private predicate synthEntryReaches(Type t, PropagateContentFlow::AccessPath store) { - synthPathEntry(_, _, t, store) - or - hasSyntheticContent(store) and - exists(PropagateContentFlow::AccessPath mid, Type midType | - hasSyntheticContent(mid) and - step(midType, mid, t, store) and - synthEntryReaches(midType, mid.reverse()) + bindingset[dc1, dc2] + private predicate uniquelyCallsPlus(DataFlowCallable dc1, DataFlowCallable dc2) = + fastTC(uniquelyCalls/2)(dc1, dc2) + + bindingset[sourceEnclosing, api] + predicate irrelevantSourceSinkApi(Callable sourceEnclosing, SourceTargetApi api) { + not exists(DataFlowCallable dc1, DataFlowCallable dc2 | + uniquelyCallsPlus(dc1, dc2) or dc1 = dc2 + | + dc1.getUnderlyingCallable() = api and + dc2.getUnderlyingCallable() = sourceEnclosing ) } - /** - * Holds if at least one of the access paths `read` (on type `t1`) and `store` (on type `t2`) - * contain content that will be translated into a synthetic field, when being used in - * a MaD summary model, and if there is a range of APIs, such that - * when chaining their flow access paths, there exists access paths `A` and `B` where - * A ->* read -> store ->* B and where `A` and `B` do not contain content that will - * be translated into a synthetic field. - * - * This is needed because we don't want to include summaries that reads from or - * stores into a "dead" synthetic field. - * - * Example: - * Assume we have a type `t` (in this case `t1` = `t2`) with methods `getX` and - * `setX`, which gets and sets a private field `X` on `t`. - * This would lead to the following content flows - * getX : Argument[this].SyntheticField[t.X] -> ReturnValue. - * setX : Argument[0] -> Argument[this].SyntheticField[t.X] - * As the reads and stores are on synthetic fields we should only make summaries - * if both of these methods exist. - */ - pragma[nomagic] - predicate acceptReadStore( - Type t1, PropagateContentFlow::AccessPath read, Type t2, PropagateContentFlow::AccessPath store - ) { - synthPathEntry(t1, read, t2, store) and reachesSynthExit(t2, store.reverse()) - or - exists(PropagateContentFlow::AccessPath store0 | store0.reverse() = read | - synthEntryReaches(t1, store0) and synthPathExit(t1, read, t2, store) - or - synthEntryReaches(t1, store0) and - step(t1, read, t2, store) and - reachesSynthExit(t2, store.reverse()) + string getInputArgument(DataFlow::Node source) { + exists(int pos | + pos = source.(DataFlow::ParameterNode).getParameter().getPosition() and + result = "Argument[" + pos + "]" ) + or + source.asExpr() instanceof DataFlowPrivate::FieldOrPropertyAccess and + result = qualifierString() } -} -/** - * Holds, if the API `api` has relevant flow from `read` on `p` to `store` on `returnNodeExt`. - * Flow is considered relevant, - * 1. If `read` or `store` do not contain a content set that translates into a synthetic field. - * 2. If `read` or `store` contain a content set that translates into a synthetic field, and if - * the synthetic content is "live" on the relevant declaring type. - */ -private predicate apiRelevantContentFlow( - ContentDataFlowSummaryTargetApi api, DataFlow::ParameterNode p, - PropagateContentFlow::AccessPath read, ReturnNodeExt returnNodeExt, - PropagateContentFlow::AccessPath store, boolean preservesValue -) { - apiContentFlow(api, p, read, returnNodeExt, store, preservesValue) and - ( - not hasSyntheticContent(read) and not hasSyntheticContent(store) - or - AccessPathSyntheticValidation::acceptReadStore(p.getType(), read, returnNodeExt.getType(), store) - ) -} + bindingset[kind] + predicate isRelevantSinkKind(string kind) { any() } -pragma[nomagic] -private predicate captureContentFlow0( - ContentDataFlowSummaryTargetApi api, string input, string output, boolean preservesValue, - boolean lift -) { - exists( - DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt, PropagateContentFlow::AccessPath reads, - PropagateContentFlow::AccessPath stores - | - apiRelevantContentFlow(api, p, reads, returnNodeExt, stores, preservesValue) and - input = parameterNodeAsContentInput(p) + printReadAccessPath(reads) and - output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores) and - input != output and - (if mentionsField(reads) or mentionsField(stores) then lift = false else lift = true) - ) -} + bindingset[kind] + predicate isRelevantSourceKind(string kind) { any() } -/** - * Gets the content based summary model(s) of the API `api` (if there is flow from a parameter to - * the return value or a parameter). - * - * Models are lifted to the best type in case the read and store access paths do not - * contain a field or synthetic field access. - */ -string captureContentFlow(ContentDataFlowSummaryTargetApi api) { - exists(string input, string output, boolean lift, boolean preservesValue | - captureContentFlow0(api, input, output, _, lift) and - preservesValue = max(boolean p | captureContentFlow0(api, input, output, p, lift)) and - result = Printing::asModel(api, input, output, preservesValue, lift) - ) -} + predicate containerContent(DataFlow::ContentSet c) { c.isElement() } -/** - * A dataflow configuration used for finding new sources. - * The sources are the already known existing sources and the sinks are the API return nodes. - * - * This can be used to generate Source summaries for an API, if the API expose an already known source - * via its return (then the API itself becomes a source). - */ -module PropagateFromSourceConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { - exists(string kind | - isRelevantSourceKind(kind) and - ExternalFlow::sourceNode(source, kind) + predicate isAdditionalContentFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + TaintTrackingPrivate::defaultAdditionalTaintStep(nodeFrom, nodeTo, _) and + not nodeTo.asExpr() instanceof CS::ElementAccess and + not exists(DataFlow::ContentSet c | + DataFlowPrivate::readStep(nodeFrom, c, nodeTo) and containerContent(c) ) } - predicate isSink(DataFlow::Node sink) { - sink instanceof ReturnNodeExt and - sink.getEnclosingCallable() instanceof DataFlowSourceTargetApi - } - - DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSinkCallContext } - - predicate isBarrier(DataFlow::Node n) { - exists(Type t | t = n.getType() and not isRelevantType(t)) - } - - predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { - isRelevantTaintStep(node1, node2) + bindingset[d] + private string getFullyQualifiedName(Declaration d) { + exists(string qualifier, string name | + d.hasFullyQualifiedName(qualifier, name) and + result = QualifiedName::getQualifiedName(qualifier, name) + ) } -} - -private module PropagateFromSource = TaintTracking::Global; - -/** - * Gets the source model(s) of `api`, if there is flow from an existing known source to the return of `api`. - */ -string captureSource(DataFlowSourceTargetApi api) { - exists(DataFlow::Node source, ReturnNodeExt sink, string kind | - PropagateFromSource::flow(source, sink) and - ExternalFlow::sourceNode(source, kind) and - api = sink.getEnclosingCallable() and - not irrelevantSourceSinkApi(source.getEnclosingCallable(), api) and - result = Printing::asSourceModel(api, getOutput(sink), kind) - ) -} -/** - * A dataflow configuration used for finding new sinks. - * The sources are the parameters of the API and the fields of the enclosing type. - * - * This can be used to generate Sink summaries for APIs, if the API propagates a parameter (or enclosing type field) - * into an existing known sink (then the API itself becomes a sink). - */ -module PropagateToSinkConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { - apiSource(source) and source.getEnclosingCallable() instanceof DataFlowSinkTargetApi + predicate isField(DataFlow::ContentSet c) { + c.isField(_) or c.isSyntheticField(_) or c.isProperty(_) } - predicate isSink(DataFlow::Node sink) { - exists(string kind | isRelevantSinkKind(kind) and ExternalFlow::sinkNode(sink, kind)) + string getSyntheticName(DataFlow::ContentSet c) { + exists(CS::Field f | + not f.isEffectivelyPublic() and + c.isField(f) and + result = getFullyQualifiedName(f) + ) + or + exists(CS::Property p | + not p.isEffectivelyPublic() and + c.isProperty(p) and + result = getFullyQualifiedName(p) + ) + or + c.isSyntheticField(result) } - predicate isBarrier(DataFlow::Node node) { - exists(Type t | t = node.getType() and not isRelevantType(t)) + string printContent(DataFlow::ContentSet c) { + exists(CS::Field f, string name | name = getFullyQualifiedName(f) | + c.isField(f) and + f.isEffectivelyPublic() and + result = "Field[" + name + "]" + ) + or + exists(CS::Property p, string name | name = getFullyQualifiedName(p) | + c.isProperty(p) and + p.isEffectivelyPublic() and + result = "Property[" + name + "]" + ) or - sinkModelSanitizer(node) + result = "SyntheticField[" + getSyntheticName(c) + "]" + or + c.isElement() and + result = "Element" } - DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext } + predicate partialModel = ExternalFlow::partialModel/6; - predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { - isRelevantTaintStep(node1, node2) - } -} + predicate sourceNode = ExternalFlow::sourceNode/2; -private module PropagateToSink = TaintTracking::Global; - -/** - * Gets the sink model(s) of `api`, if there is flow from a parameter to an existing known sink. - */ -string captureSink(DataFlowSinkTargetApi api) { - exists(DataFlow::Node src, DataFlow::Node sink, string kind | - PropagateToSink::flow(src, sink) and - ExternalFlow::sinkNode(sink, kind) and - api = src.getEnclosingCallable() and - result = Printing::asSinkModel(api, asInputArgument(src), kind) - ) + predicate sinkNode = ExternalFlow::sinkNode/2; } + +import MakeModelGenerator diff --git a/csharp/ql/src/utils/modelgenerator/internal/CaptureModelsPrinting.qll b/csharp/ql/src/utils/modelgenerator/internal/CaptureModelsPrinting.qll index 4c09f4ccba5b..90452b1fc91e 100644 --- a/csharp/ql/src/utils/modelgenerator/internal/CaptureModelsPrinting.qll +++ b/csharp/ql/src/utils/modelgenerator/internal/CaptureModelsPrinting.qll @@ -1,5 +1,5 @@ private import csharp as CS -private import codeql.mad.modelgenerator.ModelPrinting +private import codeql.mad.modelgenerator.internal.ModelPrinting private import semmle.code.csharp.dataflow.internal.ExternalFlow as ExternalFlow private module ModelPrintingLang implements ModelPrintingLangSig { diff --git a/csharp/ql/src/utils/modelgenerator/internal/CaptureModelsSpecific.qll b/csharp/ql/src/utils/modelgenerator/internal/CaptureModelsSpecific.qll deleted file mode 100644 index 8ac07342d559..000000000000 --- a/csharp/ql/src/utils/modelgenerator/internal/CaptureModelsSpecific.qll +++ /dev/null @@ -1,436 +0,0 @@ -/** - * Provides predicates related to capturing summary models of the Standard or a 3rd party library. - */ - -private import csharp as CS -private import semmle.code.csharp.commons.Util as Util -private import semmle.code.csharp.commons.Collections as Collections -private import semmle.code.csharp.commons.QualifiedName as QualifiedName -private import semmle.code.csharp.dataflow.internal.DataFlowDispatch -private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl -private import semmle.code.csharp.frameworks.system.linq.Expressions -private import semmle.code.csharp.frameworks.System -private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate as TaintTrackingPrivate -import semmle.code.csharp.dataflow.internal.ExternalFlow as ExternalFlow -import semmle.code.csharp.dataflow.internal.ContentDataFlow as ContentDataFlow -import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon -import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate -import semmle.code.csharp.dataflow.internal.DataFlowDispatch as DataFlowDispatch - -module DataFlow = CS::DataFlow; - -module TaintTracking = CS::TaintTracking; - -class Type = CS::Type; - -class Callable = CS::Callable; - -class ContentSet = DataFlow::ContentSet; - -/** - * Holds if any of the parameters of `api` are `System.Func<>`. - */ -private predicate isHigherOrder(Callable api) { - exists(Type t | t = api.getAParameter().getType().getUnboundDeclaration() | - t instanceof SystemLinqExpressions::DelegateExtType - ) -} - -private predicate irrelevantAccessor(CS::Accessor a) { - a.getDeclaration().(CS::Property).isReadWrite() -} - -private predicate isUninterestingForModels(Callable api) { - api.getDeclaringType().getNamespace().getFullName() = "" - or - api instanceof CS::ConversionOperator - or - api instanceof Util::MainMethod - or - api instanceof CS::Destructor - or - api instanceof CS::AnonymousFunctionExpr - or - api.(CS::Constructor).isParameterless() - or - exists(Type decl | decl = api.getDeclaringType() | - decl instanceof SystemObjectClass or - decl instanceof SystemValueTypeClass - ) - or - // Disregard properties that have both a get and a set accessor, - // which implicitly means auto implemented properties. - irrelevantAccessor(api) -} - -private predicate relevant(Callable api) { - [api.(CS::Modifiable), api.(CS::Accessor).getDeclaration()].isEffectivelyPublic() and - api.fromSource() and - api.isUnboundDeclaration() and - not isUninterestingForModels(api) -} - -private Callable getARelevantOverrideeOrImplementee(Overridable m) { - m.overridesOrImplements(result) and relevant(result) -} - -/** - * Gets the super implementation of `api` if it is relevant. - * If such a super implementation does not exist, returns `api` if it is relevant. - */ -private Callable liftedImpl(Callable api) { - ( - result = getARelevantOverrideeOrImplementee(api) - or - result = api and relevant(api) - ) and - not exists(getARelevantOverrideeOrImplementee(result)) -} - -private predicate hasManualSummaryModel(Callable api) { - api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()) or - api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel()) -} - -private predicate hasManualSourceModel(Callable api) { - api = any(ExternalFlow::SourceCallable sc | sc.hasManualModel()) or - api = any(FlowSummaryImpl::Public::NeutralSourceCallable sc | sc.hasManualModel()) -} - -private predicate hasManualSinkModel(Callable api) { - api = any(ExternalFlow::SinkCallable sc | sc.hasManualModel()) or - api = any(FlowSummaryImpl::Public::NeutralSinkCallable sc | sc.hasManualModel()) -} - -/** - * Holds if it is irrelevant to generate models for `api` based on data flow analysis. - * - * This serves as an extra filter for the `relevant` predicate. - */ -predicate isUninterestingForDataFlowModels(CS::Callable api) { isHigherOrder(api) } - -/** - * Holds if it is irrelevant to generate models for `api` based on type-based analysis. - * - * This serves as an extra filter for the `relevant` predicate. - */ -predicate isUninterestingForTypeBasedFlowModels(CS::Callable api) { none() } - -/** - * A class of callables that are potentially relevant for generating source or - * sink models. - */ -class SourceOrSinkTargetApi extends Callable { - SourceOrSinkTargetApi() { relevant(this) } -} - -/** - * A class of callables that are potentially relevant for generating sink models. - */ -class SinkTargetApi extends SourceOrSinkTargetApi { - SinkTargetApi() { not hasManualSinkModel(this) } -} - -/** - * A class of callables that are potentially relevant for generating source models. - */ -class SourceTargetApi extends SourceOrSinkTargetApi { - SourceTargetApi() { - not hasManualSourceModel(this) and - // Do not generate source models for overridable callables - // as virtual dispatch implies that too many methods - // will be considered sources. - not this.(Overridable).overridesOrImplements(_) - } -} - -/** - * A class of callables that are potentially relevant for generating summary or - * neutral models. - * - * In the Standard library and 3rd party libraries it is the callables (or callables that have a - * super implementation) that can be called from outside the library itself. - */ -class SummaryTargetApi extends Callable { - private Callable lift; - - SummaryTargetApi() { - lift = liftedImpl(this) and - not hasManualSummaryModel(lift) - } - - /** - * Gets the callable that a model will be lifted to. - * - * The lifted callable is relevant in terms of model - * generation (this is ensured by `liftedImpl`). - */ - Callable lift() { result = lift } - - /** - * Holds if `this` is relevant in terms of model generation. - */ - predicate isRelevant() { relevant(this) } -} - -/** - * Holds if `t` is a type that is generally used for bulk data in collection types. - * Eg. char[] is roughly equivalent to string and thus a highly - * relevant type for model generation. - */ -private predicate isPrimitiveTypeUsedForBulkData(CS::Type t) { - t instanceof CS::ByteType or - t instanceof CS::CharType -} - -/** - * Holds if the collection type `ct` is irrelevant for model generation. - * Collection types where the type of the elements are - * (1) unknown - are considered relevant. - * (2) known - at least one the child types should be relevant (a non-simple type - * or a type used for bulk data) - */ -private predicate irrelevantCollectionType(CS::Type ct) { - Collections::isCollectionType(ct) and - forex(CS::Type child | child = ct.getAChild() | - child instanceof CS::SimpleType and - not isPrimitiveTypeUsedForBulkData(child) - ) -} - -/** - * Holds for type `t` for fields that are relevant as an intermediate - * read or write step in the data flow analysis. - * That is, flow through any data-flow node that does not have a relevant type - * will be excluded. - */ -predicate isRelevantType(CS::Type t) { - not t instanceof CS::SimpleType and - not t instanceof CS::Enum and - not t instanceof SystemDateTimeStruct and - not t instanceof SystemTypeClass and - not irrelevantCollectionType(t) -} - -/** - * Gets the underlying type of the content `c`. - */ -private CS::Type getUnderlyingContType(DataFlow::Content c) { - result = c.(DataFlow::FieldContent).getField().getType() or - result = c.(DataFlow::SyntheticFieldContent).getField().getType() -} - -/** - * Gets the underlying type of the content `c`. - */ -CS::Type getUnderlyingContentType(DataFlow::ContentSet c) { - exists(DataFlow::Content cont | - c.isSingleton(cont) and - result = getUnderlyingContType(cont) - ) - or - exists(CS::Property p | - c.isProperty(p) and - result = p.getType() - ) -} - -/** - * Gets the MaD string representation of the qualifier. - */ -string qualifierString() { result = "Argument[this]" } - -string parameterAccess(CS::Parameter p) { - if Collections::isCollectionType(p.getType()) - then result = "Argument[" + p.getPosition() + "].Element" - else result = "Argument[" + p.getPosition() + "]" -} - -/** - * Gets the MaD string representation of the parameter `p` - * when used in content flow. - */ -string parameterContentAccess(CS::Parameter p) { result = "Argument[" + p.getPosition() + "]" } - -class InstanceParameterNode = DataFlowPrivate::InstanceParameterNode; - -class ParameterPosition = DataFlowDispatch::ParameterPosition; - -private signature string parameterAccessSig(Parameter p); - -module ParamReturnNodeAsOutput { - bindingset[c] - string paramReturnNodeAsOutput(CS::Callable c, ParameterPosition pos) { - result = getParamAccess(c.getParameter(pos.getPosition())) - or - pos.isThisParameter() and - result = qualifierString() - } -} - -/** - * Gets the MaD string representation of return through parameter at position - * `pos` of callable `c`. - */ -bindingset[c] -string paramReturnNodeAsOutput(CS::Callable c, ParameterPosition pos) { - result = ParamReturnNodeAsOutput::paramReturnNodeAsOutput(c, pos) -} - -bindingset[c] -string paramReturnNodeAsContentOutput(Callable c, ParameterPosition pos) { - result = ParamReturnNodeAsOutput::paramReturnNodeAsOutput(c, pos) -} - -/** - * Gets the enclosing callable of `ret`. - */ -Callable returnNodeEnclosingCallable(DataFlow::Node ret) { - result = DataFlowImplCommon::getNodeEnclosingCallable(ret).asCallable(_) -} - -/** - * Holds if `node` is an own instance access. - */ -predicate isOwnInstanceAccessNode(DataFlowPrivate::ReturnNode node) { - node.asExpr() instanceof CS::ThisAccess -} - -private predicate isRelevantMemberAccess(DataFlow::Node node) { - exists(CS::MemberAccess access | access = node.asExpr() | - access.hasThisQualifier() and - access.getTarget().isEffectivelyPublic() and - ( - access instanceof CS::FieldAccess - or - access.getTarget().(CS::Property).getSetter().isPublic() - ) - ) -} - -predicate sinkModelSanitizer(DataFlow::Node node) { none() } - -/** - * Holds if `source` is an api entrypoint relevant for creating sink models. - */ -predicate apiSource(DataFlow::Node source) { - isRelevantMemberAccess(source) or source instanceof DataFlow::ParameterNode -} - -private predicate uniquelyCalls(DataFlowCallable dc1, DataFlowCallable dc2) { - exists(DataFlowCall call | - dc1 = call.getEnclosingCallable() and - dc2 = unique(DataFlowCallable dc0 | dc0 = viableCallable(call) | dc0) - ) -} - -bindingset[dc1, dc2] -private predicate uniquelyCallsPlus(DataFlowCallable dc1, DataFlowCallable dc2) = - fastTC(uniquelyCalls/2)(dc1, dc2) - -/** - * Holds if it is not relevant to generate a source model for `api`, even - * if flow is detected from a node within `source` to a sink within `api`. - */ -bindingset[sourceEnclosing, api] -predicate irrelevantSourceSinkApi(Callable sourceEnclosing, SourceTargetApi api) { - not exists(DataFlowCallable dc1, DataFlowCallable dc2 | uniquelyCallsPlus(dc1, dc2) or dc1 = dc2 | - dc1.getUnderlyingCallable() = api and - dc2.getUnderlyingCallable() = sourceEnclosing - ) -} - -/** - * Gets the MaD input string representation of `source`. - */ -string asInputArgumentSpecific(DataFlow::Node source) { - exists(int pos | - pos = source.(DataFlow::ParameterNode).getParameter().getPosition() and - result = "Argument[" + pos + "]" - ) - or - source.asExpr() instanceof DataFlowPrivate::FieldOrPropertyAccess and - result = qualifierString() -} - -/** - * Holds if `kind` is a relevant sink kind for creating sink models. - */ -bindingset[kind] -predicate isRelevantSinkKind(string kind) { any() } - -/** - * Holds if `kind` is a relevant source kind for creating source models. - */ -bindingset[kind] -predicate isRelevantSourceKind(string kind) { any() } - -/** - * Holds if the the content `c` is a container. - */ -predicate containerContent(DataFlow::ContentSet c) { c.isElement() } - -/** - * Holds if there is a taint step from `node1` to `node2` in content flow. - */ -predicate isAdditionalContentFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - TaintTrackingPrivate::defaultAdditionalTaintStep(nodeFrom, nodeTo, _) and - not nodeTo.asExpr() instanceof CS::ElementAccess and - not exists(DataFlow::ContentSet c | - DataFlowPrivate::readStep(nodeFrom, c, nodeTo) and containerContent(c) - ) -} - -bindingset[d] -private string getFullyQualifiedName(Declaration d) { - exists(string qualifier, string name | - d.hasFullyQualifiedName(qualifier, name) and - result = QualifiedName::getQualifiedName(qualifier, name) - ) -} - -/** - * Holds if the content set `c` is a field, property or synthetic field. - */ -predicate isField(ContentSet c) { c.isField(_) or c.isSyntheticField(_) or c.isProperty(_) } - -/** - * Gets the MaD synthetic name string representation for the content set `c`, if any. - */ -string getSyntheticName(DataFlow::ContentSet c) { - exists(CS::Field f | - not f.isEffectivelyPublic() and - c.isField(f) and - result = getFullyQualifiedName(f) - ) - or - exists(CS::Property p | - not p.isEffectivelyPublic() and - c.isProperty(p) and - result = getFullyQualifiedName(p) - ) - or - c.isSyntheticField(result) -} - -/** - * Gets the MaD string representation of the content set `c`. - */ -string printContent(DataFlow::ContentSet c) { - exists(CS::Field f, string name | name = getFullyQualifiedName(f) | - c.isField(f) and - f.isEffectivelyPublic() and - result = "Field[" + name + "]" - ) - or - exists(CS::Property p, string name | name = getFullyQualifiedName(p) | - c.isProperty(p) and - p.isEffectivelyPublic() and - result = "Property[" + name + "]" - ) - or - result = "SyntheticField[" + getSyntheticName(c) + "]" - or - c.isElement() and - result = "Element" -} diff --git a/csharp/ql/src/utils/modelgenerator/internal/CaptureSummaryFlowQuery.qll b/csharp/ql/src/utils/modelgenerator/internal/CaptureSummaryFlowQuery.qll deleted file mode 100644 index 8bb706bc484c..000000000000 --- a/csharp/ql/src/utils/modelgenerator/internal/CaptureSummaryFlowQuery.qll +++ /dev/null @@ -1,93 +0,0 @@ -private import CaptureModels - -/** - * Capture fluent APIs that return `this`. - * Example of a fluent API: - * ```csharp - * public class BasicFlow { - * public BasicFlow ReturnThis(object input) - * { - * // some side effect - * return this; - * } - * ``` - * Captured Model: - * ```Summaries;BasicFlow;false;ReturnThis;(System.Object);Argument[this];ReturnValue;value;df-generated``` - * Capture APIs that transfer taint from an input parameter to an output return - * value or parameter. - * Allows a sequence of read steps followed by a sequence of store steps. - * - * Examples: - * - * ```csharp - * public class BasicFlow { - * private string tainted; - * - * public String ReturnField() - * { - * return tainted; - * } - * - * public void AssignFieldToArray(object[] target) - * { - * target[0] = tainted; - * } - * } - * ``` - * Captured Models: - * ``` - * Summaries;BasicFlow;false;ReturnField;();Argument[this];ReturnValue;taint;df-generated | - * Summaries;BasicFlow;false;AssignFieldToArray;(System.Object[]);Argument[this];Argument[0].Element;taint;df-generated - * ``` - * - * ```csharp - * public class BasicFlow { - * private string tainted; - * - * public void SetField(string s) - * { - * tainted = s; - * } - * } - * ``` - * Captured Model: - * ```Summaries;BasicFlow;false;SetField;(System.String);Argument[0];Argument[this];taint;df-generated``` - * - * ```csharp - * public class BasicFlow { - * public void ReturnSubstring(string s) - * { - * return s.Substring(0, 1); - * } - * } - * ``` - * Captured Model: - * ```Summaries;BasicFlow;false;ReturnSubstring;(System.String);Argument[0];ReturnValue;taint;df-generated``` - * - * ```csharp - * public class BasicFlow { - * public void AssignToArray(int data, int[] target) - * { - * target[0] = data; - * } - * } - * ``` - * Captured Model: - * ```Summaries;BasicFlow;false;AssignToArray;(System.Int32,System.Int32[]);Argument[0];Argument[1].Element;taint;df-generated``` - */ -string captureFlow(DataFlowSummaryTargetApi api) { - result = captureQualifierFlow(api) or - result = captureThroughFlow(api) -} - -/** - * Gets the neutral summary model for `api`, if any. - * A neutral summary model is generated, if we are not generating - * a summary model that applies to `api` and if it relevant to generate - * a model for `api`. - */ -string captureNoFlow(DataFlowSummaryTargetApi api) { - not exists(DataFlowSummaryTargetApi api0 | exists(captureFlow(api0)) and api0.lift() = api.lift()) and - api.isRelevant() and - result = Printing::asNeutralSummaryModel(api) -} diff --git a/csharp/ql/src/utils/modelgenerator/internal/CaptureTypeBasedSummaryModels.qll b/csharp/ql/src/utils/modelgenerator/internal/CaptureTypeBasedSummaryModels.qll index 1a0a3d2ca420..f7b0633ddd39 100644 --- a/csharp/ql/src/utils/modelgenerator/internal/CaptureTypeBasedSummaryModels.qll +++ b/csharp/ql/src/utils/modelgenerator/internal/CaptureTypeBasedSummaryModels.qll @@ -2,7 +2,7 @@ private import csharp private import semmle.code.csharp.frameworks.system.collections.Generic as GenericCollections private import semmle.code.csharp.dataflow.internal.DataFlowPrivate private import semmle.code.csharp.frameworks.system.linq.Expressions -private import CaptureModelsSpecific as Specific +private import CaptureModels::ModelGeneratorInput as ModelGeneratorInput private import CaptureModelsPrinting /** @@ -38,7 +38,7 @@ private predicate localTypeParameter(Callable callable, TypeParameter tp) { */ private predicate parameter(Callable callable, string input, TypeParameter tp) { exists(Parameter p | - input = Specific::parameterAccess(p) and + input = ModelGeneratorInput::parameterAccess(p) and p = callable.getAParameter() and ( // Parameter of type tp @@ -69,7 +69,7 @@ private string implicit(Callable callable, TypeParameter tp) { then access = ".Element" else access = getSyntheticField(tp) | - result = Specific::qualifierString() + access + result = ModelGeneratorInput::qualifierString() + access ) } @@ -191,9 +191,7 @@ private module Printing = ModelPrinting; * A class of callables that are relevant generating summaries for based * on the Theorems for Free approach. */ -class TypeBasedFlowTargetApi extends Specific::SummaryTargetApi { - TypeBasedFlowTargetApi() { not Specific::isUninterestingForTypeBasedFlowModels(this) } - +class TypeBasedFlowTargetApi extends ModelGeneratorInput::SummaryTargetApi { /** * Gets the string representation of all type based summaries for `this` * inspired by the Theorems for Free approach. diff --git a/csharp/ql/test/query-tests/Security Features/CWE-079/XSSAsp/AspInline.expected b/csharp/ql/test/query-tests/Security Features/CWE-079/XSSAsp/AspInline.expected index 66468b41a683..08f9aded5531 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-079/XSSAsp/AspInline.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-079/XSSAsp/AspInline.expected @@ -1,5 +1,5 @@ -| script.aspx:4:1:4:23 | <%= ... %> | XSS.cs:115:16:115:29 | someJavascript | -| script.aspx:8:1:8:12 | <%= ... %> | XSS.cs:122:24:122:28 | Field | +| script.aspx:4:1:4:23 | <%= ... %> | XSS.cs:120:16:120:29 | someJavascript | +| script.aspx:8:1:8:12 | <%= ... %> | XSS.cs:127:24:127:28 | Field | | script.aspx:12:1:12:14 | <%= ... %> | | Request | | script.aspx:16:1:16:34 | <%= ... %> | | QueryString | | script.aspx:20:1:20:41 | <%= ... %> | | QueryString | diff --git a/csharp/ql/test/query-tests/Security Features/CWE-079/XSSAsp/XSS.cs b/csharp/ql/test/query-tests/Security Features/CWE-079/XSSAsp/XSS.cs index 1fc8a99e61b6..eba40b891d58 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-079/XSSAsp/XSS.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-079/XSSAsp/XSS.cs @@ -17,6 +17,7 @@ class XSS Table table; Label label; string connectionString; + public Button button; public void WebUIXSS() { @@ -100,6 +101,10 @@ public void HtmlEncoded(HttpContextBase context) // GOOD: HTML encoding string name = context.Request.QueryString["name"]; new StringContent(HttpUtility.HtmlEncode(name)); + + // GOOD: Implicit HTML encoding + string html = context.Request.QueryString["html"]; + button.Attributes.Add("data-href", html); } public void UrlEncoded(HttpContextBase context) diff --git a/csharp/ql/test/query-tests/Security Features/CWE-079/XSSAsp/XSS.expected b/csharp/ql/test/query-tests/Security Features/CWE-079/XSSAsp/XSS.expected index cf0479cf253f..c158c599b548 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-079/XSSAsp/XSS.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-079/XSSAsp/XSS.expected @@ -1,50 +1,50 @@ #select -| XSS.cs:26:32:26:51 | call to method ToString | XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:26:32:26:51 | call to method ToString | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | User-provided value | -| XSS.cs:27:29:27:48 | call to method ToString | XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:27:29:27:48 | call to method ToString | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | User-provided value | -| XSS.cs:28:26:28:45 | call to method ToString | XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:28:26:28:45 | call to method ToString | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | User-provided value | -| XSS.cs:38:36:38:39 | access to local variable name | XSS.cs:37:27:37:53 | access to property QueryString : NameValueCollection | XSS.cs:38:36:38:39 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:37:27:37:53 | access to property QueryString : NameValueCollection | User-provided value | -| XSS.cs:59:22:59:25 | access to local variable name | XSS.cs:57:27:57:65 | access to property QueryString : NameValueCollection | XSS.cs:59:22:59:25 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:57:27:57:65 | access to property QueryString : NameValueCollection | User-provided value | -| XSS.cs:76:36:76:39 | access to local variable name | XSS.cs:75:27:75:53 | access to property QueryString : NameValueCollection | XSS.cs:76:36:76:39 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:75:27:75:53 | access to property QueryString : NameValueCollection | User-provided value | -| XSS.cs:79:36:79:40 | access to local variable name2 | XSS.cs:78:28:78:42 | access to property Request : HttpRequestBase | XSS.cs:79:36:79:40 | access to local variable name2 | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:78:28:78:42 | access to property Request : HttpRequestBase | User-provided value | -| XSS.cs:86:28:86:31 | access to local variable name | XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | XSS.cs:86:28:86:31 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | User-provided value | -| XSS.cs:87:31:87:34 | access to local variable name | XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | XSS.cs:87:31:87:34 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | User-provided value | -| XSS.cs:95:31:95:34 | access to local variable name | XSS.cs:94:27:94:53 | access to property QueryString : NameValueCollection | XSS.cs:95:31:95:34 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:94:27:94:53 | access to property QueryString : NameValueCollection | User-provided value | -| XSS.cs:135:20:135:33 | access to property RawUrl | XSS.cs:135:20:135:33 | access to property RawUrl | XSS.cs:135:20:135:33 | access to property RawUrl | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:135:20:135:33 | access to property RawUrl | User-provided value | +| XSS.cs:27:32:27:51 | call to method ToString | XSS.cs:26:48:26:62 | access to field categoryTextBox : TextBox | XSS.cs:27:32:27:51 | call to method ToString | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:26:48:26:62 | access to field categoryTextBox : TextBox | User-provided value | +| XSS.cs:28:29:28:48 | call to method ToString | XSS.cs:26:48:26:62 | access to field categoryTextBox : TextBox | XSS.cs:28:29:28:48 | call to method ToString | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:26:48:26:62 | access to field categoryTextBox : TextBox | User-provided value | +| XSS.cs:29:26:29:45 | call to method ToString | XSS.cs:26:48:26:62 | access to field categoryTextBox : TextBox | XSS.cs:29:26:29:45 | call to method ToString | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:26:48:26:62 | access to field categoryTextBox : TextBox | User-provided value | +| XSS.cs:39:36:39:39 | access to local variable name | XSS.cs:38:27:38:53 | access to property QueryString : NameValueCollection | XSS.cs:39:36:39:39 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:38:27:38:53 | access to property QueryString : NameValueCollection | User-provided value | +| XSS.cs:60:22:60:25 | access to local variable name | XSS.cs:58:27:58:65 | access to property QueryString : NameValueCollection | XSS.cs:60:22:60:25 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:58:27:58:65 | access to property QueryString : NameValueCollection | User-provided value | +| XSS.cs:77:36:77:39 | access to local variable name | XSS.cs:76:27:76:53 | access to property QueryString : NameValueCollection | XSS.cs:77:36:77:39 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:76:27:76:53 | access to property QueryString : NameValueCollection | User-provided value | +| XSS.cs:80:36:80:40 | access to local variable name2 | XSS.cs:79:28:79:42 | access to property Request : HttpRequestBase | XSS.cs:80:36:80:40 | access to local variable name2 | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:79:28:79:42 | access to property Request : HttpRequestBase | User-provided value | +| XSS.cs:87:28:87:31 | access to local variable name | XSS.cs:86:27:86:53 | access to property QueryString : NameValueCollection | XSS.cs:87:28:87:31 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:86:27:86:53 | access to property QueryString : NameValueCollection | User-provided value | +| XSS.cs:88:31:88:34 | access to local variable name | XSS.cs:86:27:86:53 | access to property QueryString : NameValueCollection | XSS.cs:88:31:88:34 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:86:27:86:53 | access to property QueryString : NameValueCollection | User-provided value | +| XSS.cs:96:31:96:34 | access to local variable name | XSS.cs:95:27:95:53 | access to property QueryString : NameValueCollection | XSS.cs:96:31:96:34 | access to local variable name | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:95:27:95:53 | access to property QueryString : NameValueCollection | User-provided value | +| XSS.cs:140:20:140:33 | access to property RawUrl | XSS.cs:140:20:140:33 | access to property RawUrl | XSS.cs:140:20:140:33 | access to property RawUrl | $@ flows to here and is written to HTML or JavaScript. | XSS.cs:140:20:140:33 | access to property RawUrl | User-provided value | | script.aspx:12:1:12:14 | <%= ... %> | script.aspx:12:1:12:14 | <%= ... %> | script.aspx:12:1:12:14 | <%= ... %> | $@ flows to here and is a remote source accessed inline in an ASPX page. | script.aspx:12:1:12:14 | <%= ... %> | User-provided value | | script.aspx:16:1:16:34 | <%= ... %> | script.aspx:16:1:16:34 | <%= ... %> | script.aspx:16:1:16:34 | <%= ... %> | $@ flows to here and is a remote source accessed inline in an ASPX page. | script.aspx:16:1:16:34 | <%= ... %> | User-provided value | | script.aspx:20:1:20:41 | <%= ... %> | script.aspx:20:1:20:41 | <%= ... %> | script.aspx:20:1:20:41 | <%= ... %> | $@ flows to here and is a remote source accessed inline in an ASPX page. | script.aspx:20:1:20:41 | <%= ... %> | User-provided value | edges -| XSS.cs:25:13:25:21 | [post] access to local variable userInput : StringBuilder | XSS.cs:26:32:26:40 | access to local variable userInput : StringBuilder | provenance | | -| XSS.cs:25:13:25:21 | [post] access to local variable userInput : StringBuilder | XSS.cs:27:29:27:37 | access to local variable userInput : StringBuilder | provenance | | -| XSS.cs:25:13:25:21 | [post] access to local variable userInput : StringBuilder | XSS.cs:28:26:28:34 | access to local variable userInput : StringBuilder | provenance | | -| XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | XSS.cs:25:48:25:67 | access to property Text : String | provenance | MaD:4 | -| XSS.cs:25:48:25:67 | access to property Text : String | XSS.cs:25:13:25:21 | [post] access to local variable userInput : StringBuilder | provenance | MaD:2 | -| XSS.cs:26:32:26:40 | access to local variable userInput : StringBuilder | XSS.cs:26:32:26:51 | call to method ToString | provenance | MaD:3 | -| XSS.cs:27:29:27:37 | access to local variable userInput : StringBuilder | XSS.cs:27:29:27:48 | call to method ToString | provenance | MaD:3 | -| XSS.cs:28:26:28:34 | access to local variable userInput : StringBuilder | XSS.cs:28:26:28:45 | call to method ToString | provenance | MaD:3 | -| XSS.cs:37:20:37:23 | access to local variable name : String | XSS.cs:38:36:38:39 | access to local variable name | provenance | Sink:MaD:5 | -| XSS.cs:37:27:37:53 | access to property QueryString : NameValueCollection | XSS.cs:37:20:37:23 | access to local variable name : String | provenance | | -| XSS.cs:37:27:37:53 | access to property QueryString : NameValueCollection | XSS.cs:37:27:37:61 | access to indexer : String | provenance | MaD:6 | -| XSS.cs:37:27:37:61 | access to indexer : String | XSS.cs:37:20:37:23 | access to local variable name : String | provenance | | -| XSS.cs:57:20:57:23 | access to local variable name : String | XSS.cs:59:22:59:25 | access to local variable name | provenance | | -| XSS.cs:57:27:57:65 | access to property QueryString : NameValueCollection | XSS.cs:57:20:57:23 | access to local variable name : String | provenance | | -| XSS.cs:57:27:57:65 | access to property QueryString : NameValueCollection | XSS.cs:57:27:57:73 | access to indexer : String | provenance | MaD:6 | -| XSS.cs:57:27:57:73 | access to indexer : String | XSS.cs:57:20:57:23 | access to local variable name : String | provenance | | -| XSS.cs:75:20:75:23 | access to local variable name : String | XSS.cs:76:36:76:39 | access to local variable name | provenance | | -| XSS.cs:75:27:75:53 | access to property QueryString : NameValueCollection | XSS.cs:75:20:75:23 | access to local variable name : String | provenance | | -| XSS.cs:75:27:75:53 | access to property QueryString : NameValueCollection | XSS.cs:75:27:75:61 | access to indexer : String | provenance | MaD:6 | -| XSS.cs:75:27:75:61 | access to indexer : String | XSS.cs:75:20:75:23 | access to local variable name : String | provenance | | -| XSS.cs:78:20:78:24 | access to local variable name2 : String | XSS.cs:79:36:79:40 | access to local variable name2 | provenance | | -| XSS.cs:78:28:78:42 | access to property Request : HttpRequestBase | XSS.cs:78:20:78:24 | access to local variable name2 : String | provenance | | -| XSS.cs:85:20:85:23 | access to local variable name : String | XSS.cs:86:28:86:31 | access to local variable name | provenance | | -| XSS.cs:85:20:85:23 | access to local variable name : String | XSS.cs:87:31:87:34 | access to local variable name | provenance | | -| XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | XSS.cs:85:20:85:23 | access to local variable name : String | provenance | | -| XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | XSS.cs:85:27:85:61 | access to indexer : String | provenance | MaD:6 | -| XSS.cs:85:27:85:61 | access to indexer : String | XSS.cs:85:20:85:23 | access to local variable name : String | provenance | | -| XSS.cs:94:20:94:23 | access to local variable name : String | XSS.cs:95:31:95:34 | access to local variable name | provenance | Sink:MaD:1 | -| XSS.cs:94:27:94:53 | access to property QueryString : NameValueCollection | XSS.cs:94:20:94:23 | access to local variable name : String | provenance | | -| XSS.cs:94:27:94:53 | access to property QueryString : NameValueCollection | XSS.cs:94:27:94:61 | access to indexer : String | provenance | MaD:6 | -| XSS.cs:94:27:94:61 | access to indexer : String | XSS.cs:94:20:94:23 | access to local variable name : String | provenance | | +| XSS.cs:26:13:26:21 | [post] access to local variable userInput : StringBuilder | XSS.cs:27:32:27:40 | access to local variable userInput : StringBuilder | provenance | | +| XSS.cs:26:13:26:21 | [post] access to local variable userInput : StringBuilder | XSS.cs:28:29:28:37 | access to local variable userInput : StringBuilder | provenance | | +| XSS.cs:26:13:26:21 | [post] access to local variable userInput : StringBuilder | XSS.cs:29:26:29:34 | access to local variable userInput : StringBuilder | provenance | | +| XSS.cs:26:48:26:62 | access to field categoryTextBox : TextBox | XSS.cs:26:48:26:67 | access to property Text : String | provenance | MaD:4 | +| XSS.cs:26:48:26:67 | access to property Text : String | XSS.cs:26:13:26:21 | [post] access to local variable userInput : StringBuilder | provenance | MaD:2 | +| XSS.cs:27:32:27:40 | access to local variable userInput : StringBuilder | XSS.cs:27:32:27:51 | call to method ToString | provenance | MaD:3 | +| XSS.cs:28:29:28:37 | access to local variable userInput : StringBuilder | XSS.cs:28:29:28:48 | call to method ToString | provenance | MaD:3 | +| XSS.cs:29:26:29:34 | access to local variable userInput : StringBuilder | XSS.cs:29:26:29:45 | call to method ToString | provenance | MaD:3 | +| XSS.cs:38:20:38:23 | access to local variable name : String | XSS.cs:39:36:39:39 | access to local variable name | provenance | Sink:MaD:5 | +| XSS.cs:38:27:38:53 | access to property QueryString : NameValueCollection | XSS.cs:38:20:38:23 | access to local variable name : String | provenance | | +| XSS.cs:38:27:38:53 | access to property QueryString : NameValueCollection | XSS.cs:38:27:38:61 | access to indexer : String | provenance | MaD:6 | +| XSS.cs:38:27:38:61 | access to indexer : String | XSS.cs:38:20:38:23 | access to local variable name : String | provenance | | +| XSS.cs:58:20:58:23 | access to local variable name : String | XSS.cs:60:22:60:25 | access to local variable name | provenance | | +| XSS.cs:58:27:58:65 | access to property QueryString : NameValueCollection | XSS.cs:58:20:58:23 | access to local variable name : String | provenance | | +| XSS.cs:58:27:58:65 | access to property QueryString : NameValueCollection | XSS.cs:58:27:58:73 | access to indexer : String | provenance | MaD:6 | +| XSS.cs:58:27:58:73 | access to indexer : String | XSS.cs:58:20:58:23 | access to local variable name : String | provenance | | +| XSS.cs:76:20:76:23 | access to local variable name : String | XSS.cs:77:36:77:39 | access to local variable name | provenance | | +| XSS.cs:76:27:76:53 | access to property QueryString : NameValueCollection | XSS.cs:76:20:76:23 | access to local variable name : String | provenance | | +| XSS.cs:76:27:76:53 | access to property QueryString : NameValueCollection | XSS.cs:76:27:76:61 | access to indexer : String | provenance | MaD:6 | +| XSS.cs:76:27:76:61 | access to indexer : String | XSS.cs:76:20:76:23 | access to local variable name : String | provenance | | +| XSS.cs:79:20:79:24 | access to local variable name2 : String | XSS.cs:80:36:80:40 | access to local variable name2 | provenance | | +| XSS.cs:79:28:79:42 | access to property Request : HttpRequestBase | XSS.cs:79:20:79:24 | access to local variable name2 : String | provenance | | +| XSS.cs:86:20:86:23 | access to local variable name : String | XSS.cs:87:28:87:31 | access to local variable name | provenance | | +| XSS.cs:86:20:86:23 | access to local variable name : String | XSS.cs:88:31:88:34 | access to local variable name | provenance | | +| XSS.cs:86:27:86:53 | access to property QueryString : NameValueCollection | XSS.cs:86:20:86:23 | access to local variable name : String | provenance | | +| XSS.cs:86:27:86:53 | access to property QueryString : NameValueCollection | XSS.cs:86:27:86:61 | access to indexer : String | provenance | MaD:6 | +| XSS.cs:86:27:86:61 | access to indexer : String | XSS.cs:86:20:86:23 | access to local variable name : String | provenance | | +| XSS.cs:95:20:95:23 | access to local variable name : String | XSS.cs:96:31:96:34 | access to local variable name | provenance | Sink:MaD:1 | +| XSS.cs:95:27:95:53 | access to property QueryString : NameValueCollection | XSS.cs:95:20:95:23 | access to local variable name : String | provenance | | +| XSS.cs:95:27:95:53 | access to property QueryString : NameValueCollection | XSS.cs:95:27:95:61 | access to indexer : String | provenance | MaD:6 | +| XSS.cs:95:27:95:61 | access to indexer : String | XSS.cs:95:20:95:23 | access to local variable name : String | provenance | | | script.aspx:12:1:12:14 | <%= ... %> | script.aspx:12:1:12:14 | <%= ... %> | provenance | | | script.aspx:16:1:16:34 | <%= ... %> | script.aspx:16:1:16:34 | <%= ... %> | provenance | | | script.aspx:20:1:20:41 | <%= ... %> | script.aspx:20:1:20:41 | <%= ... %> | provenance | | @@ -56,40 +56,40 @@ models | 5 | Sink: System.Web; HttpResponse; false; Write; ; ; Argument[0]; html-injection; manual | | 6 | Summary: System.Collections.Specialized; NameValueCollection; false; get_Item; (System.String); ; Argument[this]; ReturnValue; taint; df-generated | nodes -| XSS.cs:25:13:25:21 | [post] access to local variable userInput : StringBuilder | semmle.label | [post] access to local variable userInput : StringBuilder | -| XSS.cs:25:48:25:62 | access to field categoryTextBox : TextBox | semmle.label | access to field categoryTextBox : TextBox | -| XSS.cs:25:48:25:67 | access to property Text : String | semmle.label | access to property Text : String | -| XSS.cs:26:32:26:40 | access to local variable userInput : StringBuilder | semmle.label | access to local variable userInput : StringBuilder | -| XSS.cs:26:32:26:51 | call to method ToString | semmle.label | call to method ToString | -| XSS.cs:27:29:27:37 | access to local variable userInput : StringBuilder | semmle.label | access to local variable userInput : StringBuilder | -| XSS.cs:27:29:27:48 | call to method ToString | semmle.label | call to method ToString | -| XSS.cs:28:26:28:34 | access to local variable userInput : StringBuilder | semmle.label | access to local variable userInput : StringBuilder | -| XSS.cs:28:26:28:45 | call to method ToString | semmle.label | call to method ToString | -| XSS.cs:37:20:37:23 | access to local variable name : String | semmle.label | access to local variable name : String | -| XSS.cs:37:27:37:53 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection | -| XSS.cs:37:27:37:61 | access to indexer : String | semmle.label | access to indexer : String | -| XSS.cs:38:36:38:39 | access to local variable name | semmle.label | access to local variable name | -| XSS.cs:57:20:57:23 | access to local variable name : String | semmle.label | access to local variable name : String | -| XSS.cs:57:27:57:65 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection | -| XSS.cs:57:27:57:73 | access to indexer : String | semmle.label | access to indexer : String | -| XSS.cs:59:22:59:25 | access to local variable name | semmle.label | access to local variable name | -| XSS.cs:75:20:75:23 | access to local variable name : String | semmle.label | access to local variable name : String | -| XSS.cs:75:27:75:53 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection | -| XSS.cs:75:27:75:61 | access to indexer : String | semmle.label | access to indexer : String | -| XSS.cs:76:36:76:39 | access to local variable name | semmle.label | access to local variable name | -| XSS.cs:78:20:78:24 | access to local variable name2 : String | semmle.label | access to local variable name2 : String | -| XSS.cs:78:28:78:42 | access to property Request : HttpRequestBase | semmle.label | access to property Request : HttpRequestBase | -| XSS.cs:79:36:79:40 | access to local variable name2 | semmle.label | access to local variable name2 | -| XSS.cs:85:20:85:23 | access to local variable name : String | semmle.label | access to local variable name : String | -| XSS.cs:85:27:85:53 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection | -| XSS.cs:85:27:85:61 | access to indexer : String | semmle.label | access to indexer : String | -| XSS.cs:86:28:86:31 | access to local variable name | semmle.label | access to local variable name | -| XSS.cs:87:31:87:34 | access to local variable name | semmle.label | access to local variable name | -| XSS.cs:94:20:94:23 | access to local variable name : String | semmle.label | access to local variable name : String | -| XSS.cs:94:27:94:53 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection | -| XSS.cs:94:27:94:61 | access to indexer : String | semmle.label | access to indexer : String | -| XSS.cs:95:31:95:34 | access to local variable name | semmle.label | access to local variable name | -| XSS.cs:135:20:135:33 | access to property RawUrl | semmle.label | access to property RawUrl | +| XSS.cs:26:13:26:21 | [post] access to local variable userInput : StringBuilder | semmle.label | [post] access to local variable userInput : StringBuilder | +| XSS.cs:26:48:26:62 | access to field categoryTextBox : TextBox | semmle.label | access to field categoryTextBox : TextBox | +| XSS.cs:26:48:26:67 | access to property Text : String | semmle.label | access to property Text : String | +| XSS.cs:27:32:27:40 | access to local variable userInput : StringBuilder | semmle.label | access to local variable userInput : StringBuilder | +| XSS.cs:27:32:27:51 | call to method ToString | semmle.label | call to method ToString | +| XSS.cs:28:29:28:37 | access to local variable userInput : StringBuilder | semmle.label | access to local variable userInput : StringBuilder | +| XSS.cs:28:29:28:48 | call to method ToString | semmle.label | call to method ToString | +| XSS.cs:29:26:29:34 | access to local variable userInput : StringBuilder | semmle.label | access to local variable userInput : StringBuilder | +| XSS.cs:29:26:29:45 | call to method ToString | semmle.label | call to method ToString | +| XSS.cs:38:20:38:23 | access to local variable name : String | semmle.label | access to local variable name : String | +| XSS.cs:38:27:38:53 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection | +| XSS.cs:38:27:38:61 | access to indexer : String | semmle.label | access to indexer : String | +| XSS.cs:39:36:39:39 | access to local variable name | semmle.label | access to local variable name | +| XSS.cs:58:20:58:23 | access to local variable name : String | semmle.label | access to local variable name : String | +| XSS.cs:58:27:58:65 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection | +| XSS.cs:58:27:58:73 | access to indexer : String | semmle.label | access to indexer : String | +| XSS.cs:60:22:60:25 | access to local variable name | semmle.label | access to local variable name | +| XSS.cs:76:20:76:23 | access to local variable name : String | semmle.label | access to local variable name : String | +| XSS.cs:76:27:76:53 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection | +| XSS.cs:76:27:76:61 | access to indexer : String | semmle.label | access to indexer : String | +| XSS.cs:77:36:77:39 | access to local variable name | semmle.label | access to local variable name | +| XSS.cs:79:20:79:24 | access to local variable name2 : String | semmle.label | access to local variable name2 : String | +| XSS.cs:79:28:79:42 | access to property Request : HttpRequestBase | semmle.label | access to property Request : HttpRequestBase | +| XSS.cs:80:36:80:40 | access to local variable name2 | semmle.label | access to local variable name2 | +| XSS.cs:86:20:86:23 | access to local variable name : String | semmle.label | access to local variable name : String | +| XSS.cs:86:27:86:53 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection | +| XSS.cs:86:27:86:61 | access to indexer : String | semmle.label | access to indexer : String | +| XSS.cs:87:28:87:31 | access to local variable name | semmle.label | access to local variable name | +| XSS.cs:88:31:88:34 | access to local variable name | semmle.label | access to local variable name | +| XSS.cs:95:20:95:23 | access to local variable name : String | semmle.label | access to local variable name : String | +| XSS.cs:95:27:95:53 | access to property QueryString : NameValueCollection | semmle.label | access to property QueryString : NameValueCollection | +| XSS.cs:95:27:95:61 | access to indexer : String | semmle.label | access to indexer : String | +| XSS.cs:96:31:96:34 | access to local variable name | semmle.label | access to local variable name | +| XSS.cs:140:20:140:33 | access to property RawUrl | semmle.label | access to property RawUrl | | script.aspx:12:1:12:14 | <%= ... %> | semmle.label | <%= ... %> | | script.aspx:16:1:16:34 | <%= ... %> | semmle.label | <%= ... %> | | script.aspx:20:1:20:41 | <%= ... %> | semmle.label | <%= ... %> | diff --git a/csharp/ql/test/utils/modelgenerator/dataflow/CaptureContentSummaryModels.ql b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureContentSummaryModels.ql index f5d8593a32ac..b2777d4bc346 100644 --- a/csharp/ql/test/utils/modelgenerator/dataflow/CaptureContentSummaryModels.ql +++ b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureContentSummaryModels.ql @@ -3,7 +3,7 @@ import utils.modelgenerator.internal.CaptureModels import TestUtilities.InlineMadTest module InlineMadTestConfig implements InlineMadTestConfigSig { - string getCapturedModel(Callable c) { result = captureContentFlow(c) } + string getCapturedModel(Callable c) { result = ContentSensitive::captureFlow(c) } string getKind() { result = "contentbased-summary" } } diff --git a/csharp/ql/test/utils/modelgenerator/dataflow/CaptureNeutralModels.ql b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureNeutralModels.ql index c9fd2c2655db..922588049d26 100644 --- a/csharp/ql/test/utils/modelgenerator/dataflow/CaptureNeutralModels.ql +++ b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureNeutralModels.ql @@ -1,5 +1,5 @@ import csharp -import utils.modelgenerator.internal.CaptureSummaryFlowQuery +import utils.modelgenerator.internal.CaptureModels import TestUtilities.InlineMadTest module InlineMadTestConfig implements InlineMadTestConfigSig { diff --git a/csharp/ql/test/utils/modelgenerator/dataflow/CaptureSummaryModels.ql b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureSummaryModels.ql index 5e4a67bcf0cb..29cb8f7fb874 100644 --- a/csharp/ql/test/utils/modelgenerator/dataflow/CaptureSummaryModels.ql +++ b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureSummaryModels.ql @@ -1,5 +1,5 @@ import csharp -import utils.modelgenerator.internal.CaptureSummaryFlowQuery +import utils.modelgenerator.internal.CaptureModels import TestUtilities.InlineMadTest module InlineMadTestConfig implements InlineMadTestConfigSig { diff --git a/docs/codeql/_templates/layout.html b/docs/codeql/_templates/layout.html index 779c99cfe9f5..5b234423b673 100644 --- a/docs/codeql/_templates/layout.html +++ b/docs/codeql/_templates/layout.html @@ -60,22 +60,22 @@ diff --git a/docs/codeql/index.html b/docs/codeql/index.html index d1e91bc89e32..de47832a997c 100644 --- a/docs/codeql/index.html +++ b/docs/codeql/index.html @@ -88,7 +88,7 @@

latest release of CodeQL...
- +
Change logs
Read about the improvements to the queries, libraries, and tooling in each release...
diff --git a/docs/codeql/reusables/supported-versions-compilers.rst b/docs/codeql/reusables/supported-versions-compilers.rst index 4b941c7d17fc..d9869c35100b 100644 --- a/docs/codeql/reusables/supported-versions-compilers.rst +++ b/docs/codeql/reusables/supported-versions-compilers.rst @@ -20,7 +20,7 @@ Java,"Java 7 to 22 [5]_","javac (OpenJDK and Oracle JDK), Eclipse compiler for Java (ECJ) [6]_",``.java`` - Kotlin,"Kotlin 1.5.0 to 2.0.2\ *x*","kotlinc",``.kt`` + Kotlin,"Kotlin 1.5.0 to 2.1.0\ *x*","kotlinc",``.kt`` JavaScript,ECMAScript 2022 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [7]_" Python [8]_,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12",Not applicable,``.py`` Ruby [9]_,"up to 3.3",Not applicable,"``.rb``, ``.erb``, ``.gemspec``, ``Gemfile``" diff --git a/go/codeql-extractor.yml b/go/codeql-extractor.yml index 20cfe987ef32..f21c0ed7466d 100644 --- a/go/codeql-extractor.yml +++ b/go/codeql-extractor.yml @@ -19,3 +19,11 @@ file_types: extensions: - .go legacy_qltest_extraction: true +options: + extract_tests: + title: Whether to include Go test files in the CodeQL database. + description: > + A value indicating whether Go test files should be included in the CodeQL database. + The default is 'false'. + type: string + pattern: "^(false|true)$" diff --git a/go/extractor/cli/go-extractor/go-extractor.go b/go/extractor/cli/go-extractor/go-extractor.go index 00d3c8e7de13..425af6cd55d8 100644 --- a/go/extractor/cli/go-extractor/go-extractor.go +++ b/go/extractor/cli/go-extractor/go-extractor.go @@ -21,7 +21,9 @@ func usage() { fmt.Fprintf(os.Stderr, "--help Print this help.\n") } -func parseFlags(args []string, mimic bool) ([]string, []string) { +// extractTests is set (a) if we were manually commanded to extract tests via the relevant +// environment variable / extractor option, or (b) we're mimicking a `go test` command. +func parseFlags(args []string, mimic bool, extractTests bool) ([]string, []string, bool) { i := 0 buildFlags := []string{} for ; i < len(args) && strings.HasPrefix(args[i], "-"); i++ { @@ -44,9 +46,9 @@ func parseFlags(args []string, mimic bool) ([]string, []string) { if i+1 < len(args) { i++ command := args[i] - if command == "build" || command == "install" || command == "run" { - log.Printf("Intercepting build") - return parseFlags(args[i+1:], true) + if command == "build" || command == "install" || command == "run" || command == "test" { + log.Printf("Intercepting build for %s command", command) + return parseFlags(args[i+1:], true, command == "test") } else { log.Printf("Non-build command '%s'; skipping", strings.Join(args[1:], " ")) os.Exit(0) @@ -63,12 +65,12 @@ func parseFlags(args []string, mimic bool) ([]string, []string) { // parse go build flags switch args[i] { - // skip `-o output` and `-i`, if applicable + // skip `-o output`, `-i` and `-c`, if applicable case "-o": if i+1 < len(args) { i++ } - case "-i": + case "-i", "-c": case "-p", "-asmflags", "-buildmode", "-compiler", "-gccgoflags", "-gcflags", "-installsuffix", "-ldflags", "-mod", "-modfile", "-pkgdir", "-tags", "-toolexec", "-overlay": if i+1 < len(args) { @@ -90,11 +92,12 @@ func parseFlags(args []string, mimic bool) ([]string, []string) { cpuprofile = os.Getenv("CODEQL_EXTRACTOR_GO_CPU_PROFILE") memprofile = os.Getenv("CODEQL_EXTRACTOR_GO_MEM_PROFILE") - return buildFlags, args[i:] + return buildFlags, args[i:], extractTests } func main() { - buildFlags, patterns := parseFlags(os.Args[1:], false) + extractTestsDefault := os.Getenv("CODEQL_EXTRACTOR_GO_OPTION_EXTRACT_TESTS") == "true" + buildFlags, patterns, extractTests := parseFlags(os.Args[1:], false, extractTestsDefault) if cpuprofile != "" { f, err := os.Create(cpuprofile) @@ -114,7 +117,7 @@ func main() { } log.Printf("Build flags: '%s'; patterns: '%s'\n", strings.Join(buildFlags, " "), strings.Join(patterns, " ")) - err := extractor.ExtractWithFlags(buildFlags, patterns) + err := extractor.ExtractWithFlags(buildFlags, patterns, extractTests) if err != nil { errString := err.Error() if strings.Contains(errString, "unexpected directory layout:") { diff --git a/go/extractor/extractor.go b/go/extractor/extractor.go index 31fa2ceb4131..81e7e99dee54 100644 --- a/go/extractor/extractor.go +++ b/go/extractor/extractor.go @@ -59,11 +59,11 @@ func init() { // Extract extracts the packages specified by the given patterns func Extract(patterns []string) error { - return ExtractWithFlags(nil, patterns) + return ExtractWithFlags(nil, patterns, false) } // ExtractWithFlags extracts the packages specified by the given patterns and build flags -func ExtractWithFlags(buildFlags []string, patterns []string) error { +func ExtractWithFlags(buildFlags []string, patterns []string, extractTests bool) error { startTime := time.Now() extraction := NewExtraction(buildFlags, patterns) @@ -81,7 +81,14 @@ func ExtractWithFlags(buildFlags []string, patterns []string) error { } } - log.Println("Running packages.Load.") + testMessage := "" + if extractTests { + testMessage = " (test extraction enabled)" + } + log.Printf("Running packages.Load%s.", testMessage) + + // This includes test packages if either we're tracing a `go test` command, + // or if CODEQL_EXTRACTOR_GO_OPTION_EXTRACT_TESTS is set to "true". cfg := &packages.Config{ Mode: packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | @@ -89,6 +96,7 @@ func ExtractWithFlags(buildFlags []string, patterns []string) error { packages.NeedTypes | packages.NeedTypesSizes | packages.NeedTypesInfo | packages.NeedSyntax, BuildFlags: buildFlags, + Tests: extractTests, } pkgs, err := packages.Load(cfg, patterns...) if err != nil { @@ -123,7 +131,7 @@ func ExtractWithFlags(buildFlags []string, patterns []string) error { if os.Getenv("CODEQL_EXTRACTOR_GO_FAST_PACKAGE_INFO") != "false" { log.Printf("Running go list to resolve package and module directories.") // get all packages information - pkgInfos, err = toolchain.GetPkgsInfo(patterns, true, modFlags...) + pkgInfos, err = toolchain.GetPkgsInfo(patterns, true, extractTests, modFlags...) if err != nil { log.Fatalf("Error getting dependency package or module directories: %v.", err) } @@ -132,8 +140,36 @@ func ExtractWithFlags(buildFlags []string, patterns []string) error { pkgsNotFound := make([]string, 0, len(pkgs)) + // Build a map from package paths to their longest IDs-- + // in the context of a `go test -c` compilation, we will see the same package more than + // once, with IDs like "abc.com/pkgname [abc.com/pkgname.test]" to distinguish the version + // that contains and is used by test code. + // For our purposes it is simplest to just ignore the non-test version, since the test + // version seems to be a superset of it. + longestPackageIds := make(map[string]string) + packages.Visit(pkgs, nil, func(pkg *packages.Package) { + if longestIDSoFar, present := longestPackageIds[pkg.PkgPath]; present { + if len(pkg.ID) > len(longestIDSoFar) { + longestPackageIds[pkg.PkgPath] = pkg.ID + } + } else { + longestPackageIds[pkg.PkgPath] = pkg.ID + } + }) + // Do a post-order traversal and extract the package scope of each package packages.Visit(pkgs, nil, func(pkg *packages.Package) { + // Note that if test extraction is enabled, we will encounter a package twice here: + // once as the main package, and once as the test package (with a package ID like + // "abc.com/pkgname [abc.com/pkgname.test]"). + // + // We will extract it both times however, because we need to visit the packages + // in the right order in order to visit used types before their users, and the + // ordering determined by packages.Visit for the main and the test package may differ. + // + // This should only cause some wasted time and not inconsistency because the names for + // objects seen in this process should be the same each time. + log.Printf("Processing package %s.", pkg.PkgPath) if _, ok := pkgInfos[pkg.PkgPath]; !ok { @@ -210,6 +246,19 @@ func ExtractWithFlags(buildFlags []string, patterns []string) error { // extract AST information for all packages packages.Visit(pkgs, nil, func(pkg *packages.Package) { + + // If this is a variant of a package that also occurs with a longer ID, skip it; + // otherwise we would extract the same file more than once including extracting the + // body of methods twice, causing database inconsistencies. + // + // We prefer the version with the longest ID because that is (so far as I know) always + // the version that defines more entities -- the only case I'm aware of being a test + // variant of a package, which includes test-only functions in addition to the complete + // contents of the main variant. + if pkg.ID != longestPackageIds[pkg.PkgPath] { + return + } + for root := range wantedRoots { pkgInfo := pkgInfos[pkg.PkgPath] relDir, err := filepath.Rel(root, pkgInfo.PkgDir) diff --git a/go/extractor/toolchain/toolchain.go b/go/extractor/toolchain/toolchain.go index 029390432376..119e3782f6f6 100644 --- a/go/extractor/toolchain/toolchain.go +++ b/go/extractor/toolchain/toolchain.go @@ -223,7 +223,7 @@ type PkgInfo struct { // GetPkgsInfo gets the absolute module and package root directories for the packages matched by the // patterns `patterns`. It passes to `go list` the flags specified by `flags`. If `includingDeps` // is true, all dependencies will also be included. -func GetPkgsInfo(patterns []string, includingDeps bool, flags ...string) (map[string]PkgInfo, error) { +func GetPkgsInfo(patterns []string, includingDeps bool, extractTests bool, flags ...string) (map[string]PkgInfo, error) { // enable module mode so that we can find a module root if it exists, even if go module support is // disabled by a build if includingDeps { @@ -231,6 +231,11 @@ func GetPkgsInfo(patterns []string, includingDeps bool, flags ...string) (map[st flags = append(flags, "-deps") } + if extractTests { + // Without the `-test` flag, test packages would be omitted from the `go list` output. + flags = append(flags, "-test") + } + // using -json overrides -f format output, err := RunList("", patterns, append(flags, "-json")...) if err != nil { @@ -272,6 +277,12 @@ func GetPkgsInfo(patterns []string, includingDeps bool, flags ...string) (map[st PkgDir: pkgAbsDir, ModDir: modAbsDir, } + + if extractTests && strings.Contains(pkgInfo.ImportPath, " [") { + // Assume " [" is the start of a qualifier, and index the package by its base name + baseImportPath := strings.Split(pkgInfo.ImportPath, " [")[0] + pkgInfoMapping[baseImportPath] = pkgInfoMapping[pkgInfo.ImportPath] + } } return pkgInfoMapping, nil } diff --git a/go/ql/integration-tests/go-mod-sample/src/blackbox_test.go b/go/ql/integration-tests/go-mod-sample/src/blackbox_test.go new file mode 100644 index 000000000000..c3f434a7aa12 --- /dev/null +++ b/go/ql/integration-tests/go-mod-sample/src/blackbox_test.go @@ -0,0 +1,16 @@ +package makesample_test + +import ( + "makesample" + "testing" +) + +// Note because this is a test we do NOT expect this to be extracted. +func TestTestMe(t *testing.T) { + + publicResult := makesample.PublicFunction() + if publicResult != 1 { + t.Errorf("Expected 1, got %d", publicResult) + } + +} diff --git a/go/ql/integration-tests/go-mod-sample/src/test.go b/go/ql/integration-tests/go-mod-sample/src/test.go index 824c0b04c726..c3f0f284d4a8 100644 --- a/go/ql/integration-tests/go-mod-sample/src/test.go +++ b/go/ql/integration-tests/go-mod-sample/src/test.go @@ -10,3 +10,7 @@ func test() { header.Version = 4 } + +func PublicFunction() int { + return 1 +} diff --git a/go/ql/integration-tests/go-mod-sample/src/test_test.go b/go/ql/integration-tests/go-mod-sample/src/test_test.go new file mode 100644 index 000000000000..6693a016350c --- /dev/null +++ b/go/ql/integration-tests/go-mod-sample/src/test_test.go @@ -0,0 +1,15 @@ +package makesample + +import ( + "testing" +) + +func TestTestMe(t *testing.T) { + + // Note because this is a test we do NOT expect this to be extracted. + publicResult := PublicFunction() + if publicResult != 1 { + t.Errorf("Expected 1, got %d", publicResult) + } + +} diff --git a/go/ql/integration-tests/test-extraction-autobuild/src/Makefile b/go/ql/integration-tests/test-extraction-autobuild/src/Makefile new file mode 100644 index 000000000000..266e02877884 --- /dev/null +++ b/go/ql/integration-tests/test-extraction-autobuild/src/Makefile @@ -0,0 +1,2 @@ +all: + go get diff --git a/go/ql/integration-tests/test-extraction-autobuild/src/go.mod b/go/ql/integration-tests/test-extraction-autobuild/src/go.mod new file mode 100644 index 000000000000..c4a9f55df6c1 --- /dev/null +++ b/go/ql/integration-tests/test-extraction-autobuild/src/go.mod @@ -0,0 +1,3 @@ +go 1.14 + +module testsample diff --git a/go/ql/integration-tests/test-extraction-autobuild/src/go.sum b/go/ql/integration-tests/test-extraction-autobuild/src/go.sum new file mode 100644 index 000000000000..a8e1b59ae4b1 --- /dev/null +++ b/go/ql/integration-tests/test-extraction-autobuild/src/go.sum @@ -0,0 +1,45 @@ +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/go/ql/integration-tests/test-extraction-autobuild/src/testme.go b/go/ql/integration-tests/test-extraction-autobuild/src/testme.go new file mode 100644 index 000000000000..e24138553ce9 --- /dev/null +++ b/go/ql/integration-tests/test-extraction-autobuild/src/testme.go @@ -0,0 +1,5 @@ +package testsample + +func PublicFunction() int { return 1 } + +func privateFunction() int { return 2 } diff --git a/go/ql/integration-tests/test-extraction-autobuild/src/testme_blackbox_test.go b/go/ql/integration-tests/test-extraction-autobuild/src/testme_blackbox_test.go new file mode 100644 index 000000000000..18a507b5aa38 --- /dev/null +++ b/go/ql/integration-tests/test-extraction-autobuild/src/testme_blackbox_test.go @@ -0,0 +1,15 @@ +package testsample_test + +import ( + "testing" + "testsample" +) + +func TestTestMe(t *testing.T) { + + publicResult := testsample.PublicFunction() + if publicResult != 1 { + t.Errorf("Expected 1, got %d", publicResult) + } + +} diff --git a/go/ql/integration-tests/test-extraction-autobuild/src/testme_test.go b/go/ql/integration-tests/test-extraction-autobuild/src/testme_test.go new file mode 100644 index 000000000000..183d7cd3dffe --- /dev/null +++ b/go/ql/integration-tests/test-extraction-autobuild/src/testme_test.go @@ -0,0 +1,19 @@ +package testsample + +import ( + "testing" +) + +func TestTestMe(t *testing.T) { + + publicResult := PublicFunction() + if publicResult != 1 { + t.Errorf("Expected 1, got %d", publicResult) + } + + privateResult := privateFunction() + if privateResult != 2 { + t.Errorf("Expected 2, got %d", privateResult) + } + +} diff --git a/go/ql/integration-tests/test-extraction-autobuild/test.expected b/go/ql/integration-tests/test-extraction-autobuild/test.expected new file mode 100644 index 000000000000..9e1585fc5ef8 --- /dev/null +++ b/go/ql/integration-tests/test-extraction-autobuild/test.expected @@ -0,0 +1,9 @@ +#select +| src/testme.go:0:0:0:0 | src/testme.go | +| src/testme_blackbox_test.go:0:0:0:0 | src/testme_blackbox_test.go | +| src/testme_test.go:0:0:0:0 | src/testme_test.go | +calls +| src/testme_blackbox_test.go:10:18:10:44 | call to PublicFunction | src/testme.go:3:1:3:38 | function declaration | +| src/testme_test.go:9:18:9:33 | call to PublicFunction | src/testme.go:3:1:3:38 | function declaration | +| src/testme_test.go:14:19:14:35 | call to privateFunction | src/testme.go:5:1:5:39 | function declaration | +extractionErrors diff --git a/go/ql/integration-tests/test-extraction-autobuild/test.py b/go/ql/integration-tests/test-extraction-autobuild/test.py new file mode 100644 index 000000000000..0dc91b5212c5 --- /dev/null +++ b/go/ql/integration-tests/test-extraction-autobuild/test.py @@ -0,0 +1,4 @@ +import os + +def test(codeql, go): + codeql.database.create(source_root="src", extractor_option = ["extract_tests=true"]) diff --git a/go/ql/integration-tests/test-extraction-autobuild/test.ql b/go/ql/integration-tests/test-extraction-autobuild/test.ql new file mode 100644 index 000000000000..15eae8959862 --- /dev/null +++ b/go/ql/integration-tests/test-extraction-autobuild/test.ql @@ -0,0 +1,9 @@ +import go +import semmle.go.DiagnosticsReporting + +from GoFile f +select f + +query predicate calls(CallExpr ce, FuncDecl f) { f = ce.getTarget().getFuncDecl() } + +query predicate extractionErrors(string msg, int sev) { reportableDiagnostics(_, msg, sev) } diff --git a/go/ql/integration-tests/test-extraction-traced/src/Makefile b/go/ql/integration-tests/test-extraction-traced/src/Makefile new file mode 100644 index 000000000000..266e02877884 --- /dev/null +++ b/go/ql/integration-tests/test-extraction-traced/src/Makefile @@ -0,0 +1,2 @@ +all: + go get diff --git a/go/ql/integration-tests/test-extraction-traced/src/go.mod b/go/ql/integration-tests/test-extraction-traced/src/go.mod new file mode 100644 index 000000000000..c4a9f55df6c1 --- /dev/null +++ b/go/ql/integration-tests/test-extraction-traced/src/go.mod @@ -0,0 +1,3 @@ +go 1.14 + +module testsample diff --git a/go/ql/integration-tests/test-extraction-traced/src/go.sum b/go/ql/integration-tests/test-extraction-traced/src/go.sum new file mode 100644 index 000000000000..a8e1b59ae4b1 --- /dev/null +++ b/go/ql/integration-tests/test-extraction-traced/src/go.sum @@ -0,0 +1,45 @@ +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/go/ql/integration-tests/test-extraction-traced/src/testme.go b/go/ql/integration-tests/test-extraction-traced/src/testme.go new file mode 100644 index 000000000000..e24138553ce9 --- /dev/null +++ b/go/ql/integration-tests/test-extraction-traced/src/testme.go @@ -0,0 +1,5 @@ +package testsample + +func PublicFunction() int { return 1 } + +func privateFunction() int { return 2 } diff --git a/go/ql/integration-tests/test-extraction-traced/src/testme_blackbox_test.go b/go/ql/integration-tests/test-extraction-traced/src/testme_blackbox_test.go new file mode 100644 index 000000000000..18a507b5aa38 --- /dev/null +++ b/go/ql/integration-tests/test-extraction-traced/src/testme_blackbox_test.go @@ -0,0 +1,15 @@ +package testsample_test + +import ( + "testing" + "testsample" +) + +func TestTestMe(t *testing.T) { + + publicResult := testsample.PublicFunction() + if publicResult != 1 { + t.Errorf("Expected 1, got %d", publicResult) + } + +} diff --git a/go/ql/integration-tests/test-extraction-traced/src/testme_test.go b/go/ql/integration-tests/test-extraction-traced/src/testme_test.go new file mode 100644 index 000000000000..183d7cd3dffe --- /dev/null +++ b/go/ql/integration-tests/test-extraction-traced/src/testme_test.go @@ -0,0 +1,19 @@ +package testsample + +import ( + "testing" +) + +func TestTestMe(t *testing.T) { + + publicResult := PublicFunction() + if publicResult != 1 { + t.Errorf("Expected 1, got %d", publicResult) + } + + privateResult := privateFunction() + if privateResult != 2 { + t.Errorf("Expected 2, got %d", privateResult) + } + +} diff --git a/go/ql/integration-tests/test-extraction-traced/test.expected b/go/ql/integration-tests/test-extraction-traced/test.expected new file mode 100644 index 000000000000..9e1585fc5ef8 --- /dev/null +++ b/go/ql/integration-tests/test-extraction-traced/test.expected @@ -0,0 +1,9 @@ +#select +| src/testme.go:0:0:0:0 | src/testme.go | +| src/testme_blackbox_test.go:0:0:0:0 | src/testme_blackbox_test.go | +| src/testme_test.go:0:0:0:0 | src/testme_test.go | +calls +| src/testme_blackbox_test.go:10:18:10:44 | call to PublicFunction | src/testme.go:3:1:3:38 | function declaration | +| src/testme_test.go:9:18:9:33 | call to PublicFunction | src/testme.go:3:1:3:38 | function declaration | +| src/testme_test.go:14:19:14:35 | call to privateFunction | src/testme.go:5:1:5:39 | function declaration | +extractionErrors diff --git a/go/ql/integration-tests/test-extraction-traced/test.py b/go/ql/integration-tests/test-extraction-traced/test.py new file mode 100644 index 000000000000..2887d3fa0d09 --- /dev/null +++ b/go/ql/integration-tests/test-extraction-traced/test.py @@ -0,0 +1,4 @@ +import os + +def test(codeql, go): + codeql.database.create(source_root="src", command="go test -c") diff --git a/go/ql/integration-tests/test-extraction-traced/test.ql b/go/ql/integration-tests/test-extraction-traced/test.ql new file mode 100644 index 000000000000..15eae8959862 --- /dev/null +++ b/go/ql/integration-tests/test-extraction-traced/test.ql @@ -0,0 +1,9 @@ +import go +import semmle.go.DiagnosticsReporting + +from GoFile f +select f + +query predicate calls(CallExpr ce, FuncDecl f) { f = ce.getTarget().getFuncDecl() } + +query predicate extractionErrors(string msg, int sev) { reportableDiagnostics(_, msg, sev) } diff --git a/go/ql/integration-tests/traced-extraction/src/Makefile b/go/ql/integration-tests/traced-extraction/src/Makefile new file mode 100644 index 000000000000..266e02877884 --- /dev/null +++ b/go/ql/integration-tests/traced-extraction/src/Makefile @@ -0,0 +1,2 @@ +all: + go get diff --git a/go/ql/integration-tests/traced-extraction/src/go.mod b/go/ql/integration-tests/traced-extraction/src/go.mod new file mode 100644 index 000000000000..c4a9f55df6c1 --- /dev/null +++ b/go/ql/integration-tests/traced-extraction/src/go.mod @@ -0,0 +1,3 @@ +go 1.14 + +module testsample diff --git a/go/ql/integration-tests/traced-extraction/src/go.sum b/go/ql/integration-tests/traced-extraction/src/go.sum new file mode 100644 index 000000000000..a8e1b59ae4b1 --- /dev/null +++ b/go/ql/integration-tests/traced-extraction/src/go.sum @@ -0,0 +1,45 @@ +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/go/ql/integration-tests/traced-extraction/src/testme.go b/go/ql/integration-tests/traced-extraction/src/testme.go new file mode 100644 index 000000000000..e24138553ce9 --- /dev/null +++ b/go/ql/integration-tests/traced-extraction/src/testme.go @@ -0,0 +1,5 @@ +package testsample + +func PublicFunction() int { return 1 } + +func privateFunction() int { return 2 } diff --git a/go/ql/integration-tests/traced-extraction/src/testme_blackbox_test.go b/go/ql/integration-tests/traced-extraction/src/testme_blackbox_test.go new file mode 100644 index 000000000000..728cc651d7a3 --- /dev/null +++ b/go/ql/integration-tests/traced-extraction/src/testme_blackbox_test.go @@ -0,0 +1,16 @@ +package testsample_test + +import ( + "testing" + "testsample" +) + +func TestTestMe(t *testing.T) { + + // Note because this is a test we do NOT expect it to be extracted + publicResult := testsample.PublicFunction() + if publicResult != 1 { + t.Errorf("Expected 1, got %d", publicResult) + } + +} diff --git a/go/ql/integration-tests/traced-extraction/src/testme_test.go b/go/ql/integration-tests/traced-extraction/src/testme_test.go new file mode 100644 index 000000000000..cc77c9dd37ff --- /dev/null +++ b/go/ql/integration-tests/traced-extraction/src/testme_test.go @@ -0,0 +1,20 @@ +package testsample + +import ( + "testing" +) + +func TestTestMe(t *testing.T) { + + // Note because this is a test we do NOT expect it to be extracted + publicResult := PublicFunction() + if publicResult != 1 { + t.Errorf("Expected 1, got %d", publicResult) + } + + privateResult := privateFunction() + if privateResult != 2 { + t.Errorf("Expected 2, got %d", privateResult) + } + +} diff --git a/go/ql/integration-tests/traced-extraction/test.expected b/go/ql/integration-tests/traced-extraction/test.expected new file mode 100644 index 000000000000..7b62d6d92983 --- /dev/null +++ b/go/ql/integration-tests/traced-extraction/test.expected @@ -0,0 +1,4 @@ +#select +| src/testme.go:0:0:0:0 | src/testme.go | +calls +extractionErrors diff --git a/go/ql/integration-tests/traced-extraction/test.py b/go/ql/integration-tests/traced-extraction/test.py new file mode 100644 index 000000000000..fbb3f6a6d6c5 --- /dev/null +++ b/go/ql/integration-tests/traced-extraction/test.py @@ -0,0 +1,4 @@ +import os + +def test(codeql, go): + codeql.database.create(source_root="src", command="go build") diff --git a/go/ql/integration-tests/traced-extraction/test.ql b/go/ql/integration-tests/traced-extraction/test.ql new file mode 100644 index 000000000000..15eae8959862 --- /dev/null +++ b/go/ql/integration-tests/traced-extraction/test.ql @@ -0,0 +1,9 @@ +import go +import semmle.go.DiagnosticsReporting + +from GoFile f +select f + +query predicate calls(CallExpr ce, FuncDecl f) { f = ce.getTarget().getFuncDecl() } + +query predicate extractionErrors(string msg, int sev) { reportableDiagnostics(_, msg, sev) } diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index 645f0e3fe67e..211c966b9194 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -922,8 +922,19 @@ class SignatureType extends @signaturetype, CompositeType { language[monotonicAggregates] override string pp() { result = - "func(" + concat(int i, Type tp | tp = this.getParameterType(i) | tp.pp(), ", " order by i) + - ") " + concat(int i, Type tp | tp = this.getResultType(i) | tp.pp(), ", " order by i) + "func(" + + concat(int i, Type tp, string prefix | + if i = this.getNumParameter() - 1 and this.isVariadic() + then + tp = this.getParameterType(i).(SliceType).getElementType() and + prefix = "..." + else ( + tp = this.getParameterType(i) and + prefix = "" + ) + | + prefix + tp.pp(), ", " order by i + ) + ") " + concat(int i, Type tp | tp = this.getResultType(i) | tp.pp(), ", " order by i) } override string toString() { result = "signature type" } diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl1.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl1.qll index 359fa71744b4..ce964917e970 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl1.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl1.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl2.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl2.qll index 359fa71744b4..ce964917e970 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl2.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl2.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I diff --git a/go/ql/src/Security/CWE-681/IncorrectIntegerConversionQuery.ql b/go/ql/src/Security/CWE-681/IncorrectIntegerConversionQuery.ql index 4497ffe7c4a9..a310f024a2d0 100644 --- a/go/ql/src/Security/CWE-681/IncorrectIntegerConversionQuery.ql +++ b/go/ql/src/Security/CWE-681/IncorrectIntegerConversionQuery.ql @@ -10,7 +10,7 @@ * @tags security * external/cwe/cwe-190 * external/cwe/cwe-681 - * @precision very-high + * @precision high */ import go diff --git a/go/ql/src/change-notes/2024-09-24-incorrect-integer-conversion-query-precision.md b/go/ql/src/change-notes/2024-09-24-incorrect-integer-conversion-query-precision.md new file mode 100644 index 000000000000..b8acf46c9c5b --- /dev/null +++ b/go/ql/src/change-notes/2024-09-24-incorrect-integer-conversion-query-precision.md @@ -0,0 +1,4 @@ +--- +category: queryMetadata +--- +* The precision of the `go/incorrect-integer-conversion-query` query was decreased from `very-high` to `high`, since there is at least one known class of false positives involving dynamic bounds checking. diff --git a/go/ql/test/experimental/CWE-090/LDAPInjection.expected b/go/ql/test/experimental/CWE-090/LDAPInjection.expected index f7f3bdedd4b0..aeaeda6741c7 100644 --- a/go/ql/test/experimental/CWE-090/LDAPInjection.expected +++ b/go/ql/test/experimental/CWE-090/LDAPInjection.expected @@ -25,12 +25,9 @@ edges | LDAPInjection.go:57:15:57:29 | call to UserAgent | LDAPInjection.go:76:24:76:32 | untrusted | provenance | Src:MaD:1 | | LDAPInjection.go:57:15:57:29 | call to UserAgent | LDAPInjection.go:80:22:80:30 | untrusted | provenance | Src:MaD:1 | | LDAPInjection.go:57:15:57:29 | call to UserAgent | LDAPInjection.go:81:25:81:33 | untrusted | provenance | Src:MaD:1 | -| LDAPInjection.go:62:3:62:33 | slice literal [array] | LDAPInjection.go:62:3:62:33 | slice literal | provenance | | -| LDAPInjection.go:62:24:62:32 | untrusted | LDAPInjection.go:62:3:62:33 | slice literal [array] | provenance | | -| LDAPInjection.go:69:3:69:33 | slice literal [array] | LDAPInjection.go:69:3:69:33 | slice literal | provenance | | -| LDAPInjection.go:69:24:69:32 | untrusted | LDAPInjection.go:69:3:69:33 | slice literal [array] | provenance | | -| LDAPInjection.go:76:3:76:33 | slice literal [array] | LDAPInjection.go:76:3:76:33 | slice literal | provenance | | -| LDAPInjection.go:76:24:76:32 | untrusted | LDAPInjection.go:76:3:76:33 | slice literal [array] | provenance | | +| LDAPInjection.go:62:24:62:32 | untrusted | LDAPInjection.go:62:3:62:33 | slice literal | provenance | | +| LDAPInjection.go:69:24:69:32 | untrusted | LDAPInjection.go:69:3:69:33 | slice literal | provenance | | +| LDAPInjection.go:76:24:76:32 | untrusted | LDAPInjection.go:76:3:76:33 | slice literal | provenance | | models | 1 | Source: net/http; Request; true; UserAgent; ; ; ReturnValue; remote; manual | nodes @@ -38,17 +35,14 @@ nodes | LDAPInjection.go:59:3:59:11 | untrusted | semmle.label | untrusted | | LDAPInjection.go:61:3:61:51 | ...+... | semmle.label | ...+... | | LDAPInjection.go:62:3:62:33 | slice literal | semmle.label | slice literal | -| LDAPInjection.go:62:3:62:33 | slice literal [array] | semmle.label | slice literal [array] | | LDAPInjection.go:62:24:62:32 | untrusted | semmle.label | untrusted | | LDAPInjection.go:66:3:66:11 | untrusted | semmle.label | untrusted | | LDAPInjection.go:68:3:68:51 | ...+... | semmle.label | ...+... | | LDAPInjection.go:69:3:69:33 | slice literal | semmle.label | slice literal | -| LDAPInjection.go:69:3:69:33 | slice literal [array] | semmle.label | slice literal [array] | | LDAPInjection.go:69:24:69:32 | untrusted | semmle.label | untrusted | | LDAPInjection.go:73:3:73:11 | untrusted | semmle.label | untrusted | | LDAPInjection.go:75:3:75:51 | ...+... | semmle.label | ...+... | | LDAPInjection.go:76:3:76:33 | slice literal | semmle.label | slice literal | -| LDAPInjection.go:76:3:76:33 | slice literal [array] | semmle.label | slice literal [array] | | LDAPInjection.go:76:24:76:32 | untrusted | semmle.label | untrusted | | LDAPInjection.go:80:22:80:30 | untrusted | semmle.label | untrusted | | LDAPInjection.go:81:25:81:33 | untrusted | semmle.label | untrusted | diff --git a/go/ql/test/experimental/CWE-1004/CookieWithoutHttpOnly.expected b/go/ql/test/experimental/CWE-1004/CookieWithoutHttpOnly.expected index 467f08e74e6f..5c7bef1155ef 100644 --- a/go/ql/test/experimental/CWE-1004/CookieWithoutHttpOnly.expected +++ b/go/ql/test/experimental/CWE-1004/CookieWithoutHttpOnly.expected @@ -7,6 +7,7 @@ edges | CookieWithoutHttpOnly.go:15:20:15:21 | &... [pointer] | CookieWithoutHttpOnly.go:15:20:15:21 | &... | provenance | | | CookieWithoutHttpOnly.go:15:20:15:21 | &... [pointer] | CookieWithoutHttpOnly.go:15:20:15:21 | &... | provenance | | | CookieWithoutHttpOnly.go:15:20:15:21 | &... [pointer] | CookieWithoutHttpOnly.go:15:21:15:21 | c | provenance | | +| CookieWithoutHttpOnly.go:15:21:15:21 | c | CookieWithoutHttpOnly.go:15:20:15:21 | &... | provenance | | | CookieWithoutHttpOnly.go:15:21:15:21 | c | CookieWithoutHttpOnly.go:15:20:15:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:19:7:23:2 | struct literal | CookieWithoutHttpOnly.go:24:20:24:21 | &... | provenance | | | CookieWithoutHttpOnly.go:19:7:23:2 | struct literal | CookieWithoutHttpOnly.go:24:20:24:21 | &... | provenance | | @@ -24,6 +25,8 @@ edges | CookieWithoutHttpOnly.go:24:20:24:21 | &... [pointer] | CookieWithoutHttpOnly.go:24:20:24:21 | &... | provenance | | | CookieWithoutHttpOnly.go:24:20:24:21 | &... [pointer] | CookieWithoutHttpOnly.go:24:21:24:21 | c | provenance | | | CookieWithoutHttpOnly.go:24:20:24:21 | &... [pointer] | CookieWithoutHttpOnly.go:24:21:24:21 | c | provenance | | +| CookieWithoutHttpOnly.go:24:21:24:21 | c | CookieWithoutHttpOnly.go:24:20:24:21 | &... | provenance | | +| CookieWithoutHttpOnly.go:24:21:24:21 | c | CookieWithoutHttpOnly.go:24:20:24:21 | &... | provenance | | | CookieWithoutHttpOnly.go:24:21:24:21 | c | CookieWithoutHttpOnly.go:24:20:24:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:24:21:24:21 | c | CookieWithoutHttpOnly.go:24:20:24:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:28:7:32:2 | struct literal | CookieWithoutHttpOnly.go:33:20:33:21 | &... | provenance | | @@ -42,6 +45,8 @@ edges | CookieWithoutHttpOnly.go:33:20:33:21 | &... [pointer] | CookieWithoutHttpOnly.go:33:20:33:21 | &... | provenance | | | CookieWithoutHttpOnly.go:33:20:33:21 | &... [pointer] | CookieWithoutHttpOnly.go:33:21:33:21 | c | provenance | | | CookieWithoutHttpOnly.go:33:20:33:21 | &... [pointer] | CookieWithoutHttpOnly.go:33:21:33:21 | c | provenance | | +| CookieWithoutHttpOnly.go:33:21:33:21 | c | CookieWithoutHttpOnly.go:33:20:33:21 | &... | provenance | | +| CookieWithoutHttpOnly.go:33:21:33:21 | c | CookieWithoutHttpOnly.go:33:20:33:21 | &... | provenance | | | CookieWithoutHttpOnly.go:33:21:33:21 | c | CookieWithoutHttpOnly.go:33:20:33:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:33:21:33:21 | c | CookieWithoutHttpOnly.go:33:20:33:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:37:7:40:2 | struct literal | CookieWithoutHttpOnly.go:42:20:42:21 | &... | provenance | | @@ -60,6 +65,8 @@ edges | CookieWithoutHttpOnly.go:42:20:42:21 | &... [pointer] | CookieWithoutHttpOnly.go:42:20:42:21 | &... | provenance | | | CookieWithoutHttpOnly.go:42:20:42:21 | &... [pointer] | CookieWithoutHttpOnly.go:42:21:42:21 | c | provenance | | | CookieWithoutHttpOnly.go:42:20:42:21 | &... [pointer] | CookieWithoutHttpOnly.go:42:21:42:21 | c | provenance | | +| CookieWithoutHttpOnly.go:42:21:42:21 | c | CookieWithoutHttpOnly.go:42:20:42:21 | &... | provenance | | +| CookieWithoutHttpOnly.go:42:21:42:21 | c | CookieWithoutHttpOnly.go:42:20:42:21 | &... | provenance | | | CookieWithoutHttpOnly.go:42:21:42:21 | c | CookieWithoutHttpOnly.go:42:20:42:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:42:21:42:21 | c | CookieWithoutHttpOnly.go:42:20:42:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:46:7:49:2 | struct literal | CookieWithoutHttpOnly.go:51:20:51:21 | &... | provenance | | @@ -78,6 +85,8 @@ edges | CookieWithoutHttpOnly.go:51:20:51:21 | &... [pointer] | CookieWithoutHttpOnly.go:51:20:51:21 | &... | provenance | | | CookieWithoutHttpOnly.go:51:20:51:21 | &... [pointer] | CookieWithoutHttpOnly.go:51:21:51:21 | c | provenance | | | CookieWithoutHttpOnly.go:51:20:51:21 | &... [pointer] | CookieWithoutHttpOnly.go:51:21:51:21 | c | provenance | | +| CookieWithoutHttpOnly.go:51:21:51:21 | c | CookieWithoutHttpOnly.go:51:20:51:21 | &... | provenance | | +| CookieWithoutHttpOnly.go:51:21:51:21 | c | CookieWithoutHttpOnly.go:51:20:51:21 | &... | provenance | | | CookieWithoutHttpOnly.go:51:21:51:21 | c | CookieWithoutHttpOnly.go:51:20:51:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:51:21:51:21 | c | CookieWithoutHttpOnly.go:51:20:51:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:55:2:55:4 | definition of val | CookieWithoutHttpOnly.go:59:13:59:15 | val | provenance | | @@ -98,6 +107,8 @@ edges | CookieWithoutHttpOnly.go:61:20:61:21 | &... [pointer] | CookieWithoutHttpOnly.go:61:20:61:21 | &... | provenance | | | CookieWithoutHttpOnly.go:61:20:61:21 | &... [pointer] | CookieWithoutHttpOnly.go:61:21:61:21 | c | provenance | | | CookieWithoutHttpOnly.go:61:20:61:21 | &... [pointer] | CookieWithoutHttpOnly.go:61:21:61:21 | c | provenance | | +| CookieWithoutHttpOnly.go:61:21:61:21 | c | CookieWithoutHttpOnly.go:61:20:61:21 | &... | provenance | | +| CookieWithoutHttpOnly.go:61:21:61:21 | c | CookieWithoutHttpOnly.go:61:20:61:21 | &... | provenance | | | CookieWithoutHttpOnly.go:61:21:61:21 | c | CookieWithoutHttpOnly.go:61:20:61:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:61:21:61:21 | c | CookieWithoutHttpOnly.go:61:20:61:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:65:2:65:4 | definition of val | CookieWithoutHttpOnly.go:69:13:69:15 | val | provenance | | @@ -118,6 +129,8 @@ edges | CookieWithoutHttpOnly.go:71:20:71:21 | &... [pointer] | CookieWithoutHttpOnly.go:71:20:71:21 | &... | provenance | | | CookieWithoutHttpOnly.go:71:20:71:21 | &... [pointer] | CookieWithoutHttpOnly.go:71:21:71:21 | c | provenance | | | CookieWithoutHttpOnly.go:71:20:71:21 | &... [pointer] | CookieWithoutHttpOnly.go:71:21:71:21 | c | provenance | | +| CookieWithoutHttpOnly.go:71:21:71:21 | c | CookieWithoutHttpOnly.go:71:20:71:21 | &... | provenance | | +| CookieWithoutHttpOnly.go:71:21:71:21 | c | CookieWithoutHttpOnly.go:71:20:71:21 | &... | provenance | | | CookieWithoutHttpOnly.go:71:21:71:21 | c | CookieWithoutHttpOnly.go:71:20:71:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:71:21:71:21 | c | CookieWithoutHttpOnly.go:71:20:71:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:75:2:75:4 | definition of val | CookieWithoutHttpOnly.go:80:15:80:17 | val | provenance | | @@ -138,6 +151,8 @@ edges | CookieWithoutHttpOnly.go:81:20:81:21 | &... [pointer] | CookieWithoutHttpOnly.go:81:20:81:21 | &... | provenance | | | CookieWithoutHttpOnly.go:81:20:81:21 | &... [pointer] | CookieWithoutHttpOnly.go:81:21:81:21 | c | provenance | | | CookieWithoutHttpOnly.go:81:20:81:21 | &... [pointer] | CookieWithoutHttpOnly.go:81:21:81:21 | c | provenance | | +| CookieWithoutHttpOnly.go:81:21:81:21 | c | CookieWithoutHttpOnly.go:81:20:81:21 | &... | provenance | | +| CookieWithoutHttpOnly.go:81:21:81:21 | c | CookieWithoutHttpOnly.go:81:20:81:21 | &... | provenance | | | CookieWithoutHttpOnly.go:81:21:81:21 | c | CookieWithoutHttpOnly.go:81:20:81:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:81:21:81:21 | c | CookieWithoutHttpOnly.go:81:20:81:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:85:2:85:4 | definition of val | CookieWithoutHttpOnly.go:90:15:90:17 | val | provenance | | @@ -158,6 +173,8 @@ edges | CookieWithoutHttpOnly.go:91:20:91:21 | &... [pointer] | CookieWithoutHttpOnly.go:91:20:91:21 | &... | provenance | | | CookieWithoutHttpOnly.go:91:20:91:21 | &... [pointer] | CookieWithoutHttpOnly.go:91:21:91:21 | c | provenance | | | CookieWithoutHttpOnly.go:91:20:91:21 | &... [pointer] | CookieWithoutHttpOnly.go:91:21:91:21 | c | provenance | | +| CookieWithoutHttpOnly.go:91:21:91:21 | c | CookieWithoutHttpOnly.go:91:20:91:21 | &... | provenance | | +| CookieWithoutHttpOnly.go:91:21:91:21 | c | CookieWithoutHttpOnly.go:91:20:91:21 | &... | provenance | | | CookieWithoutHttpOnly.go:91:21:91:21 | c | CookieWithoutHttpOnly.go:91:20:91:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:91:21:91:21 | c | CookieWithoutHttpOnly.go:91:20:91:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:95:7:98:2 | struct literal | CookieWithoutHttpOnly.go:100:20:100:21 | &... | provenance | | @@ -168,6 +185,7 @@ edges | CookieWithoutHttpOnly.go:100:20:100:21 | &... [pointer] | CookieWithoutHttpOnly.go:100:20:100:21 | &... | provenance | | | CookieWithoutHttpOnly.go:100:20:100:21 | &... [pointer] | CookieWithoutHttpOnly.go:100:20:100:21 | &... | provenance | | | CookieWithoutHttpOnly.go:100:20:100:21 | &... [pointer] | CookieWithoutHttpOnly.go:100:21:100:21 | c | provenance | | +| CookieWithoutHttpOnly.go:100:21:100:21 | c | CookieWithoutHttpOnly.go:100:20:100:21 | &... | provenance | | | CookieWithoutHttpOnly.go:100:21:100:21 | c | CookieWithoutHttpOnly.go:100:20:100:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:104:10:104:18 | "session" | CookieWithoutHttpOnly.go:106:10:106:13 | name | provenance | | | CookieWithoutHttpOnly.go:105:7:108:2 | struct literal | CookieWithoutHttpOnly.go:110:20:110:21 | &... | provenance | | @@ -186,6 +204,8 @@ edges | CookieWithoutHttpOnly.go:110:20:110:21 | &... [pointer] | CookieWithoutHttpOnly.go:110:20:110:21 | &... | provenance | | | CookieWithoutHttpOnly.go:110:20:110:21 | &... [pointer] | CookieWithoutHttpOnly.go:110:21:110:21 | c | provenance | | | CookieWithoutHttpOnly.go:110:20:110:21 | &... [pointer] | CookieWithoutHttpOnly.go:110:21:110:21 | c | provenance | | +| CookieWithoutHttpOnly.go:110:21:110:21 | c | CookieWithoutHttpOnly.go:110:20:110:21 | &... | provenance | | +| CookieWithoutHttpOnly.go:110:21:110:21 | c | CookieWithoutHttpOnly.go:110:20:110:21 | &... | provenance | | | CookieWithoutHttpOnly.go:110:21:110:21 | c | CookieWithoutHttpOnly.go:110:20:110:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:110:21:110:21 | c | CookieWithoutHttpOnly.go:110:20:110:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:114:13:114:24 | "login_name" | CookieWithoutHttpOnly.go:116:10:116:16 | session | provenance | | @@ -205,6 +225,8 @@ edges | CookieWithoutHttpOnly.go:120:20:120:21 | &... [pointer] | CookieWithoutHttpOnly.go:120:20:120:21 | &... | provenance | | | CookieWithoutHttpOnly.go:120:20:120:21 | &... [pointer] | CookieWithoutHttpOnly.go:120:21:120:21 | c | provenance | | | CookieWithoutHttpOnly.go:120:20:120:21 | &... [pointer] | CookieWithoutHttpOnly.go:120:21:120:21 | c | provenance | | +| CookieWithoutHttpOnly.go:120:21:120:21 | c | CookieWithoutHttpOnly.go:120:20:120:21 | &... | provenance | | +| CookieWithoutHttpOnly.go:120:21:120:21 | c | CookieWithoutHttpOnly.go:120:20:120:21 | &... | provenance | | | CookieWithoutHttpOnly.go:120:21:120:21 | c | CookieWithoutHttpOnly.go:120:20:120:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:120:21:120:21 | c | CookieWithoutHttpOnly.go:120:20:120:21 | &... [pointer] | provenance | | | CookieWithoutHttpOnly.go:123:13:123:49 | call to NewCookieStore | CookieWithoutHttpOnly.go:126:16:126:20 | store | provenance | | diff --git a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAst.expected b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAst.expected index e2424aa4575d..eb792c7028ed 100644 --- a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAst.expected +++ b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAst.expected @@ -53,10 +53,10 @@ input.go: # 20| 0: [CallExpr] call to Println # 20| Type = (int, error) # 20| 0: [FunctionName, SelectorExpr] selection of Println -# 20| Type = func([]interface { }) int, error +# 20| Type = func(...interface { }) int, error # 20| 0: [Ident, PackageName] fmt # 20| 1: [FunctionName, Ident] Println -# 20| Type = func([]interface { }) int, error +# 20| Type = func(...interface { }) int, error # 20| 1: [StringLit] "Hi" # 20| Type = string # 20| Value = [StringLit] Hi @@ -203,10 +203,10 @@ input.go: # 52| 0: [CallExpr] call to Println # 52| Type = (int, error) # 52| 0: [FunctionName, SelectorExpr] selection of Println -# 52| Type = func([]interface { }) int, error +# 52| Type = func(...interface { }) int, error # 52| 0: [Ident, PackageName] fmt # 52| 1: [FunctionName, Ident] Println -# 52| Type = func([]interface { }) int, error +# 52| Type = func(...interface { }) int, error # 52| 1: [StringLit] "Heard from ch1" # 52| Type = string # 52| Value = [StringLit] Heard from ch1 @@ -229,20 +229,20 @@ input.go: # 54| 0: [CallExpr] call to Println # 54| Type = (int, error) # 54| 0: [FunctionName, SelectorExpr] selection of Println -# 54| Type = func([]interface { }) int, error +# 54| Type = func(...interface { }) int, error # 54| 0: [Ident, PackageName] fmt # 54| 1: [FunctionName, Ident] Println -# 54| Type = func([]interface { }) int, error +# 54| Type = func(...interface { }) int, error # 54| 1: [Ident, VariableName] a # 54| Type = [1]float32 # 55| 2: [ExprStmt] expression statement # 55| 0: [CallExpr] call to Println # 55| Type = (int, error) # 55| 0: [FunctionName, SelectorExpr] selection of Println -# 55| Type = func([]interface { }) int, error +# 55| Type = func(...interface { }) int, error # 55| 0: [Ident, PackageName] fmt # 55| 1: [FunctionName, Ident] Println -# 55| Type = func([]interface { }) int, error +# 55| Type = func(...interface { }) int, error # 55| 1: [Ident, VariableName] w # 55| Type = bool # 56| 2: [CommClause] comm clause @@ -250,10 +250,10 @@ input.go: # 57| 0: [CallExpr] call to Println # 57| Type = (int, error) # 57| 0: [FunctionName, SelectorExpr] selection of Println -# 57| Type = func([]interface { }) int, error +# 57| Type = func(...interface { }) int, error # 57| 0: [Ident, PackageName] fmt # 57| 1: [FunctionName, Ident] Println -# 57| Type = func([]interface { }) int, error +# 57| Type = func(...interface { }) int, error # 58| 3: [CommClause] comm clause # 58| 0: [SendStmt] send statement # 58| 0: [Ident, VariableName] ch1 @@ -297,10 +297,10 @@ input.go: # 67| 0: [CallExpr] call to Println # 67| Type = (int, error) # 67| 0: [FunctionName, SelectorExpr] selection of Println -# 67| Type = func([]interface { }) int, error +# 67| Type = func(...interface { }) int, error # 67| 0: [Ident, PackageName] fmt # 67| 1: [FunctionName, Ident] Println -# 67| Type = func([]interface { }) int, error +# 67| Type = func(...interface { }) int, error # 67| 1: [Ident, VariableName] x # 67| Type = int # 68| 2: [BlockStmt] block statement @@ -316,10 +316,10 @@ input.go: # 69| 0: [CallExpr] call to Println # 69| Type = (int, error) # 69| 0: [FunctionName, SelectorExpr] selection of Println -# 69| Type = func([]interface { }) int, error +# 69| Type = func(...interface { }) int, error # 69| 0: [Ident, PackageName] fmt # 69| 1: [FunctionName, Ident] Println -# 69| Type = func([]interface { }) int, error +# 69| Type = func(...interface { }) int, error # 69| 1: [MinusExpr] -... # 69| Type = int # 69| 0: [Ident, VariableName] x @@ -474,10 +474,10 @@ input.go: # 115| 0: [CallExpr] call to Println # 115| Type = (int, error) # 115| 0: [FunctionName, SelectorExpr] selection of Println -# 115| Type = func([]interface { }) int, error +# 115| Type = func(...interface { }) int, error # 115| 0: [Ident, PackageName] fmt # 115| 1: [FunctionName, Ident] Println -# 115| Type = func([]interface { }) int, error +# 115| Type = func(...interface { }) int, error # 115| 1: [Ident, VariableName] y # 115| Type = interface { } # 116| 1: [CaseClause] case clause @@ -566,10 +566,10 @@ input.go: # 138| 0: [CallExpr] call to Print # 138| Type = (int, error) # 138| 0: [FunctionName, SelectorExpr] selection of Print -# 138| Type = func([]interface { }) int, error +# 138| Type = func(...interface { }) int, error # 138| 0: [Ident, PackageName] fmt # 138| 1: [FunctionName, Ident] Print -# 138| Type = func([]interface { }) int, error +# 138| Type = func(...interface { }) int, error # 138| 1: [Ident, VariableName] x # 138| Type = int # 141| 1: [RangeStmt] range statement @@ -584,10 +584,10 @@ input.go: # 142| 0: [CallExpr] call to Print # 142| Type = (int, error) # 142| 0: [FunctionName, SelectorExpr] selection of Print -# 142| Type = func([]interface { }) int, error +# 142| Type = func(...interface { }) int, error # 142| 0: [Ident, PackageName] fmt # 142| 1: [FunctionName, Ident] Print -# 142| Type = func([]interface { }) int, error +# 142| Type = func(...interface { }) int, error # 142| 1: [Ident, VariableName] i # 142| Type = int # 142| 2: [Ident, VariableName] v diff --git a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstExcludeComments.expected b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstExcludeComments.expected index 57fbeb881a52..e0777268f048 100644 --- a/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstExcludeComments.expected +++ b/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstExcludeComments.expected @@ -33,10 +33,10 @@ input.go: # 20| 0: [CallExpr] call to Println # 20| Type = (int, error) # 20| 0: [FunctionName, SelectorExpr] selection of Println -# 20| Type = func([]interface { }) int, error +# 20| Type = func(...interface { }) int, error # 20| 0: [Ident, PackageName] fmt # 20| 1: [FunctionName, Ident] Println -# 20| Type = func([]interface { }) int, error +# 20| Type = func(...interface { }) int, error # 20| 1: [StringLit] "Hi" # 20| Type = string # 20| Value = [StringLit] Hi @@ -183,10 +183,10 @@ input.go: # 52| 0: [CallExpr] call to Println # 52| Type = (int, error) # 52| 0: [FunctionName, SelectorExpr] selection of Println -# 52| Type = func([]interface { }) int, error +# 52| Type = func(...interface { }) int, error # 52| 0: [Ident, PackageName] fmt # 52| 1: [FunctionName, Ident] Println -# 52| Type = func([]interface { }) int, error +# 52| Type = func(...interface { }) int, error # 52| 1: [StringLit] "Heard from ch1" # 52| Type = string # 52| Value = [StringLit] Heard from ch1 @@ -209,20 +209,20 @@ input.go: # 54| 0: [CallExpr] call to Println # 54| Type = (int, error) # 54| 0: [FunctionName, SelectorExpr] selection of Println -# 54| Type = func([]interface { }) int, error +# 54| Type = func(...interface { }) int, error # 54| 0: [Ident, PackageName] fmt # 54| 1: [FunctionName, Ident] Println -# 54| Type = func([]interface { }) int, error +# 54| Type = func(...interface { }) int, error # 54| 1: [Ident, VariableName] a # 54| Type = [1]float32 # 55| 2: [ExprStmt] expression statement # 55| 0: [CallExpr] call to Println # 55| Type = (int, error) # 55| 0: [FunctionName, SelectorExpr] selection of Println -# 55| Type = func([]interface { }) int, error +# 55| Type = func(...interface { }) int, error # 55| 0: [Ident, PackageName] fmt # 55| 1: [FunctionName, Ident] Println -# 55| Type = func([]interface { }) int, error +# 55| Type = func(...interface { }) int, error # 55| 1: [Ident, VariableName] w # 55| Type = bool # 56| 2: [CommClause] comm clause @@ -230,10 +230,10 @@ input.go: # 57| 0: [CallExpr] call to Println # 57| Type = (int, error) # 57| 0: [FunctionName, SelectorExpr] selection of Println -# 57| Type = func([]interface { }) int, error +# 57| Type = func(...interface { }) int, error # 57| 0: [Ident, PackageName] fmt # 57| 1: [FunctionName, Ident] Println -# 57| Type = func([]interface { }) int, error +# 57| Type = func(...interface { }) int, error # 58| 3: [CommClause] comm clause # 58| 0: [SendStmt] send statement # 58| 0: [Ident, VariableName] ch1 @@ -277,10 +277,10 @@ input.go: # 67| 0: [CallExpr] call to Println # 67| Type = (int, error) # 67| 0: [FunctionName, SelectorExpr] selection of Println -# 67| Type = func([]interface { }) int, error +# 67| Type = func(...interface { }) int, error # 67| 0: [Ident, PackageName] fmt # 67| 1: [FunctionName, Ident] Println -# 67| Type = func([]interface { }) int, error +# 67| Type = func(...interface { }) int, error # 67| 1: [Ident, VariableName] x # 67| Type = int # 68| 2: [BlockStmt] block statement @@ -296,10 +296,10 @@ input.go: # 69| 0: [CallExpr] call to Println # 69| Type = (int, error) # 69| 0: [FunctionName, SelectorExpr] selection of Println -# 69| Type = func([]interface { }) int, error +# 69| Type = func(...interface { }) int, error # 69| 0: [Ident, PackageName] fmt # 69| 1: [FunctionName, Ident] Println -# 69| Type = func([]interface { }) int, error +# 69| Type = func(...interface { }) int, error # 69| 1: [MinusExpr] -... # 69| Type = int # 69| 0: [Ident, VariableName] x @@ -454,10 +454,10 @@ input.go: # 115| 0: [CallExpr] call to Println # 115| Type = (int, error) # 115| 0: [FunctionName, SelectorExpr] selection of Println -# 115| Type = func([]interface { }) int, error +# 115| Type = func(...interface { }) int, error # 115| 0: [Ident, PackageName] fmt # 115| 1: [FunctionName, Ident] Println -# 115| Type = func([]interface { }) int, error +# 115| Type = func(...interface { }) int, error # 115| 1: [Ident, VariableName] y # 115| Type = interface { } # 116| 1: [CaseClause] case clause @@ -546,10 +546,10 @@ input.go: # 138| 0: [CallExpr] call to Print # 138| Type = (int, error) # 138| 0: [FunctionName, SelectorExpr] selection of Print -# 138| Type = func([]interface { }) int, error +# 138| Type = func(...interface { }) int, error # 138| 0: [Ident, PackageName] fmt # 138| 1: [FunctionName, Ident] Print -# 138| Type = func([]interface { }) int, error +# 138| Type = func(...interface { }) int, error # 138| 1: [Ident, VariableName] x # 138| Type = int # 141| 1: [RangeStmt] range statement @@ -564,10 +564,10 @@ input.go: # 142| 0: [CallExpr] call to Print # 142| Type = (int, error) # 142| 0: [FunctionName, SelectorExpr] selection of Print -# 142| Type = func([]interface { }) int, error +# 142| Type = func(...interface { }) int, error # 142| 0: [Ident, PackageName] fmt # 142| 1: [FunctionName, Ident] Print -# 142| Type = func([]interface { }) int, error +# 142| Type = func(...interface { }) int, error # 142| 1: [Ident, VariableName] i # 142| Type = int # 142| 2: [Ident, VariableName] v diff --git a/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/ReflectedXss.expected b/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/ReflectedXss.expected index 7cd78374940d..c4f6a2e13376 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/ReflectedXss.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/ReflectedXss.expected @@ -54,6 +54,7 @@ edges | test.go:45:22:45:31 | &... [pointer] | test.go:45:22:45:31 | &... | provenance | | | test.go:45:22:45:31 | &... [pointer] | test.go:45:22:45:31 | &... | provenance | | | test.go:45:22:45:31 | &... [pointer] | test.go:45:23:45:31 | cleanNode | provenance | | +| test.go:45:23:45:31 | cleanNode | test.go:45:22:45:31 | &... | provenance | | | test.go:45:23:45:31 | cleanNode | test.go:45:22:45:31 | &... [pointer] | provenance | | | test.go:47:6:47:15 | definition of cleanNode2 | test.go:50:22:50:32 | &... | provenance | | | test.go:47:6:47:15 | definition of cleanNode2 | test.go:50:22:50:32 | &... | provenance | | @@ -65,6 +66,7 @@ edges | test.go:50:22:50:32 | &... [pointer] | test.go:50:22:50:32 | &... | provenance | | | test.go:50:22:50:32 | &... [pointer] | test.go:50:22:50:32 | &... | provenance | | | test.go:50:22:50:32 | &... [pointer] | test.go:50:23:50:32 | cleanNode2 | provenance | | +| test.go:50:23:50:32 | cleanNode2 | test.go:50:22:50:32 | &... | provenance | | | test.go:50:23:50:32 | cleanNode2 | test.go:50:22:50:32 | &... [pointer] | provenance | | models | 1 | Summary: golang.org/x/net/html; ; false; NewTokenizer; ; ; Argument[0]; ReturnValue; taint; manual | diff --git a/go/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/go/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index 998f8c09bd02..3743e7fc4541 100644 --- a/go/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/go/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -59,8 +59,7 @@ edges | SanitizingDoubleDash.go:13:15:13:32 | array literal [array] | SanitizingDoubleDash.go:14:23:14:30 | arrayLit [array] | provenance | | | SanitizingDoubleDash.go:13:25:13:31 | tainted | SanitizingDoubleDash.go:13:15:13:32 | array literal [array] | provenance | | | SanitizingDoubleDash.go:14:23:14:30 | arrayLit [array] | SanitizingDoubleDash.go:14:23:14:33 | slice element node | provenance | | -| SanitizingDoubleDash.go:14:23:14:33 | slice element node | SanitizingDoubleDash.go:14:23:14:33 | slice expression [array] | provenance | | -| SanitizingDoubleDash.go:14:23:14:33 | slice expression [array] | SanitizingDoubleDash.go:14:23:14:33 | slice expression | provenance | | +| SanitizingDoubleDash.go:14:23:14:33 | slice element node | SanitizingDoubleDash.go:14:23:14:33 | slice expression | provenance | | | SanitizingDoubleDash.go:39:14:39:44 | []type{args} [array] | SanitizingDoubleDash.go:39:14:39:44 | call to append | provenance | MaD:3 | | SanitizingDoubleDash.go:39:14:39:44 | []type{args} [array] | SanitizingDoubleDash.go:39:14:39:44 | call to append [array] | provenance | MaD:3 | | SanitizingDoubleDash.go:39:14:39:44 | call to append | SanitizingDoubleDash.go:40:23:40:30 | arrayLit | provenance | | @@ -102,13 +101,11 @@ edges | SanitizingDoubleDash.go:95:15:95:32 | array literal [array] | SanitizingDoubleDash.go:96:24:96:31 | arrayLit [array] | provenance | | | SanitizingDoubleDash.go:95:25:95:31 | tainted | SanitizingDoubleDash.go:95:15:95:32 | array literal [array] | provenance | | | SanitizingDoubleDash.go:96:24:96:31 | arrayLit [array] | SanitizingDoubleDash.go:96:24:96:34 | slice element node | provenance | | -| SanitizingDoubleDash.go:96:24:96:34 | slice element node | SanitizingDoubleDash.go:96:24:96:34 | slice expression [array] | provenance | | -| SanitizingDoubleDash.go:96:24:96:34 | slice expression [array] | SanitizingDoubleDash.go:96:24:96:34 | slice expression | provenance | | +| SanitizingDoubleDash.go:96:24:96:34 | slice element node | SanitizingDoubleDash.go:96:24:96:34 | slice expression | provenance | | | SanitizingDoubleDash.go:100:15:100:38 | array literal [array] | SanitizingDoubleDash.go:101:24:101:31 | arrayLit [array] | provenance | | | SanitizingDoubleDash.go:100:31:100:37 | tainted | SanitizingDoubleDash.go:100:15:100:38 | array literal [array] | provenance | | | SanitizingDoubleDash.go:101:24:101:31 | arrayLit [array] | SanitizingDoubleDash.go:101:24:101:34 | slice element node | provenance | | -| SanitizingDoubleDash.go:101:24:101:34 | slice element node | SanitizingDoubleDash.go:101:24:101:34 | slice expression [array] | provenance | | -| SanitizingDoubleDash.go:101:24:101:34 | slice expression [array] | SanitizingDoubleDash.go:101:24:101:34 | slice expression | provenance | | +| SanitizingDoubleDash.go:101:24:101:34 | slice element node | SanitizingDoubleDash.go:101:24:101:34 | slice expression | provenance | | | SanitizingDoubleDash.go:105:15:105:37 | slice literal [array] | SanitizingDoubleDash.go:106:24:106:31 | arrayLit | provenance | | | SanitizingDoubleDash.go:105:30:105:36 | tainted | SanitizingDoubleDash.go:105:15:105:37 | slice literal [array] | provenance | | | SanitizingDoubleDash.go:111:14:111:44 | []type{args} [array] | SanitizingDoubleDash.go:111:14:111:44 | call to append | provenance | MaD:3 | @@ -190,7 +187,6 @@ nodes | SanitizingDoubleDash.go:14:23:14:30 | arrayLit [array] | semmle.label | arrayLit [array] | | SanitizingDoubleDash.go:14:23:14:33 | slice element node | semmle.label | slice element node | | SanitizingDoubleDash.go:14:23:14:33 | slice expression | semmle.label | slice expression | -| SanitizingDoubleDash.go:14:23:14:33 | slice expression [array] | semmle.label | slice expression [array] | | SanitizingDoubleDash.go:39:14:39:44 | []type{args} [array] | semmle.label | []type{args} [array] | | SanitizingDoubleDash.go:39:14:39:44 | call to append | semmle.label | call to append | | SanitizingDoubleDash.go:39:14:39:44 | call to append [array] | semmle.label | call to append [array] | @@ -220,13 +216,11 @@ nodes | SanitizingDoubleDash.go:96:24:96:31 | arrayLit [array] | semmle.label | arrayLit [array] | | SanitizingDoubleDash.go:96:24:96:34 | slice element node | semmle.label | slice element node | | SanitizingDoubleDash.go:96:24:96:34 | slice expression | semmle.label | slice expression | -| SanitizingDoubleDash.go:96:24:96:34 | slice expression [array] | semmle.label | slice expression [array] | | SanitizingDoubleDash.go:100:15:100:38 | array literal [array] | semmle.label | array literal [array] | | SanitizingDoubleDash.go:100:31:100:37 | tainted | semmle.label | tainted | | SanitizingDoubleDash.go:101:24:101:31 | arrayLit [array] | semmle.label | arrayLit [array] | | SanitizingDoubleDash.go:101:24:101:34 | slice element node | semmle.label | slice element node | | SanitizingDoubleDash.go:101:24:101:34 | slice expression | semmle.label | slice expression | -| SanitizingDoubleDash.go:101:24:101:34 | slice expression [array] | semmle.label | slice expression [array] | | SanitizingDoubleDash.go:105:15:105:37 | slice literal [array] | semmle.label | slice literal [array] | | SanitizingDoubleDash.go:105:30:105:36 | tainted | semmle.label | tainted | | SanitizingDoubleDash.go:106:24:106:31 | arrayLit | semmle.label | arrayLit | diff --git a/java/documentation/library-coverage/coverage.csv b/java/documentation/library-coverage/coverage.csv index d9c920f443c3..5978894130b4 100644 --- a/java/documentation/library-coverage/coverage.csv +++ b/java/documentation/library-coverage/coverage.csv @@ -233,7 +233,7 @@ org.springframework.beans,,,30,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3 org.springframework.boot.jdbc,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,, org.springframework.cache,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13 org.springframework.context,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, -org.springframework.core.io,17,,5,,,,,,,,,,,,,,,,,,,,,,,,16,,,,,,,,,1,,,,,,,,,,,,,,,5, +org.springframework.core.io,17,,6,,,,,,,,,,,,,,,,,,,,,,,,16,,,,,,,,,1,,,,,,,,,,,,,,,6, org.springframework.data.repository,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 org.springframework.http,14,,77,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,14,,,,,,,,,,,,,,,67,10 org.springframework.jdbc.core,19,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,19,,,,,,,,,,,,,, @@ -248,7 +248,7 @@ org.springframework.util,10,,142,,,,,,,,,,,,,,,,,,,,,,,,10,,,,,,,,,,,,,,,,,,,,,, org.springframework.validation,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13, org.springframework.web.client,13,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13,,,,,,,,,,,,,,3,, org.springframework.web.context.request,,8,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,8,, -org.springframework.web.multipart,,12,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,12,13, +org.springframework.web.multipart,,12,12,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,12,12, org.springframework.web.portlet,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,, org.springframework.web.reactive.function.client,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,, org.springframework.web.servlet,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,, diff --git a/java/downgrades/876cabc76c5c83912271db331481f8cba2749643/fields.ql b/java/downgrades/876cabc76c5c83912271db331481f8cba2749643/fields.ql new file mode 100644 index 000000000000..614cb9b4afe5 --- /dev/null +++ b/java/downgrades/876cabc76c5c83912271db331481f8cba2749643/fields.ql @@ -0,0 +1,15 @@ +class Field extends @field { + string toString() { none() } +} + +class Type extends @type { + string toString() { none() } +} + +class RefType extends @reftype { + string toString() { none() } +} + +from Field f, string name, Type t, RefType parent +where fields(f, name, t, parent) +select f, name, t, parent, f diff --git a/java/downgrades/876cabc76c5c83912271db331481f8cba2749643/old.dbscheme b/java/downgrades/876cabc76c5c83912271db331481f8cba2749643/old.dbscheme new file mode 100644 index 000000000000..876cabc76c5c --- /dev/null +++ b/java/downgrades/876cabc76c5c83912271db331481f8cba2749643/old.dbscheme @@ -0,0 +1,1232 @@ +/** + * 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, + int kind: int ref, + string cwd : string ref, + string name : string ref +); + +case @compilation.kind of + 1 = @javacompilation +| 2 = @kotlincompilation +; + +compilation_started( + int id : @compilation ref +) + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: 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 expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@@@someFile` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_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 +); + +/** + * For each file recorded in `compilation_compiling_files`, + * there will be a corresponding row in + * `compilation_compiling_files_completed` once extraction + * of that file is complete. The `result` will indicate the + * extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +#keyset[id, num] +compilation_compiling_files_completed( + int id : @compilation ref, + int num : int ref, + int result : int 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 +); + +/** + * The `cpu_seconds` and `elapsed_seconds` are the CPU time and elapsed + * time (respectively) that the original compilation (not the extraction) + * took for compiler invocation `id`. + */ +compilation_compiler_times( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float 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`. + * The `result` will indicate the extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref, + int result : int ref +); + +diagnostics( + unique int id: @diagnostic, + string generated_by: string ref, // TODO: Sync this with the other languages? + 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 +); + +/** + * 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 +); + +/* + * External artifacts + */ + +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +sourceLocationPrefix( + string prefix : string 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 +); + +/** + * An errortype is used when the extractor is unable to extract a type + * correctly for some reason. + */ +error_type( + unique int id: @errortype +); + +classes_or_interfaces( + unique int id: @classorinterface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @classorinterface ref +); + +file_class( + int id: @classorinterface ref +); + +class_object( + unique int id: @classorinterface ref, + unique int instance: @field ref +); + +type_companion_object( + unique int id: @classorinterface ref, + unique int instance: @field ref, + unique int companion_object: @classorinterface ref +); + +kt_nullable_types( + unique int id: @kt_nullable_type, + int classid: @reftype ref +) + +kt_notnull_types( + unique int id: @kt_notnull_type, + int classid: @reftype ref +) + +kt_type_alias( + unique int id: @kt_type_alias, + string name: string ref, + int kttypeid: @kt_type ref +) + +@kt_type = @kt_nullable_type | @kt_notnull_type + +isInterface( + unique int id: @classorinterface ref +); + +isRecord( + unique int id: @classorinterface 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 +); + +fieldsKotlinType( + unique int id: @field ref, + int kttypeid: @kt_type 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 +); + +constrsKotlinType( + unique int id: @constructor ref, + int kttypeid: @kt_type 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 +); + +methodsKotlinType( + unique int id: @method ref, + int kttypeid: @kt_type 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 +); + +paramsKotlinType( + unique int id: @param ref, + int kttypeid: @kt_type 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: @classorinterface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @classorinterface ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int parentid: @classorinterfaceorcallable 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: @classorinterfaceorcallable 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: @classorinterface 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 +); + +isCanonicalConstr( + int constructorid: @constructor 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: @classorinterface 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: @classorinterfaceorpackage 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 | @whenexpr| @stmtexpr; + +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 +| 24 = @errorstmt +| 25 = @whenbranch +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +exprsKotlinType( + unique int id: @expr ref, + int kttypeid: @kt_type 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 +| 74 = @errorexpr +| 75 = @whenexpr +| 76 = @getclassexpr +| 77 = @safecastexpr +| 78 = @implicitcastexpr +| 79 = @implicitnotnullexpr +| 80 = @implicitcoerciontounitexpr +| 81 = @notinstanceofexpr +| 82 = @stmtexpr +| 83 = @stringtemplateexpr +| 84 = @notnullexpr +| 85 = @unsafecoerceexpr +| 86 = @valueeqexpr +| 87 = @valueneexpr +| 88 = @propertyref +| 89 = @recordpatternexpr +; + +/** Holds if this `when` expression was written as an `if` expression. */ +when_if(unique int id: @whenexpr ref); + +/** Holds if this `when` branch was written as an `else` branch. */ +when_branch_else(unique int id: @whenbranch ref); + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref | @propertyref + +@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 + | @valueeqexpr + | @valueneexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr + | @notnullexpr; + +@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 +); + +propertyRefGetBinding( + unique int id: @expr ref, + int getter: @callable ref +); + +propertyRefFieldBinding( + unique int id: @expr ref, + int field: @field ref +); + +propertyRefSetBinding( + unique int id: @expr ref, + int setter: @callable ref +); + +@exprparent = @stmt | @expr | @whenbranch | @callable | @field | @fielddecl | @classorinterface | @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 +); + +localvarsKotlinType( + unique int id: @localvar ref, + int kttypeid: @kt_type 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 +); + +isNullDefaultCase( + int id: @case 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; + +@classorinterfaceorpackage = @classorinterface | @package; +@classorinterfaceorcallable = @classorinterface | @callable; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype | @errortype; +@classorarray = @classorinterface | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; + +/** A program element that has a name. */ +@element = @package | @modifier | @annotation | @errortype | + @locatableElement; + +@locatableElement = @file | @primitive | @classorinterface | @method | @constructor | @param | @exception | @field | + @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl | @kt_type | @kt_type_alias | + @kt_property; + +@modifiable = @member_modifiable| @param | @localvar | @typevariable; + +@member_modifiable = @classorinterface | @method | @constructor | @field | @kt_property; + +@member = @method | @constructor | @field | @reftype ; + +/** A program element that has a location. */ +@locatable = @typebound | @javadoc | @javadocTag | @javadocText | @xmllocatable | @ktcomment | + @locatableElement; + +@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; + +ktComments( + unique int id: @ktcomment, + int kind: int ref, + string text : string ref +) + +ktCommentSections( + unique int id: @ktcommentsection, + int comment: @ktcomment ref, + string content : string ref +) + +ktCommentSectionNames( + unique int id: @ktcommentsection ref, + string name : string ref +) + +ktCommentSectionSubjectNames( + unique int id: @ktcommentsection ref, + string subjectname : string ref +) + +#keyset[id, owner] +ktCommentOwners( + int id: @ktcomment ref, + int owner: @top ref +) + +ktExtensionFunctions( + unique int id: @method ref, + int typeid: @type ref, + int kttypeid: @kt_type ref +) + +ktProperties( + unique int id: @kt_property, + string nodeName: string ref +) + +ktPropertyGetters( + unique int id: @kt_property ref, + int getter: @method ref +) + +ktPropertySetters( + unique int id: @kt_property ref, + int setter: @method ref +) + +ktPropertyBackingFields( + unique int id: @kt_property ref, + int backingField: @field ref +) + +ktSyntheticBody( + unique int id: @callable ref, + int kind: int ref + // 1: ENUM_VALUES + // 2: ENUM_VALUEOF + // 3: ENUM_ENTRIES +) + +ktLocalFunction( + unique int id: @method ref +) + +ktInitializerAssignment( + unique int id: @assignexpr ref +) + +ktPropertyDelegates( + unique int id: @kt_property ref, + unique int variableId: @variable ref +) + +/** + * If `id` is a compiler generated element, then the kind indicates the + * reason that the compiler generated it. + * See `Element.compilerGeneratedReason()` for an explanation of what + * each `kind` means. + */ +compiler_generated( + unique int id: @element ref, + int kind: int ref +) + +ktFunctionOriginalNames( + unique int id: @method ref, + string name: string ref +) + +ktDataClasses( + unique int id: @classorinterface ref +) diff --git a/java/downgrades/876cabc76c5c83912271db331481f8cba2749643/semmlecode.dbscheme b/java/downgrades/876cabc76c5c83912271db331481f8cba2749643/semmlecode.dbscheme new file mode 100644 index 000000000000..376ce7dad793 --- /dev/null +++ b/java/downgrades/876cabc76c5c83912271db331481f8cba2749643/semmlecode.dbscheme @@ -0,0 +1,1233 @@ +/** + * 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, + int kind: int ref, + string cwd : string ref, + string name : string ref +); + +case @compilation.kind of + 1 = @javacompilation +| 2 = @kotlincompilation +; + +compilation_started( + int id : @compilation ref +) + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: 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 expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@@@someFile` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_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 +); + +/** + * For each file recorded in `compilation_compiling_files`, + * there will be a corresponding row in + * `compilation_compiling_files_completed` once extraction + * of that file is complete. The `result` will indicate the + * extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +#keyset[id, num] +compilation_compiling_files_completed( + int id : @compilation ref, + int num : int ref, + int result : int 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 +); + +/** + * The `cpu_seconds` and `elapsed_seconds` are the CPU time and elapsed + * time (respectively) that the original compilation (not the extraction) + * took for compiler invocation `id`. + */ +compilation_compiler_times( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float 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`. + * The `result` will indicate the extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref, + int result : int ref +); + +diagnostics( + unique int id: @diagnostic, + string generated_by: string ref, // TODO: Sync this with the other languages? + 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 +); + +/** + * 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 +); + +/* + * External artifacts + */ + +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +sourceLocationPrefix( + string prefix : string 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 +); + +/** + * An errortype is used when the extractor is unable to extract a type + * correctly for some reason. + */ +error_type( + unique int id: @errortype +); + +classes_or_interfaces( + unique int id: @classorinterface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @classorinterface ref +); + +file_class( + int id: @classorinterface ref +); + +class_object( + unique int id: @classorinterface ref, + unique int instance: @field ref +); + +type_companion_object( + unique int id: @classorinterface ref, + unique int instance: @field ref, + unique int companion_object: @classorinterface ref +); + +kt_nullable_types( + unique int id: @kt_nullable_type, + int classid: @reftype ref +) + +kt_notnull_types( + unique int id: @kt_notnull_type, + int classid: @reftype ref +) + +kt_type_alias( + unique int id: @kt_type_alias, + string name: string ref, + int kttypeid: @kt_type ref +) + +@kt_type = @kt_nullable_type | @kt_notnull_type + +isInterface( + unique int id: @classorinterface ref +); + +isRecord( + unique int id: @classorinterface 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 +); + +fieldsKotlinType( + unique int id: @field ref, + int kttypeid: @kt_type 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 +); + +constrsKotlinType( + unique int id: @constructor ref, + int kttypeid: @kt_type 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 +); + +methodsKotlinType( + unique int id: @method ref, + int kttypeid: @kt_type 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 +); + +paramsKotlinType( + unique int id: @param ref, + int kttypeid: @kt_type 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: @classorinterface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @classorinterface ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int parentid: @classorinterfaceorcallable 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: @classorinterfaceorcallable 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: @classorinterface 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 +); + +isCanonicalConstr( + int constructorid: @constructor 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: @classorinterface 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: @classorinterfaceorpackage 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 | @whenexpr| @stmtexpr; + +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 +| 24 = @errorstmt +| 25 = @whenbranch +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +exprsKotlinType( + unique int id: @expr ref, + int kttypeid: @kt_type 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 +| 74 = @errorexpr +| 75 = @whenexpr +| 76 = @getclassexpr +| 77 = @safecastexpr +| 78 = @implicitcastexpr +| 79 = @implicitnotnullexpr +| 80 = @implicitcoerciontounitexpr +| 81 = @notinstanceofexpr +| 82 = @stmtexpr +| 83 = @stringtemplateexpr +| 84 = @notnullexpr +| 85 = @unsafecoerceexpr +| 86 = @valueeqexpr +| 87 = @valueneexpr +| 88 = @propertyref +| 89 = @recordpatternexpr +; + +/** Holds if this `when` expression was written as an `if` expression. */ +when_if(unique int id: @whenexpr ref); + +/** Holds if this `when` branch was written as an `else` branch. */ +when_branch_else(unique int id: @whenbranch ref); + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref | @propertyref + +@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 + | @valueeqexpr + | @valueneexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr + | @notnullexpr; + +@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 +); + +propertyRefGetBinding( + unique int id: @expr ref, + int getter: @callable ref +); + +propertyRefFieldBinding( + unique int id: @expr ref, + int field: @field ref +); + +propertyRefSetBinding( + unique int id: @expr ref, + int setter: @callable ref +); + +@exprparent = @stmt | @expr | @whenbranch | @callable | @field | @fielddecl | @classorinterface | @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 +); + +localvarsKotlinType( + unique int id: @localvar ref, + int kttypeid: @kt_type 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 +); + +isNullDefaultCase( + int id: @case 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; + +@classorinterfaceorpackage = @classorinterface | @package; +@classorinterfaceorcallable = @classorinterface | @callable; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype | @errortype; +@classorarray = @classorinterface | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; + +/** A program element that has a name. */ +@element = @package | @modifier | @annotation | @errortype | + @locatableElement; + +@locatableElement = @file | @primitive | @classorinterface | @method | @constructor | @param | @exception | @field | + @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl | @kt_type | @kt_type_alias | + @kt_property; + +@modifiable = @member_modifiable| @param | @localvar | @typevariable; + +@member_modifiable = @classorinterface | @method | @constructor | @field | @kt_property; + +@member = @method | @constructor | @field | @reftype ; + +/** A program element that has a location. */ +@locatable = @typebound | @javadoc | @javadocTag | @javadocText | @xmllocatable | @ktcomment | + @locatableElement; + +@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; + +ktComments( + unique int id: @ktcomment, + int kind: int ref, + string text : string ref +) + +ktCommentSections( + unique int id: @ktcommentsection, + int comment: @ktcomment ref, + string content : string ref +) + +ktCommentSectionNames( + unique int id: @ktcommentsection ref, + string name : string ref +) + +ktCommentSectionSubjectNames( + unique int id: @ktcommentsection ref, + string subjectname : string ref +) + +#keyset[id, owner] +ktCommentOwners( + int id: @ktcomment ref, + int owner: @top ref +) + +ktExtensionFunctions( + unique int id: @method ref, + int typeid: @type ref, + int kttypeid: @kt_type ref +) + +ktProperties( + unique int id: @kt_property, + string nodeName: string ref +) + +ktPropertyGetters( + unique int id: @kt_property ref, + int getter: @method ref +) + +ktPropertySetters( + unique int id: @kt_property ref, + int setter: @method ref +) + +ktPropertyBackingFields( + unique int id: @kt_property ref, + int backingField: @field ref +) + +ktSyntheticBody( + unique int id: @callable ref, + int kind: int ref + // 1: ENUM_VALUES + // 2: ENUM_VALUEOF + // 3: ENUM_ENTRIES +) + +ktLocalFunction( + unique int id: @method ref +) + +ktInitializerAssignment( + unique int id: @assignexpr ref +) + +ktPropertyDelegates( + unique int id: @kt_property ref, + unique int variableId: @variable ref +) + +/** + * If `id` is a compiler generated element, then the kind indicates the + * reason that the compiler generated it. + * See `Element.compilerGeneratedReason()` for an explanation of what + * each `kind` means. + */ +compiler_generated( + unique int id: @element ref, + int kind: int ref +) + +ktFunctionOriginalNames( + unique int id: @method ref, + string name: string ref +) + +ktDataClasses( + unique int id: @classorinterface ref +) diff --git a/java/downgrades/876cabc76c5c83912271db331481f8cba2749643/upgrade.properties b/java/downgrades/876cabc76c5c83912271db331481f8cba2749643/upgrade.properties new file mode 100644 index 000000000000..64fe711dd701 --- /dev/null +++ b/java/downgrades/876cabc76c5c83912271db331481f8cba2749643/upgrade.properties @@ -0,0 +1,3 @@ +description: Remove fields.sourceid +compatibility: full +fields.rel: run fields.qlo diff --git a/java/kotlin-extractor/deps/kotlin-compiler-2.1.0-Beta1.jar b/java/kotlin-extractor/deps/kotlin-compiler-2.1.0-Beta1.jar new file mode 100644 index 000000000000..6d94bcd231b9 --- /dev/null +++ b/java/kotlin-extractor/deps/kotlin-compiler-2.1.0-Beta1.jar @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2ec66b3523c69b3436b8c9777707db4da86d680d6652aeda539fff7d5a84aeab +size 59837198 diff --git a/java/kotlin-extractor/deps/kotlin-compiler-embeddable-2.1.0-Beta1.jar b/java/kotlin-extractor/deps/kotlin-compiler-embeddable-2.1.0-Beta1.jar new file mode 100644 index 000000000000..b3abb08ad6e9 --- /dev/null +++ b/java/kotlin-extractor/deps/kotlin-compiler-embeddable-2.1.0-Beta1.jar @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b4581ffe576a33322fe51435a1b5ea4f4717bb6f7ce18b68106df63056e385c +size 58409745 diff --git a/java/kotlin-extractor/deps/kotlin-stdlib-2.1.0-Beta1.jar b/java/kotlin-extractor/deps/kotlin-stdlib-2.1.0-Beta1.jar new file mode 100644 index 000000000000..b517f360e216 --- /dev/null +++ b/java/kotlin-extractor/deps/kotlin-stdlib-2.1.0-Beta1.jar @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ef9c5c246cd2e7d06cd5741995753c0b697107efae40657af3010c6c6311ab2 +size 1688722 diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt index 0ca8cb4af09a..e0b020b56734 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt @@ -27,30 +27,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection -import org.jetbrains.kotlin.ir.util.companionObject -import org.jetbrains.kotlin.ir.util.constructors -import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable -import org.jetbrains.kotlin.ir.util.hasAnnotation -import org.jetbrains.kotlin.ir.util.hasInterfaceParent -import org.jetbrains.kotlin.ir.util.isAnnotationClass -import org.jetbrains.kotlin.ir.util.isAnonymousObject -import org.jetbrains.kotlin.ir.util.isFakeOverride -import org.jetbrains.kotlin.ir.util.isFunctionOrKFunction -import org.jetbrains.kotlin.ir.util.isInterface -import org.jetbrains.kotlin.ir.util.isLocal -import org.jetbrains.kotlin.ir.util.isNonCompanionObject -import org.jetbrains.kotlin.ir.util.isObject -import org.jetbrains.kotlin.ir.util.isSuspend -import org.jetbrains.kotlin.ir.util.isSuspendFunctionOrKFunction -import org.jetbrains.kotlin.ir.util.isVararg -import org.jetbrains.kotlin.ir.util.kotlinFqName -import org.jetbrains.kotlin.ir.util.packageFqName -import org.jetbrains.kotlin.ir.util.parentAsClass -import org.jetbrains.kotlin.ir.util.parentClassOrNull -import org.jetbrains.kotlin.ir.util.parents -import org.jetbrains.kotlin.ir.util.primaryConstructor -import org.jetbrains.kotlin.ir.util.render -import org.jetbrains.kotlin.ir.util.target +import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.load.java.NOT_NULL_ANNOTATIONS import org.jetbrains.kotlin.load.java.NULLABLE_ANNOTATIONS @@ -826,7 +803,7 @@ open class KotlinFileExtractor( fun exprId() = tw.getLabelFor("@\"annotationExpr;{$parent};$idx\"") return when (v) { - is IrConst<*> -> { + is CodeQLIrConst<*> -> { extractConstant(v, parent, idx, null, null, overrideId = exprId()) } is IrGetEnumValue -> { @@ -1020,7 +997,7 @@ open class KotlinFileExtractor( // here. val instance = useObjectClassInstance(c) val type = useSimpleTypeClass(c, emptyList(), false) - tw.writeFields(instance.id, instance.name, type.javaResult.id, id, instance.id) + tw.writeFields(instance.id, instance.name, type.javaResult.id, id) tw.writeFieldsKotlinType(instance.id, type.kotlinResult.id) tw.writeHasLocation(instance.id, locId) addModifiers(instance.id, "public", "static", "final") @@ -1237,8 +1214,7 @@ open class KotlinFileExtractor( instance.id, instance.name, type.javaResult.id, - parentId, - instance.id + parentId ) tw.writeFieldsKotlinType(instance.id, type.kotlinResult.id) tw.writeHasLocation(instance.id, innerLocId) @@ -2600,7 +2576,7 @@ open class KotlinFileExtractor( isStatic: Boolean ): Label { val t = useType(type) - tw.writeFields(id, name, t.javaResult.id, parentId, id) + tw.writeFields(id, name, t.javaResult.id, parentId) tw.writeFieldsKotlinType(id, t.kotlinResult.id) tw.writeHasLocation(id, locId) @@ -2757,7 +2733,7 @@ open class KotlinFileExtractor( DeclarationStackAdjuster(ee).use { val id = useEnumEntry(ee) val type = getEnumEntryType(ee) ?: return - tw.writeFields(id, ee.name.asString(), type.javaResult.id, parentId, id) + tw.writeFields(id, ee.name.asString(), type.javaResult.id, parentId) tw.writeFieldsKotlinType(id, type.kotlinResult.id) val locId = tw.getLocation(ee) tw.writeHasLocation(id, locId) @@ -5999,7 +5975,7 @@ open class KotlinFileExtractor( extractExpressionExpr(a, callable, id, i, exprParent.enclosingStmt) } } - is IrConst<*> -> { + is CodeQLIrConst<*> -> { val exprParent = parent.expr(e, callable) extractConstant( e, @@ -6211,9 +6187,9 @@ open class KotlinFileExtractor( if ( (isAndAnd || isOrOr) && e.branches.size == 2 && - (e.branches[1].condition as? IrConst<*>)?.value == true && + (e.branches[1].condition as? CodeQLIrConst<*>)?.value == true && (e.branches[if (e.origin == IrStatementOrigin.ANDAND) 1 else 0].result - as? IrConst<*>) + as? CodeQLIrConst<*>) ?.value == isOrOr ) { @@ -6869,7 +6845,7 @@ open class KotlinFileExtractor( } private fun extractConstant( - e: IrConst<*>, + e: CodeQLIrConst<*>, parent: Label, idx: Int, enclosingCallable: Label?, diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt index 3be94d65690f..03b74db19fac 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt @@ -5,7 +5,7 @@ import com.github.codeql.utils.versions.* import com.semmle.extractor.java.OdasaOutput import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.backend.common.ir.* -import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor +import org.jetbrains.kotlin.backend.jvm.ir.* import org.jetbrains.kotlin.codegen.JvmCodegenUtil import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.load.kotlin.getJvmModuleNameForDeserializedDescripto import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.NameUtils import org.jetbrains.kotlin.name.SpecialNames +import org.jetbrains.kotlin.resolve.descriptorUtil.propertyIfAccessor import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.util.OperatorNameConventions @@ -84,7 +85,7 @@ open class KotlinUsesExtractor( } private fun extractFileClass(fqName: FqName): Label { - val pkg = if (fqName.isRoot()) "" else fqName.parent().asString() + val pkg = if (fqName.codeQlIsRoot()) "" else fqName.parent().asString() val jvmName = fqName.shortName().asString() return extractFileClass(pkg, jvmName) } @@ -779,7 +780,7 @@ open class KotlinUsesExtractor( // array.length val length = tw.getLabelFor("@\"field;{$it};length\"") val intTypeIds = useType(pluginContext.irBuiltIns.intType) - tw.writeFields(length, "length", intTypeIds.javaResult.id, it, length) + tw.writeFields(length, "length", intTypeIds.javaResult.id, it) tw.writeFieldsKotlinType(length, intTypeIds.kotlinResult.id) addModifiers(length, "public", "final") @@ -906,7 +907,7 @@ open class KotlinUsesExtractor( return arrayInfo.componentTypeResults } owner is IrClass -> { - val args = if (s.isRawType()) null else s.arguments + val args = if (s.codeQlIsRawType()) null else s.arguments return useSimpleTypeClass(owner, args, s.isNullable()) } @@ -1232,9 +1233,10 @@ open class KotlinUsesExtractor( // false if it has `@JvmSuppressWildcards(false)`, // and null if the annotation is not present. @Suppress("UNCHECKED_CAST") - private fun getWildcardSuppressionDirective(t: IrAnnotationContainer) = + private fun getWildcardSuppressionDirective(t: IrAnnotationContainer): Boolean? = t.getAnnotation(jvmWildcardSuppressionAnnotation)?.let { - (it.getValueArgument(0) as? IrConst)?.value ?: true + @Suppress("USELESS_CAST") // `as? Boolean` is not needed for Kotlin < 2.1 + (it.getValueArgument(0) as? CodeQLIrConst)?.value as? Boolean ?: true } private fun addJavaLoweringArgumentWildcards( diff --git a/java/kotlin-extractor/src/main/kotlin/MetaAnnotationSupport.kt b/java/kotlin-extractor/src/main/kotlin/MetaAnnotationSupport.kt index 2dc7382bf166..e591eed3eca6 100644 --- a/java/kotlin-extractor/src/main/kotlin/MetaAnnotationSupport.kt +++ b/java/kotlin-extractor/src/main/kotlin/MetaAnnotationSupport.kt @@ -27,13 +27,7 @@ import org.jetbrains.kotlin.ir.expressions.IrClassReference import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.expressions.IrGetEnumValue import org.jetbrains.kotlin.ir.expressions.IrVararg -import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrGetEnumValueImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl +import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.util.constructedClass diff --git a/java/kotlin-extractor/src/main/kotlin/utils/JvmNames.kt b/java/kotlin-extractor/src/main/kotlin/utils/JvmNames.kt index b6b51fde5430..ec7c17b39fc6 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/JvmNames.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/JvmNames.kt @@ -1,12 +1,12 @@ package com.github.codeql.utils import com.github.codeql.utils.versions.allOverriddenIncludingSelf +import com.github.codeql.utils.versions.CodeQLIrConst import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction -import org.jetbrains.kotlin.ir.expressions.IrConst import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable @@ -82,7 +82,7 @@ fun getJvmName(container: IrAnnotationContainer): String? { if (owner is IrClass) { val aPkg = owner.packageFqName?.asString() val name = owner.name.asString() - if (aPkg == "kotlin.jvm" && name == "JvmName" && v is IrConst<*>) { + if (aPkg == "kotlin.jvm" && name == "JvmName" && v is CodeQLIrConst<*>) { val value = v.value if (value is String) { return value diff --git a/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt b/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt index 91cd5ec9f13d..6f8d0d33f373 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/TypeSubstitution.kt @@ -15,7 +15,7 @@ import org.jetbrains.kotlin.ir.declarations.IrTypeParametersContainer import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl import org.jetbrains.kotlin.ir.expressions.IrConstructorCall -import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl +import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol import org.jetbrains.kotlin.ir.types.* diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_5_0/CodeQLIrConst.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_5_0/CodeQLIrConst.kt new file mode 100644 index 000000000000..0f8f6bda71ae --- /dev/null +++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_5_0/CodeQLIrConst.kt @@ -0,0 +1,5 @@ +package com.github.codeql.utils.versions + +import org.jetbrains.kotlin.ir.expressions.IrConst + +typealias CodeQLIrConst = IrConst diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_5_0/CodeQLIsRoot.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_5_0/CodeQLIsRoot.kt new file mode 100644 index 000000000000..bf523ca88215 --- /dev/null +++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_5_0/CodeQLIsRoot.kt @@ -0,0 +1,5 @@ +package com.github.codeql.utils.versions + +import org.jetbrains.kotlin.name.FqName + +fun FqName.codeQlIsRoot() = this.isRoot() diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_5_0/Types.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_5_0/Types.kt index 630d649907ca..61a580e2a279 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_5_0/Types.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_5_0/Types.kt @@ -3,4 +3,4 @@ package com.github.codeql.utils.versions import org.jetbrains.kotlin.backend.jvm.codegen.isRawType import org.jetbrains.kotlin.ir.types.IrSimpleType -fun IrSimpleType.isRawType() = this.isRawType() +fun IrSimpleType.codeQlIsRawType() = this.isRawType() diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_6_20/Types.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_6_20/Types.kt index d44e44074005..7db5d520b29f 100644 --- a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_6_20/Types.kt +++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_6_20/Types.kt @@ -3,4 +3,4 @@ package com.github.codeql.utils.versions import org.jetbrains.kotlin.backend.jvm.ir.isRawType import org.jetbrains.kotlin.ir.types.IrSimpleType -fun IrSimpleType.isRawType() = this.isRawType() +fun IrSimpleType.codeQlIsRawType() = this.isRawType() diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_2_1_0-Beta1/CodeQLIrConst.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_2_1_0-Beta1/CodeQLIrConst.kt new file mode 100644 index 000000000000..60ff588cd97f --- /dev/null +++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_2_1_0-Beta1/CodeQLIrConst.kt @@ -0,0 +1,5 @@ +package com.github.codeql.utils.versions + +import org.jetbrains.kotlin.ir.expressions.IrConst + +typealias CodeQLIrConst = IrConst diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_2_1_0-Beta1/CodeQLIsRoot.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_2_1_0-Beta1/CodeQLIsRoot.kt new file mode 100644 index 000000000000..e8eff805f21a --- /dev/null +++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_2_1_0-Beta1/CodeQLIsRoot.kt @@ -0,0 +1,5 @@ +package com.github.codeql.utils.versions + +import org.jetbrains.kotlin.name.FqName + +fun FqName.codeQlIsRoot() = this.isRoot diff --git a/java/kotlin-extractor/versions.bzl b/java/kotlin-extractor/versions.bzl index e124d6e150a7..aecb170b6304 100644 --- a/java/kotlin-extractor/versions.bzl +++ b/java/kotlin-extractor/versions.bzl @@ -13,6 +13,7 @@ VERSIONS = [ "1.9.20-Beta", "2.0.0-RC1", "2.0.20-Beta2", + "2.1.0-Beta1", ] def _version_to_tuple(v): diff --git a/java/ql/integration-tests/kotlin/all-platforms/diagnostics/kotlin-version-too-new/diagnostics.expected b/java/ql/integration-tests/kotlin/all-platforms/diagnostics/kotlin-version-too-new/diagnostics.expected index 4f7b421d600c..401eaa6ee9d1 100644 --- a/java/ql/integration-tests/kotlin/all-platforms/diagnostics/kotlin-version-too-new/diagnostics.expected +++ b/java/ql/integration-tests/kotlin/all-platforms/diagnostics/kotlin-version-too-new/diagnostics.expected @@ -1,5 +1,5 @@ { - "markdownMessage": "The Kotlin version installed (`999.999.999`) is too recent for this version of CodeQL. Install a version lower than 2.0.30.", + "markdownMessage": "The Kotlin version installed (`999.999.999`) is too recent for this version of CodeQL. Install a version lower than 2.1.10.", "severity": "error", "source": { "extractorName": "java", diff --git a/java/ql/lib/change-notes/2024-09-18-fields.md b/java/ql/lib/change-notes/2024-09-18-fields.md new file mode 100644 index 000000000000..d2367bf2b04e --- /dev/null +++ b/java/ql/lib/change-notes/2024-09-18-fields.md @@ -0,0 +1,5 @@ +--- +category: deprecated +--- +* The `Field.getSourceDeclaration()` predicate has been deprecated. The result was always the original field, so calls to it can simply be removed. +* The `Field.isSourceDeclaration()` predicate has been deprecated. It always holds. diff --git a/java/ql/lib/change-notes/2024-09-20-kotlin-2.1.0.md b/java/ql/lib/change-notes/2024-09-20-kotlin-2.1.0.md new file mode 100644 index 000000000000..f9b19e63d320 --- /dev/null +++ b/java/ql/lib/change-notes/2024-09-20-kotlin-2.1.0.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* Kotlin versions up to 2.1.0\ *x* are now supported. diff --git a/java/ql/lib/change-notes/2024-09-25-java-23.md b/java/ql/lib/change-notes/2024-09-25-java-23.md new file mode 100644 index 000000000000..cc620c54d6e7 --- /dev/null +++ b/java/ql/lib/change-notes/2024-09-25-java-23.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* The Java extractor and QL libraries now support Java 23. diff --git a/java/ql/lib/config/semmlecode.dbscheme b/java/ql/lib/config/semmlecode.dbscheme index 376ce7dad793..876cabc76c5c 100644 --- a/java/ql/lib/config/semmlecode.dbscheme +++ b/java/ql/lib/config/semmlecode.dbscheme @@ -392,8 +392,7 @@ fields( unique int id: @field, string nodeName: string ref, int typeid: @type ref, - int parentid: @reftype ref, - int sourceid: @field ref + int parentid: @reftype ref ); fieldsKotlinType( diff --git a/java/ql/lib/config/semmlecode.dbscheme.stats b/java/ql/lib/config/semmlecode.dbscheme.stats index 0a89bd2d1ec0..18f6ac5b4a85 100644 --- a/java/ql/lib/config/semmlecode.dbscheme.stats +++ b/java/ql/lib/config/semmlecode.dbscheme.stats @@ -9197,10 +9197,6 @@ parentid 249278 - - sourceid - 2886451 - @@ -9251,22 +9247,6 @@ - - id - sourceid - - - 12 - - - 1 - 2 - 2886451 - - - - - nodeName id @@ -9330,27 +9310,6 @@ - - nodeName - sourceid - - - 12 - - - 1 - 2 - 2356342 - - - 2 - 302 - 152116 - - - - - typeid id @@ -9449,42 +9408,6 @@ - - typeid - sourceid - - - 12 - - - 1 - 2 - 124952 - - - 2 - 3 - 21104 - - - 3 - 4 - 10447 - - - 4 - 8 - 14835 - - - 8 - 9650 - 11283 - - - - - parentid id @@ -9633,126 +9556,6 @@ - - parentid - sourceid - - - 12 - - - 1 - 2 - 115132 - - - 2 - 3 - 25074 - - - 3 - 4 - 20477 - - - 4 - 5 - 15253 - - - 5 - 6 - 12328 - - - 6 - 8 - 18387 - - - 8 - 14 - 19641 - - - 14 - 93 - 18805 - - - 95 - 1772 - 4179 - - - - - - - sourceid - id - - - 12 - - - 1 - 2 - 2886451 - - - - - - - sourceid - nodeName - - - 12 - - - 1 - 2 - 2886451 - - - - - - - sourceid - typeid - - - 12 - - - 1 - 2 - 2886451 - - - - - - - sourceid - parentid - - - 12 - - - 1 - 2 - 2886451 - - - - - diff --git a/java/ql/lib/definitions.qll b/java/ql/lib/definitions.qll index e4b93f6f7e14..aa5de3eb4019 100644 --- a/java/ql/lib/definitions.qll +++ b/java/ql/lib/definitions.qll @@ -159,7 +159,7 @@ private Element definition(Element e, string kind) { e.(TypeAccess).getType().(RefType).getSourceDeclaration() = result and kind = "T" or exists(Variable v | v = e.(VarAccess).getVariable() | - result = v.(Field).getSourceDeclaration() or + result = v.(Field) or result = v.(Parameter).getSourceDeclaration() or result = v.(LocalVariableDecl) ) and diff --git a/java/ql/lib/semmle/code/Location.qll b/java/ql/lib/semmle/code/Location.qll index 1a6ddc737289..abc1d19d0f89 100644 --- a/java/ql/lib/semmle/code/Location.qll +++ b/java/ql/lib/semmle/code/Location.qll @@ -18,7 +18,7 @@ predicate hasName(Element e, string name) { or methods(e, name, _, _, _, _) or - fields(e, name, _, _, _) + fields(e, name, _, _) or packages(e, name) or diff --git a/java/ql/lib/semmle/code/java/Dependency.qll b/java/ql/lib/semmle/code/java/Dependency.qll index 29dc81a19600..8514bcb466a1 100644 --- a/java/ql/lib/semmle/code/java/Dependency.qll +++ b/java/ql/lib/semmle/code/java/Dependency.qll @@ -52,7 +52,7 @@ predicate depends(RefType t, RefType dep) { or // the declaring type of a field accessed in `t`, exists(Field f | f.getAnAccess().getEnclosingCallable().getDeclaringType() = t | - usesType(f.getSourceDeclaration().getDeclaringType(), dep) + usesType(f.getDeclaringType(), dep) ) or // the type of a local variable declared in `t`, diff --git a/java/ql/lib/semmle/code/java/DependencyCounts.qll b/java/ql/lib/semmle/code/java/DependencyCounts.qll index 464f88471884..4cb958373a93 100644 --- a/java/ql/lib/semmle/code/java/DependencyCounts.qll +++ b/java/ql/lib/semmle/code/java/DependencyCounts.qll @@ -64,7 +64,7 @@ predicate numDepends(RefType t, RefType dep, int value) { elem = fa and fa.getEnclosingCallable().getDeclaringType() = t | - usesType(fa.getField().getSourceDeclaration().getDeclaringType(), dep) + usesType(fa.getField().getDeclaringType(), dep) ) or // the type of a local variable declared in `t`, diff --git a/java/ql/lib/semmle/code/java/Element.qll b/java/ql/lib/semmle/code/java/Element.qll index 493bf7cec0ff..2032d72ee5f9 100644 --- a/java/ql/lib/semmle/code/java/Element.qll +++ b/java/ql/lib/semmle/code/java/Element.qll @@ -115,7 +115,7 @@ private predicate hasChildElement(Element parent, Element e) { or params(e, _, _, parent, _) or - fields(e, _, _, parent, _) + fields(e, _, _, parent) or typeVars(e, _, _, parent) } diff --git a/java/ql/lib/semmle/code/java/Member.qll b/java/ql/lib/semmle/code/java/Member.qll index 7c625ae48c61..f6f4ca56f92d 100644 --- a/java/ql/lib/semmle/code/java/Member.qll +++ b/java/ql/lib/semmle/code/java/Member.qll @@ -756,13 +756,13 @@ class FieldDeclaration extends ExprParent, @fielddecl, Annotatable { /** A class or instance field. */ class Field extends Member, ExprParent, @field, Variable { /** Gets the declared type of this field. */ - override Type getType() { fields(this, _, result, _, _) } + override Type getType() { fields(this, _, result, _) } /** Gets the Kotlin type of this field. */ override KotlinType getKotlinType() { fieldsKotlinType(this, result) } /** Gets the type in which this field is declared. */ - override RefType getDeclaringType() { fields(this, _, _, result, _) } + override RefType getDeclaringType() { fields(this, _, _, result) } /** * Gets the field declaration in which this field is declared. @@ -794,18 +794,12 @@ class Field extends Member, ExprParent, @field, Variable { } /** - * Gets the source declaration of this field. - * - * For fields that are members of a parameterized - * instance of a generic type, the source declaration is the - * corresponding field in the generic type. - * - * For all other fields, the source declaration is the field itself. + * DEPRECATED: The result is always `this`. */ - Field getSourceDeclaration() { fields(this, _, _, _, result) } + deprecated Field getSourceDeclaration() { result = this } - /** Holds if this field is the same as its source declaration. */ - predicate isSourceDeclaration() { this.getSourceDeclaration() = this } + /** DEPRECATED: This always holds. */ + deprecated predicate isSourceDeclaration() { any() } override predicate isPublic() { Member.super.isPublic() diff --git a/java/ql/lib/semmle/code/java/Type.qll b/java/ql/lib/semmle/code/java/Type.qll index f2709d3dda1a..5036bbea6224 100644 --- a/java/ql/lib/semmle/code/java/Type.qll +++ b/java/ql/lib/semmle/code/java/Type.qll @@ -324,7 +324,7 @@ predicate declaresMember(Type t, @member m) { or constrs(m, _, _, _, t, _) or - fields(m, _, _, t, _) + fields(m, _, _, t) or enclInReftype(m, t) and // Since the type `@member` in the dbscheme includes all `@reftype`s, @@ -1195,12 +1195,10 @@ class EnumType extends Class { EnumType() { isEnumType(this) } /** Gets the enum constant with the specified name. */ - EnumConstant getEnumConstant(string name) { - fields(result, _, _, this, _) and result.hasName(name) - } + EnumConstant getEnumConstant(string name) { fields(result, _, _, this) and result.hasName(name) } /** Gets an enum constant declared in this enum type. */ - EnumConstant getAnEnumConstant() { fields(result, _, _, this, _) } + EnumConstant getAnEnumConstant() { fields(result, _, _, this) } override predicate isFinal() { // JLS 8.9: An enum declaration is implicitly `final` unless it contains diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl1.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl1.qll index 359fa71744b4..ce964917e970 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl1.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl1.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 359fa71744b4..ce964917e970 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 359fa71744b4..ce964917e970 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 359fa71744b4..ce964917e970 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 359fa71744b4..ce964917e970 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll index 359fa71744b4..ce964917e970 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll index 784d248d8dce..589d75c3635d 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll @@ -760,7 +760,7 @@ ContentApprox getContentApprox(Content c) { /** * Holds if the the content `c` is a container. */ -predicate containerContent(Content c) { +predicate containerContent(ContentSet c) { c instanceof ArrayContent or c instanceof CollectionContent or c instanceof MapKeyContent or diff --git a/java/ql/lib/semmle/code/java/security/AndroidIntentRedirectionQuery.qll b/java/ql/lib/semmle/code/java/security/AndroidIntentRedirectionQuery.qll index b179a4f92e07..0943fe8feaf7 100644 --- a/java/ql/lib/semmle/code/java/security/AndroidIntentRedirectionQuery.qll +++ b/java/ql/lib/semmle/code/java/security/AndroidIntentRedirectionQuery.qll @@ -18,6 +18,8 @@ module IntentRedirectionConfig implements DataFlow::ConfigSig { predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { any(IntentRedirectionAdditionalTaintStep c).step(node1, node2) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** Tracks the flow of tainted Intents being used to start Android components. */ diff --git a/java/ql/lib/semmle/code/java/security/ExternallyControlledFormatStringQuery.qll b/java/ql/lib/semmle/code/java/security/ExternallyControlledFormatStringQuery.qll index 606e31a07cb7..4c8639010e2c 100644 --- a/java/ql/lib/semmle/code/java/security/ExternallyControlledFormatStringQuery.qll +++ b/java/ql/lib/semmle/code/java/security/ExternallyControlledFormatStringQuery.qll @@ -23,6 +23,8 @@ module ExternallyControlledFormatStringConfig implements DataFlow::ConfigSig { predicate isBarrier(DataFlow::Node node) { node.getType() instanceof NumericType or node.getType() instanceof BooleanType } + + predicate observeDiffInformedIncrementalMode() { any() } } /** diff --git a/java/ql/lib/semmle/code/java/security/FragmentInjectionQuery.qll b/java/ql/lib/semmle/code/java/security/FragmentInjectionQuery.qll index f625807470df..b2ab5464e235 100644 --- a/java/ql/lib/semmle/code/java/security/FragmentInjectionQuery.qll +++ b/java/ql/lib/semmle/code/java/security/FragmentInjectionQuery.qll @@ -17,6 +17,8 @@ module FragmentInjectionTaintConfig implements DataFlow::ConfigSig { predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) { any(FragmentInjectionAdditionalTaintStep c).step(n1, n2) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** diff --git a/java/ql/lib/semmle/code/java/security/GroovyInjectionQuery.qll b/java/ql/lib/semmle/code/java/security/GroovyInjectionQuery.qll index 3af836cac97a..8151755f69fc 100644 --- a/java/ql/lib/semmle/code/java/security/GroovyInjectionQuery.qll +++ b/java/ql/lib/semmle/code/java/security/GroovyInjectionQuery.qll @@ -17,6 +17,8 @@ module GroovyInjectionConfig implements DataFlow::ConfigSig { predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) { any(GroovyInjectionAdditionalTaintStep c).step(fromNode, toNode) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** diff --git a/java/ql/lib/semmle/code/java/security/ImplicitPendingIntentsQuery.qll b/java/ql/lib/semmle/code/java/security/ImplicitPendingIntentsQuery.qll index 0a8e0686549d..a57f643d8176 100644 --- a/java/ql/lib/semmle/code/java/security/ImplicitPendingIntentsQuery.qll +++ b/java/ql/lib/semmle/code/java/security/ImplicitPendingIntentsQuery.qll @@ -48,6 +48,8 @@ module ImplicitPendingIntentStartConfig implements DataFlow::StateConfigSig { node.getType().(Array).getElementType() instanceof TypeIntent and c instanceof DataFlow::ArrayContent } + + predicate observeDiffInformedIncrementalMode() { any() } } module ImplicitPendingIntentStartFlow = diff --git a/java/ql/lib/semmle/code/java/security/InsecureBeanValidationQuery.qll b/java/ql/lib/semmle/code/java/security/InsecureBeanValidationQuery.qll index 1ad0677ca615..be42e09a1cce 100644 --- a/java/ql/lib/semmle/code/java/security/InsecureBeanValidationQuery.qll +++ b/java/ql/lib/semmle/code/java/security/InsecureBeanValidationQuery.qll @@ -49,6 +49,8 @@ module BeanValidationConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof ThreatModelFlowSource } predicate isSink(DataFlow::Node sink) { sink instanceof BeanValidationSink } + + predicate observeDiffInformedIncrementalMode() { any() } } /** Tracks flow from user input to the argument of a method that builds constraint error messages. */ diff --git a/java/ql/lib/semmle/code/java/security/InsecureLdapAuthQuery.qll b/java/ql/lib/semmle/code/java/security/InsecureLdapAuthQuery.qll index 498a9401071a..94d80b9b37b0 100644 --- a/java/ql/lib/semmle/code/java/security/InsecureLdapAuthQuery.qll +++ b/java/ql/lib/semmle/code/java/security/InsecureLdapAuthQuery.qll @@ -22,6 +22,8 @@ module InsecureLdapUrlConfig implements DataFlow::ConfigSig { succ.asExpr() = ma.getQualifier() ) } + + predicate observeDiffInformedIncrementalMode() { any() } } module InsecureLdapUrlFlow = TaintTracking::Global; diff --git a/java/ql/lib/semmle/code/java/security/InsecureRandomnessQuery.qll b/java/ql/lib/semmle/code/java/security/InsecureRandomnessQuery.qll index 423046b6746e..77da25d35866 100644 --- a/java/ql/lib/semmle/code/java/security/InsecureRandomnessQuery.qll +++ b/java/ql/lib/semmle/code/java/security/InsecureRandomnessQuery.qll @@ -96,6 +96,8 @@ module InsecureRandomnessConfig implements DataFlow::ConfigSig { n2.asExpr() = c ) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** diff --git a/java/ql/lib/semmle/code/java/security/InsufficientKeySizeQuery.qll b/java/ql/lib/semmle/code/java/security/InsufficientKeySizeQuery.qll index e08cd50cdb3f..876b2efd8409 100644 --- a/java/ql/lib/semmle/code/java/security/InsufficientKeySizeQuery.qll +++ b/java/ql/lib/semmle/code/java/security/InsufficientKeySizeQuery.qll @@ -16,6 +16,8 @@ module KeySizeConfig implements DataFlow::StateConfigSig { predicate isSink(DataFlow::Node sink, KeySizeState state) { sink.(InsufficientKeySizeSink).hasState(state) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** Tracks key sizes used in cryptographic algorithms. */ diff --git a/java/ql/lib/semmle/code/java/security/IntentUriPermissionManipulationQuery.qll b/java/ql/lib/semmle/code/java/security/IntentUriPermissionManipulationQuery.qll index 740ce24bf62b..855694b299b6 100644 --- a/java/ql/lib/semmle/code/java/security/IntentUriPermissionManipulationQuery.qll +++ b/java/ql/lib/semmle/code/java/security/IntentUriPermissionManipulationQuery.qll @@ -23,6 +23,8 @@ module IntentUriPermissionManipulationConfig implements DataFlow::ConfigSig { predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { any(IntentUriPermissionManipulationAdditionalTaintStep c).step(node1, node2) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** diff --git a/java/ql/lib/semmle/code/java/security/JexlInjectionQuery.qll b/java/ql/lib/semmle/code/java/security/JexlInjectionQuery.qll index de49560e7792..bf87df361b3c 100644 --- a/java/ql/lib/semmle/code/java/security/JexlInjectionQuery.qll +++ b/java/ql/lib/semmle/code/java/security/JexlInjectionQuery.qll @@ -51,6 +51,8 @@ module JexlInjectionConfig implements DataFlow::ConfigSig { predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { any(JexlInjectionAdditionalTaintStep c).step(node1, node2) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** diff --git a/java/ql/lib/semmle/code/java/security/JndiInjectionQuery.qll b/java/ql/lib/semmle/code/java/security/JndiInjectionQuery.qll index 3c1f4b8e68eb..167d56732cd3 100644 --- a/java/ql/lib/semmle/code/java/security/JndiInjectionQuery.qll +++ b/java/ql/lib/semmle/code/java/security/JndiInjectionQuery.qll @@ -23,6 +23,8 @@ module JndiInjectionFlowConfig implements DataFlow::ConfigSig { predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { any(JndiInjectionAdditionalTaintStep c).step(node1, node2) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** Tracks flow of unvalidated user input that is used in JNDI lookup */ diff --git a/java/ql/lib/semmle/code/java/security/LdapInjectionQuery.qll b/java/ql/lib/semmle/code/java/security/LdapInjectionQuery.qll index 5c055c005167..b6daea4b4738 100644 --- a/java/ql/lib/semmle/code/java/security/LdapInjectionQuery.qll +++ b/java/ql/lib/semmle/code/java/security/LdapInjectionQuery.qll @@ -17,6 +17,8 @@ module LdapInjectionFlowConfig implements DataFlow::ConfigSig { predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) { any(LdapInjectionAdditionalTaintStep a).step(pred, succ) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** Tracks flow from remote sources to LDAP injection vulnerabilities. */ diff --git a/java/ql/lib/semmle/code/java/security/MissingJWTSignatureCheckQuery.qll b/java/ql/lib/semmle/code/java/security/MissingJWTSignatureCheckQuery.qll index eaa4c6320c1d..4f1f614dbc42 100644 --- a/java/ql/lib/semmle/code/java/security/MissingJWTSignatureCheckQuery.qll +++ b/java/ql/lib/semmle/code/java/security/MissingJWTSignatureCheckQuery.qll @@ -16,6 +16,8 @@ module MissingJwtSignatureCheckConfig implements DataFlow::ConfigSig { predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { any(JwtParserWithInsecureParseAdditionalFlowStep c).step(node1, node2) } + + predicate observeDiffInformedIncrementalMode() { any() } } module MissingJwtSignatureCheckFlow = DataFlow::Global; diff --git a/java/ql/lib/semmle/code/java/security/MvelInjectionQuery.qll b/java/ql/lib/semmle/code/java/security/MvelInjectionQuery.qll index 4bf81804f827..da5bcb6931bc 100644 --- a/java/ql/lib/semmle/code/java/security/MvelInjectionQuery.qll +++ b/java/ql/lib/semmle/code/java/security/MvelInjectionQuery.qll @@ -19,6 +19,8 @@ module MvelInjectionFlowConfig implements DataFlow::ConfigSig { predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { any(MvelInjectionAdditionalTaintStep c).step(node1, node2) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** Tracks flow of unsafe user input that is used to construct and evaluate a MVEL expression. */ diff --git a/java/ql/lib/semmle/code/java/security/NumericCastTaintedQuery.qll b/java/ql/lib/semmle/code/java/security/NumericCastTaintedQuery.qll index b6bd505c38b8..2dd3cf89add5 100644 --- a/java/ql/lib/semmle/code/java/security/NumericCastTaintedQuery.qll +++ b/java/ql/lib/semmle/code/java/security/NumericCastTaintedQuery.qll @@ -102,6 +102,8 @@ module NumericCastFlowConfig implements DataFlow::ConfigSig { } predicate isBarrierIn(DataFlow::Node node) { isSource(node) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** diff --git a/java/ql/lib/semmle/code/java/security/OgnlInjectionQuery.qll b/java/ql/lib/semmle/code/java/security/OgnlInjectionQuery.qll index 3acf18c453ce..a25b257574b6 100644 --- a/java/ql/lib/semmle/code/java/security/OgnlInjectionQuery.qll +++ b/java/ql/lib/semmle/code/java/security/OgnlInjectionQuery.qll @@ -18,6 +18,8 @@ module OgnlInjectionFlowConfig implements DataFlow::ConfigSig { predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { any(OgnlInjectionAdditionalTaintStep c).step(node1, node2) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** Tracks flow of unvalidated user input that is used in OGNL EL evaluation. */ diff --git a/java/ql/lib/semmle/code/java/security/PartialPathTraversalQuery.qll b/java/ql/lib/semmle/code/java/security/PartialPathTraversalQuery.qll index c4c3e6b093cb..e4d2d60b92e9 100644 --- a/java/ql/lib/semmle/code/java/security/PartialPathTraversalQuery.qll +++ b/java/ql/lib/semmle/code/java/security/PartialPathTraversalQuery.qll @@ -17,6 +17,8 @@ module PartialPathTraversalFromRemoteConfig implements DataFlow::ConfigSig { predicate isSink(DataFlow::Node node) { any(PartialPathTraversalMethodCall ma).getQualifier() = node.asExpr() } + + predicate observeDiffInformedIncrementalMode() { any() } } /** Tracks flow of unsafe user input that is used to validate against path traversal, but is insufficient and remains vulnerable to Partial Path Traversal. */ diff --git a/java/ql/lib/semmle/code/java/security/RequestForgeryConfig.qll b/java/ql/lib/semmle/code/java/security/RequestForgeryConfig.qll index e8415cc19786..f929e97a8ff3 100644 --- a/java/ql/lib/semmle/code/java/security/RequestForgeryConfig.qll +++ b/java/ql/lib/semmle/code/java/security/RequestForgeryConfig.qll @@ -28,6 +28,8 @@ module RequestForgeryConfig implements DataFlow::ConfigSig { predicate isBarrier(DataFlow::Node node) { node instanceof RequestForgerySanitizer } predicate isBarrierIn(DataFlow::Node node) { isSource(node) } + + predicate observeDiffInformedIncrementalMode() { any() } } module RequestForgeryFlow = TaintTracking::Global; diff --git a/java/ql/lib/semmle/code/java/security/ResponseSplittingQuery.qll b/java/ql/lib/semmle/code/java/security/ResponseSplittingQuery.qll index 40e1ec1b4dbb..7c43d32a407e 100644 --- a/java/ql/lib/semmle/code/java/security/ResponseSplittingQuery.qll +++ b/java/ql/lib/semmle/code/java/security/ResponseSplittingQuery.qll @@ -31,6 +31,8 @@ module ResponseSplittingConfig implements DataFlow::ConfigSig { ) ) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** diff --git a/java/ql/lib/semmle/code/java/security/RsaWithoutOaepQuery.qll b/java/ql/lib/semmle/code/java/security/RsaWithoutOaepQuery.qll index 66e4a0537d2c..8fed05f2186b 100644 --- a/java/ql/lib/semmle/code/java/security/RsaWithoutOaepQuery.qll +++ b/java/ql/lib/semmle/code/java/security/RsaWithoutOaepQuery.qll @@ -20,6 +20,8 @@ module RsaWithoutOaepConfig implements DataFlow::ConfigSig { predicate isSink(DataFlow::Node sink) { exists(CryptoAlgoSpec cr | sink.asExpr() = cr.getAlgoSpec()) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** Flow for finding RSA ciphers initialized without using OAEP padding. */ diff --git a/java/ql/lib/semmle/code/java/security/SpelInjectionQuery.qll b/java/ql/lib/semmle/code/java/security/SpelInjectionQuery.qll index 848aae8da30a..55e8eb94f83f 100644 --- a/java/ql/lib/semmle/code/java/security/SpelInjectionQuery.qll +++ b/java/ql/lib/semmle/code/java/security/SpelInjectionQuery.qll @@ -18,6 +18,8 @@ module SpelInjectionConfig implements DataFlow::ConfigSig { predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { any(SpelExpressionInjectionAdditionalTaintStep c).step(node1, node2) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** Tracks flow of unsafe user input that is used to construct and evaluate a SpEL expression. */ diff --git a/java/ql/lib/semmle/code/java/security/StaticInitializationVectorQuery.qll b/java/ql/lib/semmle/code/java/security/StaticInitializationVectorQuery.qll index 9ba848d1e0df..282133ec5c67 100644 --- a/java/ql/lib/semmle/code/java/security/StaticInitializationVectorQuery.qll +++ b/java/ql/lib/semmle/code/java/security/StaticInitializationVectorQuery.qll @@ -126,6 +126,8 @@ module StaticInitializationVectorConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof StaticInitializationVectorSource } predicate isSink(DataFlow::Node sink) { sink instanceof EncryptionInitializationSink } + + predicate observeDiffInformedIncrementalMode() { any() } } /** Tracks the flow from a static initialization vector to the initialization of a cipher */ diff --git a/java/ql/lib/semmle/code/java/security/TaintedPathQuery.qll b/java/ql/lib/semmle/code/java/security/TaintedPathQuery.qll index c396b48a7b88..6be7b4dc83fb 100644 --- a/java/ql/lib/semmle/code/java/security/TaintedPathQuery.qll +++ b/java/ql/lib/semmle/code/java/security/TaintedPathQuery.qll @@ -72,6 +72,8 @@ module TaintedPathConfig implements DataFlow::ConfigSig { predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) { any(TaintedPathAdditionalTaintStep s).step(n1, n2) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** Tracks flow from remote sources to the creation of a path. */ diff --git a/java/ql/lib/semmle/code/java/security/TemplateInjectionQuery.qll b/java/ql/lib/semmle/code/java/security/TemplateInjectionQuery.qll index a9595b0f6f19..536c8f33dafb 100644 --- a/java/ql/lib/semmle/code/java/security/TemplateInjectionQuery.qll +++ b/java/ql/lib/semmle/code/java/security/TemplateInjectionQuery.qll @@ -16,6 +16,8 @@ module TemplateInjectionFlowConfig implements DataFlow::ConfigSig { predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { any(TemplateInjectionAdditionalTaintStep a).isAdditionalTaintStep(node1, node2) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** Tracks server-side template injection (SST) vulnerabilities */ diff --git a/java/ql/lib/semmle/code/java/security/UnsafeContentUriResolutionQuery.qll b/java/ql/lib/semmle/code/java/security/UnsafeContentUriResolutionQuery.qll index db629143d5ce..8c214d59b9eb 100644 --- a/java/ql/lib/semmle/code/java/security/UnsafeContentUriResolutionQuery.qll +++ b/java/ql/lib/semmle/code/java/security/UnsafeContentUriResolutionQuery.qll @@ -20,6 +20,8 @@ module UnsafeContentResolutionConfig implements DataFlow::ConfigSig { predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { any(ContentUriResolutionAdditionalTaintStep s).step(node1, node2) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** Taint-tracking flow to find paths from remote sources to content URI resolutions. */ diff --git a/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll b/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll index 739b2713780b..de9a920446d5 100644 --- a/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll +++ b/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll @@ -325,6 +325,8 @@ private module UnsafeDeserializationConfig implements DataFlow::ConfigSig { } predicate isBarrier(DataFlow::Node node) { isUnsafeDeserializationSanitizer(node) } + + predicate observeDiffInformedIncrementalMode() { any() } } module UnsafeDeserializationFlow = TaintTracking::Global; diff --git a/java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll b/java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll index 2ca38d695512..48c8e50bfaf4 100644 --- a/java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll +++ b/java/ql/lib/semmle/code/java/security/UrlForwardQuery.qll @@ -195,6 +195,8 @@ module UrlForwardFlowConfig implements DataFlow::ConfigSig { predicate isBarrier(DataFlow::Node node) { node instanceof UrlForwardBarrier } DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext } + + predicate observeDiffInformedIncrementalMode() { any() } } /** diff --git a/java/ql/lib/semmle/code/java/security/UrlRedirectQuery.qll b/java/ql/lib/semmle/code/java/security/UrlRedirectQuery.qll index 675937985c48..fff546fc5030 100644 --- a/java/ql/lib/semmle/code/java/security/UrlRedirectQuery.qll +++ b/java/ql/lib/semmle/code/java/security/UrlRedirectQuery.qll @@ -13,6 +13,8 @@ module UrlRedirectConfig implements DataFlow::ConfigSig { predicate isSink(DataFlow::Node sink) { sink instanceof UrlRedirectSink } predicate isBarrier(DataFlow::Node node) { node instanceof UrlRedirectSanitizer } + + predicate observeDiffInformedIncrementalMode() { any() } } /** diff --git a/java/ql/lib/semmle/code/java/security/WebviewDebuggingEnabledQuery.qll b/java/ql/lib/semmle/code/java/security/WebviewDebuggingEnabledQuery.qll index 8e5b177268df..90e47521bf04 100644 --- a/java/ql/lib/semmle/code/java/security/WebviewDebuggingEnabledQuery.qll +++ b/java/ql/lib/semmle/code/java/security/WebviewDebuggingEnabledQuery.qll @@ -44,6 +44,8 @@ module WebviewDebugEnabledConfig implements DataFlow::ConfigSig { or node.getEnclosingCallable().getDeclaringType() instanceof NonSecurityTestClass } + + predicate observeDiffInformedIncrementalMode() { any() } } /** diff --git a/java/ql/lib/semmle/code/java/security/XPathInjectionQuery.qll b/java/ql/lib/semmle/code/java/security/XPathInjectionQuery.qll index 38dc1ff993c4..6c541f66940e 100644 --- a/java/ql/lib/semmle/code/java/security/XPathInjectionQuery.qll +++ b/java/ql/lib/semmle/code/java/security/XPathInjectionQuery.qll @@ -12,6 +12,8 @@ module XPathInjectionConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof ThreatModelFlowSource } predicate isSink(DataFlow::Node sink) { sink instanceof XPathInjectionSink } + + predicate observeDiffInformedIncrementalMode() { any() } } /** diff --git a/java/ql/lib/semmle/code/java/security/XsltInjectionQuery.qll b/java/ql/lib/semmle/code/java/security/XsltInjectionQuery.qll index d437ca860d5f..304ec3327a17 100644 --- a/java/ql/lib/semmle/code/java/security/XsltInjectionQuery.qll +++ b/java/ql/lib/semmle/code/java/security/XsltInjectionQuery.qll @@ -20,6 +20,8 @@ module XsltInjectionFlowConfig implements DataFlow::ConfigSig { predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { any(XsltInjectionAdditionalTaintStep c).step(node1, node2) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** diff --git a/java/ql/lib/semmle/code/java/security/XssQuery.qll b/java/ql/lib/semmle/code/java/security/XssQuery.qll index 6fec86a78dd6..dba80ecc1391 100644 --- a/java/ql/lib/semmle/code/java/security/XssQuery.qll +++ b/java/ql/lib/semmle/code/java/security/XssQuery.qll @@ -20,6 +20,8 @@ module XssConfig implements DataFlow::ConfigSig { predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { any(XssAdditionalTaintStep s).step(node1, node2) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** Tracks flow from remote sources to cross site scripting vulnerabilities. */ diff --git a/java/ql/lib/semmle/code/java/security/XxeRemoteQuery.qll b/java/ql/lib/semmle/code/java/security/XxeRemoteQuery.qll index 58b1e5bfed1a..da092d2e11f3 100644 --- a/java/ql/lib/semmle/code/java/security/XxeRemoteQuery.qll +++ b/java/ql/lib/semmle/code/java/security/XxeRemoteQuery.qll @@ -18,6 +18,8 @@ module XxeConfig implements DataFlow::ConfigSig { predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) { any(XxeAdditionalTaintStep s).step(n1, n2) } + + predicate observeDiffInformedIncrementalMode() { any() } } /** diff --git a/java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll b/java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll index 0055670d895c..9e2e5e4a6c7e 100644 --- a/java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll +++ b/java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll @@ -43,6 +43,8 @@ module ZipSlipConfig implements DataFlow::ConfigSig { node instanceof SimpleTypeSanitizer or node instanceof PathInjectionSanitizer } + + predicate observeDiffInformedIncrementalMode() { any() } } /** Tracks flow from archive entries to file creation. */ diff --git a/java/ql/lib/semmle/code/java/security/regexp/RegexInjectionQuery.qll b/java/ql/lib/semmle/code/java/security/regexp/RegexInjectionQuery.qll index 887100618196..81246814dc21 100644 --- a/java/ql/lib/semmle/code/java/security/regexp/RegexInjectionQuery.qll +++ b/java/ql/lib/semmle/code/java/security/regexp/RegexInjectionQuery.qll @@ -14,6 +14,8 @@ module RegexInjectionConfig implements DataFlow::ConfigSig { predicate isSink(DataFlow::Node sink) { sink instanceof RegexInjectionSink } predicate isBarrier(DataFlow::Node node) { node instanceof RegexInjectionSanitizer } + + predicate observeDiffInformedIncrementalMode() { any() } } /** diff --git a/java/ql/lib/upgrades/376ce7dad79375c0772b8edb938da82ca5271ba1/fields.ql b/java/ql/lib/upgrades/376ce7dad79375c0772b8edb938da82ca5271ba1/fields.ql new file mode 100644 index 000000000000..a8b9b57c3f63 --- /dev/null +++ b/java/ql/lib/upgrades/376ce7dad79375c0772b8edb938da82ca5271ba1/fields.ql @@ -0,0 +1,15 @@ +class Field extends @field { + string toString() { none() } +} + +class Type extends @type { + string toString() { none() } +} + +class RefType extends @reftype { + string toString() { none() } +} + +from Field f, string name, Type t, RefType parent +where fields(f, name, t, parent, _) +select f, name, t, parent diff --git a/java/ql/lib/upgrades/376ce7dad79375c0772b8edb938da82ca5271ba1/old.dbscheme b/java/ql/lib/upgrades/376ce7dad79375c0772b8edb938da82ca5271ba1/old.dbscheme new file mode 100644 index 000000000000..376ce7dad793 --- /dev/null +++ b/java/ql/lib/upgrades/376ce7dad79375c0772b8edb938da82ca5271ba1/old.dbscheme @@ -0,0 +1,1233 @@ +/** + * 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, + int kind: int ref, + string cwd : string ref, + string name : string ref +); + +case @compilation.kind of + 1 = @javacompilation +| 2 = @kotlincompilation +; + +compilation_started( + int id : @compilation ref +) + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: 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 expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@@@someFile` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_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 +); + +/** + * For each file recorded in `compilation_compiling_files`, + * there will be a corresponding row in + * `compilation_compiling_files_completed` once extraction + * of that file is complete. The `result` will indicate the + * extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +#keyset[id, num] +compilation_compiling_files_completed( + int id : @compilation ref, + int num : int ref, + int result : int 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 +); + +/** + * The `cpu_seconds` and `elapsed_seconds` are the CPU time and elapsed + * time (respectively) that the original compilation (not the extraction) + * took for compiler invocation `id`. + */ +compilation_compiler_times( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float 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`. + * The `result` will indicate the extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref, + int result : int ref +); + +diagnostics( + unique int id: @diagnostic, + string generated_by: string ref, // TODO: Sync this with the other languages? + 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 +); + +/** + * 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 +); + +/* + * External artifacts + */ + +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +sourceLocationPrefix( + string prefix : string 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 +); + +/** + * An errortype is used when the extractor is unable to extract a type + * correctly for some reason. + */ +error_type( + unique int id: @errortype +); + +classes_or_interfaces( + unique int id: @classorinterface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @classorinterface ref +); + +file_class( + int id: @classorinterface ref +); + +class_object( + unique int id: @classorinterface ref, + unique int instance: @field ref +); + +type_companion_object( + unique int id: @classorinterface ref, + unique int instance: @field ref, + unique int companion_object: @classorinterface ref +); + +kt_nullable_types( + unique int id: @kt_nullable_type, + int classid: @reftype ref +) + +kt_notnull_types( + unique int id: @kt_notnull_type, + int classid: @reftype ref +) + +kt_type_alias( + unique int id: @kt_type_alias, + string name: string ref, + int kttypeid: @kt_type ref +) + +@kt_type = @kt_nullable_type | @kt_notnull_type + +isInterface( + unique int id: @classorinterface ref +); + +isRecord( + unique int id: @classorinterface 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 +); + +fieldsKotlinType( + unique int id: @field ref, + int kttypeid: @kt_type 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 +); + +constrsKotlinType( + unique int id: @constructor ref, + int kttypeid: @kt_type 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 +); + +methodsKotlinType( + unique int id: @method ref, + int kttypeid: @kt_type 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 +); + +paramsKotlinType( + unique int id: @param ref, + int kttypeid: @kt_type 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: @classorinterface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @classorinterface ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int parentid: @classorinterfaceorcallable 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: @classorinterfaceorcallable 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: @classorinterface 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 +); + +isCanonicalConstr( + int constructorid: @constructor 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: @classorinterface 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: @classorinterfaceorpackage 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 | @whenexpr| @stmtexpr; + +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 +| 24 = @errorstmt +| 25 = @whenbranch +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +exprsKotlinType( + unique int id: @expr ref, + int kttypeid: @kt_type 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 +| 74 = @errorexpr +| 75 = @whenexpr +| 76 = @getclassexpr +| 77 = @safecastexpr +| 78 = @implicitcastexpr +| 79 = @implicitnotnullexpr +| 80 = @implicitcoerciontounitexpr +| 81 = @notinstanceofexpr +| 82 = @stmtexpr +| 83 = @stringtemplateexpr +| 84 = @notnullexpr +| 85 = @unsafecoerceexpr +| 86 = @valueeqexpr +| 87 = @valueneexpr +| 88 = @propertyref +| 89 = @recordpatternexpr +; + +/** Holds if this `when` expression was written as an `if` expression. */ +when_if(unique int id: @whenexpr ref); + +/** Holds if this `when` branch was written as an `else` branch. */ +when_branch_else(unique int id: @whenbranch ref); + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref | @propertyref + +@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 + | @valueeqexpr + | @valueneexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr + | @notnullexpr; + +@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 +); + +propertyRefGetBinding( + unique int id: @expr ref, + int getter: @callable ref +); + +propertyRefFieldBinding( + unique int id: @expr ref, + int field: @field ref +); + +propertyRefSetBinding( + unique int id: @expr ref, + int setter: @callable ref +); + +@exprparent = @stmt | @expr | @whenbranch | @callable | @field | @fielddecl | @classorinterface | @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 +); + +localvarsKotlinType( + unique int id: @localvar ref, + int kttypeid: @kt_type 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 +); + +isNullDefaultCase( + int id: @case 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; + +@classorinterfaceorpackage = @classorinterface | @package; +@classorinterfaceorcallable = @classorinterface | @callable; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype | @errortype; +@classorarray = @classorinterface | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; + +/** A program element that has a name. */ +@element = @package | @modifier | @annotation | @errortype | + @locatableElement; + +@locatableElement = @file | @primitive | @classorinterface | @method | @constructor | @param | @exception | @field | + @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl | @kt_type | @kt_type_alias | + @kt_property; + +@modifiable = @member_modifiable| @param | @localvar | @typevariable; + +@member_modifiable = @classorinterface | @method | @constructor | @field | @kt_property; + +@member = @method | @constructor | @field | @reftype ; + +/** A program element that has a location. */ +@locatable = @typebound | @javadoc | @javadocTag | @javadocText | @xmllocatable | @ktcomment | + @locatableElement; + +@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; + +ktComments( + unique int id: @ktcomment, + int kind: int ref, + string text : string ref +) + +ktCommentSections( + unique int id: @ktcommentsection, + int comment: @ktcomment ref, + string content : string ref +) + +ktCommentSectionNames( + unique int id: @ktcommentsection ref, + string name : string ref +) + +ktCommentSectionSubjectNames( + unique int id: @ktcommentsection ref, + string subjectname : string ref +) + +#keyset[id, owner] +ktCommentOwners( + int id: @ktcomment ref, + int owner: @top ref +) + +ktExtensionFunctions( + unique int id: @method ref, + int typeid: @type ref, + int kttypeid: @kt_type ref +) + +ktProperties( + unique int id: @kt_property, + string nodeName: string ref +) + +ktPropertyGetters( + unique int id: @kt_property ref, + int getter: @method ref +) + +ktPropertySetters( + unique int id: @kt_property ref, + int setter: @method ref +) + +ktPropertyBackingFields( + unique int id: @kt_property ref, + int backingField: @field ref +) + +ktSyntheticBody( + unique int id: @callable ref, + int kind: int ref + // 1: ENUM_VALUES + // 2: ENUM_VALUEOF + // 3: ENUM_ENTRIES +) + +ktLocalFunction( + unique int id: @method ref +) + +ktInitializerAssignment( + unique int id: @assignexpr ref +) + +ktPropertyDelegates( + unique int id: @kt_property ref, + unique int variableId: @variable ref +) + +/** + * If `id` is a compiler generated element, then the kind indicates the + * reason that the compiler generated it. + * See `Element.compilerGeneratedReason()` for an explanation of what + * each `kind` means. + */ +compiler_generated( + unique int id: @element ref, + int kind: int ref +) + +ktFunctionOriginalNames( + unique int id: @method ref, + string name: string ref +) + +ktDataClasses( + unique int id: @classorinterface ref +) diff --git a/java/ql/lib/upgrades/376ce7dad79375c0772b8edb938da82ca5271ba1/semmlecode.dbscheme b/java/ql/lib/upgrades/376ce7dad79375c0772b8edb938da82ca5271ba1/semmlecode.dbscheme new file mode 100644 index 000000000000..876cabc76c5c --- /dev/null +++ b/java/ql/lib/upgrades/376ce7dad79375c0772b8edb938da82ca5271ba1/semmlecode.dbscheme @@ -0,0 +1,1232 @@ +/** + * 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, + int kind: int ref, + string cwd : string ref, + string name : string ref +); + +case @compilation.kind of + 1 = @javacompilation +| 2 = @kotlincompilation +; + +compilation_started( + int id : @compilation ref +) + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: 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 expanded arguments that were passed to the extractor for a + * compiler invocation. This is similar to `compilation_args`, but + * for a `@@@someFile` argument, it includes the arguments from that + * file, rather than just taking the argument literally. + */ +#keyset[id, num] +compilation_expanded_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 +); + +/** + * For each file recorded in `compilation_compiling_files`, + * there will be a corresponding row in + * `compilation_compiling_files_completed` once extraction + * of that file is complete. The `result` will indicate the + * extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +#keyset[id, num] +compilation_compiling_files_completed( + int id : @compilation ref, + int num : int ref, + int result : int 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 +); + +/** + * The `cpu_seconds` and `elapsed_seconds` are the CPU time and elapsed + * time (respectively) that the original compilation (not the extraction) + * took for compiler invocation `id`. + */ +compilation_compiler_times( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float 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`. + * The `result` will indicate the extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref, + int result : int ref +); + +diagnostics( + unique int id: @diagnostic, + string generated_by: string ref, // TODO: Sync this with the other languages? + 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 +); + +/** + * 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 +); + +/* + * External artifacts + */ + +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +sourceLocationPrefix( + string prefix : string 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 +); + +/** + * An errortype is used when the extractor is unable to extract a type + * correctly for some reason. + */ +error_type( + unique int id: @errortype +); + +classes_or_interfaces( + unique int id: @classorinterface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @classorinterface ref +); + +file_class( + int id: @classorinterface ref +); + +class_object( + unique int id: @classorinterface ref, + unique int instance: @field ref +); + +type_companion_object( + unique int id: @classorinterface ref, + unique int instance: @field ref, + unique int companion_object: @classorinterface ref +); + +kt_nullable_types( + unique int id: @kt_nullable_type, + int classid: @reftype ref +) + +kt_notnull_types( + unique int id: @kt_notnull_type, + int classid: @reftype ref +) + +kt_type_alias( + unique int id: @kt_type_alias, + string name: string ref, + int kttypeid: @kt_type ref +) + +@kt_type = @kt_nullable_type | @kt_notnull_type + +isInterface( + unique int id: @classorinterface ref +); + +isRecord( + unique int id: @classorinterface 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 +); + +fieldsKotlinType( + unique int id: @field ref, + int kttypeid: @kt_type 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 +); + +constrsKotlinType( + unique int id: @constructor ref, + int kttypeid: @kt_type 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 +); + +methodsKotlinType( + unique int id: @method ref, + int kttypeid: @kt_type 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 +); + +paramsKotlinType( + unique int id: @param ref, + int kttypeid: @kt_type 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: @classorinterface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @classorinterface ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int parentid: @classorinterfaceorcallable 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: @classorinterfaceorcallable 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: @classorinterface 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 +); + +isCanonicalConstr( + int constructorid: @constructor 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: @classorinterface 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: @classorinterfaceorpackage 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 | @whenexpr| @stmtexpr; + +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 +| 24 = @errorstmt +| 25 = @whenbranch +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +exprsKotlinType( + unique int id: @expr ref, + int kttypeid: @kt_type 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 +| 74 = @errorexpr +| 75 = @whenexpr +| 76 = @getclassexpr +| 77 = @safecastexpr +| 78 = @implicitcastexpr +| 79 = @implicitnotnullexpr +| 80 = @implicitcoerciontounitexpr +| 81 = @notinstanceofexpr +| 82 = @stmtexpr +| 83 = @stringtemplateexpr +| 84 = @notnullexpr +| 85 = @unsafecoerceexpr +| 86 = @valueeqexpr +| 87 = @valueneexpr +| 88 = @propertyref +| 89 = @recordpatternexpr +; + +/** Holds if this `when` expression was written as an `if` expression. */ +when_if(unique int id: @whenexpr ref); + +/** Holds if this `when` branch was written as an `else` branch. */ +when_branch_else(unique int id: @whenbranch ref); + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref | @propertyref + +@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 + | @valueeqexpr + | @valueneexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr + | @notnullexpr; + +@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 +); + +propertyRefGetBinding( + unique int id: @expr ref, + int getter: @callable ref +); + +propertyRefFieldBinding( + unique int id: @expr ref, + int field: @field ref +); + +propertyRefSetBinding( + unique int id: @expr ref, + int setter: @callable ref +); + +@exprparent = @stmt | @expr | @whenbranch | @callable | @field | @fielddecl | @classorinterface | @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 +); + +localvarsKotlinType( + unique int id: @localvar ref, + int kttypeid: @kt_type 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 +); + +isNullDefaultCase( + int id: @case 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; + +@classorinterfaceorpackage = @classorinterface | @package; +@classorinterfaceorcallable = @classorinterface | @callable; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype | @errortype; +@classorarray = @classorinterface | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; + +/** A program element that has a name. */ +@element = @package | @modifier | @annotation | @errortype | + @locatableElement; + +@locatableElement = @file | @primitive | @classorinterface | @method | @constructor | @param | @exception | @field | + @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl | @kt_type | @kt_type_alias | + @kt_property; + +@modifiable = @member_modifiable| @param | @localvar | @typevariable; + +@member_modifiable = @classorinterface | @method | @constructor | @field | @kt_property; + +@member = @method | @constructor | @field | @reftype ; + +/** A program element that has a location. */ +@locatable = @typebound | @javadoc | @javadocTag | @javadocText | @xmllocatable | @ktcomment | + @locatableElement; + +@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; + +ktComments( + unique int id: @ktcomment, + int kind: int ref, + string text : string ref +) + +ktCommentSections( + unique int id: @ktcommentsection, + int comment: @ktcomment ref, + string content : string ref +) + +ktCommentSectionNames( + unique int id: @ktcommentsection ref, + string name : string ref +) + +ktCommentSectionSubjectNames( + unique int id: @ktcommentsection ref, + string subjectname : string ref +) + +#keyset[id, owner] +ktCommentOwners( + int id: @ktcomment ref, + int owner: @top ref +) + +ktExtensionFunctions( + unique int id: @method ref, + int typeid: @type ref, + int kttypeid: @kt_type ref +) + +ktProperties( + unique int id: @kt_property, + string nodeName: string ref +) + +ktPropertyGetters( + unique int id: @kt_property ref, + int getter: @method ref +) + +ktPropertySetters( + unique int id: @kt_property ref, + int setter: @method ref +) + +ktPropertyBackingFields( + unique int id: @kt_property ref, + int backingField: @field ref +) + +ktSyntheticBody( + unique int id: @callable ref, + int kind: int ref + // 1: ENUM_VALUES + // 2: ENUM_VALUEOF + // 3: ENUM_ENTRIES +) + +ktLocalFunction( + unique int id: @method ref +) + +ktInitializerAssignment( + unique int id: @assignexpr ref +) + +ktPropertyDelegates( + unique int id: @kt_property ref, + unique int variableId: @variable ref +) + +/** + * If `id` is a compiler generated element, then the kind indicates the + * reason that the compiler generated it. + * See `Element.compilerGeneratedReason()` for an explanation of what + * each `kind` means. + */ +compiler_generated( + unique int id: @element ref, + int kind: int ref +) + +ktFunctionOriginalNames( + unique int id: @method ref, + string name: string ref +) + +ktDataClasses( + unique int id: @classorinterface ref +) diff --git a/java/ql/lib/upgrades/376ce7dad79375c0772b8edb938da82ca5271ba1/upgrade.properties b/java/ql/lib/upgrades/376ce7dad79375c0772b8edb938da82ca5271ba1/upgrade.properties new file mode 100644 index 000000000000..64fe711dd701 --- /dev/null +++ b/java/ql/lib/upgrades/376ce7dad79375c0772b8edb938da82ca5271ba1/upgrade.properties @@ -0,0 +1,3 @@ +description: Remove fields.sourceid +compatibility: full +fields.rel: run fields.qlo diff --git a/java/ql/src/Advisory/Declarations/NonFinalImmutableField.ql b/java/ql/src/Advisory/Declarations/NonFinalImmutableField.ql index d025466ae5ac..493168d80a7e 100644 --- a/java/ql/src/Advisory/Declarations/NonFinalImmutableField.ql +++ b/java/ql/src/Advisory/Declarations/NonFinalImmutableField.ql @@ -40,7 +40,7 @@ class ImmutableField extends Field { this.getType() instanceof ImmutableType and // The field is only assigned to in a constructor or static initializer of the type it is declared in. forall(FieldAccess fw, AnyAssignment ae | - fw.getField().getSourceDeclaration() = this and + fw.getField() = this and fw = ae.getDest() | ae.getEnclosingCallable().getDeclaringType() = this.getDeclaringType() and diff --git a/java/ql/src/Violations of Best Practice/Dead Code/NonAssignedFields.ql b/java/ql/src/Violations of Best Practice/Dead Code/NonAssignedFields.ql index 2c618f94aad3..28f06c4edfc0 100644 --- a/java/ql/src/Violations of Best Practice/Dead Code/NonAssignedFields.ql +++ b/java/ql/src/Violations of Best Practice/Dead Code/NonAssignedFields.ql @@ -63,15 +63,10 @@ predicate isVMObserver(RefType rt) { from Field f, FieldRead fr where f.fromSource() and - fr.getField().getSourceDeclaration() = f and + fr.getField() = f and not f.getDeclaringType() instanceof EnumType and - forall(Assignment ae, Field g | ae.getDest() = g.getAnAccess() and g.getSourceDeclaration() = f | - ae.getSource() instanceof NullLiteral - ) and - not exists(UnaryAssignExpr ua, Field g | - ua.getExpr() = g.getAnAccess() and - g.getSourceDeclaration() = f - ) and + forall(Assignment ae | ae.getDest() = f.getAnAccess() | ae.getSource() instanceof NullLiteral) and + not exists(UnaryAssignExpr ua | ua.getExpr() = f.getAnAccess()) and not f.isFinal() and // Exclude fields that may be accessed reflectively. not reflectivelyWritten(f) and diff --git a/java/ql/src/Violations of Best Practice/Dead Code/UnusedField.ql b/java/ql/src/Violations of Best Practice/Dead Code/UnusedField.ql index b5cb9f1c3c14..fab4e76bbda8 100644 --- a/java/ql/src/Violations of Best Practice/Dead Code/UnusedField.ql +++ b/java/ql/src/Violations of Best Practice/Dead Code/UnusedField.ql @@ -19,7 +19,7 @@ where not (f.isPublic() or f.isProtected()) and f.fromSource() and not f.getDeclaringType() instanceof EnumType and - not exists(VarAccess va | va.getVariable().(Field).getSourceDeclaration() = f) and + not exists(VarAccess va | va.getVariable() = f) and // Exclude results in generated classes. not f.getDeclaringType() instanceof GeneratedClass and // Exclude fields that may be reflectively read (this includes standard serialization). diff --git a/java/ql/src/Violations of Best Practice/Naming Conventions/Shadowing.qll b/java/ql/src/Violations of Best Practice/Naming Conventions/Shadowing.qll index f37d7fdcab00..561c57b7cd9b 100644 --- a/java/ql/src/Violations of Best Practice/Naming Conventions/Shadowing.qll +++ b/java/ql/src/Violations of Best Practice/Naming Conventions/Shadowing.qll @@ -33,7 +33,7 @@ private Field getField(Class c, string name, Type t) { predicate thisAccess(LocalVariableDecl d, Field f) { shadows(d, _, f, _) and - exists(VarAccess va | va.getVariable().(Field).getSourceDeclaration() = f | + exists(VarAccess va | va.getVariable() = f | va.getQualifier() instanceof ThisAccess and va.getEnclosingCallable() = d.getCallable() ) @@ -41,7 +41,7 @@ predicate thisAccess(LocalVariableDecl d, Field f) { predicate confusingAccess(LocalVariableDecl d, Field f) { shadows(d, _, f, _) and - exists(VarAccess va | va.getVariable().(Field).getSourceDeclaration() = f | + exists(VarAccess va | va.getVariable() = f | not exists(va.getQualifier()) and va.getEnclosingCallable() = d.getCallable() ) @@ -52,10 +52,7 @@ predicate assignmentToShadowingLocal(LocalVariableDecl d, Field f) { exists(Expr assignedValue, Expr use | d.getAnAssignedValue() = assignedValue and getARelevantChild(assignedValue) = use | - exists(FieldAccess access, Field ff | access = assignedValue | - ff = access.getField() and - ff.getSourceDeclaration() = f - ) + exists(FieldAccess access | access = assignedValue | f = access.getField()) or exists(MethodCall get, Method getter | get = assignedValue and getter = get.getMethod() | getterFor(getter, f) @@ -73,10 +70,9 @@ predicate assignmentFromShadowingLocal(LocalVariableDecl d, Field f) { setterFor(setter, f) ) or - exists(Field instance, Expr assignedValue | + exists(Expr assignedValue | access = getARelevantChild(assignedValue) and - assignedValue = instance.getAnAssignedValue() and - instance.getSourceDeclaration() = f + assignedValue = f.getAnAssignedValue() ) ) } diff --git a/java/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql b/java/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql index e0e793348f59..ad3008e54a59 100644 --- a/java/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql +++ b/java/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql @@ -9,5 +9,5 @@ import internal.CaptureModels from DataFlowSummaryTargetApi api, string flow -where flow = captureContentFlow(api) +where flow = ContentSensitive::captureFlow(api) select flow order by flow diff --git a/java/ql/src/utils/modelgenerator/CaptureNeutralModels.ql b/java/ql/src/utils/modelgenerator/CaptureNeutralModels.ql index 2ff65ad7fae0..c91f182f6038 100644 --- a/java/ql/src/utils/modelgenerator/CaptureNeutralModels.ql +++ b/java/ql/src/utils/modelgenerator/CaptureNeutralModels.ql @@ -7,7 +7,6 @@ */ import internal.CaptureModels -import internal.CaptureSummaryFlowQuery from DataFlowSummaryTargetApi api, string noflow where noflow = captureNoFlow(api) diff --git a/java/ql/src/utils/modelgenerator/CaptureSummaryModels.ql b/java/ql/src/utils/modelgenerator/CaptureSummaryModels.ql index 3f18bf49428a..7fc7c0f7a571 100644 --- a/java/ql/src/utils/modelgenerator/CaptureSummaryModels.ql +++ b/java/ql/src/utils/modelgenerator/CaptureSummaryModels.ql @@ -7,7 +7,6 @@ */ import internal.CaptureModels -import internal.CaptureSummaryFlowQuery from DataFlowSummaryTargetApi api, string flow where flow = captureFlow(api) diff --git a/java/ql/src/utils/modelgenerator/internal/CaptureModels.qll b/java/ql/src/utils/modelgenerator/internal/CaptureModels.qll index ab5de0d01979..6724527a1b17 100644 --- a/java/ql/src/utils/modelgenerator/internal/CaptureModels.qll +++ b/java/ql/src/utils/modelgenerator/internal/CaptureModels.qll @@ -1,635 +1,292 @@ /** - * Provides classes and predicates related to capturing summary, source, - * and sink models of the Standard or a 3rd party library. + * Provides predicates related to capturing summary models of the Standard or a 3rd party library. */ -private import CaptureModelsSpecific -private import CaptureModelsPrinting +private import java as J +private import semmle.code.java.dataflow.DataFlow +private import semmle.code.java.dataflow.ExternalFlow as ExternalFlow +private import semmle.code.java.dataflow.internal.ContainerFlow as ContainerFlow +private import semmle.code.java.dataflow.internal.DataFlowDispatch +private import semmle.code.java.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon +private import semmle.code.java.dataflow.internal.DataFlowImplSpecific +private import semmle.code.java.dataflow.internal.DataFlowPrivate as DataFlowPrivate +private import semmle.code.java.dataflow.internal.DataFlowUtil as DataFlowUtil +private import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl +private import semmle.code.java.dataflow.internal.ModelExclusions +private import semmle.code.java.dataflow.internal.TaintTrackingImplSpecific +private import semmle.code.java.dataflow.SSA as Ssa +private import semmle.code.java.dataflow.TaintTracking +private import codeql.mad.modelgenerator.internal.ModelGeneratorImpl /** - * A node from which flow can return to the caller. This is either a regular - * `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter. + * Holds if the type `t` is a primitive type used for bulk data. */ -private class ReturnNodeExt extends DataFlow::Node { - private DataFlowImplCommon::ReturnKindExt kind; - - ReturnNodeExt() { - kind = DataFlowImplCommon::getValueReturnPosition(this).getKind() or - kind = DataFlowImplCommon::getParamReturnPosition(this, _).getKind() - } - - /** - * Gets the kind of the return node. - */ - DataFlowImplCommon::ReturnKindExt getKind() { result = kind } +predicate isPrimitiveTypeUsedForBulkData(J::Type t) { + t.hasName(["byte", "char", "Byte", "Character"]) } -bindingset[c] -private signature string printCallableParamSig(Callable c, ParameterPosition p); - -private module PrintReturnNodeExt { - string getOutput(ReturnNodeExt node) { - node.getKind() instanceof DataFlowImplCommon::ValueReturnKind and - result = "ReturnValue" - or - exists(ParameterPosition pos | - pos = node.getKind().(DataFlowImplCommon::ParamUpdateReturnKind).getPosition() and - result = printCallableParam(returnNodeEnclosingCallable(node), pos) - ) - } -} +module ModelGeneratorInput implements ModelGeneratorInputSig { + class Type = J::Type; -string getOutput(ReturnNodeExt node) { - result = PrintReturnNodeExt::getOutput(node) -} + class Parameter = J::Parameter; -string getContentOutput(ReturnNodeExt node) { - result = PrintReturnNodeExt::getOutput(node) -} + class Callable = J::Callable; -class DataFlowSummaryTargetApi extends SummaryTargetApi { - DataFlowSummaryTargetApi() { not isUninterestingForDataFlowModels(this) } -} - -class DataFlowSourceTargetApi = SourceTargetApi; - -class DataFlowSinkTargetApi = SinkTargetApi; - -private module ModelPrintingInput implements ModelPrintingSig { - class SummaryApi = DataFlowSummaryTargetApi; - - class SourceOrSinkApi = SourceOrSinkTargetApi; - - string getProvenance() { result = "df-generated" } -} - -module Printing = ModelPrinting; - -/** - * Holds if `c` is a relevant content kind, where the underlying type is relevant. - */ -private predicate isRelevantTypeInContent(DataFlow::ContentSet c) { - isRelevantType(getUnderlyingContentType(c)) -} - -/** - * Holds if data can flow from `node1` to `node2` either via a read or a write of an intermediate field `f`. - */ -private predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2) { - exists(DataFlow::ContentSet f | - DataFlowPrivate::readStep(node1, f, node2) and - // Partially restrict the content types used for intermediate steps. - (not exists(getUnderlyingContentType(f)) or isRelevantTypeInContent(f)) - ) - or - exists(DataFlow::ContentSet f | DataFlowPrivate::storeStep(node1, f, node2) | containerContent(f)) -} - -/** - * Holds if content `c` is either a field, a synthetic field or language specific - * content of a relevant type or a container like content. - */ -pragma[nomagic] -private predicate isRelevantContent0(DataFlow::ContentSet c) { - isRelevantTypeInContent(c) or - containerContent(c) -} - -/** - * Gets the MaD string representation of the parameter node `p`. - */ -string parameterNodeAsInput(DataFlow::ParameterNode p) { - result = parameterAccess(p.asParameter()) - or - result = qualifierString() and p instanceof InstanceParameterNode -} - -/** - * Gets the MaD string representation of the parameter `p` - * when used in content flow. - */ -string parameterNodeAsContentInput(DataFlow::ParameterNode p) { - result = parameterContentAccess(p.asParameter()) - or - result = qualifierString() and p instanceof InstanceParameterNode -} - -/** - * Gets the MaD input string representation of `source`. - */ -string asInputArgument(DataFlow::Node source) { result = asInputArgumentSpecific(source) } - -/** - * Gets the summary model of `api`, if it follows the `fluent` programming pattern (returns `this`). - */ -string captureQualifierFlow(DataFlowSummaryTargetApi api) { - exists(ReturnNodeExt ret | - api = returnNodeEnclosingCallable(ret) and - isOwnInstanceAccessNode(ret) - ) and - result = Printing::asLiftedValueModel(api, qualifierString(), "ReturnValue") -} - -private int accessPathLimit0() { result = 2 } - -private newtype TTaintState = - TTaintRead(int n) { n in [0 .. accessPathLimit0()] } or - TTaintStore(int n) { n in [1 .. accessPathLimit0()] } - -abstract private class TaintState extends TTaintState { - abstract string toString(); -} - -/** - * A FlowState representing a tainted read. - */ -private class TaintRead extends TaintState, TTaintRead { - private int step; - - TaintRead() { this = TTaintRead(step) } - - /** - * Gets the flow state step number. - */ - int getStep() { result = step } + class NodeExtended extends DataFlow::Node { + Callable getAsExprEnclosingCallable() { result = this.asExpr().getEnclosingCallable() } + } - override string toString() { result = "TaintRead(" + step + ")" } -} + private predicate isInfrequentlyUsed(J::CompilationUnit cu) { + cu.getPackage().getName().matches("javax.swing%") or + cu.getPackage().getName().matches("java.awt%") + } -/** - * A FlowState representing a tainted write. - */ -private class TaintStore extends TaintState, TTaintStore { - private int step; + private predicate relevant(Callable api) { + api.isPublic() and + api.getDeclaringType().isPublic() and + api.fromSource() and + not isUninterestingForModels(api) and + not isInfrequentlyUsed(api.getCompilationUnit()) + } - TaintStore() { this = TTaintStore(step) } + private J::Method getARelevantOverride(J::Method m) { + result = m.getAnOverride() and + relevant(result) and + // Other exclusions for overrides. + not m instanceof J::ToStringMethod + } /** - * Gets the flow state step number. + * Gets the super implementation of `m` if it is relevant. + * If such a super implementations does not exist, returns `m` if it is relevant. */ - int getStep() { result = step } - - override string toString() { result = "TaintStore(" + step + ")" } -} - -/** - * A data-flow configuration for tracking flow through APIs. - * The sources are the parameters of an API and the sinks are the return values (excluding `this`) and parameters. - * - * This can be used to generate Flow summaries for APIs from parameter to return. - */ -module PropagateFlowConfig implements DataFlow::StateConfigSig { - class FlowState = TaintState; - - predicate isSource(DataFlow::Node source, FlowState state) { - source instanceof DataFlow::ParameterNode and - source.getEnclosingCallable() instanceof DataFlowSummaryTargetApi and - state.(TaintRead).getStep() = 0 + private J::Callable liftedImpl(J::Callable m) { + ( + result = getARelevantOverride(m) + or + result = m and relevant(m) + ) and + not exists(getARelevantOverride(result)) } - predicate isSink(DataFlow::Node sink, FlowState state) { - sink instanceof ReturnNodeExt and - not isOwnInstanceAccessNode(sink) and - not exists(captureQualifierFlow(sink.asExpr().getEnclosingCallable())) and - (state instanceof TaintRead or state instanceof TaintStore) + private predicate hasManualSummaryModel(Callable api) { + api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()).asCallable() or + api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel()).asCallable() } - predicate isAdditionalFlowStep( - DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2 - ) { - exists(DataFlow::ContentSet c | - DataFlowImplCommon::store(node1, c.getAStoreContent(), node2, _, _) and - isRelevantContent0(c) and - ( - state1 instanceof TaintRead and state2.(TaintStore).getStep() = 1 - or - state1.(TaintStore).getStep() + 1 = state2.(TaintStore).getStep() - ) - ) - or - exists(DataFlow::ContentSet c | - DataFlowPrivate::readStep(node1, c, node2) and - isRelevantContent0(c) and - state1.(TaintRead).getStep() + 1 = state2.(TaintRead).getStep() - ) + private predicate hasManualSourceModel(Callable api) { + api = any(ExternalFlow::SourceCallable sc | sc.hasManualModel()) or + api = any(FlowSummaryImpl::Public::NeutralSourceCallable sc | sc.hasManualModel()).asCallable() } - predicate isBarrier(DataFlow::Node n) { - exists(Type t | t = n.getType() and not isRelevantType(t)) + private predicate hasManualSinkModel(Callable api) { + api = any(ExternalFlow::SinkCallable sc | sc.hasManualModel()) or + api = any(FlowSummaryImpl::Public::NeutralSinkCallable sc | sc.hasManualModel()).asCallable() } - DataFlow::FlowFeature getAFeature() { - result instanceof DataFlow::FeatureEqualSourceSinkCallContext + predicate isUninterestingForDataFlowModels(Callable api) { + api.getDeclaringType() instanceof J::Interface and not exists(api.getBody()) } -} - -module PropagateFlow = TaintTracking::GlobalWithState; -/** - * Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter. - */ -string captureThroughFlow0( - DataFlowSummaryTargetApi api, DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt -) { - exists(string input, string output | - p.getEnclosingCallable() = api and - returnNodeExt.(DataFlow::Node).getEnclosingCallable() = api and - input = parameterNodeAsInput(p) and - output = getOutput(returnNodeExt) and - input != output and - result = Printing::asLiftedTaintModel(api, input, output) - ) -} - -/** - * Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter. - */ -string captureThroughFlow(DataFlowSummaryTargetApi api) { - exists(DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt | - PropagateFlow::flow(p, returnNodeExt) and - result = captureThroughFlow0(api, p, returnNodeExt) - ) -} - -private module PropagateContentFlowConfig implements ContentDataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { - source instanceof DataFlow::ParameterNode and - source.getEnclosingCallable() instanceof DataFlowSummaryTargetApi + class SourceOrSinkTargetApi extends Callable { + SourceOrSinkTargetApi() { relevant(this) } } - predicate isSink(DataFlow::Node sink) { - sink instanceof ReturnNodeExt and - sink.getEnclosingCallable() instanceof DataFlowSummaryTargetApi + class SinkTargetApi extends SourceOrSinkTargetApi { + SinkTargetApi() { not hasManualSinkModel(this) } } - predicate isAdditionalFlowStep = isAdditionalContentFlowStep/2; - - predicate isBarrier(DataFlow::Node n) { - exists(Type t | t = n.getType() and not isRelevantType(t)) + class SourceTargetApi extends SourceOrSinkTargetApi { + SourceTargetApi() { not hasManualSourceModel(this) } } - int accessPathLimit() { result = 2 } + class SummaryTargetApi extends Callable { + private Callable lift; - predicate isRelevantContent(DataFlow::ContentSet s) { isRelevantContent0(s) } + SummaryTargetApi() { + lift = liftedImpl(this) and + not hasManualSummaryModel(lift) + } - DataFlow::FlowFeature getAFeature() { - result instanceof DataFlow::FeatureEqualSourceSinkCallContext - } -} + Callable lift() { result = lift } -private module PropagateContentFlow = ContentDataFlow::Global; - -private string getContent(PropagateContentFlow::AccessPath ap, int i) { - exists(ContentSet head, PropagateContentFlow::AccessPath tail | - head = ap.getHead() and - tail = ap.getTail() - | - i = 0 and - result = "." + printContent(head) - or - i > 0 and result = getContent(tail, i - 1) - ) -} - -/** - * Gets the MaD string representation of a store step access path. - */ -private string printStoreAccessPath(PropagateContentFlow::AccessPath ap) { - result = concat(int i | | getContent(ap, i), "" order by i) -} - -/** - * Gets the MaD string representation of a read step access path. - */ -private string printReadAccessPath(PropagateContentFlow::AccessPath ap) { - result = concat(int i | | getContent(ap, i), "" order by i desc) -} - -/** - * Holds if the access path `ap` contains a field or synthetic field access. - */ -private predicate mentionsField(PropagateContentFlow::AccessPath ap) { - exists(ContentSet head, PropagateContentFlow::AccessPath tail | - head = ap.getHead() and - tail = ap.getTail() - | - mentionsField(tail) or isField(head) - ) -} - -private predicate apiFlow( - DataFlowSummaryTargetApi api, DataFlow::ParameterNode p, PropagateContentFlow::AccessPath reads, - ReturnNodeExt returnNodeExt, PropagateContentFlow::AccessPath stores, boolean preservesValue -) { - PropagateContentFlow::flow(p, reads, returnNodeExt, stores, preservesValue) and - returnNodeExt.getEnclosingCallable() = api and - p.getEnclosingCallable() = api -} - -/** - * A class of APIs relevant for modeling using content flow. - * The following heuristic is applied: - * Content flow is only relevant for an API, if - * #content flow <= 2 * #parameters + 3 - * If an API produces more content flow, it is likely that - * 1. Types are not sufficiently constrained leading to a combinatorial - * explosion in dispatch and thus in the generated summaries. - * 2. It is a reasonable approximation to use the non-content based flow - * detection instead, as reads and stores would use a significant - * part of an objects internal state. - */ -private class ContentDataFlowSummaryTargetApi extends DataFlowSummaryTargetApi { - ContentDataFlowSummaryTargetApi() { - count(string input, string output | - exists( - DataFlow::ParameterNode p, PropagateContentFlow::AccessPath reads, - ReturnNodeExt returnNodeExt, PropagateContentFlow::AccessPath stores - | - apiFlow(this, p, reads, returnNodeExt, stores, _) and - input = parameterNodeAsContentInput(p) + printReadAccessPath(reads) and - output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores) - ) - ) <= 2 * this.getNumberOfParameters() + 3 + predicate isRelevant() { relevant(this) } } -} - -pragma[nomagic] -private predicate apiContentFlow( - ContentDataFlowSummaryTargetApi api, DataFlow::ParameterNode p, - PropagateContentFlow::AccessPath reads, ReturnNodeExt returnNodeExt, - PropagateContentFlow::AccessPath stores, boolean preservesValue -) { - PropagateContentFlow::flow(p, reads, returnNodeExt, stores, preservesValue) and - returnNodeExt.getEnclosingCallable() = api and - p.getEnclosingCallable() = api -} -/** - * Holds if any of the content sets in `path` translates into a synthetic field. - */ -private predicate hasSyntheticContent(PropagateContentFlow::AccessPath path) { - exists(PropagateContentFlow::AccessPath tail, ContentSet head | - head = path.getHead() and - tail = path.getTail() - | - exists(getSyntheticName(head)) or - hasSyntheticContent(tail) - ) -} + private string isExtensible(Callable c) { + if c.getDeclaringType().isFinal() then result = "false" else result = "true" + } -/** - * A module containing predicates for validating access paths containing content sets - * that translates into synthetic fields, when used for generated summary models. - */ -private module AccessPathSyntheticValidation { /** - * Holds if there exists an API that has content flow from `read` (on type `t1`) - * to `store` (on type `t2`). + * Holds if the callable `c` is in package `package` + * and is a member of `type`. */ - private predicate step( - Type t1, PropagateContentFlow::AccessPath read, Type t2, PropagateContentFlow::AccessPath store - ) { - exists(DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt | - p.getType() = t1 and - returnNodeExt.getType() = t2 and - apiContentFlow(_, p, read, returnNodeExt, store, _) + private predicate qualifiedName(Callable c, string package, string type) { + exists(RefType t | t = c.getDeclaringType() | + package = t.getCompilationUnit().getPackage().getName() and + type = t.getErasure().(J::RefType).getNestedName() ) } - /** - * Holds if there exists an API that has content flow from `read` (on type `t1`) - * to `store` (on type `t2`), where `read` does not have synthetic content and `store` does. - * - * Step A -> Synth. - */ - private predicate synthPathEntry( - Type t1, PropagateContentFlow::AccessPath read, Type t2, PropagateContentFlow::AccessPath store - ) { - not hasSyntheticContent(read) and - hasSyntheticContent(store) and - step(t1, read, t2, store) + predicate isRelevantType(Type t) { + not t instanceof J::TypeClass and + not t instanceof J::EnumType and + not t instanceof J::PrimitiveType and + not t instanceof J::BoxedType and + not t.(J::RefType).getAnAncestor().hasQualifiedName("java.lang", "Number") and + not t.(J::RefType).getAnAncestor().hasQualifiedName("java.nio.charset", "Charset") and + ( + not t.(J::Array).getElementType() instanceof J::PrimitiveType or + isPrimitiveTypeUsedForBulkData(t.(J::Array).getElementType()) + ) and + ( + not t.(J::Array).getElementType() instanceof J::BoxedType or + isPrimitiveTypeUsedForBulkData(t.(J::Array).getElementType()) + ) and + ( + not t.(ContainerFlow::CollectionType).getElementType() instanceof J::BoxedType or + isPrimitiveTypeUsedForBulkData(t.(ContainerFlow::CollectionType).getElementType()) + ) } - /** - * Holds if there exists an API that has content flow from `read` (on type `t1`) - * to `store` (on type `t2`), where `read` has synthetic content - * and `store` does not. - * - * Step Synth -> A. - */ - private predicate synthPathExit( - Type t1, PropagateContentFlow::AccessPath read, Type t2, PropagateContentFlow::AccessPath store - ) { - hasSyntheticContent(read) and - not hasSyntheticContent(store) and - step(t1, read, t2, store) + Type getUnderlyingContentType(DataFlow::ContentSet c) { + result = c.(DataFlow::FieldContent).getField().getType() or + result = c.(DataFlow::SyntheticFieldContent).getField().getType() } - /** - * Holds if there exists a path of steps from `read` to an exit. - * - * read ->* Synth -> A - */ - private predicate reachesSynthExit(Type t, PropagateContentFlow::AccessPath read) { - synthPathExit(t, read, _, _) - or - hasSyntheticContent(read) and - exists(PropagateContentFlow::AccessPath mid, Type midType | - hasSyntheticContent(mid) and - step(t, read, midType, mid) and - reachesSynthExit(midType, mid.reverse()) - ) + string qualifierString() { result = "Argument[this]" } + + string parameterAccess(J::Parameter p) { + if + p.getType() instanceof J::Array and + not isPrimitiveTypeUsedForBulkData(p.getType().(J::Array).getElementType()) + then result = "Argument[" + p.getPosition() + "].ArrayElement" + else + if p.getType() instanceof ContainerFlow::ContainerType + then result = "Argument[" + p.getPosition() + "].Element" + else result = "Argument[" + p.getPosition() + "]" } - /** - * Holds if there exists a path of steps from an entry to `store`. - * - * A -> Synth ->* store - */ - private predicate synthEntryReaches(Type t, PropagateContentFlow::AccessPath store) { - synthPathEntry(_, _, t, store) - or - hasSyntheticContent(store) and - exists(PropagateContentFlow::AccessPath mid, Type midType | - hasSyntheticContent(mid) and - step(midType, mid, t, store) and - synthEntryReaches(midType, mid.reverse()) - ) - } + string parameterContentAccess(J::Parameter p) { result = "Argument[" + p.getPosition() + "]" } - /** - * Holds if at least one of the access paths `read` (on type `t1`) and `store` (on type `t2`) - * contain content that will be translated into a synthetic field, when being used in - * a MaD summary model, and if there is a range of APIs, such that - * when chaining their flow access paths, there exists access paths `A` and `B` where - * A ->* read -> store ->* B and where `A` and `B` do not contain content that will - * be translated into a synthetic field. - * - * This is needed because we don't want to include summaries that reads from or - * stores into a "dead" synthetic field. - * - * Example: - * Assume we have a type `t` (in this case `t1` = `t2`) with methods `getX` and - * `setX`, which gets and sets a private field `X` on `t`. - * This would lead to the following content flows - * getX : Argument[this].SyntheticField[t.X] -> ReturnValue. - * setX : Argument[0] -> Argument[this].SyntheticField[t.X] - * As the reads and stores are on synthetic fields we should only make summaries - * if both of these methods exist. - */ - pragma[nomagic] - predicate acceptReadStore( - Type t1, PropagateContentFlow::AccessPath read, Type t2, PropagateContentFlow::AccessPath store - ) { - synthPathEntry(t1, read, t2, store) and reachesSynthExit(t2, store.reverse()) + class InstanceParameterNode = DataFlow::InstanceParameterNode; + + bindingset[c] + string paramReturnNodeAsOutput(Callable c, ParameterPosition pos) { + result = parameterAccess(c.getParameter(pos)) or - exists(PropagateContentFlow::AccessPath store0 | store0.reverse() = read | - synthEntryReaches(t1, store0) and synthPathExit(t1, read, t2, store) - or - synthEntryReaches(t1, store0) and - step(t1, read, t2, store) and - reachesSynthExit(t2, store.reverse()) - ) + result = qualifierString() and pos = -1 } -} -/** - * Holds, if the API `api` has relevant flow from `read` on `p` to `store` on `returnNodeExt`. - * Flow is considered relevant, - * 1. If `read` or `store` do not contain a content set that translates into a synthetic field. - * 2. If `read` or `store` contain a content set that translates into a synthetic field, and if - * the synthetic content is "live" on the relevant declaring type. - */ -private predicate apiRelevantContentFlow( - ContentDataFlowSummaryTargetApi api, DataFlow::ParameterNode p, - PropagateContentFlow::AccessPath read, ReturnNodeExt returnNodeExt, - PropagateContentFlow::AccessPath store, boolean preservesValue -) { - apiContentFlow(api, p, read, returnNodeExt, store, preservesValue) and - ( - not hasSyntheticContent(read) and not hasSyntheticContent(store) + bindingset[c] + string paramReturnNodeAsContentOutput(Callable c, ParameterPosition pos) { + result = parameterContentAccess(c.getParameter(pos)) or - AccessPathSyntheticValidation::acceptReadStore(p.getType(), read, returnNodeExt.getType(), store) - ) -} + result = qualifierString() and pos = -1 + } -pragma[nomagic] -private predicate captureContentFlow0( - ContentDataFlowSummaryTargetApi api, string input, string output, boolean preservesValue, - boolean lift -) { - exists( - DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt, PropagateContentFlow::AccessPath reads, - PropagateContentFlow::AccessPath stores - | - apiRelevantContentFlow(api, p, reads, returnNodeExt, stores, preservesValue) and - input = parameterNodeAsContentInput(p) + printReadAccessPath(reads) and - output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores) and - input != output and - (if mentionsField(reads) or mentionsField(stores) then lift = false else lift = true) - ) -} + Callable returnNodeEnclosingCallable(DataFlow::Node ret) { + result = DataFlowImplCommon::getNodeEnclosingCallable(ret).asCallable() + } -/** - * Gets the content based summary model(s) of the API `api` (if there is flow from a parameter to - * the return value or a parameter). - * - * Models are lifted to the best type in case the read and store access paths do not - * contain a field or synthetic field access. - */ -string captureContentFlow(ContentDataFlowSummaryTargetApi api) { - exists(string input, string output, boolean lift, boolean preservesValue | - captureContentFlow0(api, input, output, _, lift) and - preservesValue = max(boolean p | captureContentFlow0(api, input, output, p, lift)) and - result = Printing::asModel(api, input, output, preservesValue, lift) - ) -} + predicate isOwnInstanceAccessNode(DataFlowPrivate::ReturnNode node) { + node.asExpr().(J::ThisAccess).isOwnInstanceAccess() + } -/** - * A dataflow configuration used for finding new sources. - * The sources are the already known existing sources and the sinks are the API return nodes. - * - * This can be used to generate Source summaries for an API, if the API expose an already known source - * via its return (then the API itself becomes a source). - */ -module PropagateFromSourceConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { - exists(string kind | - isRelevantSourceKind(kind) and - ExternalFlow::sourceNode(source, kind) + predicate sinkModelSanitizer(DataFlow::Node node) { + // exclude variable capture jump steps + exists(Ssa::SsaImplicitInit closure | + closure.captures(_) and + node.asExpr() = closure.getAFirstUse() ) } - predicate isSink(DataFlow::Node sink) { - sink instanceof ReturnNodeExt and - sink.getEnclosingCallable() instanceof DataFlowSourceTargetApi + predicate apiSource(DataFlow::Node source) { + ( + source.asExpr().(J::FieldAccess).isOwnFieldAccess() or + source instanceof DataFlow::ParameterNode + ) and + exists(J::RefType t | + t = source.getEnclosingCallable().getDeclaringType().getAnAncestor() and + not t instanceof J::TypeObject and + t.isPublic() + ) } - DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSinkCallContext } + predicate irrelevantSourceSinkApi(Callable source, SourceTargetApi api) { none() } - predicate isBarrier(DataFlow::Node n) { - exists(Type t | t = n.getType() and not isRelevantType(t)) + string getInputArgument(DataFlow::Node source) { + exists(int pos | + source.(DataFlow::ParameterNode).isParameterOf(_, pos) and + if pos >= 0 then result = "Argument[" + pos + "]" else result = qualifierString() + ) + or + source.asExpr() instanceof J::FieldAccess and + result = qualifierString() } - predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { - isRelevantTaintStep(node1, node2) + bindingset[kind] + predicate isRelevantSinkKind(string kind) { + not kind = "log-injection" and + not kind.matches("regex-use%") and + not kind = "file-content-store" } -} -private module PropagateFromSource = TaintTracking::Global; + bindingset[kind] + predicate isRelevantSourceKind(string kind) { any() } -/** - * Gets the source model(s) of `api`, if there is flow from an existing known source to the return of `api`. - */ -string captureSource(DataFlowSourceTargetApi api) { - exists(DataFlow::Node source, ReturnNodeExt sink, string kind | - PropagateFromSource::flow(source, sink) and - ExternalFlow::sourceNode(source, kind) and - api = sink.getEnclosingCallable() and - not irrelevantSourceSinkApi(source.getEnclosingCallable(), api) and - result = Printing::asSourceModel(api, getOutput(sink), kind) - ) -} + predicate containerContent = DataFlowPrivate::containerContent/1; -/** - * A dataflow configuration used for finding new sinks. - * The sources are the parameters of the API and the fields of the enclosing type. - * - * This can be used to generate Sink summaries for APIs, if the API propagates a parameter (or enclosing type field) - * into an existing known sink (then the API itself becomes a sink). - */ -module PropagateToSinkConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { - apiSource(source) and source.getEnclosingCallable() instanceof DataFlowSinkTargetApi + predicate isAdditionalContentFlowStep(DataFlow::Node node1, DataFlow::Node node2) { + TaintTracking::defaultAdditionalTaintStep(node1, node2, _) and + not exists(DataFlow::Content f | + DataFlowPrivate::readStep(node1, f, node2) and containerContent(f) + ) } - predicate isSink(DataFlow::Node sink) { - exists(string kind | isRelevantSinkKind(kind) and ExternalFlow::sinkNode(sink, kind)) + predicate isField(DataFlow::ContentSet c) { + c instanceof DataFlowUtil::FieldContent or + c instanceof DataFlowUtil::SyntheticFieldContent } - predicate isBarrier(DataFlow::Node node) { - exists(Type t | t = node.getType() and not isRelevantType(t)) + string getSyntheticName(DataFlow::ContentSet c) { + exists(Field f | + not f.isPublic() and + f = c.(DataFlowUtil::FieldContent).getField() and + result = f.getQualifiedName() + ) or - sinkModelSanitizer(node) + result = c.(DataFlowUtil::SyntheticFieldContent).getField() } - DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext } + string printContent(DataFlow::ContentSet c) { + exists(Field f | f = c.(DataFlowUtil::FieldContent).getField() and f.isPublic() | + result = "Field[" + f.getQualifiedName() + "]" + ) + or + result = "SyntheticField[" + getSyntheticName(c) + "]" + or + c instanceof DataFlowUtil::CollectionContent and result = "Element" + or + c instanceof DataFlowUtil::ArrayContent and result = "ArrayElement" + or + c instanceof DataFlowUtil::MapValueContent and result = "MapValue" + or + c instanceof DataFlowUtil::MapKeyContent and result = "MapKey" + } - predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { - isRelevantTaintStep(node1, node2) + predicate partialModel( + Callable api, string package, string type, string extensible, string name, string parameters + ) { + qualifiedName(api, package, type) and + extensible = isExtensible(api) and + name = api.getName() and + parameters = ExternalFlow::paramsString(api) } -} -private module PropagateToSink = TaintTracking::Global; + predicate sourceNode = ExternalFlow::sourceNode/2; -/** - * Gets the sink model(s) of `api`, if there is flow from a parameter to an existing known sink. - */ -string captureSink(DataFlowSinkTargetApi api) { - exists(DataFlow::Node src, DataFlow::Node sink, string kind | - PropagateToSink::flow(src, sink) and - ExternalFlow::sinkNode(sink, kind) and - api = src.getEnclosingCallable() and - result = Printing::asSinkModel(api, asInputArgument(src), kind) - ) + predicate sinkNode = ExternalFlow::sinkNode/2; } + +import MakeModelGenerator diff --git a/java/ql/src/utils/modelgenerator/internal/CaptureModelsPrinting.qll b/java/ql/src/utils/modelgenerator/internal/CaptureModelsPrinting.qll index 33d176c3d893..dbf08b15e902 100644 --- a/java/ql/src/utils/modelgenerator/internal/CaptureModelsPrinting.qll +++ b/java/ql/src/utils/modelgenerator/internal/CaptureModelsPrinting.qll @@ -1,11 +1,11 @@ private import java as J -private import codeql.mad.modelgenerator.ModelPrinting -private import CaptureModelsSpecific as Specific +private import codeql.mad.modelgenerator.internal.ModelPrinting +private import CaptureModels::ModelGeneratorInput as ModelGeneratorInput private module ModelPrintingLang implements ModelPrintingLangSig { class Callable = J::Callable; - predicate partialModel = Specific::partialModel/6; + predicate partialModel = ModelGeneratorInput::partialModel/6; } import ModelPrintingImpl diff --git a/java/ql/src/utils/modelgenerator/internal/CaptureModelsSpecific.qll b/java/ql/src/utils/modelgenerator/internal/CaptureModelsSpecific.qll deleted file mode 100644 index f359d59973ca..000000000000 --- a/java/ql/src/utils/modelgenerator/internal/CaptureModelsSpecific.qll +++ /dev/null @@ -1,380 +0,0 @@ -/** - * Provides predicates related to capturing summary models of the Standard or a 3rd party library. - */ - -private import java as J -private import semmle.code.java.dataflow.internal.DataFlowPrivate -private import semmle.code.java.dataflow.internal.DataFlowUtil as DataFlowUtil -private import semmle.code.java.dataflow.internal.ContainerFlow as ContainerFlow -private import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl -private import semmle.code.java.dataflow.internal.ModelExclusions -private import semmle.code.java.dataflow.DataFlow as Df -private import semmle.code.java.dataflow.internal.ContentDataFlow as Cdf -private import semmle.code.java.dataflow.SSA as Ssa -private import semmle.code.java.dataflow.TaintTracking as Tt -import semmle.code.java.dataflow.ExternalFlow as ExternalFlow -import semmle.code.java.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon -import semmle.code.java.dataflow.internal.DataFlowPrivate as DataFlowPrivate -import semmle.code.java.dataflow.internal.DataFlowDispatch as DataFlowDispatch - -module DataFlow = Df::DataFlow; - -module ContentDataFlow = Cdf::ContentDataFlow; - -module TaintTracking = Tt::TaintTracking; - -class Type = J::Type; - -class Unit = J::Unit; - -class Callable = J::Callable; - -class ContentSet = DataFlowUtil::ContentSet; - -private predicate isInfrequentlyUsed(J::CompilationUnit cu) { - cu.getPackage().getName().matches("javax.swing%") or - cu.getPackage().getName().matches("java.awt%") -} - -private predicate relevant(Callable api) { - api.isPublic() and - api.getDeclaringType().isPublic() and - api.fromSource() and - not isUninterestingForModels(api) and - not isInfrequentlyUsed(api.getCompilationUnit()) -} - -private J::Method getARelevantOverride(J::Method m) { - result = m.getAnOverride() and - relevant(result) and - // Other exclusions for overrides. - not m instanceof J::ToStringMethod -} - -/** - * Gets the super implementation of `m` if it is relevant. - * If such a super implementations does not exist, returns `m` if it is relevant. - */ -private J::Callable liftedImpl(J::Callable m) { - ( - result = getARelevantOverride(m) - or - result = m and relevant(m) - ) and - not exists(getARelevantOverride(result)) -} - -private predicate hasManualSummaryModel(Callable api) { - api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()).asCallable() or - api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel()).asCallable() -} - -private predicate hasManualSourceModel(Callable api) { - api = any(ExternalFlow::SourceCallable sc | sc.hasManualModel()) or - api = any(FlowSummaryImpl::Public::NeutralSourceCallable sc | sc.hasManualModel()).asCallable() -} - -private predicate hasManualSinkModel(Callable api) { - api = any(ExternalFlow::SinkCallable sc | sc.hasManualModel()) or - api = any(FlowSummaryImpl::Public::NeutralSinkCallable sc | sc.hasManualModel()).asCallable() -} - -/** - * Holds if it is irrelevant to generate models for `api` based on data flow analysis. - * - * This serves as an extra filter for the `relevant` predicate. - */ -predicate isUninterestingForDataFlowModels(Callable api) { - api.getDeclaringType() instanceof J::Interface and not exists(api.getBody()) -} - -/** - * A class of callables that are potentially relevant for generating source or - * sink models. - */ -class SourceOrSinkTargetApi extends Callable { - SourceOrSinkTargetApi() { relevant(this) } -} - -/** - * A class of callables that are potentially relevant for generating sink models. - */ -class SinkTargetApi extends SourceOrSinkTargetApi { - SinkTargetApi() { not hasManualSinkModel(this) } -} - -/** - * A class of callables that are potentially relevant for generating source models. - */ -class SourceTargetApi extends SourceOrSinkTargetApi { - SourceTargetApi() { not hasManualSourceModel(this) } -} - -/** - * Holds if it is irrelevant to generate models for `api` based on type-based analysis. - * - * This serves as an extra filter for the `relevant` predicate. - */ -predicate isUninterestingForTypeBasedFlowModels(Callable api) { none() } - -/** - * A class of callables that are potentially relevant for generating summary or - * neutral models. - * - * In the Standard library and 3rd party libraries it is the callables (or callables that have a - * super implementation) that can be called from outside the library itself. - */ -class SummaryTargetApi extends Callable { - private Callable lift; - - SummaryTargetApi() { - lift = liftedImpl(this) and - not hasManualSummaryModel(lift) - } - - /** - * Gets the callable that a model will be lifted to. - */ - Callable lift() { result = lift } - - /** - * Holds if this callable is relevant in terms of generating models. - */ - predicate isRelevant() { relevant(this) } -} - -private string isExtensible(Callable c) { - if c.getDeclaringType().isFinal() then result = "false" else result = "true" -} - -/** - * Holds if the callable `c` is in package `package` - * and is a member of `type`. - */ -private predicate qualifiedName(Callable c, string package, string type) { - exists(RefType t | t = c.getDeclaringType() | - package = t.getCompilationUnit().getPackage().getName() and - type = t.getErasure().(J::RefType).getNestedName() - ) -} - -predicate partialModel( - Callable api, string package, string type, string extensible, string name, string parameters -) { - qualifiedName(api, package, type) and - extensible = isExtensible(api) and - name = api.getName() and - parameters = ExternalFlow::paramsString(api) -} - -predicate isPrimitiveTypeUsedForBulkData(J::Type t) { - t.hasName(["byte", "char", "Byte", "Character"]) -} - -/** - * Holds for type `t` for fields that are relevant as an intermediate - * read or write step in the data flow analysis. - */ -predicate isRelevantType(J::Type t) { - not t instanceof J::TypeClass and - not t instanceof J::EnumType and - not t instanceof J::PrimitiveType and - not t instanceof J::BoxedType and - not t.(J::RefType).getAnAncestor().hasQualifiedName("java.lang", "Number") and - not t.(J::RefType).getAnAncestor().hasQualifiedName("java.nio.charset", "Charset") and - ( - not t.(J::Array).getElementType() instanceof J::PrimitiveType or - isPrimitiveTypeUsedForBulkData(t.(J::Array).getElementType()) - ) and - ( - not t.(J::Array).getElementType() instanceof J::BoxedType or - isPrimitiveTypeUsedForBulkData(t.(J::Array).getElementType()) - ) and - ( - not t.(ContainerFlow::CollectionType).getElementType() instanceof J::BoxedType or - isPrimitiveTypeUsedForBulkData(t.(ContainerFlow::CollectionType).getElementType()) - ) -} - -/** - * Gets the underlying type of the content `c`. - */ -J::Type getUnderlyingContentType(DataFlow::Content c) { - result = c.(DataFlow::FieldContent).getField().getType() or - result = c.(DataFlow::SyntheticFieldContent).getField().getType() -} - -/** - * Gets the MaD string representation of the qualifier. - */ -string qualifierString() { result = "Argument[this]" } - -/** - * Gets the MaD string representation of the parameter `p`. - */ -string parameterAccess(J::Parameter p) { - if - p.getType() instanceof J::Array and - not isPrimitiveTypeUsedForBulkData(p.getType().(J::Array).getElementType()) - then result = "Argument[" + p.getPosition() + "].ArrayElement" - else - if p.getType() instanceof ContainerFlow::ContainerType - then result = "Argument[" + p.getPosition() + "].Element" - else result = "Argument[" + p.getPosition() + "]" -} - -/** - * Gets the MaD string representation of the parameter `p` - * when used in content flow. - */ -string parameterContentAccess(J::Parameter p) { result = "Argument[" + p.getPosition() + "]" } - -class InstanceParameterNode = DataFlow::InstanceParameterNode; - -class ParameterPosition = DataFlowDispatch::ParameterPosition; - -/** - * Gets the MaD string representation of return through parameter at position - * `pos` of callable `c`. - */ -bindingset[c] -string paramReturnNodeAsOutput(Callable c, ParameterPosition pos) { - result = parameterAccess(c.getParameter(pos)) - or - result = qualifierString() and pos = -1 -} - -/** - * Gets the MaD string representation of return through parameter at position - * `pos` of callable `c` for content flow. - */ -bindingset[c] -string paramReturnNodeAsContentOutput(Callable c, ParameterPosition pos) { - result = parameterContentAccess(c.getParameter(pos)) - or - result = qualifierString() and pos = -1 -} - -/** - * Gets the enclosing callable of `ret`. - */ -Callable returnNodeEnclosingCallable(DataFlow::Node ret) { - result = DataFlowImplCommon::getNodeEnclosingCallable(ret).asCallable() -} - -/** - * Holds if `node` is an own instance access. - */ -predicate isOwnInstanceAccessNode(ReturnNode node) { - node.asExpr().(J::ThisAccess).isOwnInstanceAccess() -} - -predicate sinkModelSanitizer(DataFlow::Node node) { - // exclude variable capture jump steps - exists(Ssa::SsaImplicitInit closure | - closure.captures(_) and - node.asExpr() = closure.getAFirstUse() - ) -} - -/** - * Holds if `source` is an api entrypoint relevant for creating sink models. - */ -predicate apiSource(DataFlow::Node source) { - ( - source.asExpr().(J::FieldAccess).isOwnFieldAccess() or - source instanceof DataFlow::ParameterNode - ) and - exists(J::RefType t | - t = source.getEnclosingCallable().getDeclaringType().getAnAncestor() and - not t instanceof J::TypeObject and - t.isPublic() - ) -} - -/** - * Holds if it is not relevant to generate a source model for `api`, even - * if flow is detected from a node within `source` to a sink within `api`. - */ -predicate irrelevantSourceSinkApi(Callable source, SourceTargetApi api) { none() } - -/** - * Gets the MaD input string representation of `source`. - */ -string asInputArgumentSpecific(DataFlow::Node source) { - exists(int pos | - source.(DataFlow::ParameterNode).isParameterOf(_, pos) and - if pos >= 0 then result = "Argument[" + pos + "]" else result = qualifierString() - ) - or - source.asExpr() instanceof J::FieldAccess and - result = qualifierString() -} - -/** - * Holds if `kind` is a relevant sink kind for creating sink models. - */ -bindingset[kind] -predicate isRelevantSinkKind(string kind) { - not kind = "log-injection" and - not kind.matches("regex-use%") and - not kind = "file-content-store" -} - -/** - * Holds if `kind` is a relevant source kind for creating source models. - */ -bindingset[kind] -predicate isRelevantSourceKind(string kind) { any() } - -predicate containerContent = DataFlowPrivate::containerContent/1; - -/** - * Holds if there is a taint step from `node1` to `node2` in content flow. - */ -predicate isAdditionalContentFlowStep(DataFlow::Node node1, DataFlow::Node node2) { - TaintTracking::defaultAdditionalTaintStep(node1, node2, _) and - not exists(DataFlow::Content f | - DataFlowPrivate::readStep(node1, f, node2) and containerContent(f) - ) -} - -/** - * Holds if the content set `c` is a field or a synthetic field. - */ -predicate isField(ContentSet c) { - c instanceof DataFlowUtil::FieldContent or - c instanceof DataFlowUtil::SyntheticFieldContent -} - -/** - * Gets the MaD synthetic name string representation for the content set `c`, if any. - */ -string getSyntheticName(DataFlow::ContentSet c) { - exists(Field f | - not f.isPublic() and - f = c.(DataFlowUtil::FieldContent).getField() and - result = f.getQualifiedName() - ) - or - result = c.(DataFlowUtil::SyntheticFieldContent).getField() -} - -/** - * Gets the MaD string representation of the content set `c`. - */ -string printContent(ContentSet c) { - exists(Field f | f = c.(DataFlowUtil::FieldContent).getField() and f.isPublic() | - result = "Field[" + f.getQualifiedName() + "]" - ) - or - result = "SyntheticField[" + getSyntheticName(c) + "]" - or - c instanceof DataFlowUtil::CollectionContent and result = "Element" - or - c instanceof DataFlowUtil::ArrayContent and result = "ArrayElement" - or - c instanceof DataFlowUtil::MapValueContent and result = "MapValue" - or - c instanceof DataFlowUtil::MapKeyContent and result = "MapKey" -} diff --git a/java/ql/src/utils/modelgenerator/internal/CaptureSummaryFlowQuery.qll b/java/ql/src/utils/modelgenerator/internal/CaptureSummaryFlowQuery.qll deleted file mode 100644 index 5b1a6fc031b0..000000000000 --- a/java/ql/src/utils/modelgenerator/internal/CaptureSummaryFlowQuery.qll +++ /dev/null @@ -1,84 +0,0 @@ -private import CaptureModels - -/** - * Capture fluent APIs that return `this`. - * Example of a fluent API: - * ```java - * public class Foo { - * public Foo someAPI() { - * // some side-effect - * return this; - * } - * } - * ``` - * - * Capture APIs that transfer taint from an input parameter to an output return - * value or parameter. - * Allows a sequence of read steps followed by a sequence of store steps. - * - * Examples: - * - * ```java - * public class Foo { - * private String tainted; - * - * public String returnsTainted() { - * return tainted; - * } - * - * public void putsTaintIntoParameter(List foo) { - * foo.add(tainted); - * } - * } - * ``` - * Captured Models: - * ``` - * p;Foo;true;returnsTainted;;Argument[this];ReturnValue;taint;df-generated - * p;Foo;true;putsTaintIntoParameter;(List);Argument[this];Argument[0];taint;df-generated - * ``` - * - * ```java - * public class Foo { - * private String tainted; - * public void doSomething(String input) { - * tainted = input; - * } - * ``` - * Captured Model: - * ```p;Foo;true;doSomething;(String);Argument[0];Argument[this];taint;df-generated``` - * - * ```java - * public class Foo { - * public String returnData(String tainted) { - * return tainted.substring(0,10) - * } - * } - * ``` - * Captured Model: - * ```p;Foo;true;returnData;;Argument[0];ReturnValue;taint;df-generated``` - * - * ```java - * public class Foo { - * public void addToList(String tainted, List foo) { - * foo.add(tainted); - * } - * } - * ``` - * Captured Model: - * ```p;Foo;true;addToList;;Argument[0];Argument[1];taint;df-generated``` - */ -string captureFlow(DataFlowSummaryTargetApi api) { - result = captureQualifierFlow(api) or - result = captureThroughFlow(api) -} - -/** - * Gets the neutral summary model for `api`, if any. - * A neutral summary model is generated, if we are not generating - * a summary model that applies to `api`. - */ -string captureNoFlow(DataFlowSummaryTargetApi api) { - not exists(DataFlowSummaryTargetApi api0 | exists(captureFlow(api0)) and api0.lift() = api.lift()) and - api.isRelevant() and - result = Printing::asNeutralSummaryModel(api) -} diff --git a/java/ql/src/utils/modelgenerator/internal/CaptureTypeBasedSummaryModels.qll b/java/ql/src/utils/modelgenerator/internal/CaptureTypeBasedSummaryModels.qll index 3d56dff50726..36aec8053196 100644 --- a/java/ql/src/utils/modelgenerator/internal/CaptureTypeBasedSummaryModels.qll +++ b/java/ql/src/utils/modelgenerator/internal/CaptureTypeBasedSummaryModels.qll @@ -1,7 +1,8 @@ private import java private import semmle.code.java.Collections private import semmle.code.java.dataflow.internal.ContainerFlow -private import CaptureModelsSpecific as Specific +private import CaptureModels as CaptureModels +private import CaptureModels::ModelGeneratorInput as ModelGeneratorInput private import CaptureModelsPrinting /** @@ -81,7 +82,7 @@ private predicate localTypeParameter(Callable callable, TypeVariable tv) { private string getAccessPath(Type t) { if t instanceof Array and - not Specific::isPrimitiveTypeUsedForBulkData(t.(Array).getElementType()) + not CaptureModels::isPrimitiveTypeUsedForBulkData(t.(Array).getElementType()) then result = ".ArrayElement" else if t instanceof ContainerType or t instanceof IterableClass @@ -134,7 +135,7 @@ private string implicit(Callable callable, TypeVariable tv) { then access = getAccessPath(decl) else access = getSyntheticField(tv) | - result = Specific::qualifierString() + access + result = ModelGeneratorInput::qualifierString() + access ) } @@ -286,7 +287,7 @@ private predicate output(Callable callable, TypeVariable tv, string output) { module ModelPrintingInput implements ModelPrintingSig { class SummaryApi = TypeBasedFlowTargetApi; - class SourceOrSinkApi = Specific::SourceOrSinkTargetApi; + class SourceOrSinkApi = ModelGeneratorInput::SourceOrSinkTargetApi; string getProvenance() { result = "tb-generated" } } @@ -297,9 +298,7 @@ private module Printing = ModelPrinting; * A class of callables that are relevant generating summaries for based * on the Theorems for Free approach. */ -class TypeBasedFlowTargetApi extends Specific::SummaryTargetApi { - TypeBasedFlowTargetApi() { not Specific::isUninterestingForTypeBasedFlowModels(this) } - +class TypeBasedFlowTargetApi extends ModelGeneratorInput::SummaryTargetApi { /** * Gets the string representation of all type based summaries for `this` * inspired by the Theorems for Free approach. diff --git a/java/ql/test/experimental/query-tests/security/CWE-078/CommandInjectionRuntimeExecLocal.expected b/java/ql/test/experimental/query-tests/security/CWE-078/CommandInjectionRuntimeExecLocal.expected index d9a25998db97..4b46d4d5cd49 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-078/CommandInjectionRuntimeExecLocal.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-078/CommandInjectionRuntimeExecLocal.expected @@ -14,8 +14,7 @@ edges | RuntimeExecTest.java:25:66:25:71 | script : String | RuntimeExecTest.java:25:42:25:72 | {...} : String[] [[]] : String | provenance | | | RuntimeExecTest.java:31:17:31:29 | commandArray2 [post update] : String[] [[]] : String | RuntimeExecTest.java:32:43:32:55 | commandArray2 | provenance | Sink:MaD:1 | | RuntimeExecTest.java:31:36:31:41 | script : String | RuntimeExecTest.java:31:17:31:29 | commandArray2 [post update] : String[] [[]] : String | provenance | | -| RuntimeExecTest.java:36:21:39:21 | concat(...) : Stream [] : String | RuntimeExecTest.java:36:21:39:44 | toArray(...) : String[] [[]] : String | provenance | MaD:5 | -| RuntimeExecTest.java:36:21:39:44 | toArray(...) : String[] [[]] : String | RuntimeExecTest.java:36:21:39:44 | toArray(...) | provenance | Sink:MaD:1 | +| RuntimeExecTest.java:36:21:39:21 | concat(...) : Stream [] : String | RuntimeExecTest.java:36:21:39:44 | toArray(...) | provenance | MaD:5 Sink:MaD:1 | | RuntimeExecTest.java:38:25:38:59 | stream(...) : Stream [] : String | RuntimeExecTest.java:36:21:39:21 | concat(...) : Stream [] : String | provenance | MaD:4 | | RuntimeExecTest.java:38:39:38:58 | new String[] : String[] [[]] : String | RuntimeExecTest.java:38:25:38:59 | stream(...) : Stream [] : String | provenance | MaD:3 | | RuntimeExecTest.java:38:39:38:58 | {...} : String[] [[]] : String | RuntimeExecTest.java:38:39:38:58 | new String[] : String[] [[]] : String | provenance | | @@ -39,7 +38,6 @@ nodes | RuntimeExecTest.java:32:43:32:55 | commandArray2 | semmle.label | commandArray2 | | RuntimeExecTest.java:36:21:39:21 | concat(...) : Stream [] : String | semmle.label | concat(...) : Stream [] : String | | RuntimeExecTest.java:36:21:39:44 | toArray(...) | semmle.label | toArray(...) | -| RuntimeExecTest.java:36:21:39:44 | toArray(...) : String[] [[]] : String | semmle.label | toArray(...) : String[] [[]] : String | | RuntimeExecTest.java:38:25:38:59 | stream(...) : Stream [] : String | semmle.label | stream(...) : Stream [] : String | | RuntimeExecTest.java:38:39:38:58 | new String[] : String[] [[]] : String | semmle.label | new String[] : String[] [[]] : String | | RuntimeExecTest.java:38:39:38:58 | {...} : String[] [[]] : String | semmle.label | {...} : String[] [[]] : String | diff --git a/java/ql/test/library-tests/frameworks/apache-commons-lang3/flow.expected b/java/ql/test/library-tests/frameworks/apache-commons-lang3/flow.expected index 9031c242a1c8..ac257eebe339 100644 --- a/java/ql/test/library-tests/frameworks/apache-commons-lang3/flow.expected +++ b/java/ql/test/library-tests/frameworks/apache-commons-lang3/flow.expected @@ -682,62 +682,38 @@ edges | ArrayUtilsTest.java:20:33:20:56 | {...} : String[] [[]] : String | ArrayUtilsTest.java:59:32:59:45 | alreadyTainted : String[] [[]] : String | provenance | | | ArrayUtilsTest.java:20:33:20:56 | {...} : String[] [[]] : String | ArrayUtilsTest.java:63:29:63:42 | alreadyTainted : String[] [[]] : String | provenance | | | ArrayUtilsTest.java:20:48:20:54 | taint(...) : String | ArrayUtilsTest.java:20:33:20:56 | {...} : String[] [[]] : String | provenance | | -| ArrayUtilsTest.java:23:12:23:44 | add(...) : String[] [[]] : String | ArrayUtilsTest.java:23:12:23:44 | add(...) | provenance | | -| ArrayUtilsTest.java:23:37:23:43 | taint(...) : String | ArrayUtilsTest.java:23:12:23:44 | add(...) : String[] [[]] : String | provenance | MaD:32 | -| ArrayUtilsTest.java:24:12:24:53 | add(...) : String[] [[]] : String | ArrayUtilsTest.java:24:12:24:53 | add(...) | provenance | | -| ArrayUtilsTest.java:24:27:24:40 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:24:12:24:53 | add(...) : String[] [[]] : String | provenance | MaD:31 | -| ArrayUtilsTest.java:26:12:26:41 | add(...) : String[] [[]] : String | ArrayUtilsTest.java:26:12:26:41 | add(...) | provenance | | -| ArrayUtilsTest.java:26:34:26:40 | taint(...) : String | ArrayUtilsTest.java:26:12:26:41 | add(...) : String[] [[]] : String | provenance | MaD:33 | -| ArrayUtilsTest.java:27:12:27:50 | add(...) : String[] [[]] : String | ArrayUtilsTest.java:27:12:27:50 | add(...) | provenance | | -| ArrayUtilsTest.java:27:27:27:40 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:27:12:27:50 | add(...) : String[] [[]] : String | provenance | MaD:31 | -| ArrayUtilsTest.java:28:12:28:53 | addAll(...) : String[] [[]] : String | ArrayUtilsTest.java:28:12:28:53 | addAll(...) | provenance | | -| ArrayUtilsTest.java:28:12:28:53 | new ..[] { .. } : Object[] [[]] : String | ArrayUtilsTest.java:28:12:28:53 | addAll(...) : String[] [[]] : String | provenance | MaD:34 | +| ArrayUtilsTest.java:23:37:23:43 | taint(...) : String | ArrayUtilsTest.java:23:12:23:44 | add(...) | provenance | MaD:32 | +| ArrayUtilsTest.java:24:27:24:40 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:24:12:24:53 | add(...) | provenance | MaD:31 | +| ArrayUtilsTest.java:26:34:26:40 | taint(...) : String | ArrayUtilsTest.java:26:12:26:41 | add(...) | provenance | MaD:33 | +| ArrayUtilsTest.java:27:27:27:40 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:27:12:27:50 | add(...) | provenance | MaD:31 | +| ArrayUtilsTest.java:28:12:28:53 | new ..[] { .. } : Object[] [[]] : String | ArrayUtilsTest.java:28:12:28:53 | addAll(...) | provenance | MaD:34 | | ArrayUtilsTest.java:28:46:28:52 | taint(...) : String | ArrayUtilsTest.java:28:12:28:53 | new ..[] { .. } : Object[] [[]] : String | provenance | | -| ArrayUtilsTest.java:29:12:29:53 | addAll(...) : String[] [[]] : String | ArrayUtilsTest.java:29:12:29:53 | addAll(...) | provenance | | -| ArrayUtilsTest.java:29:12:29:53 | new ..[] { .. } : Object[] [[]] : String | ArrayUtilsTest.java:29:12:29:53 | addAll(...) : String[] [[]] : String | provenance | MaD:34 | +| ArrayUtilsTest.java:29:12:29:53 | new ..[] { .. } : Object[] [[]] : String | ArrayUtilsTest.java:29:12:29:53 | addAll(...) | provenance | MaD:34 | | ArrayUtilsTest.java:29:37:29:43 | taint(...) : String | ArrayUtilsTest.java:29:12:29:53 | new ..[] { .. } : Object[] [[]] : String | provenance | | -| ArrayUtilsTest.java:30:12:30:67 | addAll(...) : String[] [[]] : String | ArrayUtilsTest.java:30:12:30:67 | addAll(...) | provenance | | -| ArrayUtilsTest.java:30:30:30:43 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:30:12:30:67 | addAll(...) : String[] [[]] : String | provenance | MaD:34 | -| ArrayUtilsTest.java:31:12:31:46 | addFirst(...) : String[] [[]] : String | ArrayUtilsTest.java:31:12:31:46 | addFirst(...) | provenance | | -| ArrayUtilsTest.java:31:39:31:45 | taint(...) : String | ArrayUtilsTest.java:31:12:31:46 | addFirst(...) : String[] [[]] : String | provenance | MaD:36 | -| ArrayUtilsTest.java:32:12:32:55 | addFirst(...) : String[] [[]] : String | ArrayUtilsTest.java:32:12:32:55 | addFirst(...) | provenance | | -| ArrayUtilsTest.java:32:32:32:45 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:32:12:32:55 | addFirst(...) : String[] [[]] : String | provenance | MaD:35 | -| ArrayUtilsTest.java:33:12:33:43 | clone(...) : String[] [[]] : String | ArrayUtilsTest.java:33:12:33:43 | clone(...) | provenance | | -| ArrayUtilsTest.java:33:29:33:42 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:33:12:33:43 | clone(...) : String[] [[]] : String | provenance | MaD:37 | +| ArrayUtilsTest.java:30:30:30:43 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:30:12:30:67 | addAll(...) | provenance | MaD:34 | +| ArrayUtilsTest.java:31:39:31:45 | taint(...) : String | ArrayUtilsTest.java:31:12:31:46 | addFirst(...) | provenance | MaD:36 | +| ArrayUtilsTest.java:32:32:32:45 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:32:12:32:55 | addFirst(...) | provenance | MaD:35 | +| ArrayUtilsTest.java:33:29:33:42 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:33:12:33:43 | clone(...) | provenance | MaD:37 | | ArrayUtilsTest.java:34:27:34:40 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:34:12:34:44 | get(...) | provenance | MaD:38 | | ArrayUtilsTest.java:36:27:36:40 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:36:12:36:61 | get(...) | provenance | MaD:38 | | ArrayUtilsTest.java:38:37:38:43 | taint(...) : String | ArrayUtilsTest.java:38:12:38:44 | get(...) | provenance | MaD:39 | -| ArrayUtilsTest.java:40:12:40:67 | insert(...) : String[] [[]] : String | ArrayUtilsTest.java:40:12:40:67 | insert(...) | provenance | | -| ArrayUtilsTest.java:40:33:40:46 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:40:12:40:67 | insert(...) : String[] [[]] : String | provenance | MaD:40 | -| ArrayUtilsTest.java:41:12:41:57 | insert(...) : String[] [[]] : String | ArrayUtilsTest.java:41:12:41:57 | insert(...) | provenance | | -| ArrayUtilsTest.java:41:12:41:57 | new ..[] { .. } : Object[] [[]] : String | ArrayUtilsTest.java:41:12:41:57 | insert(...) : String[] [[]] : String | provenance | MaD:40 | +| ArrayUtilsTest.java:40:33:40:46 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:40:12:40:67 | insert(...) | provenance | MaD:40 | +| ArrayUtilsTest.java:41:12:41:57 | new ..[] { .. } : Object[] [[]] : String | ArrayUtilsTest.java:41:12:41:57 | insert(...) | provenance | MaD:40 | | ArrayUtilsTest.java:41:40:41:46 | taint(...) : String | ArrayUtilsTest.java:41:12:41:57 | new ..[] { .. } : Object[] [[]] : String | provenance | | -| ArrayUtilsTest.java:42:12:42:57 | insert(...) : String[] [[]] : String | ArrayUtilsTest.java:42:12:42:57 | insert(...) | provenance | | -| ArrayUtilsTest.java:42:12:42:57 | new ..[] { .. } : Object[] [[]] : String | ArrayUtilsTest.java:42:12:42:57 | insert(...) : String[] [[]] : String | provenance | MaD:40 | +| ArrayUtilsTest.java:42:12:42:57 | new ..[] { .. } : Object[] [[]] : String | ArrayUtilsTest.java:42:12:42:57 | insert(...) | provenance | MaD:40 | | ArrayUtilsTest.java:42:50:42:56 | taint(...) : String | ArrayUtilsTest.java:42:12:42:57 | new ..[] { .. } : Object[] [[]] : String | provenance | | -| ArrayUtilsTest.java:43:12:43:49 | nullToEmpty(...) : String[] [[]] : String | ArrayUtilsTest.java:43:12:43:49 | nullToEmpty(...) | provenance | | -| ArrayUtilsTest.java:43:35:43:48 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:43:12:43:49 | nullToEmpty(...) : String[] [[]] : String | provenance | MaD:42 | -| ArrayUtilsTest.java:44:12:44:65 | nullToEmpty(...) : String[] [[]] : String | ArrayUtilsTest.java:44:12:44:65 | nullToEmpty(...) | provenance | | -| ArrayUtilsTest.java:44:35:44:48 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:44:12:44:65 | nullToEmpty(...) : String[] [[]] : String | provenance | MaD:41 | -| ArrayUtilsTest.java:45:12:45:47 | remove(...) : String[] [[]] : String | ArrayUtilsTest.java:45:12:45:47 | remove(...) | provenance | | -| ArrayUtilsTest.java:45:30:45:43 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:45:12:45:47 | remove(...) : String[] [[]] : String | provenance | MaD:43 | -| ArrayUtilsTest.java:47:12:47:53 | removeAll(...) : String[] [[]] : String | ArrayUtilsTest.java:47:12:47:53 | removeAll(...) | provenance | | -| ArrayUtilsTest.java:47:33:47:46 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:47:12:47:53 | removeAll(...) : String[] [[]] : String | provenance | MaD:44 | -| ArrayUtilsTest.java:51:12:51:76 | removeAllOccurences(...) : String[] [[]] : String | ArrayUtilsTest.java:51:12:51:76 | removeAllOccurences(...) | provenance | | -| ArrayUtilsTest.java:51:43:51:56 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:51:12:51:76 | removeAllOccurences(...) : String[] [[]] : String | provenance | MaD:45 | -| ArrayUtilsTest.java:53:12:53:77 | removeAllOccurrences(...) : String[] [[]] : String | ArrayUtilsTest.java:53:12:53:77 | removeAllOccurrences(...) | provenance | | -| ArrayUtilsTest.java:53:44:53:57 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:53:12:53:77 | removeAllOccurrences(...) : String[] [[]] : String | provenance | MaD:46 | -| ArrayUtilsTest.java:55:12:55:70 | removeElement(...) : String[] [[]] : String | ArrayUtilsTest.java:55:12:55:70 | removeElement(...) | provenance | | -| ArrayUtilsTest.java:55:37:55:50 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:55:12:55:70 | removeElement(...) : String[] [[]] : String | provenance | MaD:47 | -| ArrayUtilsTest.java:56:12:56:58 | removeElements(...) : Object[] [[]] : String | ArrayUtilsTest.java:56:12:56:58 | removeElements(...) | provenance | | -| ArrayUtilsTest.java:56:38:56:51 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:56:12:56:58 | removeElements(...) : Object[] [[]] : String | provenance | MaD:48 | -| ArrayUtilsTest.java:59:12:59:52 | subarray(...) : String[] [[]] : String | ArrayUtilsTest.java:59:12:59:52 | subarray(...) | provenance | | -| ArrayUtilsTest.java:59:32:59:45 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:59:12:59:52 | subarray(...) : String[] [[]] : String | provenance | MaD:49 | -| ArrayUtilsTest.java:61:12:61:47 | new ..[] { .. } : Object[] [[]] : String | ArrayUtilsTest.java:61:12:61:47 | toArray(...) : String[] [[]] : String | provenance | MaD:50 | -| ArrayUtilsTest.java:61:12:61:47 | toArray(...) : String[] [[]] : String | ArrayUtilsTest.java:61:12:61:47 | toArray(...) | provenance | | +| ArrayUtilsTest.java:43:35:43:48 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:43:12:43:49 | nullToEmpty(...) | provenance | MaD:42 | +| ArrayUtilsTest.java:44:35:44:48 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:44:12:44:65 | nullToEmpty(...) | provenance | MaD:41 | +| ArrayUtilsTest.java:45:30:45:43 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:45:12:45:47 | remove(...) | provenance | MaD:43 | +| ArrayUtilsTest.java:47:33:47:46 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:47:12:47:53 | removeAll(...) | provenance | MaD:44 | +| ArrayUtilsTest.java:51:43:51:56 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:51:12:51:76 | removeAllOccurences(...) | provenance | MaD:45 | +| ArrayUtilsTest.java:53:44:53:57 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:53:12:53:77 | removeAllOccurrences(...) | provenance | MaD:46 | +| ArrayUtilsTest.java:55:37:55:50 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:55:12:55:70 | removeElement(...) | provenance | MaD:47 | +| ArrayUtilsTest.java:56:38:56:51 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:56:12:56:58 | removeElements(...) | provenance | MaD:48 | +| ArrayUtilsTest.java:59:32:59:45 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:59:12:59:52 | subarray(...) | provenance | MaD:49 | +| ArrayUtilsTest.java:61:12:61:47 | new ..[] { .. } : Object[] [[]] : String | ArrayUtilsTest.java:61:12:61:47 | toArray(...) | provenance | MaD:50 | | ArrayUtilsTest.java:61:40:61:46 | taint(...) : String | ArrayUtilsTest.java:61:12:61:47 | new ..[] { .. } : Object[] [[]] : String | provenance | | -| ArrayUtilsTest.java:62:12:62:47 | new ..[] { .. } : Object[] [[]] : String | ArrayUtilsTest.java:62:12:62:47 | toArray(...) : String[] [[]] : String | provenance | MaD:50 | -| ArrayUtilsTest.java:62:12:62:47 | toArray(...) : String[] [[]] : String | ArrayUtilsTest.java:62:12:62:47 | toArray(...) | provenance | | +| ArrayUtilsTest.java:62:12:62:47 | new ..[] { .. } : Object[] [[]] : String | ArrayUtilsTest.java:62:12:62:47 | toArray(...) | provenance | MaD:50 | | ArrayUtilsTest.java:62:31:62:37 | taint(...) : String | ArrayUtilsTest.java:62:12:62:47 | new ..[] { .. } : Object[] [[]] : String | provenance | | | ArrayUtilsTest.java:63:12:63:43 | toMap(...) : Map [] : Object | ArrayUtilsTest.java:63:12:63:54 | get(...) | provenance | MaD:15 | | ArrayUtilsTest.java:63:29:63:42 | alreadyTainted : String[] [[]] : String | ArrayUtilsTest.java:63:12:63:43 | toMap(...) : Map [] : Object | provenance | MaD:51 | @@ -747,10 +723,8 @@ edges | ArrayUtilsTest.java:69:36:69:67 | toObject(...) : Integer[] [[]] : Number | ArrayUtilsTest.java:70:12:70:27 | taintedBoxedInts | provenance | | | ArrayUtilsTest.java:69:36:69:67 | toObject(...) : Integer[] [[]] : Number | ArrayUtilsTest.java:71:35:71:50 | taintedBoxedInts : Integer[] [[]] : Number | provenance | | | ArrayUtilsTest.java:69:56:69:66 | taintedInts : int[] [[]] : Number | ArrayUtilsTest.java:69:36:69:67 | toObject(...) : Integer[] [[]] : Number | provenance | MaD:53 | -| ArrayUtilsTest.java:71:12:71:51 | toPrimitive(...) : int[] [[]] : Number | ArrayUtilsTest.java:71:12:71:51 | toPrimitive(...) | provenance | | -| ArrayUtilsTest.java:71:35:71:50 | taintedBoxedInts : Integer[] [[]] : Number | ArrayUtilsTest.java:71:12:71:51 | toPrimitive(...) : int[] [[]] : Number | provenance | MaD:54 | -| ArrayUtilsTest.java:72:12:72:70 | toPrimitive(...) : int[] [[]] : Number | ArrayUtilsTest.java:72:12:72:70 | toPrimitive(...) | provenance | | -| ArrayUtilsTest.java:72:53:72:69 | taint(...) : Number | ArrayUtilsTest.java:72:12:72:70 | toPrimitive(...) : int[] [[]] : Number | provenance | MaD:55 | +| ArrayUtilsTest.java:71:35:71:50 | taintedBoxedInts : Integer[] [[]] : Number | ArrayUtilsTest.java:71:12:71:51 | toPrimitive(...) | provenance | MaD:54 | +| ArrayUtilsTest.java:72:53:72:69 | taint(...) : Number | ArrayUtilsTest.java:72:12:72:70 | toPrimitive(...) | provenance | MaD:55 | | MutableTest.java:11:39:11:66 | new MutableObject(...) : MutableObject [org.apache.commons.lang3.mutable.MutableObject.value] : String | MutableTest.java:20:12:20:18 | tainted : MutableObject [org.apache.commons.lang3.mutable.MutableObject.value] : String | provenance | | | MutableTest.java:11:39:11:66 | new MutableObject(...) : MutableObject [org.apache.commons.lang3.mutable.MutableObject.value] : String | MutableTest.java:21:12:21:23 | taintedAlias : MutableObject [org.apache.commons.lang3.mutable.MutableObject.value] : String | provenance | | | MutableTest.java:11:59:11:65 | taint(...) : String | MutableTest.java:11:39:11:66 | new MutableObject(...) : MutableObject [org.apache.commons.lang3.mutable.MutableObject.value] : String | provenance | MaD:225 | @@ -3338,36 +3312,26 @@ nodes | ArrayUtilsTest.java:20:33:20:56 | {...} : String[] [[]] : String | semmle.label | {...} : String[] [[]] : String | | ArrayUtilsTest.java:20:48:20:54 | taint(...) : String | semmle.label | taint(...) : String | | ArrayUtilsTest.java:23:12:23:44 | add(...) | semmle.label | add(...) | -| ArrayUtilsTest.java:23:12:23:44 | add(...) : String[] [[]] : String | semmle.label | add(...) : String[] [[]] : String | | ArrayUtilsTest.java:23:37:23:43 | taint(...) : String | semmle.label | taint(...) : String | | ArrayUtilsTest.java:24:12:24:53 | add(...) | semmle.label | add(...) | -| ArrayUtilsTest.java:24:12:24:53 | add(...) : String[] [[]] : String | semmle.label | add(...) : String[] [[]] : String | | ArrayUtilsTest.java:24:27:24:40 | alreadyTainted : String[] [[]] : String | semmle.label | alreadyTainted : String[] [[]] : String | | ArrayUtilsTest.java:26:12:26:41 | add(...) | semmle.label | add(...) | -| ArrayUtilsTest.java:26:12:26:41 | add(...) : String[] [[]] : String | semmle.label | add(...) : String[] [[]] : String | | ArrayUtilsTest.java:26:34:26:40 | taint(...) : String | semmle.label | taint(...) : String | | ArrayUtilsTest.java:27:12:27:50 | add(...) | semmle.label | add(...) | -| ArrayUtilsTest.java:27:12:27:50 | add(...) : String[] [[]] : String | semmle.label | add(...) : String[] [[]] : String | | ArrayUtilsTest.java:27:27:27:40 | alreadyTainted : String[] [[]] : String | semmle.label | alreadyTainted : String[] [[]] : String | | ArrayUtilsTest.java:28:12:28:53 | addAll(...) | semmle.label | addAll(...) | -| ArrayUtilsTest.java:28:12:28:53 | addAll(...) : String[] [[]] : String | semmle.label | addAll(...) : String[] [[]] : String | | ArrayUtilsTest.java:28:12:28:53 | new ..[] { .. } : Object[] [[]] : String | semmle.label | new ..[] { .. } : Object[] [[]] : String | | ArrayUtilsTest.java:28:46:28:52 | taint(...) : String | semmle.label | taint(...) : String | | ArrayUtilsTest.java:29:12:29:53 | addAll(...) | semmle.label | addAll(...) | -| ArrayUtilsTest.java:29:12:29:53 | addAll(...) : String[] [[]] : String | semmle.label | addAll(...) : String[] [[]] : String | | ArrayUtilsTest.java:29:12:29:53 | new ..[] { .. } : Object[] [[]] : String | semmle.label | new ..[] { .. } : Object[] [[]] : String | | ArrayUtilsTest.java:29:37:29:43 | taint(...) : String | semmle.label | taint(...) : String | | ArrayUtilsTest.java:30:12:30:67 | addAll(...) | semmle.label | addAll(...) | -| ArrayUtilsTest.java:30:12:30:67 | addAll(...) : String[] [[]] : String | semmle.label | addAll(...) : String[] [[]] : String | | ArrayUtilsTest.java:30:30:30:43 | alreadyTainted : String[] [[]] : String | semmle.label | alreadyTainted : String[] [[]] : String | | ArrayUtilsTest.java:31:12:31:46 | addFirst(...) | semmle.label | addFirst(...) | -| ArrayUtilsTest.java:31:12:31:46 | addFirst(...) : String[] [[]] : String | semmle.label | addFirst(...) : String[] [[]] : String | | ArrayUtilsTest.java:31:39:31:45 | taint(...) : String | semmle.label | taint(...) : String | | ArrayUtilsTest.java:32:12:32:55 | addFirst(...) | semmle.label | addFirst(...) | -| ArrayUtilsTest.java:32:12:32:55 | addFirst(...) : String[] [[]] : String | semmle.label | addFirst(...) : String[] [[]] : String | | ArrayUtilsTest.java:32:32:32:45 | alreadyTainted : String[] [[]] : String | semmle.label | alreadyTainted : String[] [[]] : String | | ArrayUtilsTest.java:33:12:33:43 | clone(...) | semmle.label | clone(...) | -| ArrayUtilsTest.java:33:12:33:43 | clone(...) : String[] [[]] : String | semmle.label | clone(...) : String[] [[]] : String | | ArrayUtilsTest.java:33:29:33:42 | alreadyTainted : String[] [[]] : String | semmle.label | alreadyTainted : String[] [[]] : String | | ArrayUtilsTest.java:34:12:34:44 | get(...) | semmle.label | get(...) | | ArrayUtilsTest.java:34:27:34:40 | alreadyTainted : String[] [[]] : String | semmle.label | alreadyTainted : String[] [[]] : String | @@ -3376,50 +3340,36 @@ nodes | ArrayUtilsTest.java:38:12:38:44 | get(...) | semmle.label | get(...) | | ArrayUtilsTest.java:38:37:38:43 | taint(...) : String | semmle.label | taint(...) : String | | ArrayUtilsTest.java:40:12:40:67 | insert(...) | semmle.label | insert(...) | -| ArrayUtilsTest.java:40:12:40:67 | insert(...) : String[] [[]] : String | semmle.label | insert(...) : String[] [[]] : String | | ArrayUtilsTest.java:40:33:40:46 | alreadyTainted : String[] [[]] : String | semmle.label | alreadyTainted : String[] [[]] : String | | ArrayUtilsTest.java:41:12:41:57 | insert(...) | semmle.label | insert(...) | -| ArrayUtilsTest.java:41:12:41:57 | insert(...) : String[] [[]] : String | semmle.label | insert(...) : String[] [[]] : String | | ArrayUtilsTest.java:41:12:41:57 | new ..[] { .. } : Object[] [[]] : String | semmle.label | new ..[] { .. } : Object[] [[]] : String | | ArrayUtilsTest.java:41:40:41:46 | taint(...) : String | semmle.label | taint(...) : String | | ArrayUtilsTest.java:42:12:42:57 | insert(...) | semmle.label | insert(...) | -| ArrayUtilsTest.java:42:12:42:57 | insert(...) : String[] [[]] : String | semmle.label | insert(...) : String[] [[]] : String | | ArrayUtilsTest.java:42:12:42:57 | new ..[] { .. } : Object[] [[]] : String | semmle.label | new ..[] { .. } : Object[] [[]] : String | | ArrayUtilsTest.java:42:50:42:56 | taint(...) : String | semmle.label | taint(...) : String | | ArrayUtilsTest.java:43:12:43:49 | nullToEmpty(...) | semmle.label | nullToEmpty(...) | -| ArrayUtilsTest.java:43:12:43:49 | nullToEmpty(...) : String[] [[]] : String | semmle.label | nullToEmpty(...) : String[] [[]] : String | | ArrayUtilsTest.java:43:35:43:48 | alreadyTainted : String[] [[]] : String | semmle.label | alreadyTainted : String[] [[]] : String | | ArrayUtilsTest.java:44:12:44:65 | nullToEmpty(...) | semmle.label | nullToEmpty(...) | -| ArrayUtilsTest.java:44:12:44:65 | nullToEmpty(...) : String[] [[]] : String | semmle.label | nullToEmpty(...) : String[] [[]] : String | | ArrayUtilsTest.java:44:35:44:48 | alreadyTainted : String[] [[]] : String | semmle.label | alreadyTainted : String[] [[]] : String | | ArrayUtilsTest.java:45:12:45:47 | remove(...) | semmle.label | remove(...) | -| ArrayUtilsTest.java:45:12:45:47 | remove(...) : String[] [[]] : String | semmle.label | remove(...) : String[] [[]] : String | | ArrayUtilsTest.java:45:30:45:43 | alreadyTainted : String[] [[]] : String | semmle.label | alreadyTainted : String[] [[]] : String | | ArrayUtilsTest.java:47:12:47:53 | removeAll(...) | semmle.label | removeAll(...) | -| ArrayUtilsTest.java:47:12:47:53 | removeAll(...) : String[] [[]] : String | semmle.label | removeAll(...) : String[] [[]] : String | | ArrayUtilsTest.java:47:33:47:46 | alreadyTainted : String[] [[]] : String | semmle.label | alreadyTainted : String[] [[]] : String | | ArrayUtilsTest.java:51:12:51:76 | removeAllOccurences(...) | semmle.label | removeAllOccurences(...) | -| ArrayUtilsTest.java:51:12:51:76 | removeAllOccurences(...) : String[] [[]] : String | semmle.label | removeAllOccurences(...) : String[] [[]] : String | | ArrayUtilsTest.java:51:43:51:56 | alreadyTainted : String[] [[]] : String | semmle.label | alreadyTainted : String[] [[]] : String | | ArrayUtilsTest.java:53:12:53:77 | removeAllOccurrences(...) | semmle.label | removeAllOccurrences(...) | -| ArrayUtilsTest.java:53:12:53:77 | removeAllOccurrences(...) : String[] [[]] : String | semmle.label | removeAllOccurrences(...) : String[] [[]] : String | | ArrayUtilsTest.java:53:44:53:57 | alreadyTainted : String[] [[]] : String | semmle.label | alreadyTainted : String[] [[]] : String | | ArrayUtilsTest.java:55:12:55:70 | removeElement(...) | semmle.label | removeElement(...) | -| ArrayUtilsTest.java:55:12:55:70 | removeElement(...) : String[] [[]] : String | semmle.label | removeElement(...) : String[] [[]] : String | | ArrayUtilsTest.java:55:37:55:50 | alreadyTainted : String[] [[]] : String | semmle.label | alreadyTainted : String[] [[]] : String | | ArrayUtilsTest.java:56:12:56:58 | removeElements(...) | semmle.label | removeElements(...) | -| ArrayUtilsTest.java:56:12:56:58 | removeElements(...) : Object[] [[]] : String | semmle.label | removeElements(...) : Object[] [[]] : String | | ArrayUtilsTest.java:56:38:56:51 | alreadyTainted : String[] [[]] : String | semmle.label | alreadyTainted : String[] [[]] : String | | ArrayUtilsTest.java:59:12:59:52 | subarray(...) | semmle.label | subarray(...) | -| ArrayUtilsTest.java:59:12:59:52 | subarray(...) : String[] [[]] : String | semmle.label | subarray(...) : String[] [[]] : String | | ArrayUtilsTest.java:59:32:59:45 | alreadyTainted : String[] [[]] : String | semmle.label | alreadyTainted : String[] [[]] : String | | ArrayUtilsTest.java:61:12:61:47 | new ..[] { .. } : Object[] [[]] : String | semmle.label | new ..[] { .. } : Object[] [[]] : String | | ArrayUtilsTest.java:61:12:61:47 | toArray(...) | semmle.label | toArray(...) | -| ArrayUtilsTest.java:61:12:61:47 | toArray(...) : String[] [[]] : String | semmle.label | toArray(...) : String[] [[]] : String | | ArrayUtilsTest.java:61:40:61:46 | taint(...) : String | semmle.label | taint(...) : String | | ArrayUtilsTest.java:62:12:62:47 | new ..[] { .. } : Object[] [[]] : String | semmle.label | new ..[] { .. } : Object[] [[]] : String | | ArrayUtilsTest.java:62:12:62:47 | toArray(...) | semmle.label | toArray(...) | -| ArrayUtilsTest.java:62:12:62:47 | toArray(...) : String[] [[]] : String | semmle.label | toArray(...) : String[] [[]] : String | | ArrayUtilsTest.java:62:31:62:37 | taint(...) : String | semmle.label | taint(...) : String | | ArrayUtilsTest.java:63:12:63:43 | toMap(...) : Map [] : Object | semmle.label | toMap(...) : Map [] : Object | | ArrayUtilsTest.java:63:12:63:54 | get(...) | semmle.label | get(...) | @@ -3430,10 +3380,8 @@ nodes | ArrayUtilsTest.java:69:56:69:66 | taintedInts : int[] [[]] : Number | semmle.label | taintedInts : int[] [[]] : Number | | ArrayUtilsTest.java:70:12:70:27 | taintedBoxedInts | semmle.label | taintedBoxedInts | | ArrayUtilsTest.java:71:12:71:51 | toPrimitive(...) | semmle.label | toPrimitive(...) | -| ArrayUtilsTest.java:71:12:71:51 | toPrimitive(...) : int[] [[]] : Number | semmle.label | toPrimitive(...) : int[] [[]] : Number | | ArrayUtilsTest.java:71:35:71:50 | taintedBoxedInts : Integer[] [[]] : Number | semmle.label | taintedBoxedInts : Integer[] [[]] : Number | | ArrayUtilsTest.java:72:12:72:70 | toPrimitive(...) | semmle.label | toPrimitive(...) | -| ArrayUtilsTest.java:72:12:72:70 | toPrimitive(...) : int[] [[]] : Number | semmle.label | toPrimitive(...) : int[] [[]] : Number | | ArrayUtilsTest.java:72:53:72:69 | taint(...) : Number | semmle.label | taint(...) : Number | | MutableTest.java:11:39:11:66 | new MutableObject(...) : MutableObject [org.apache.commons.lang3.mutable.MutableObject.value] : String | semmle.label | new MutableObject(...) : MutableObject [org.apache.commons.lang3.mutable.MutableObject.value] : String | | MutableTest.java:11:59:11:65 | taint(...) : String | semmle.label | taint(...) : String | diff --git a/java/ql/test/query-tests/security/CWE-078/ExecTainted.expected b/java/ql/test/query-tests/security/CWE-078/ExecTainted.expected index 703ca977c8e0..e65a61d76988 100644 --- a/java/ql/test/query-tests/security/CWE-078/ExecTainted.expected +++ b/java/ql/test/query-tests/security/CWE-078/ExecTainted.expected @@ -9,8 +9,7 @@ edges | Test.java:6:35:6:44 | arg : String | Test.java:10:61:10:73 | ... + ... : String | provenance | | | Test.java:6:35:6:44 | arg : String | Test.java:16:13:16:25 | ... + ... : String | provenance | | | Test.java:6:35:6:44 | arg : String | Test.java:22:15:22:27 | ... + ... : String | provenance | | -| Test.java:7:25:7:70 | new ..[] { .. } : String[] [[]] : String | Test.java:7:25:7:70 | new ..[] { .. } | provenance | Sink:MaD:2 | -| Test.java:7:44:7:69 | ... + ... : String | Test.java:7:25:7:70 | new ..[] { .. } : String[] [[]] : String | provenance | | +| Test.java:7:44:7:69 | ... + ... : String | Test.java:7:25:7:70 | new ..[] { .. } | provenance | Sink:MaD:2 | | Test.java:10:29:10:74 | {...} : String[] [[]] : String | Test.java:10:29:10:74 | new String[] | provenance | Sink:MaD:2 | | Test.java:10:61:10:73 | ... + ... : String | Test.java:10:29:10:74 | {...} : String[] [[]] : String | provenance | | | Test.java:16:5:16:7 | cmd [post update] : ArrayList [] : String | Test.java:18:29:18:31 | cmd | provenance | Sink:MaD:1 | @@ -18,8 +17,7 @@ edges | Test.java:22:5:22:8 | cmd1 [post update] : String[] [[]] : String | Test.java:24:29:24:32 | cmd1 | provenance | Sink:MaD:2 | | Test.java:22:15:22:27 | ... + ... : String | Test.java:22:5:22:8 | cmd1 [post update] : String[] [[]] : String | provenance | | | Test.java:28:38:28:47 | arg : String | Test.java:29:44:29:64 | ... + ... : String | provenance | | -| Test.java:29:25:29:65 | new ..[] { .. } : String[] [[]] : String | Test.java:29:25:29:65 | new ..[] { .. } | provenance | Sink:MaD:2 | -| Test.java:29:44:29:64 | ... + ... : String | Test.java:29:25:29:65 | new ..[] { .. } : String[] [[]] : String | provenance | | +| Test.java:29:44:29:64 | ... + ... : String | Test.java:29:25:29:65 | new ..[] { .. } | provenance | Sink:MaD:2 | | Test.java:57:27:57:39 | args : String[] | Test.java:60:20:60:22 | arg : String | provenance | | | Test.java:57:27:57:39 | args : String[] | Test.java:61:23:61:25 | arg : String | provenance | | | Test.java:60:20:60:22 | arg : String | Test.java:6:35:6:44 | arg : String | provenance | | @@ -31,7 +29,6 @@ models nodes | Test.java:6:35:6:44 | arg : String | semmle.label | arg : String | | Test.java:7:25:7:70 | new ..[] { .. } | semmle.label | new ..[] { .. } | -| Test.java:7:25:7:70 | new ..[] { .. } : String[] [[]] : String | semmle.label | new ..[] { .. } : String[] [[]] : String | | Test.java:7:44:7:69 | ... + ... : String | semmle.label | ... + ... : String | | Test.java:10:29:10:74 | new String[] | semmle.label | new String[] | | Test.java:10:29:10:74 | {...} : String[] [[]] : String | semmle.label | {...} : String[] [[]] : String | @@ -44,7 +41,6 @@ nodes | Test.java:24:29:24:32 | cmd1 | semmle.label | cmd1 | | Test.java:28:38:28:47 | arg : String | semmle.label | arg : String | | Test.java:29:25:29:65 | new ..[] { .. } | semmle.label | new ..[] { .. } | -| Test.java:29:25:29:65 | new ..[] { .. } : String[] [[]] : String | semmle.label | new ..[] { .. } : String[] [[]] : String | | Test.java:29:44:29:64 | ... + ... : String | semmle.label | ... + ... : String | | Test.java:57:27:57:39 | args : String[] | semmle.label | args : String[] | | Test.java:60:20:60:22 | arg : String | semmle.label | arg : String | diff --git a/java/ql/test/utils/modelgenerator/dataflow/CaptureContentSummaryModels.ql b/java/ql/test/utils/modelgenerator/dataflow/CaptureContentSummaryModels.ql index 3d2a2e07ac6e..4cb7f4604039 100644 --- a/java/ql/test/utils/modelgenerator/dataflow/CaptureContentSummaryModels.ql +++ b/java/ql/test/utils/modelgenerator/dataflow/CaptureContentSummaryModels.ql @@ -3,7 +3,7 @@ import utils.modelgenerator.internal.CaptureModels import TestUtilities.InlineMadTest module InlineMadTestConfig implements InlineMadTestConfigSig { - string getCapturedModel(Callable c) { result = captureContentFlow(c) } + string getCapturedModel(Callable c) { result = ContentSensitive::captureFlow(c) } string getKind() { result = "contentbased-summary" } } diff --git a/java/ql/test/utils/modelgenerator/dataflow/CaptureNeutralModels.ql b/java/ql/test/utils/modelgenerator/dataflow/CaptureNeutralModels.ql index e68730cc0edd..cdc2dfcaa459 100644 --- a/java/ql/test/utils/modelgenerator/dataflow/CaptureNeutralModels.ql +++ b/java/ql/test/utils/modelgenerator/dataflow/CaptureNeutralModels.ql @@ -1,5 +1,5 @@ import java -import utils.modelgenerator.internal.CaptureSummaryFlowQuery +import utils.modelgenerator.internal.CaptureModels import TestUtilities.InlineMadTest module InlineMadTestConfig implements InlineMadTestConfigSig { diff --git a/java/ql/test/utils/modelgenerator/dataflow/CaptureSummaryModels.ql b/java/ql/test/utils/modelgenerator/dataflow/CaptureSummaryModels.ql index 415ebab13439..c9e5050fc1fc 100644 --- a/java/ql/test/utils/modelgenerator/dataflow/CaptureSummaryModels.ql +++ b/java/ql/test/utils/modelgenerator/dataflow/CaptureSummaryModels.ql @@ -1,5 +1,5 @@ import java -import utils.modelgenerator.internal.CaptureSummaryFlowQuery +import utils.modelgenerator.internal.CaptureModels import TestUtilities.InlineMadTest module InlineMadTestConfig implements InlineMadTestConfigSig { diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.ql b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.ql index 9a27e9db4d41..df9c43e3b5b4 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.ql +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.ql @@ -5,7 +5,7 @@ * @kind path-problem * @problem.severity error * @precision high - * @id js/xss + * @id js/xss-additional-sources-dom-test * @tags security * external/cwe/cwe-079 * external/cwe/cwe-116 diff --git a/misc/codegen/generators/rustgen.py b/misc/codegen/generators/rustgen.py index 5d981197b375..f4c977c0fdbe 100644 --- a/misc/codegen/generators/rustgen.py +++ b/misc/codegen/generators/rustgen.py @@ -72,13 +72,28 @@ def __init__(self, data: schema.Schema): def _get_class(self, name: str) -> rust.Class: cls = self._classmap[name] + properties = [ + (c, p) + for c, p in _get_properties(cls, self._classmap) + if "rust_skip" not in p.pragmas and not p.synth + ] + fields = [] + detached_fields = [] + for c, p in properties: + if "rust_detach" in p.pragmas: + # only generate detached fields in the actual class defining them, not the derived ones + if c is cls: + # TODO lift this restriction if required (requires change in dbschemegen as well) + assert c.derived or not p.is_single, \ + f"property {p.name} in concrete class marked as detached but not optional" + detached_fields.append(_get_field(c, p)) + elif not cls.derived: + # for non-detached ones, only generate fields in the concrete classes + fields.append(_get_field(c, p)) return rust.Class( name=name, - fields=[ - _get_field(c, p) - for c, p in _get_properties(cls, self._classmap) - if "rust_skip" not in p.pragmas and not p.synth - ] if not cls.derived else [], + fields=fields, + detached_fields=detached_fields, ancestors=sorted(set(a.name for a in _get_ancestors(cls, self._classmap))), entry_table=inflection.tableize(cls.name) if not cls.derived else None, ) diff --git a/misc/codegen/generators/rusttestgen.py b/misc/codegen/generators/rusttestgen.py index 0888bcbf6a14..d360db27a658 100644 --- a/misc/codegen/generators/rusttestgen.py +++ b/misc/codegen/generators/rusttestgen.py @@ -1,5 +1,7 @@ import dataclasses import typing +from collections.abc import Iterable + import inflection from misc.codegen.loaders import schemaloader @@ -27,6 +29,25 @@ class TestCode: function: Function | None = None +def _get_code(doc: list[str]) -> list[str]: + adding_code = False + has_code = False + code = [] + for line in doc: + match line, adding_code: + case ("```", _) | ("```rust", _): + adding_code = not adding_code + has_code = True + case _, False: + code.append(f"// {line}") + case _, True: + code.append(line) + assert not adding_code, "Unterminated code block in docstring:\n " + "\n ".join(doc) + if has_code: + return code + return [] + + def generate(opts, renderer): assert opts.ql_test_output schema = schemaloader.load_file(opts.schema) @@ -36,24 +57,18 @@ def generate(opts, renderer): force=opts.force) as renderer: for cls in schema.classes.values(): if (qlgen.should_skip_qltest(cls, schema.classes) or - "rust_skip_test_from_doc" in cls.pragmas or - not cls.doc): + "rust_skip_doc_test" in cls.pragmas): continue - code = [] - adding_code = False - has_code = False - for line in cls.doc: - match line, adding_code: - case ("```", _) | ("```rust", _): - adding_code = not adding_code - has_code = True - case _, False: - code.append(f"// {line}") - case _, True: - code.append(line) - if not has_code: + code = _get_code(cls.doc) + for p in schema.iter_properties(cls.name): + if "rust_skip_doc_test" in p.pragmas: + continue + property_code = _get_code(p.description) + if property_code: + code.append(f"// # {p.name}") + code += property_code + if not code: continue - assert not adding_code, "Unterminated code block in docstring: " + "\n".join(cls.doc) test_name = inflection.underscore(cls.name) signature = cls.pragmas.get("rust_doc_test_signature", "() -> ()") fn = signature and Function(f"test_{test_name}", signature) diff --git a/misc/codegen/lib/rust.py b/misc/codegen/lib/rust.py index e4ec8e871c20..4c34952311c9 100644 --- a/misc/codegen/lib/rust.py +++ b/misc/codegen/lib/rust.py @@ -1,6 +1,7 @@ import dataclasses import re import typing +import inflection # taken from https://doc.rust-lang.org/reference/keywords.html keywords = { @@ -106,12 +107,17 @@ def is_single(self): def is_label(self): return self.base_type == "trap::Label" + @property + def singular_field_name(self) -> str: + return inflection.singularize(self.field_name.rstrip("_")) + @dataclasses.dataclass class Class: name: str entry_table: str | None = None fields: list[Field] = dataclasses.field(default_factory=list) + detached_fields: list[Field] = dataclasses.field(default_factory=list) ancestors: list[str] = dataclasses.field(default_factory=list) @property @@ -128,6 +134,10 @@ def single_field_entries(self) -> dict[str, list[dict]]: ret.setdefault(f.table_name, []).append(f) return [{"table_name": k, "fields": v} for k, v in ret.items()] + @property + def has_detached_fields(self) -> bool: + return bool(self.detached_fields) + @dataclasses.dataclass class ClassList: diff --git a/misc/codegen/lib/schema.py b/misc/codegen/lib/schema.py index 21a4cdcfc06c..c5c3dc810b68 100644 --- a/misc/codegen/lib/schema.py +++ b/misc/codegen/lib/schema.py @@ -1,6 +1,7 @@ """ schema format representation """ import abc import typing +from collections.abc import Iterable from dataclasses import dataclass, field from typing import List, Set, Union, Dict, Optional from enum import Enum, auto @@ -144,6 +145,12 @@ def root_class(self): def null_class(self): return self.classes[self.null] if self.null else None + def iter_properties(self, cls: str) -> Iterable[Property]: + cls = self.classes[cls] + for b in cls.bases: + yield from self.iter_properties(b) + yield from cls.properties + predicate_marker = object() diff --git a/misc/codegen/lib/schemadefs.py b/misc/codegen/lib/schemadefs.py index 37c976bad3db..7152c32d12b1 100644 --- a/misc/codegen/lib/schemadefs.py +++ b/misc/codegen/lib/schemadefs.py @@ -237,6 +237,7 @@ def __getitem__(self, item): cpp.add(_Pragma("skip")) +rust.add(_Pragma("detach")) rust.add(_Pragma("skip_doc_test")) rust.add(_ParametrizedClassPragma("doc_test_signature", factory=lambda signature: signature)) diff --git a/misc/codegen/templates/rust_classes.mustache b/misc/codegen/templates/rust_classes.mustache index 94dd957da029..0fa29b1eb690 100644 --- a/misc/codegen/templates/rust_classes.mustache +++ b/misc/codegen/templates/rust_classes.mustache @@ -59,6 +59,16 @@ pub struct {{name}} { _unused: () } {{/is_entry}} +{{#has_detached_fields}} + +impl {{name}} { +{{#detached_fields}} + pub fn emit_{{singular_field_name}}(id: trap::Label, {{#is_repeated}}{{^is_unordered}}i: usize, {{/is_unordered}}{{/is_repeated}}value: {{base_type}}, out: &mut trap::Writer) { + out.add_tuple("{{table_name}}", vec![id.into(), {{#is_repeated}}{{^is_unordered}}i.into(), {{/is_unordered}}{{/is_repeated}}value.into()]); + } +{{/detached_fields}} +} +{{/has_detached_fields}} impl trap::TrapClass for {{name}} { fn class_name() -> &'static str { "{{name}}" } diff --git a/python/ql/lib/change-notes/2024-09-20-const-compare-gaurd.md b/python/ql/lib/change-notes/2024-09-20-const-compare-gaurd.md new file mode 100644 index 000000000000..2adb7fa82a88 --- /dev/null +++ b/python/ql/lib/change-notes/2024-09-20-const-compare-gaurd.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The common sanitizer guard `StringConstCompareBarrier` has been renamed to `ConstCompareBarrier` and expanded to cover comparisons with other constant values such as `None`. This may result in fewer false positive results for several queries. \ No newline at end of file diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index 50506439dfba..cc0712d181b7 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -1467,6 +1467,59 @@ module Http { override DataFlow::Node getValueArg() { none() } } + /** + * A data-flow node that enables or disables CORS + * in a global manner. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `CorsMiddleware::Range` instead. + */ + class CorsMiddleware extends DataFlow::Node instanceof CorsMiddleware::Range { + /** + * Gets the string corresponding to the middleware + */ + string getMiddlewareName() { result = super.getMiddlewareName() } + + /** + * Gets the dataflow node corresponding to the allowed CORS origins + */ + DataFlow::Node getOrigins() { result = super.getOrigins() } + + /** + * Gets the boolean value corresponding to if CORS credentials is enabled + * (`true`) or disabled (`false`) by this node. + */ + DataFlow::Node getCredentialsAllowed() { result = super.getCredentialsAllowed() } + } + + /** Provides a class for modeling new CORS middleware APIs. */ + module CorsMiddleware { + /** + * A data-flow node that enables or disables Cross-site request forgery protection + * in a global manner. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `CorsMiddleware` instead. + */ + abstract class Range extends DataFlow::Node { + /** + * Gets the name corresponding to the middleware + */ + abstract string getMiddlewareName(); + + /** + * Gets the strings corresponding to the origins allowed by the cors policy + */ + abstract DataFlow::Node getOrigins(); + + /** + * Gets the boolean value corresponding to if CORS credentials is enabled + * (`true`) or disabled (`false`) by this node. + */ + abstract DataFlow::Node getCredentialsAllowed(); + } + } + /** * A data-flow node that enables or disables Cross-site request forgery protection * in a global manner. diff --git a/python/ql/lib/semmle/python/dataflow/new/BarrierGuards.qll b/python/ql/lib/semmle/python/dataflow/new/BarrierGuards.qll index ad8b668a94ad..fefa30965cec 100644 --- a/python/ql/lib/semmle/python/dataflow/new/BarrierGuards.qll +++ b/python/ql/lib/semmle/python/dataflow/new/BarrierGuards.qll @@ -3,34 +3,45 @@ private import python private import semmle.python.dataflow.new.DataFlow -private predicate stringConstCompare(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) { +private predicate constCompare(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) { exists(CompareNode cn | cn = g | - exists(StringLiteral str_const, Cmpop op | + exists(ImmutableLiteral const, Cmpop op | op = any(Eq eq) and branch = true or op = any(NotEq ne) and branch = false | - cn.operands(str_const.getAFlowNode(), op, node) + cn.operands(const.getAFlowNode(), op, node) or - cn.operands(node, op, str_const.getAFlowNode()) + cn.operands(node, op, const.getAFlowNode()) ) or - exists(IterableNode str_const_iterable, Cmpop op | + exists(NameConstant const, Cmpop op | + op = any(Is is_) and branch = true + or + op = any(IsNot isn) and branch = false + | + cn.operands(const.getAFlowNode(), op, node) + or + cn.operands(node, op, const.getAFlowNode()) + ) + or + exists(IterableNode const_iterable, Cmpop op | op = any(In in_) and branch = true or op = any(NotIn ni) and branch = false | - forall(ControlFlowNode elem | elem = str_const_iterable.getAnElement() | - elem.getNode() instanceof StringLiteral + forall(ControlFlowNode elem | elem = const_iterable.getAnElement() | + elem.getNode() instanceof ImmutableLiteral ) and - cn.operands(node, op, str_const_iterable) + cn.operands(node, op, const_iterable) ) ) } -/** A validation of unknown node by comparing with a constant string value. */ -class StringConstCompareBarrier extends DataFlow::Node { - StringConstCompareBarrier() { - this = DataFlow::BarrierGuard::getABarrierNode() - } +/** A validation of unknown node by comparing with a constant value. */ +class ConstCompareBarrier extends DataFlow::Node { + ConstCompareBarrier() { this = DataFlow::BarrierGuard::getABarrierNode() } } + +/** DEPRECATED: Use ConstCompareBarrier instead. */ +deprecated class StringConstCompareBarrier = ConstCompareBarrier; diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl1.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl1.qll index 359fa71744b4..ce964917e970 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl1.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl1.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I 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 359fa71744b4..ce964917e970 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I 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 359fa71744b4..ce964917e970 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I 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 359fa71744b4..ce964917e970 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I diff --git a/python/ql/lib/semmle/python/frameworks/FastApi.qll b/python/ql/lib/semmle/python/frameworks/FastApi.qll index 3a15ca6fbcc3..ed28f18a85a9 100644 --- a/python/ql/lib/semmle/python/frameworks/FastApi.qll +++ b/python/ql/lib/semmle/python/frameworks/FastApi.qll @@ -30,6 +30,51 @@ module FastApi { API::Node instance() { result = cls().getReturn() } } + /** + * A call to `app.add_middleware` adding a generic middleware. + */ + private class AddMiddlewareCall extends DataFlow::CallCfgNode { + AddMiddlewareCall() { this = App::instance().getMember("add_middleware").getACall() } + + /** + * Gets the string corresponding to the middleware + */ + string getMiddlewareName() { result = this.getArg(0).asExpr().(Name).getId() } + } + + /** + * A call to `app.add_middleware` adding CORSMiddleware. + */ + class AddCorsMiddlewareCall extends Http::Server::CorsMiddleware::Range, AddMiddlewareCall { + /** + * Gets the string corresponding to the middleware + */ + override string getMiddlewareName() { result = this.getArg(0).asExpr().(Name).getId() } + + /** + * Gets the dataflow node corresponding to the allowed CORS origins + */ + override DataFlow::Node getOrigins() { result = this.getArgByName("allow_origins") } + + /** + * Gets the boolean value corresponding to if CORS credentials is enabled + * (`true`) or disabled (`false`) by this node. + */ + override DataFlow::Node getCredentialsAllowed() { + result = this.getArgByName("allow_credentials") + } + + /** + * Gets the dataflow node corresponding to the allowed CORS methods + */ + DataFlow::Node getMethods() { result = this.getArgByName("allow_methods") } + + /** + * Gets the dataflow node corresponding to the allowed CORS headers + */ + DataFlow::Node getHeaders() { result = this.getArgByName("allow_headers") } + } + /** * Provides models for the `fastapi.APIRouter` class * diff --git a/python/ql/lib/semmle/python/frameworks/Starlette.qll b/python/ql/lib/semmle/python/frameworks/Starlette.qll index ec62888ecb0c..7ced137fcfca 100644 --- a/python/ql/lib/semmle/python/frameworks/Starlette.qll +++ b/python/ql/lib/semmle/python/frameworks/Starlette.qll @@ -25,6 +25,74 @@ private import semmle.python.frameworks.data.ModelsAsData * - https://www.starlette.io/ */ module Starlette { + /** + * Provides models for the `starlette.app` class + */ + module App { + /** Gets import of `starlette.app`. */ + API::Node cls() { result = API::moduleImport("starlette").getMember("app") } + + /** Gets a reference to a Starlette application (an instance of `starlette.app`). */ + API::Node instance() { result = cls().getAnInstance() } + } + + /** + * A call to any of the execute methods on a `app.add_middleware`. + */ + class AddMiddlewareCall extends DataFlow::CallCfgNode { + AddMiddlewareCall() { + this = [App::instance().getMember("add_middleware").getACall(), Middleware::instance()] + } + + /** + * Gets the string corresponding to the middleware + */ + string getMiddlewareName() { result = this.getArg(0).asExpr().(Name).getId() } + } + + /** + * A call to any of the execute methods on a `app.add_middleware` with CORSMiddleware. + */ + class AddCorsMiddlewareCall extends AddMiddlewareCall, Http::Server::CorsMiddleware::Range { + /** + * Gets the string corresponding to the middleware + */ + override string getMiddlewareName() { result = this.getArg(0).asExpr().(Name).getId() } + + override DataFlow::Node getOrigins() { result = this.getArgByName("allow_origins") } + + override DataFlow::Node getCredentialsAllowed() { + result = this.getArgByName("allow_credentials") + } + + /** + * Gets the dataflow node corresponding to the allowed CORS methods + */ + DataFlow::Node getMethods() { result = this.getArgByName("allow_methods") } + + /** + * Gets the dataflow node corresponding to the allowed CORS headers + */ + DataFlow::Node getHeaders() { result = this.getArgByName("allow_headers") } + } + + /** + * Provides models for the `starlette.middleware.Middleware` class + * + * See https://www.starlette.io/. + */ + module Middleware { + /** Gets a reference to the `starlette.middleware.Middleware` class. */ + API::Node classRef() { + result = API::moduleImport("starlette").getMember("middleware").getMember("Middleware") + or + result = ModelOutput::getATypeNode("starlette.middleware.Middleware~Subclass").getASubclass*() + } + + /** Gets a reference to an instance of `starlette.middleware.Middleware`. */ + DataFlow::Node instance() { result = classRef().getACall() } + } + /** * Provides models for the `starlette.websockets.WebSocket` class * diff --git a/python/ql/lib/semmle/python/security/dataflow/CodeInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/CodeInjectionCustomizations.qll index 354d098186f6..a7c2ad90a35a 100644 --- a/python/ql/lib/semmle/python/security/dataflow/CodeInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/CodeInjectionCustomizations.qll @@ -54,7 +54,10 @@ module CodeInjection { } /** - * A comparison with a constant string, considered as a sanitizer-guard. + * A comparison with a constant, considered as a sanitizer-guard. */ - class StringConstCompareAsSanitizer extends Sanitizer, StringConstCompareBarrier { } + class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { } + + /** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */ + deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard; } diff --git a/python/ql/lib/semmle/python/security/dataflow/CommandInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/CommandInjectionCustomizations.qll index f3786700967b..83f6ccff0a51 100644 --- a/python/ql/lib/semmle/python/security/dataflow/CommandInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/CommandInjectionCustomizations.qll @@ -89,7 +89,10 @@ module CommandInjection { } /** - * A comparison with a constant string, considered as a sanitizer-guard. + * A comparison with a constant, considered as a sanitizer-guard. */ - class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { } + class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { } + + /** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */ + deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard; } diff --git a/python/ql/lib/semmle/python/security/dataflow/LdapInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/LdapInjectionCustomizations.qll index f0229bc0c824..e67d02dc67e9 100644 --- a/python/ql/lib/semmle/python/security/dataflow/LdapInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/LdapInjectionCustomizations.qll @@ -66,15 +66,20 @@ module LdapInjection { } /** - * A comparison with a constant string, considered as a sanitizer-guard. + * A comparison with a constant, considered as a sanitizer-guard. */ - class StringConstCompareAsDnSanitizerGuard extends DnSanitizer, StringConstCompareBarrier { } + class ConstCompareAsDnSanitizerGuard extends DnSanitizer, ConstCompareBarrier { } + + /** DEPRECATED: Use ConstCompareAsDnSanitizerGuard instead. */ + deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsDnSanitizerGuard; /** - * A comparison with a constant string, considered as a sanitizer-guard. + * A comparison with a constant, considered as a sanitizer-guard. */ - class StringConstCompareAsFilterSanitizerGuard extends FilterSanitizer, StringConstCompareBarrier { - } + class ConstCompareAsFilterSanitizerGuard extends FilterSanitizer, ConstCompareBarrier { } + + /** DEPRECATED: Use ConstCompareAsFilterSanitizerGuard instead. */ + deprecated class StringConstCompareAsFilterSanitizerGuard = ConstCompareAsFilterSanitizerGuard; /** * A call to replace line breaks functions as a sanitizer. diff --git a/python/ql/lib/semmle/python/security/dataflow/LogInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/LogInjectionCustomizations.qll index 71648b2c6281..40aa83e17443 100644 --- a/python/ql/lib/semmle/python/security/dataflow/LogInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/LogInjectionCustomizations.qll @@ -82,9 +82,12 @@ module LogInjection { } /** - * A comparison with a constant string, considered as a sanitizer-guard. + * A comparison with a constant, considered as a sanitizer-guard. */ - class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { } + class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { } + + /** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */ + deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard; /** * A call to replace line breaks, considered as a sanitizer. diff --git a/python/ql/lib/semmle/python/security/dataflow/PathInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/PathInjectionCustomizations.qll index eff7d715c268..8b8e2f696739 100644 --- a/python/ql/lib/semmle/python/security/dataflow/PathInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/PathInjectionCustomizations.qll @@ -92,7 +92,10 @@ module PathInjection { } /** - * A comparison with a constant string, considered as a sanitizer-guard. + * A comparison with a constant, considered as a sanitizer-guard. */ - class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { } + class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { } + + /** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */ + deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard; } diff --git a/python/ql/lib/semmle/python/security/dataflow/PolynomialReDoSCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/PolynomialReDoSCustomizations.qll index 2cd8b0a64bd7..4cc464ca4caa 100644 --- a/python/ql/lib/semmle/python/security/dataflow/PolynomialReDoSCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/PolynomialReDoSCustomizations.qll @@ -75,7 +75,10 @@ module PolynomialReDoS { } /** - * A comparison with a constant string, considered as a sanitizer-guard. + * A comparison with a constant, considered as a sanitizer-guard. */ - class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { } + class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { } + + /** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */ + deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard; } diff --git a/python/ql/lib/semmle/python/security/dataflow/ReflectedXSSCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/ReflectedXSSCustomizations.qll index 3a7177eb4c74..14db509df2f3 100644 --- a/python/ql/lib/semmle/python/security/dataflow/ReflectedXSSCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/ReflectedXSSCustomizations.qll @@ -80,7 +80,10 @@ module ReflectedXss { } /** - * A comparison with a constant string, considered as a sanitizer-guard. + * A comparison with a constant, considered as a sanitizer-guard. */ - class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { } + class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { } + + /** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */ + deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard; } diff --git a/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll index 552d022c98ec..274e7ee57ad6 100644 --- a/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll @@ -77,9 +77,12 @@ module ServerSideRequestForgery { } /** - * A comparison with a constant string, considered as a sanitizer-guard. + * A comparison with a constant, considered as a sanitizer-guard. */ - class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { } + class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { } + + /** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */ + deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard; /** * A string construction (concat, format, f-string) where the left side is not diff --git a/python/ql/lib/semmle/python/security/dataflow/SqlInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/SqlInjectionCustomizations.qll index e2a5b4d624a2..b614eaeebec4 100644 --- a/python/ql/lib/semmle/python/security/dataflow/SqlInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/SqlInjectionCustomizations.qll @@ -56,9 +56,12 @@ module SqlInjection { } /** - * A comparison with a constant string, considered as a sanitizer-guard. + * A comparison with a constant, considered as a sanitizer-guard. */ - class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { } + class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { } + + /** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */ + deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard; private import semmle.python.frameworks.data.ModelsAsData diff --git a/python/ql/lib/semmle/python/security/dataflow/UnsafeDeserializationCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/UnsafeDeserializationCustomizations.qll index ca909e5de1a0..d71d36279b50 100644 --- a/python/ql/lib/semmle/python/security/dataflow/UnsafeDeserializationCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/UnsafeDeserializationCustomizations.qll @@ -59,7 +59,10 @@ module UnsafeDeserialization { } /** - * A comparison with a constant string, considered as a sanitizer-guard. + * A comparison with a constant, considered as a sanitizer-guard. */ - class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { } + class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { } + + /** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */ + deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard; } diff --git a/python/ql/lib/semmle/python/security/dataflow/UrlRedirectCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/UrlRedirectCustomizations.qll index 0c05a36eaebb..f5810944f8d9 100644 --- a/python/ql/lib/semmle/python/security/dataflow/UrlRedirectCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/UrlRedirectCustomizations.qll @@ -145,12 +145,15 @@ module UrlRedirect { } /** - * A comparison with a constant string, considered as a sanitizer-guard. + * A comparison with a constant, considered as a sanitizer-guard. */ - class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { + class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { override predicate sanitizes(FlowState state) { // sanitize all flow states any() } } + + /** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */ + deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard; } diff --git a/python/ql/src/change-notes/2024-08-26-Cors-misconfiguration-middleware.md b/python/ql/src/change-notes/2024-08-26-Cors-misconfiguration-middleware.md new file mode 100644 index 000000000000..aa8bc7198b31 --- /dev/null +++ b/python/ql/src/change-notes/2024-08-26-Cors-misconfiguration-middleware.md @@ -0,0 +1,4 @@ +--- +category: newQuery +--- +* The `py/cors-misconfiguration-with-credentials` query, which finds insecure CORS middleware configurations. \ No newline at end of file diff --git a/python/ql/src/experimental/Security/CWE-074/TemplateInjectionCustomizations.qll b/python/ql/src/experimental/Security/CWE-074/TemplateInjectionCustomizations.qll index e5c5013f3ba6..593ca9fee4cf 100644 --- a/python/ql/src/experimental/Security/CWE-074/TemplateInjectionCustomizations.qll +++ b/python/ql/src/experimental/Security/CWE-074/TemplateInjectionCustomizations.qll @@ -50,7 +50,10 @@ module TemplateInjection { } /** - * A comparison with a constant string, considered as a sanitizer-guard. + * A comparison with a constant, considered as a sanitizer-guard. */ - class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { } + class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { } + + /** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */ + deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard; } diff --git a/python/ql/src/experimental/Security/CWE-091/XsltInjectionCustomizations.qll b/python/ql/src/experimental/Security/CWE-091/XsltInjectionCustomizations.qll index 4cacf1f85dee..6e6abea97f95 100644 --- a/python/ql/src/experimental/Security/CWE-091/XsltInjectionCustomizations.qll +++ b/python/ql/src/experimental/Security/CWE-091/XsltInjectionCustomizations.qll @@ -57,7 +57,10 @@ module XsltInjection { } /** - * A comparison with a constant string, considered as a sanitizer-guard. + * A comparison with a constant, considered as a sanitizer-guard. */ - class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { } + class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { } + + /** DEPRECATED: Use ConstCompareAsSanitizerGuard instead. */ + deprecated class StringConstCompareAsSanitizerGuard = ConstCompareAsSanitizerGuard; } diff --git a/python/ql/src/experimental/Security/CWE-942/CorsMisconfigurationMiddleware.qhelp b/python/ql/src/experimental/Security/CWE-942/CorsMisconfigurationMiddleware.qhelp new file mode 100644 index 000000000000..21a670019c33 --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-942/CorsMisconfigurationMiddleware.qhelp @@ -0,0 +1,64 @@ + + + +

+ Web browsers, by default, disallow cross-origin resource sharing via direct HTTP requests. + Still, to satisfy some needs that arose with the growth of the web, an expedient was created to make exceptions possible. + CORS (Cross-origin resource sharing) is a mechanism that allows resources of a web endpoint (let's call it "Peer A") + to be accessed from another web page belonging to a different domain ("Peer B"). +

+

+ For that to happen, Peer A needs to make available its CORS configuration via special headers on the desired endpoint + via the OPTIONS method. +

+

+ This configuration can also allow the inclusion of cookies on the cross-origin request, + (i.e. when the Access-Control-Allow-Credentials header is set to true) + meaning that Peer B can send a request to Peer A that will include the cookies as if the request was executed by the user. +

+

+ That can have dangerous effects if the origin of Peer B is not restricted correctly. + An example of a dangerous scenario is when Access-Control-Allow-Origin header is set to a value obtained from the request made by Peer B + (and not correctly validated), or is set to special values such as * or null. + The above values can allow any Peer B to send requests to the misconfigured Peer A on behalf of the user. +

+

+ Example scenario: + User is client of a bank that has its API misconfigured to accept CORS requests from any domain. + When the user loads an evil page, the evil page sends a request to the bank's API to transfer all funds + to evil party's account. + Given that the user was already logged in to the bank website, and had its session cookies set, + the evil party's request succeeds. +

+
+ +

+ When configuring CORS that allow credentials passing, + it's best not to use user-provided values for the allowed origins response header, + especially if the cookies grant session permissions on the user's account. +

+

+ It also can be very dangerous to set the allowed origins to null (which can be bypassed). +

+
+ +

+ The first example shows a possible CORS misconfiguration case: +

+ +

+ The second example shows a better configuration: +

+ +
+ +
  • + Reference 1: PortSwigger Web Security Academy on CORS. +
  • +
  • + Reference 2: AppSec EU 2017 Exploiting CORS Misconfigurations For Bitcoins And Bounties by James Kettle. +
  • +
    +
    \ No newline at end of file diff --git a/python/ql/src/experimental/Security/CWE-942/CorsMisconfigurationMiddleware.ql b/python/ql/src/experimental/Security/CWE-942/CorsMisconfigurationMiddleware.ql new file mode 100644 index 000000000000..9d2b461b9865 --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-942/CorsMisconfigurationMiddleware.ql @@ -0,0 +1,39 @@ +/** + * @name Cors misconfiguration with credentials + * @description Disabling or weakening SOP protection may make the application + * vulnerable to a CORS attack. + * @kind problem + * @problem.severity warning + * @security-severity 8.8 + * @precision high + * @id py/cors-misconfiguration-with-credentials + * @tags security + * external/cwe/cwe-942 + */ + +import python +import semmle.python.Concepts +private import semmle.python.dataflow.new.DataFlow + +predicate containsStar(DataFlow::Node array) { + array.asExpr() instanceof List and + array.asExpr().getASubExpression().(StringLiteral).getText() in ["*", "null"] + or + array.asExpr().(StringLiteral).getText() in ["*", "null"] +} + +predicate isCorsMiddleware(Http::Server::CorsMiddleware middleware) { + middleware.getMiddlewareName() = "CORSMiddleware" +} + +predicate credentialsAllowed(Http::Server::CorsMiddleware middleware) { + middleware.getCredentialsAllowed().asExpr() instanceof True +} + +from Http::Server::CorsMiddleware a +where + credentialsAllowed(a) and + containsStar(a.getOrigins().getALocalSource()) and + isCorsMiddleware(a) +select a, + "This CORS middleware uses a vulnerable configuration that allows arbitrary websites to make authenticated cross-site requests" diff --git a/python/ql/src/experimental/Security/CWE-942/CorsMisconfigurationMiddlewareBad.py b/python/ql/src/experimental/Security/CWE-942/CorsMisconfigurationMiddlewareBad.py new file mode 100644 index 000000000000..2b1c3c58a7e0 --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-942/CorsMisconfigurationMiddlewareBad.py @@ -0,0 +1,21 @@ +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware + +app = FastAPI() + +origins = [ + "*" +] + +app.add_middleware( + CORSMiddleware, + allow_origins=origins, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + + +@app.get("/") +async def main(): + return {"message": "Hello World"} \ No newline at end of file diff --git a/python/ql/src/experimental/Security/CWE-942/CorsMisconfigurationMiddlewareGood.py b/python/ql/src/experimental/Security/CWE-942/CorsMisconfigurationMiddlewareGood.py new file mode 100644 index 000000000000..bfcb559feb2c --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-942/CorsMisconfigurationMiddlewareGood.py @@ -0,0 +1,24 @@ +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware + +app = FastAPI() + +origins = [ + "http://localhost.tiangolo.com", + "https://localhost.tiangolo.com", + "http://localhost", + "http://localhost:8080", +] + +app.add_middleware( + CORSMiddleware, + allow_origins=origins, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + + +@app.get("/") +async def main(): + return {"message": "Hello World"} \ No newline at end of file diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/EmailXss.qll b/python/ql/src/experimental/semmle/python/security/dataflow/EmailXss.qll index 88e9af89ba63..c08a0e6b258b 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/EmailXss.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/EmailXss.qll @@ -19,7 +19,7 @@ private module EmailXssConfig implements DataFlow::ConfigSig { predicate isBarrier(DataFlow::Node sanitizer) { sanitizer = any(HtmlEscaping esc).getOutput() or - sanitizer instanceof StringConstCompareBarrier + sanitizer instanceof ConstCompareBarrier } predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { diff --git a/python/ql/src/experimental/semmle/python/security/injection/CsvInjection.qll b/python/ql/src/experimental/semmle/python/security/injection/CsvInjection.qll index 316dd4d26035..d08e9b090a6f 100644 --- a/python/ql/src/experimental/semmle/python/security/injection/CsvInjection.qll +++ b/python/ql/src/experimental/semmle/python/security/injection/CsvInjection.qll @@ -15,7 +15,7 @@ private module CsvInjectionConfig implements DataFlow::ConfigSig { predicate isBarrier(DataFlow::Node node) { node = DataFlow::BarrierGuard::getABarrierNode() or - node instanceof StringConstCompareBarrier + node instanceof ConstCompareBarrier } } diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index 87addb8a1fc3..8ab87e56d1c4 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -649,13 +649,27 @@ module ThreatModelSourceTest implements TestSig { } } +module CorsMiddlewareTest implements TestSig { + string getARelevantTag() { result = "CorsMiddleware" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(location.getFile().getRelativePath()) and + exists(Http::Server::CorsMiddleware cm | + location = cm.getLocation() and + element = cm.toString() and + value = cm.getMiddlewareName().toString() and + tag = "CorsMiddleware" + ) + } +} + import MakeTest, MergeTests5, MergeTests5>, + MergeTests3>, MergeTests5, MergeTests5 diff --git a/python/ql/test/library-tests/dataflow/tainttracking/commonSanitizer/test_string_const_compare.py b/python/ql/test/library-tests/dataflow/tainttracking/commonSanitizer/test_const_compare.py similarity index 86% rename from python/ql/test/library-tests/dataflow/tainttracking/commonSanitizer/test_string_const_compare.py rename to python/ql/test/library-tests/dataflow/tainttracking/commonSanitizer/test_const_compare.py index f1b01f4f84a5..2e7fff62c0d7 100644 --- a/python/ql/test/library-tests/dataflow/tainttracking/commonSanitizer/test_string_const_compare.py +++ b/python/ql/test/library-tests/dataflow/tainttracking/commonSanitizer/test_const_compare.py @@ -85,6 +85,32 @@ def test_in_local_variable(): else: ensure_tainted(ts) # $ tainted +def test_is_none(): + ts = TAINTED_STRING + if ts is None: + ensure_not_tainted(ts) + else: + ensure_tainted(ts) # $ tainted + +def test_is_not_none(): + ts = TAINTED_STRING + if ts is not None: + ensure_tainted(ts) # $ tainted + else: + ensure_not_tainted(ts) + +def test_in_list_with_constants(): + ts = TAINTED_STRING + if ts in ["safe", None, 3, False]: + ensure_not_tainted(ts) + else: + ensure_tainted(ts) # $ tainted + + if ts in ["safe", not_constant(), None]: + ensure_tainted(ts) # $ tainted + +def not_constant(): + return "x" SAFE = ["safe", "also_safe"] @@ -184,6 +210,9 @@ def test_eq_thorugh_func(): test_in_set() test_in_local_variable() test_in_global_variable() +test_is_none() +test_is_not_none() +test_in_list_with_constants() make_modification("unsafe") test_in_modified_global_variable() test_in_unsafe1(["unsafe", "foo"]) diff --git a/python/ql/test/library-tests/frameworks/fastapi/middleware.py b/python/ql/test/library-tests/frameworks/fastapi/middleware.py new file mode 100644 index 000000000000..0829fccf7beb --- /dev/null +++ b/python/ql/test/library-tests/frameworks/fastapi/middleware.py @@ -0,0 +1,10 @@ +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware + +app = FastAPI() + +origins = [ + "*" +] + +app.add_middleware(CORSMiddleware, allow_origins=origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"]) # $ CorsMiddleware=CORSMiddleware \ No newline at end of file diff --git a/python/ql/test/library-tests/frameworks/starlette/Middleware.py b/python/ql/test/library-tests/frameworks/starlette/Middleware.py new file mode 100644 index 000000000000..1225327df823 --- /dev/null +++ b/python/ql/test/library-tests/frameworks/starlette/Middleware.py @@ -0,0 +1,11 @@ +from starlette.applications import Starlette +from starlette.middleware import Middleware +from starlette.middleware.cors import CORSMiddleware + +routes = ... + +middleware = [ + Middleware(CORSMiddleware, allow_origins=['*'], allow_credentials=True) # $ CorsMiddleware=CORSMiddleware +] + +app = Starlette(routes=routes, middleware=middleware) \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/CWE-942-CorsMisconfigurationMiddleware/CorsMisconfigurationMiddleware.expected b/python/ql/test/query-tests/Security/CWE-942-CorsMisconfigurationMiddleware/CorsMisconfigurationMiddleware.expected new file mode 100644 index 000000000000..520cf9ab0d2e --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-942-CorsMisconfigurationMiddleware/CorsMisconfigurationMiddleware.expected @@ -0,0 +1,2 @@ +| fastapi.py:10:1:16:1 | ControlFlowNode for Attribute() | This CORS middleware uses a vulnerable configuration that allows arbitrary websites to make authenticated cross-site requests | +| starlette.py:8:5:8:75 | ControlFlowNode for Middleware() | This CORS middleware uses a vulnerable configuration that allows arbitrary websites to make authenticated cross-site requests | diff --git a/python/ql/test/query-tests/Security/CWE-942-CorsMisconfigurationMiddleware/CorsMisconfigurationMiddleware.qlref b/python/ql/test/query-tests/Security/CWE-942-CorsMisconfigurationMiddleware/CorsMisconfigurationMiddleware.qlref new file mode 100644 index 000000000000..f7017ada0d83 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-942-CorsMisconfigurationMiddleware/CorsMisconfigurationMiddleware.qlref @@ -0,0 +1 @@ +experimental/Security/CWE-942/CorsMisconfigurationMiddleware.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/CWE-942-CorsMisconfigurationMiddleware/fastapi.py b/python/ql/test/query-tests/Security/CWE-942-CorsMisconfigurationMiddleware/fastapi.py new file mode 100644 index 000000000000..2b1c3c58a7e0 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-942-CorsMisconfigurationMiddleware/fastapi.py @@ -0,0 +1,21 @@ +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware + +app = FastAPI() + +origins = [ + "*" +] + +app.add_middleware( + CORSMiddleware, + allow_origins=origins, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + + +@app.get("/") +async def main(): + return {"message": "Hello World"} \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/CWE-942-CorsMisconfigurationMiddleware/starlette.py b/python/ql/test/query-tests/Security/CWE-942-CorsMisconfigurationMiddleware/starlette.py new file mode 100644 index 000000000000..1d6e7705369c --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-942-CorsMisconfigurationMiddleware/starlette.py @@ -0,0 +1,11 @@ +from starlette.applications import Starlette +from starlette.middleware import Middleware +from starlette.middleware.cors import CORSMiddleware + +routes = ... + +middleware = [ + Middleware(CORSMiddleware, allow_origins=['*'], allow_credentials=True) +] + +app = Starlette(routes=routes, middleware=middleware) \ No newline at end of file diff --git a/ruby/ql/consistency-queries/CfgConsistency.ql b/ruby/ql/consistency-queries/CfgConsistency.ql index d7d5b84a4025..a57cb03ebb2b 100644 --- a/ruby/ql/consistency-queries/CfgConsistency.ql +++ b/ruby/ql/consistency-queries/CfgConsistency.ql @@ -19,8 +19,3 @@ query predicate nonPostOrderExpr(Expr e, string cls) { c instanceof NormalCompletion ) } - -query predicate multipleToString(CfgNode n, string s) { - s = strictconcat(n.toString(), ",") and - strictcount(n.toString()) > 1 -} diff --git a/ruby/ql/lib/codeql/ruby/Diagnostics.qll b/ruby/ql/lib/codeql/ruby/Diagnostics.qll index faf7b8420a0e..5902bb594141 100644 --- a/ruby/ql/lib/codeql/ruby/Diagnostics.qll +++ b/ruby/ql/lib/codeql/ruby/Diagnostics.qll @@ -1,3 +1,5 @@ +/** Provides classes relating to extraction diagnostics. */ + private import codeql.Locations /** A diagnostic emitted during extraction, such as a parse error */ diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl1.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl1.qll index 359fa71744b4..ce964917e970 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl1.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl1.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll index 359fa71744b4..ce964917e970 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I diff --git a/ruby/ql/test/library-tests/dataflow/flow-summaries/semantics.expected b/ruby/ql/test/library-tests/dataflow/flow-summaries/semantics.expected index 63f33ab5b550..34093c8b8cd7 100644 --- a/ruby/ql/test/library-tests/dataflow/flow-summaries/semantics.expected +++ b/ruby/ql/test/library-tests/dataflow/flow-summaries/semantics.expected @@ -78,14 +78,10 @@ edges | semantics.rb:60:5:60:5 | a | semantics.rb:66:14:66:15 | &... | provenance | | | semantics.rb:60:9:60:18 | call to source | semantics.rb:60:5:60:5 | a | provenance | | | semantics.rb:60:9:60:18 | call to source | semantics.rb:60:5:60:5 | a | provenance | | -| semantics.rb:61:10:61:15 | call to s10 [element 0] | semantics.rb:61:10:61:15 | call to s10 | provenance | | | semantics.rb:61:14:61:14 | a | semantics.rb:61:10:61:15 | call to s10 | provenance | | | semantics.rb:61:14:61:14 | a | semantics.rb:61:10:61:15 | call to s10 | provenance | | -| semantics.rb:61:14:61:14 | a | semantics.rb:61:10:61:15 | call to s10 [element 0] | provenance | | -| semantics.rb:62:10:62:18 | call to s10 [element 1] | semantics.rb:62:10:62:18 | call to s10 | provenance | | | semantics.rb:62:17:62:17 | a | semantics.rb:62:10:62:18 | call to s10 | provenance | | | semantics.rb:62:17:62:17 | a | semantics.rb:62:10:62:18 | call to s10 | provenance | | -| semantics.rb:62:17:62:17 | a | semantics.rb:62:10:62:18 | call to s10 [element 1] | provenance | | | semantics.rb:63:19:63:19 | a | semantics.rb:63:10:63:20 | call to s10 | provenance | | | semantics.rb:63:19:63:19 | a | semantics.rb:63:10:63:20 | call to s10 | provenance | | | semantics.rb:64:27:64:27 | a | semantics.rb:64:10:64:28 | call to s10 | provenance | | @@ -192,10 +188,8 @@ edges | semantics.rb:126:5:126:5 | b | semantics.rb:129:17:129:17 | b | provenance | | | semantics.rb:126:9:126:18 | call to source | semantics.rb:126:5:126:5 | b | provenance | | | semantics.rb:126:9:126:18 | call to source | semantics.rb:126:5:126:5 | b | provenance | | -| semantics.rb:127:10:127:18 | call to s17 [element 0] | semantics.rb:127:10:127:18 | call to s17 | provenance | | -| semantics.rb:127:10:127:18 | call to s17 [element 1] | semantics.rb:127:10:127:18 | call to s17 | provenance | | -| semantics.rb:127:14:127:14 | a | semantics.rb:127:10:127:18 | call to s17 [element 0] | provenance | | -| semantics.rb:127:17:127:17 | b | semantics.rb:127:10:127:18 | call to s17 [element 1] | provenance | | +| semantics.rb:127:14:127:14 | a | semantics.rb:127:10:127:18 | call to s17 | provenance | | +| semantics.rb:127:17:127:17 | b | semantics.rb:127:10:127:18 | call to s17 | provenance | | | semantics.rb:128:10:128:18 | call to s17 [element 0] | semantics.rb:128:10:128:21 | ...[...] | provenance | | | semantics.rb:128:10:128:18 | call to s17 [element 0] | semantics.rb:128:10:128:21 | ...[...] | provenance | | | semantics.rb:128:14:128:14 | a | semantics.rb:128:10:128:18 | call to s17 [element 0] | provenance | | @@ -1191,12 +1185,10 @@ nodes | semantics.rb:60:9:60:18 | call to source | semmle.label | call to source | | semantics.rb:61:10:61:15 | call to s10 | semmle.label | call to s10 | | semantics.rb:61:10:61:15 | call to s10 | semmle.label | call to s10 | -| semantics.rb:61:10:61:15 | call to s10 [element 0] | semmle.label | call to s10 [element 0] | | semantics.rb:61:14:61:14 | a | semmle.label | a | | semantics.rb:61:14:61:14 | a | semmle.label | a | | semantics.rb:62:10:62:18 | call to s10 | semmle.label | call to s10 | | semantics.rb:62:10:62:18 | call to s10 | semmle.label | call to s10 | -| semantics.rb:62:10:62:18 | call to s10 [element 1] | semmle.label | call to s10 [element 1] | | semantics.rb:62:17:62:17 | a | semmle.label | a | | semantics.rb:62:17:62:17 | a | semmle.label | a | | semantics.rb:63:10:63:20 | call to s10 | semmle.label | call to s10 | @@ -1322,8 +1314,6 @@ nodes | semantics.rb:126:9:126:18 | call to source | semmle.label | call to source | | semantics.rb:126:9:126:18 | call to source | semmle.label | call to source | | semantics.rb:127:10:127:18 | call to s17 | semmle.label | call to s17 | -| semantics.rb:127:10:127:18 | call to s17 [element 0] | semmle.label | call to s17 [element 0] | -| semantics.rb:127:10:127:18 | call to s17 [element 1] | semmle.label | call to s17 [element 1] | | semantics.rb:127:14:127:14 | a | semmle.label | a | | semantics.rb:127:17:127:17 | b | semmle.label | b | | semantics.rb:128:10:128:18 | call to s17 [element 0] | semmle.label | call to s17 [element 0] | diff --git a/ruby/ql/test/library-tests/dataflow/summaries/Summaries.expected b/ruby/ql/test/library-tests/dataflow/summaries/Summaries.expected index cbfa5730e5b7..ce89d3f549f6 100644 --- a/ruby/ql/test/library-tests/dataflow/summaries/Summaries.expected +++ b/ruby/ql/test/library-tests/dataflow/summaries/Summaries.expected @@ -292,8 +292,8 @@ edges | summaries.rb:128:1:128:1 | [post] x | summaries.rb:129:6:129:6 | x | provenance | | | summaries.rb:128:14:128:20 | tainted | summaries.rb:128:1:128:1 | [post] x | provenance | MaD:21 | | summaries.rb:131:16:131:22 | tainted | summaries.rb:131:1:131:23 | synthetic splat argument | provenance | Sink:MaD:4 | -| summaries.rb:157:14:160:3 | do ... end [captured tainted] | summaries.rb:158:15:158:21 | tainted | provenance | heuristic-callback | -| summaries.rb:157:14:160:3 | do ... end [captured tainted] | summaries.rb:158:15:158:21 | tainted | provenance | heuristic-callback | +| summaries.rb:157:14:160:3 | do ... end [captured tainted] | summaries.rb:158:15:158:21 | tainted | provenance | heuristic-callback Sink:MaD:6 | +| summaries.rb:157:14:160:3 | do ... end [captured tainted] | summaries.rb:158:15:158:21 | tainted | provenance | heuristic-callback Sink:MaD:6 | nodes | summaries.rb:1:11:1:36 | call to identity | semmle.label | call to identity | | summaries.rb:1:11:1:36 | call to identity | semmle.label | call to identity | diff --git a/ruby/ql/test/library-tests/frameworks/action_controller/params-flow.expected b/ruby/ql/test/library-tests/frameworks/action_controller/params-flow.expected index f443f7669867..73f4ab1f46d8 100644 --- a/ruby/ql/test/library-tests/frameworks/action_controller/params-flow.expected +++ b/ruby/ql/test/library-tests/frameworks/action_controller/params-flow.expected @@ -56,28 +56,18 @@ edges | params_flow.rb:83:10:83:15 | call to params | params_flow.rb:83:10:83:27 | call to to_unsafe_h | provenance | | | params_flow.rb:87:10:87:15 | call to params | params_flow.rb:87:10:87:30 | call to to_unsafe_hash | provenance | | | params_flow.rb:91:10:91:15 | call to params | params_flow.rb:91:10:91:40 | call to transform_keys | provenance | | -| params_flow.rb:91:10:91:15 | call to params | params_flow.rb:91:10:91:40 | call to transform_keys [element] | provenance | | -| params_flow.rb:91:10:91:40 | call to transform_keys [element] | params_flow.rb:91:10:91:40 | call to transform_keys | provenance | | | params_flow.rb:95:10:95:15 | call to params | params_flow.rb:95:10:95:41 | call to transform_keys! | provenance | | | params_flow.rb:99:10:99:15 | call to params | params_flow.rb:99:10:99:42 | call to transform_values | provenance | | | params_flow.rb:103:10:103:15 | call to params | params_flow.rb:103:10:103:43 | call to transform_values! | provenance | | | params_flow.rb:107:10:107:15 | call to params | params_flow.rb:107:10:107:33 | call to values_at | provenance | | -| params_flow.rb:107:10:107:15 | call to params | params_flow.rb:107:10:107:33 | call to values_at [element 0] | provenance | | -| params_flow.rb:107:10:107:15 | call to params | params_flow.rb:107:10:107:33 | call to values_at [element 1] | provenance | | -| params_flow.rb:107:10:107:33 | call to values_at [element 0] | params_flow.rb:107:10:107:33 | call to values_at | provenance | | -| params_flow.rb:107:10:107:33 | call to values_at [element 1] | params_flow.rb:107:10:107:33 | call to values_at | provenance | | | params_flow.rb:111:10:111:15 | call to params | params_flow.rb:111:10:111:29 | call to merge | provenance | | -| params_flow.rb:112:10:112:29 | call to merge [element 0] | params_flow.rb:112:10:112:29 | call to merge | provenance | | | params_flow.rb:112:23:112:28 | call to params | params_flow.rb:112:10:112:29 | call to merge | provenance | | -| params_flow.rb:112:23:112:28 | call to params | params_flow.rb:112:10:112:29 | call to merge [element 0] | provenance | | | params_flow.rb:116:10:116:15 | call to params | params_flow.rb:116:10:116:37 | call to reverse_merge | provenance | | | params_flow.rb:117:31:117:36 | call to params | params_flow.rb:117:10:117:37 | call to reverse_merge | provenance | | | params_flow.rb:121:10:121:15 | call to params | params_flow.rb:121:10:121:43 | call to with_defaults | provenance | | | params_flow.rb:122:31:122:36 | call to params | params_flow.rb:122:10:122:37 | call to with_defaults | provenance | | | params_flow.rb:126:10:126:15 | call to params | params_flow.rb:126:10:126:30 | call to merge! | provenance | | -| params_flow.rb:127:10:127:30 | call to merge! [element 0] | params_flow.rb:127:10:127:30 | call to merge! | provenance | | | params_flow.rb:127:24:127:29 | call to params | params_flow.rb:127:10:127:30 | call to merge! | provenance | | -| params_flow.rb:127:24:127:29 | call to params | params_flow.rb:127:10:127:30 | call to merge! [element 0] | provenance | | | params_flow.rb:130:5:130:5 | [post] p | params_flow.rb:131:10:131:10 | p | provenance | | | params_flow.rb:130:5:130:5 | [post] p [element 0] | params_flow.rb:131:10:131:10 | p | provenance | | | params_flow.rb:130:14:130:19 | call to params | params_flow.rb:130:5:130:5 | [post] p | provenance | | @@ -199,7 +189,6 @@ nodes | params_flow.rb:87:10:87:30 | call to to_unsafe_hash | semmle.label | call to to_unsafe_hash | | params_flow.rb:91:10:91:15 | call to params | semmle.label | call to params | | params_flow.rb:91:10:91:40 | call to transform_keys | semmle.label | call to transform_keys | -| params_flow.rb:91:10:91:40 | call to transform_keys [element] | semmle.label | call to transform_keys [element] | | params_flow.rb:95:10:95:15 | call to params | semmle.label | call to params | | params_flow.rb:95:10:95:41 | call to transform_keys! | semmle.label | call to transform_keys! | | params_flow.rb:99:10:99:15 | call to params | semmle.label | call to params | @@ -208,12 +197,9 @@ nodes | params_flow.rb:103:10:103:43 | call to transform_values! | semmle.label | call to transform_values! | | params_flow.rb:107:10:107:15 | call to params | semmle.label | call to params | | params_flow.rb:107:10:107:33 | call to values_at | semmle.label | call to values_at | -| params_flow.rb:107:10:107:33 | call to values_at [element 0] | semmle.label | call to values_at [element 0] | -| params_flow.rb:107:10:107:33 | call to values_at [element 1] | semmle.label | call to values_at [element 1] | | params_flow.rb:111:10:111:15 | call to params | semmle.label | call to params | | params_flow.rb:111:10:111:29 | call to merge | semmle.label | call to merge | | params_flow.rb:112:10:112:29 | call to merge | semmle.label | call to merge | -| params_flow.rb:112:10:112:29 | call to merge [element 0] | semmle.label | call to merge [element 0] | | params_flow.rb:112:23:112:28 | call to params | semmle.label | call to params | | params_flow.rb:116:10:116:15 | call to params | semmle.label | call to params | | params_flow.rb:116:10:116:37 | call to reverse_merge | semmle.label | call to reverse_merge | @@ -226,7 +212,6 @@ nodes | params_flow.rb:126:10:126:15 | call to params | semmle.label | call to params | | params_flow.rb:126:10:126:30 | call to merge! | semmle.label | call to merge! | | params_flow.rb:127:10:127:30 | call to merge! | semmle.label | call to merge! | -| params_flow.rb:127:10:127:30 | call to merge! [element 0] | semmle.label | call to merge! [element 0] | | params_flow.rb:127:24:127:29 | call to params | semmle.label | call to params | | params_flow.rb:130:5:130:5 | [post] p | semmle.label | [post] p | | params_flow.rb:130:5:130:5 | [post] p [element 0] | semmle.label | [post] p [element 0] | diff --git a/ruby/ql/test/query-tests/experimental/LdapInjection/Ldapinjection.expected b/ruby/ql/test/query-tests/experimental/LdapInjection/Ldapinjection.expected index a69064a3d099..1eec0daa4c4c 100644 --- a/ruby/ql/test/query-tests/experimental/LdapInjection/Ldapinjection.expected +++ b/ruby/ql/test/query-tests/experimental/LdapInjection/Ldapinjection.expected @@ -6,9 +6,8 @@ edges | LdapInjection.rb:9:5:9:8 | name | LdapInjection.rb:33:88:33:91 | name | provenance | | | LdapInjection.rb:9:12:9:17 | call to params | LdapInjection.rb:9:12:9:29 | ...[...] | provenance | | | LdapInjection.rb:9:12:9:29 | ...[...] | LdapInjection.rb:9:5:9:8 | name | provenance | | -| LdapInjection.rb:33:87:33:92 | call to [] [element 0] | LdapInjection.rb:33:87:33:92 | call to [] | provenance | | +| LdapInjection.rb:33:88:33:91 | name | LdapInjection.rb:33:87:33:92 | call to [] | provenance | | | LdapInjection.rb:33:88:33:91 | name | LdapInjection.rb:33:87:33:92 | call to [] | provenance | Config | -| LdapInjection.rb:33:88:33:91 | name | LdapInjection.rb:33:87:33:92 | call to [] [element 0] | provenance | | | LdapInjection.rb:33:88:33:91 | name | LdapInjection.rb:37:41:37:44 | name | provenance | | | LdapInjection.rb:37:5:37:10 | filter | LdapInjection.rb:38:62:38:67 | filter | provenance | | | LdapInjection.rb:37:14:37:45 | call to eq | LdapInjection.rb:37:5:37:10 | filter | provenance | | @@ -23,7 +22,6 @@ nodes | LdapInjection.rb:25:23:25:49 | "ou=people,dc=#{...},dc=com" | semmle.label | "ou=people,dc=#{...},dc=com" | | LdapInjection.rb:29:62:29:73 | "cn=#{...}" | semmle.label | "cn=#{...}" | | LdapInjection.rb:33:87:33:92 | call to [] | semmle.label | call to [] | -| LdapInjection.rb:33:87:33:92 | call to [] [element 0] | semmle.label | call to [] [element 0] | | LdapInjection.rb:33:88:33:91 | name | semmle.label | name | | LdapInjection.rb:37:5:37:10 | filter | semmle.label | filter | | LdapInjection.rb:37:14:37:45 | call to eq | semmle.label | call to eq | diff --git a/ruby/ql/test/query-tests/security/cwe-079/ReflectedXSS.expected b/ruby/ql/test/query-tests/security/cwe-079/ReflectedXSS.expected index 067a0933e534..8434b2761e0b 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/ReflectedXSS.expected +++ b/ruby/ql/test/query-tests/security/cwe-079/ReflectedXSS.expected @@ -36,14 +36,12 @@ edges | app/controllers/foo/bars_controller.rb:36:34:36:51 | ...[...] | app/controllers/foo/bars_controller.rb:36:5:36:52 | call to t | provenance | | | app/controllers/foo/bars_controller.rb:37:42:37:47 | call to params | app/controllers/foo/bars_controller.rb:37:42:37:59 | ...[...] | provenance | | | app/controllers/foo/bars_controller.rb:37:42:37:59 | ...[...] | app/controllers/foo/bars_controller.rb:37:5:37:60 | call to translate | provenance | | -| app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text [element] | app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text | provenance | | -| app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text, element] | app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] [element] | provenance | | +| app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text, element] | app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] | provenance | | | app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text] | app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] | provenance | | -| app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] [element] | app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] | provenance | | | app/views/foo/bars/show.html.erb:8:9:8:21 | call to local_assigns [element :display_text] | app/views/foo/bars/show.html.erb:8:9:8:36 | ...[...] | provenance | | | app/views/foo/bars/show.html.erb:12:9:12:21 | call to local_assigns [element :display_text] | app/views/foo/bars/show.html.erb:12:9:12:26 | ...[...] | provenance | | | app/views/foo/bars/show.html.erb:17:15:17:27 | call to local_assigns [element :display_text] | app/views/foo/bars/show.html.erb:17:15:17:32 | ...[...] | provenance | | -| app/views/foo/bars/show.html.erb:43:48:43:89 | call to [] [element :display_text, element] | app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text [element] | provenance | | +| app/views/foo/bars/show.html.erb:43:48:43:89 | call to [] [element :display_text, element] | app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text | provenance | | | app/views/foo/bars/show.html.erb:43:48:43:89 | call to [] [element :display_text, element] | app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text, element] | provenance | | | app/views/foo/bars/show.html.erb:43:48:43:89 | call to [] [element :display_text] | app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text | provenance | | | app/views/foo/bars/show.html.erb:43:48:43:89 | call to [] [element :display_text] | app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text] | provenance | | @@ -91,11 +89,9 @@ nodes | app/controllers/foo/bars_controller.rb:37:42:37:47 | call to params | semmle.label | call to params | | app/controllers/foo/bars_controller.rb:37:42:37:59 | ...[...] | semmle.label | ...[...] | | app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text | semmle.label | call to display_text | -| app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text [element] | semmle.label | call to display_text [element] | | app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text, element] | semmle.label | call to local_assigns [element :display_text, element] | | app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text] | semmle.label | call to local_assigns [element :display_text] | | app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] | semmle.label | ...[...] | -| app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] [element] | semmle.label | ...[...] [element] | | app/views/foo/bars/show.html.erb:2:18:2:30 | @user_website | semmle.label | @user_website | | app/views/foo/bars/show.html.erb:5:9:5:20 | call to display_text | semmle.label | call to display_text | | app/views/foo/bars/show.html.erb:8:9:8:21 | call to local_assigns [element :display_text] | semmle.label | call to local_assigns [element :display_text] | diff --git a/ruby/ql/test/query-tests/security/cwe-079/StoredXSS.expected b/ruby/ql/test/query-tests/security/cwe-079/StoredXSS.expected index d778dadc91b9..ac33b45f06fa 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/StoredXSS.expected +++ b/ruby/ql/test/query-tests/security/cwe-079/StoredXSS.expected @@ -10,14 +10,12 @@ edges | app/controllers/foo/stores_controller.rb:13:39:13:78 | call to [] [element :display_text] | app/views/foo/stores/show.html.erb:32:3:32:14 | call to display_text | provenance | | | app/controllers/foo/stores_controller.rb:13:39:13:78 | call to [] [element :display_text] | app/views/foo/stores/show.html.erb:40:76:40:87 | call to display_text | provenance | | | app/controllers/foo/stores_controller.rb:13:55:13:56 | dt | app/controllers/foo/stores_controller.rb:13:39:13:78 | call to [] [element :display_text] | provenance | | -| app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text [element] | app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text | provenance | | -| app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text, element] | app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] [element] | provenance | | +| app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text, element] | app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] | provenance | | | app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text] | app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] | provenance | | -| app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] [element] | app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] | provenance | | | app/views/foo/stores/show.html.erb:5:9:5:21 | call to local_assigns [element :display_text] | app/views/foo/stores/show.html.erb:5:9:5:36 | ...[...] | provenance | | | app/views/foo/stores/show.html.erb:9:9:9:21 | call to local_assigns [element :display_text] | app/views/foo/stores/show.html.erb:9:9:9:26 | ...[...] | provenance | | | app/views/foo/stores/show.html.erb:14:15:14:27 | call to local_assigns [element :display_text] | app/views/foo/stores/show.html.erb:14:15:14:32 | ...[...] | provenance | | -| app/views/foo/stores/show.html.erb:40:48:40:89 | call to [] [element :display_text, element] | app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text [element] | provenance | | +| app/views/foo/stores/show.html.erb:40:48:40:89 | call to [] [element :display_text, element] | app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text | provenance | | | app/views/foo/stores/show.html.erb:40:48:40:89 | call to [] [element :display_text, element] | app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text, element] | provenance | | | app/views/foo/stores/show.html.erb:40:48:40:89 | call to [] [element :display_text] | app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text | provenance | | | app/views/foo/stores/show.html.erb:40:48:40:89 | call to [] [element :display_text] | app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text] | provenance | | @@ -33,11 +31,9 @@ nodes | app/controllers/foo/stores_controller.rb:13:39:13:78 | call to [] [element :display_text] | semmle.label | call to [] [element :display_text] | | app/controllers/foo/stores_controller.rb:13:55:13:56 | dt | semmle.label | dt | | app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text | semmle.label | call to display_text | -| app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text [element] | semmle.label | call to display_text [element] | | app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text, element] | semmle.label | call to local_assigns [element :display_text, element] | | app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text] | semmle.label | call to local_assigns [element :display_text] | | app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] | semmle.label | ...[...] | -| app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] [element] | semmle.label | ...[...] [element] | | app/views/foo/stores/show.html.erb:2:9:2:20 | call to display_text | semmle.label | call to display_text | | app/views/foo/stores/show.html.erb:5:9:5:21 | call to local_assigns [element :display_text] | semmle.label | call to local_assigns [element :display_text] | | app/views/foo/stores/show.html.erb:5:9:5:36 | ...[...] | semmle.label | ...[...] | diff --git a/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected b/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected index 38b5e8f7e12e..a4a254806aac 100644 --- a/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected +++ b/ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected @@ -11,12 +11,10 @@ edges | ActiveRecordInjection.rb:50:29:50:39 | ...[...] | ActiveRecordInjection.rb:50:20:50:42 | "id = '#{...}'" | provenance | AdditionalTaintStep | | ActiveRecordInjection.rb:55:30:55:35 | call to params | ActiveRecordInjection.rb:55:30:55:40 | ...[...] | provenance | | | ActiveRecordInjection.rb:55:30:55:40 | ...[...] | ActiveRecordInjection.rb:55:21:55:43 | "id = '#{...}'" | provenance | AdditionalTaintStep | -| ActiveRecordInjection.rb:59:21:59:45 | call to [] [element 0] | ActiveRecordInjection.rb:59:21:59:45 | call to [] | provenance | | -| ActiveRecordInjection.rb:59:22:59:44 | "id = '#{...}'" | ActiveRecordInjection.rb:59:21:59:45 | call to [] [element 0] | provenance | | +| ActiveRecordInjection.rb:59:22:59:44 | "id = '#{...}'" | ActiveRecordInjection.rb:59:21:59:45 | call to [] | provenance | | | ActiveRecordInjection.rb:59:31:59:36 | call to params | ActiveRecordInjection.rb:59:31:59:41 | ...[...] | provenance | | | ActiveRecordInjection.rb:59:31:59:41 | ...[...] | ActiveRecordInjection.rb:59:22:59:44 | "id = '#{...}'" | provenance | AdditionalTaintStep | -| ActiveRecordInjection.rb:64:22:64:46 | call to [] [element 0] | ActiveRecordInjection.rb:64:22:64:46 | call to [] | provenance | | -| ActiveRecordInjection.rb:64:23:64:45 | "id = '#{...}'" | ActiveRecordInjection.rb:64:22:64:46 | call to [] [element 0] | provenance | | +| ActiveRecordInjection.rb:64:23:64:45 | "id = '#{...}'" | ActiveRecordInjection.rb:64:22:64:46 | call to [] | provenance | | | ActiveRecordInjection.rb:64:32:64:37 | call to params | ActiveRecordInjection.rb:64:32:64:42 | ...[...] | provenance | | | ActiveRecordInjection.rb:64:32:64:42 | ...[...] | ActiveRecordInjection.rb:64:23:64:45 | "id = '#{...}'" | provenance | AdditionalTaintStep | | ActiveRecordInjection.rb:69:21:69:26 | call to params | ActiveRecordInjection.rb:69:21:69:35 | ...[...] | provenance | | @@ -58,8 +56,7 @@ edges | ActiveRecordInjection.rb:136:11:136:17 | ...[...] | ActiveRecordInjection.rb:136:5:136:7 | uid | provenance | | | ActiveRecordInjection.rb:137:5:137:9 | uidEq | ActiveRecordInjection.rb:141:20:141:32 | ... + ... | provenance | | | ActiveRecordInjection.rb:137:5:137:9 | uidEq | ActiveRecordInjection.rb:141:28:141:32 | uidEq | provenance | | -| ActiveRecordInjection.rb:141:20:141:32 | ... + ... [element] | ActiveRecordInjection.rb:141:20:141:32 | ... + ... | provenance | | -| ActiveRecordInjection.rb:141:28:141:32 | uidEq | ActiveRecordInjection.rb:141:20:141:32 | ... + ... [element] | provenance | | +| ActiveRecordInjection.rb:141:28:141:32 | uidEq | ActiveRecordInjection.rb:141:20:141:32 | ... + ... | provenance | | | ActiveRecordInjection.rb:174:21:174:26 | call to params | ActiveRecordInjection.rb:174:21:174:44 | ...[...] | provenance | | | ActiveRecordInjection.rb:174:21:174:26 | call to params | ActiveRecordInjection.rb:174:21:174:44 | ...[...] | provenance | | | ActiveRecordInjection.rb:174:21:174:44 | ...[...] | ActiveRecordInjection.rb:27:22:27:30 | condition | provenance | | @@ -117,12 +114,10 @@ nodes | ActiveRecordInjection.rb:55:30:55:35 | call to params | semmle.label | call to params | | ActiveRecordInjection.rb:55:30:55:40 | ...[...] | semmle.label | ...[...] | | ActiveRecordInjection.rb:59:21:59:45 | call to [] | semmle.label | call to [] | -| ActiveRecordInjection.rb:59:21:59:45 | call to [] [element 0] | semmle.label | call to [] [element 0] | | ActiveRecordInjection.rb:59:22:59:44 | "id = '#{...}'" | semmle.label | "id = '#{...}'" | | ActiveRecordInjection.rb:59:31:59:36 | call to params | semmle.label | call to params | | ActiveRecordInjection.rb:59:31:59:41 | ...[...] | semmle.label | ...[...] | | ActiveRecordInjection.rb:64:22:64:46 | call to [] | semmle.label | call to [] | -| ActiveRecordInjection.rb:64:22:64:46 | call to [] [element 0] | semmle.label | call to [] [element 0] | | ActiveRecordInjection.rb:64:23:64:45 | "id = '#{...}'" | semmle.label | "id = '#{...}'" | | ActiveRecordInjection.rb:64:32:64:37 | call to params | semmle.label | call to params | | ActiveRecordInjection.rb:64:32:64:42 | ...[...] | semmle.label | ...[...] | @@ -186,7 +181,6 @@ nodes | ActiveRecordInjection.rb:136:11:136:17 | ...[...] | semmle.label | ...[...] | | ActiveRecordInjection.rb:137:5:137:9 | uidEq | semmle.label | uidEq | | ActiveRecordInjection.rb:141:20:141:32 | ... + ... | semmle.label | ... + ... | -| ActiveRecordInjection.rb:141:20:141:32 | ... + ... [element] | semmle.label | ... + ... [element] | | ActiveRecordInjection.rb:141:28:141:32 | uidEq | semmle.label | uidEq | | ActiveRecordInjection.rb:174:21:174:26 | call to params | semmle.label | call to params | | ActiveRecordInjection.rb:174:21:174:44 | ...[...] | semmle.label | ...[...] | diff --git a/ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.expected b/ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.expected index ca8345d92eeb..bc709a0e469d 100644 --- a/ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.expected +++ b/ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.expected @@ -26,8 +26,7 @@ edges | CodeInjection.rb:78:12:78:17 | call to params | CodeInjection.rb:78:12:78:24 | ...[...] | provenance | | | CodeInjection.rb:78:12:78:24 | ...[...] | CodeInjection.rb:78:5:78:8 | code | provenance | | | CodeInjection.rb:78:12:78:24 | ...[...] | CodeInjection.rb:78:5:78:8 | code | provenance | | -| CodeInjection.rb:86:10:86:25 | ... + ... [element] | CodeInjection.rb:86:10:86:37 | ... + ... [element] | provenance | | -| CodeInjection.rb:86:10:86:37 | ... + ... [element] | CodeInjection.rb:86:10:86:37 | ... + ... | provenance | | +| CodeInjection.rb:86:10:86:25 | ... + ... [element] | CodeInjection.rb:86:10:86:37 | ... + ... | provenance | | | CodeInjection.rb:86:22:86:25 | code | CodeInjection.rb:86:10:86:25 | ... + ... [element] | provenance | | | CodeInjection.rb:101:3:102:5 | self in index [@foo] | CodeInjection.rb:111:3:113:5 | self in baz [@foo] | provenance | | | CodeInjection.rb:101:3:102:5 | self in index [@foo] | CodeInjection.rb:111:3:113:5 | self in baz [@foo] | provenance | | @@ -74,7 +73,6 @@ nodes | CodeInjection.rb:80:16:80:19 | code | semmle.label | code | | CodeInjection.rb:86:10:86:25 | ... + ... [element] | semmle.label | ... + ... [element] | | CodeInjection.rb:86:10:86:37 | ... + ... | semmle.label | ... + ... | -| CodeInjection.rb:86:10:86:37 | ... + ... [element] | semmle.label | ... + ... [element] | | CodeInjection.rb:86:22:86:25 | code | semmle.label | code | | CodeInjection.rb:88:10:88:32 | "prefix_#{...}_suffix" | semmle.label | "prefix_#{...}_suffix" | | CodeInjection.rb:90:10:90:13 | code | semmle.label | code | diff --git a/ruby/ql/test/query-tests/security/cwe-117/LogInjection.expected b/ruby/ql/test/query-tests/security/cwe-117/LogInjection.expected index 573ec810a60a..4dbd42ac6c6d 100644 --- a/ruby/ql/test/query-tests/security/cwe-117/LogInjection.expected +++ b/ruby/ql/test/query-tests/security/cwe-117/LogInjection.expected @@ -5,23 +5,19 @@ edges | app/controllers/users_controller.rb:15:5:15:15 | unsanitized | app/controllers/users_controller.rb:23:20:23:30 | unsanitized | provenance | | | app/controllers/users_controller.rb:15:19:15:24 | call to params | app/controllers/users_controller.rb:15:19:15:30 | ...[...] | provenance | | | app/controllers/users_controller.rb:15:19:15:30 | ...[...] | app/controllers/users_controller.rb:15:5:15:15 | unsanitized | provenance | | -| app/controllers/users_controller.rb:17:19:17:41 | ... + ... [element] | app/controllers/users_controller.rb:17:19:17:41 | ... + ... | provenance | | -| app/controllers/users_controller.rb:17:31:17:41 | unsanitized | app/controllers/users_controller.rb:17:19:17:41 | ... + ... [element] | provenance | | +| app/controllers/users_controller.rb:17:31:17:41 | unsanitized | app/controllers/users_controller.rb:17:19:17:41 | ... + ... | provenance | | | app/controllers/users_controller.rb:23:20:23:30 | unsanitized | app/controllers/users_controller.rb:23:20:23:44 | call to sub | provenance | | | app/controllers/users_controller.rb:23:20:23:44 | call to sub | app/controllers/users_controller.rb:24:18:26:7 | do ... end [captured unsanitized2] | provenance | | | app/controllers/users_controller.rb:23:20:23:44 | call to sub | app/controllers/users_controller.rb:27:16:27:39 | ... + ... | provenance | | | app/controllers/users_controller.rb:23:20:23:44 | call to sub | app/controllers/users_controller.rb:27:28:27:39 | unsanitized2 | provenance | | | app/controllers/users_controller.rb:24:18:26:7 | do ... end [captured unsanitized2] | app/controllers/users_controller.rb:25:7:25:18 | unsanitized2 | provenance | heuristic-callback | -| app/controllers/users_controller.rb:27:16:27:39 | ... + ... [element] | app/controllers/users_controller.rb:27:16:27:39 | ... + ... | provenance | | -| app/controllers/users_controller.rb:27:28:27:39 | unsanitized2 | app/controllers/users_controller.rb:27:16:27:39 | ... + ... [element] | provenance | | +| app/controllers/users_controller.rb:27:28:27:39 | unsanitized2 | app/controllers/users_controller.rb:27:16:27:39 | ... + ... | provenance | | | app/controllers/users_controller.rb:33:19:33:25 | call to cookies | app/controllers/users_controller.rb:33:19:33:31 | ...[...] | provenance | | | app/controllers/users_controller.rb:33:19:33:31 | ...[...] | app/controllers/users_controller.rb:34:31:34:45 | { ... } [captured unsanitized] | provenance | | | app/controllers/users_controller.rb:33:19:33:31 | ...[...] | app/controllers/users_controller.rb:35:31:35:57 | { ... } [captured unsanitized] | provenance | | | app/controllers/users_controller.rb:34:31:34:45 | { ... } [captured unsanitized] | app/controllers/users_controller.rb:34:33:34:43 | unsanitized | provenance | heuristic-callback | | app/controllers/users_controller.rb:35:31:35:57 | { ... } [captured unsanitized] | app/controllers/users_controller.rb:35:45:35:55 | unsanitized | provenance | heuristic-callback | -| app/controllers/users_controller.rb:35:33:35:55 | ... + ... [element] | app/controllers/users_controller.rb:35:33:35:55 | ... + ... | provenance | | | app/controllers/users_controller.rb:35:45:35:55 | unsanitized | app/controllers/users_controller.rb:35:33:35:55 | ... + ... | provenance | | -| app/controllers/users_controller.rb:35:45:35:55 | unsanitized | app/controllers/users_controller.rb:35:33:35:55 | ... + ... [element] | provenance | | | app/controllers/users_controller.rb:49:19:49:24 | call to params | app/controllers/users_controller.rb:49:19:49:30 | ...[...] | provenance | | nodes | app/controllers/users_controller.rb:15:5:15:15 | unsanitized | semmle.label | unsanitized | @@ -29,14 +25,12 @@ nodes | app/controllers/users_controller.rb:15:19:15:30 | ...[...] | semmle.label | ...[...] | | app/controllers/users_controller.rb:16:19:16:29 | unsanitized | semmle.label | unsanitized | | app/controllers/users_controller.rb:17:19:17:41 | ... + ... | semmle.label | ... + ... | -| app/controllers/users_controller.rb:17:19:17:41 | ... + ... [element] | semmle.label | ... + ... [element] | | app/controllers/users_controller.rb:17:31:17:41 | unsanitized | semmle.label | unsanitized | | app/controllers/users_controller.rb:23:20:23:30 | unsanitized | semmle.label | unsanitized | | app/controllers/users_controller.rb:23:20:23:44 | call to sub | semmle.label | call to sub | | app/controllers/users_controller.rb:24:18:26:7 | do ... end [captured unsanitized2] | semmle.label | do ... end [captured unsanitized2] | | app/controllers/users_controller.rb:25:7:25:18 | unsanitized2 | semmle.label | unsanitized2 | | app/controllers/users_controller.rb:27:16:27:39 | ... + ... | semmle.label | ... + ... | -| app/controllers/users_controller.rb:27:16:27:39 | ... + ... [element] | semmle.label | ... + ... [element] | | app/controllers/users_controller.rb:27:28:27:39 | unsanitized2 | semmle.label | unsanitized2 | | app/controllers/users_controller.rb:33:19:33:25 | call to cookies | semmle.label | call to cookies | | app/controllers/users_controller.rb:33:19:33:31 | ...[...] | semmle.label | ...[...] | @@ -44,7 +38,6 @@ nodes | app/controllers/users_controller.rb:34:33:34:43 | unsanitized | semmle.label | unsanitized | | app/controllers/users_controller.rb:35:31:35:57 | { ... } [captured unsanitized] | semmle.label | { ... } [captured unsanitized] | | app/controllers/users_controller.rb:35:33:35:55 | ... + ... | semmle.label | ... + ... | -| app/controllers/users_controller.rb:35:33:35:55 | ... + ... [element] | semmle.label | ... + ... [element] | | app/controllers/users_controller.rb:35:45:35:55 | unsanitized | semmle.label | unsanitized | | app/controllers/users_controller.rb:49:19:49:24 | call to params | semmle.label | call to params | | app/controllers/users_controller.rb:49:19:49:30 | ...[...] | semmle.label | ...[...] | diff --git a/ruby/ql/test/query-tests/security/cwe-1333-regexp-injection/RegExpInjection.expected b/ruby/ql/test/query-tests/security/cwe-1333-regexp-injection/RegExpInjection.expected index a6c8636a5cfb..13643e2c07e5 100644 --- a/ruby/ql/test/query-tests/security/cwe-1333-regexp-injection/RegExpInjection.expected +++ b/ruby/ql/test/query-tests/security/cwe-1333-regexp-injection/RegExpInjection.expected @@ -12,14 +12,12 @@ edges | RegExpInjection.rb:22:5:22:8 | name | RegExpInjection.rb:23:30:23:33 | name | provenance | | | RegExpInjection.rb:22:12:22:17 | call to params | RegExpInjection.rb:22:12:22:24 | ...[...] | provenance | | | RegExpInjection.rb:22:12:22:24 | ...[...] | RegExpInjection.rb:22:5:22:8 | name | provenance | | -| RegExpInjection.rb:23:24:23:33 | ... + ... [element] | RegExpInjection.rb:23:24:23:33 | ... + ... | provenance | | -| RegExpInjection.rb:23:30:23:33 | name | RegExpInjection.rb:23:24:23:33 | ... + ... [element] | provenance | | +| RegExpInjection.rb:23:30:23:33 | name | RegExpInjection.rb:23:24:23:33 | ... + ... | provenance | | | RegExpInjection.rb:54:5:54:8 | name | RegExpInjection.rb:55:28:55:37 | ... + ... | provenance | | | RegExpInjection.rb:54:5:54:8 | name | RegExpInjection.rb:55:34:55:37 | name | provenance | | | RegExpInjection.rb:54:12:54:17 | call to params | RegExpInjection.rb:54:12:54:24 | ...[...] | provenance | | | RegExpInjection.rb:54:12:54:24 | ...[...] | RegExpInjection.rb:54:5:54:8 | name | provenance | | -| RegExpInjection.rb:55:28:55:37 | ... + ... [element] | RegExpInjection.rb:55:28:55:37 | ... + ... | provenance | | -| RegExpInjection.rb:55:34:55:37 | name | RegExpInjection.rb:55:28:55:37 | ... + ... [element] | provenance | | +| RegExpInjection.rb:55:34:55:37 | name | RegExpInjection.rb:55:28:55:37 | ... + ... | provenance | | nodes | RegExpInjection.rb:4:5:4:8 | name | semmle.label | name | | RegExpInjection.rb:4:12:4:17 | call to params | semmle.label | call to params | @@ -37,13 +35,11 @@ nodes | RegExpInjection.rb:22:12:22:17 | call to params | semmle.label | call to params | | RegExpInjection.rb:22:12:22:24 | ...[...] | semmle.label | ...[...] | | RegExpInjection.rb:23:24:23:33 | ... + ... | semmle.label | ... + ... | -| RegExpInjection.rb:23:24:23:33 | ... + ... [element] | semmle.label | ... + ... [element] | | RegExpInjection.rb:23:30:23:33 | name | semmle.label | name | | RegExpInjection.rb:54:5:54:8 | name | semmle.label | name | | RegExpInjection.rb:54:12:54:17 | call to params | semmle.label | call to params | | RegExpInjection.rb:54:12:54:24 | ...[...] | semmle.label | ...[...] | | RegExpInjection.rb:55:28:55:37 | ... + ... | semmle.label | ... + ... | -| RegExpInjection.rb:55:28:55:37 | ... + ... [element] | semmle.label | ... + ... [element] | | RegExpInjection.rb:55:34:55:37 | name | semmle.label | name | subpaths #select diff --git a/ruby/ql/test/query-tests/security/cwe-134/TaintedFormatString.expected b/ruby/ql/test/query-tests/security/cwe-134/TaintedFormatString.expected index 635dfaf82c01..104b9d3ada07 100644 --- a/ruby/ql/test/query-tests/security/cwe-134/TaintedFormatString.expected +++ b/ruby/ql/test/query-tests/security/cwe-134/TaintedFormatString.expected @@ -8,10 +8,8 @@ edges | tainted_format_string.rb:21:27:21:32 | call to params | tainted_format_string.rb:21:27:21:41 | ...[...] | provenance | | | tainted_format_string.rb:22:20:22:25 | call to params | tainted_format_string.rb:22:20:22:34 | ...[...] | provenance | | | tainted_format_string.rb:28:19:28:24 | call to params | tainted_format_string.rb:28:19:28:33 | ...[...] | provenance | | -| tainted_format_string.rb:33:12:33:46 | ... + ... [element] | tainted_format_string.rb:33:12:33:46 | ... + ... | provenance | | | tainted_format_string.rb:33:32:33:37 | call to params | tainted_format_string.rb:33:32:33:46 | ...[...] | provenance | | | tainted_format_string.rb:33:32:33:46 | ...[...] | tainted_format_string.rb:33:12:33:46 | ... + ... | provenance | | -| tainted_format_string.rb:33:32:33:46 | ...[...] | tainted_format_string.rb:33:12:33:46 | ... + ... [element] | provenance | | | tainted_format_string.rb:36:30:36:35 | call to params | tainted_format_string.rb:36:30:36:44 | ...[...] | provenance | | | tainted_format_string.rb:36:30:36:44 | ...[...] | tainted_format_string.rb:36:12:36:46 | "A log message: #{...}" | provenance | AdditionalTaintStep | | tainted_format_string.rb:39:22:39:27 | call to params | tainted_format_string.rb:39:22:39:36 | ...[...] | provenance | | @@ -38,7 +36,6 @@ nodes | tainted_format_string.rb:28:19:28:24 | call to params | semmle.label | call to params | | tainted_format_string.rb:28:19:28:33 | ...[...] | semmle.label | ...[...] | | tainted_format_string.rb:33:12:33:46 | ... + ... | semmle.label | ... + ... | -| tainted_format_string.rb:33:12:33:46 | ... + ... [element] | semmle.label | ... + ... [element] | | tainted_format_string.rb:33:32:33:37 | call to params | semmle.label | call to params | | tainted_format_string.rb:33:32:33:46 | ...[...] | semmle.label | ...[...] | | tainted_format_string.rb:36:12:36:46 | "A log message: #{...}" | semmle.label | "A log message: #{...}" | diff --git a/rust/extractor/src/main.rs b/rust/extractor/src/main.rs index 160421456626..81032636ceb0 100644 --- a/rust/extractor/src/main.rs +++ b/rust/extractor/src/main.rs @@ -1,11 +1,79 @@ use anyhow::Context; use ra_ap_ide_db::line_index::LineIndex; +use ra_ap_parser::Edition; +use std::borrow::Cow; mod archive; mod config; pub mod generated; mod translate; pub mod trap; +use ra_ap_syntax::ast::SourceFile; +use ra_ap_syntax::{AstNode, SyntaxError, TextRange, TextSize}; +fn from_utf8_lossy(v: &[u8]) -> (Cow<'_, str>, Option) { + let mut iter = v.utf8_chunks(); + let (first_valid, first_invalid) = if let Some(chunk) = iter.next() { + let valid = chunk.valid(); + let invalid = chunk.invalid(); + if invalid.is_empty() { + debug_assert_eq!(valid.len(), v.len()); + return (Cow::Borrowed(valid), None); + } + (valid, invalid) + } else { + return (Cow::Borrowed(""), None); + }; + + const REPLACEMENT: &str = "\u{FFFD}"; + let error_start = first_valid.len() as u32; + let error_end = error_start + first_invalid.len() as u32; + let error_range = TextRange::new(TextSize::new(error_start), TextSize::new(error_end)); + let error = SyntaxError::new("invalid utf-8 sequence".to_owned(), error_range); + let mut res = String::with_capacity(v.len()); + res.push_str(first_valid); + + res.push_str(REPLACEMENT); + + for chunk in iter { + res.push_str(chunk.valid()); + if !chunk.invalid().is_empty() { + res.push_str(REPLACEMENT); + } + } + + (Cow::Owned(res), Some(error)) +} + +fn extract( + archiver: &archive::Archiver, + traps: &trap::TrapFileProvider, + file: std::path::PathBuf, +) -> anyhow::Result<()> { + let file = std::path::absolute(&file).unwrap_or(file); + let file = std::fs::canonicalize(&file).unwrap_or(file); + archiver.archive(&file); + let input = std::fs::read(&file)?; + let (input, err) = from_utf8_lossy(&input); + let line_index = LineIndex::new(&input); + let display_path = file.to_string_lossy(); + let mut trap = traps.create("source", &file); + let label = trap.emit_file(&file); + let mut translator = translate::Translator::new(trap, label, line_index); + if let Some(err) = err { + translator.emit_parse_error(display_path.as_ref(), err); + } + let parse = ra_ap_syntax::ast::SourceFile::parse(&input, Edition::CURRENT); + for err in parse.errors() { + translator.emit_parse_error(display_path.as_ref(), err); + } + if let Some(ast) = SourceFile::cast(parse.syntax_node()) { + translator.emit_source_file(ast); + } else { + log::warn!("Skipped {}", display_path); + } + translator.trap.commit()?; + Ok(()) +} fn main() -> anyhow::Result<()> { let cfg = config::Config::extract().context("failed to load configuration")?; stderrlog::new() @@ -18,18 +86,7 @@ fn main() -> anyhow::Result<()> { root: cfg.source_archive_dir, }; for file in cfg.inputs { - let file = std::path::absolute(&file).unwrap_or(file); - let file = std::fs::canonicalize(&file).unwrap_or(file); - archiver.archive(&file); - let input = std::fs::read(&file)?; - let input = String::from_utf8(input)?; - let line_index = LineIndex::new(&input); - let display_path = file.to_string_lossy(); - let mut trap = traps.create("source", &file); - let label = trap.emit_file(&file); - translate::SourceFileTranslator::new(trap, label, line_index) - .extract(&display_path, &input) - .context("writing trap file")?; + extract(&archiver, &traps, file)?; } Ok(()) diff --git a/rust/extractor/src/translate.rs b/rust/extractor/src/translate.rs index 3e415db0e7cc..cf8c9c670204 100644 --- a/rust/extractor/src/translate.rs +++ b/rust/extractor/src/translate.rs @@ -1,2176 +1,4 @@ -use crate::generated; -use crate::trap::{Label, TrapClass, TrapFile, TrapId}; -use codeql_extractor::trap::{self}; -use ra_ap_ide_db::line_index::LineIndex; -use ra_ap_syntax::ast::{ - HasArgList, HasAttrs, HasGenericArgs, HasGenericParams, HasLoopBody, HasModuleItem, HasName, - HasTypeBounds, HasVisibility, RangeItem, -}; -use ra_ap_syntax::{ast, AstNode, Edition, SourceFile, TextSize}; +mod base; +mod generated; -pub struct SourceFileTranslator { - trap: TrapFile, - label: trap::Label, - line_index: LineIndex, -} - -trait TextValue { - fn try_get_text(&self) -> Option; -} - -impl TextValue for ast::Lifetime { - fn try_get_text(&self) -> Option { - self.text().to_string().into() - } -} -impl TextValue for ast::Name { - fn try_get_text(&self) -> Option { - self.text().to_string().into() - } -} -impl TextValue for ast::Literal { - fn try_get_text(&self) -> Option { - self.token().text().to_string().into() - } -} -impl TextValue for ast::NameRef { - fn try_get_text(&self) -> Option { - self.text().to_string().into() - } -} -impl TextValue for ast::Abi { - fn try_get_text(&self) -> Option { - self.abi_string().map(|x| x.to_string()) - } -} - -impl TextValue for ast::BinExpr { - fn try_get_text(&self) -> Option { - self.op_token().map(|x| x.text().to_string()) - } -} -impl TextValue for ast::PrefixExpr { - fn try_get_text(&self) -> Option { - self.op_token().map(|x| x.text().to_string()) - } -} -impl TextValue for ast::RangeExpr { - fn try_get_text(&self) -> Option { - self.op_token().map(|x| x.text().to_string()) - } -} -impl TextValue for ast::RangePat { - fn try_get_text(&self) -> Option { - self.op_token().map(|x| x.text().to_string()) - } -} -impl SourceFileTranslator { - pub fn new(trap: TrapFile, label: trap::Label, line_index: LineIndex) -> SourceFileTranslator { - SourceFileTranslator { - trap, - label, - line_index, - } - } - pub fn extract(&mut self, path: &str, input: &str) -> Result<(), std::io::Error> { - let parse = ra_ap_syntax::ast::SourceFile::parse(input, Edition::CURRENT); - for err in parse.errors() { - let start = self.line_index.line_col(err.range().start()); - log::warn!("{}:{}:{}: {}", path, start.line + 1, start.col + 1, err); - } - if let Some(ast) = SourceFile::cast(parse.syntax_node()) { - self.emit_source_file(ast); - } else { - log::warn!("Skipped {}", path); - } - self.trap.commit() - } - fn emit_else_branch(&mut self, node: ast::ElseBranch) -> Label { - match node { - ast::ElseBranch::IfExpr(inner) => self.emit_if_expr(inner).into(), - ast::ElseBranch::Block(inner) => self.emit_block_expr(inner).into(), - } - } - fn emit_location(&mut self, label: Label, node: impl AstNode) { - let range = node.syntax().text_range(); - let start = self.line_index.line_col(range.start()); - let end = self.line_index.line_col( - range - .end() - .checked_sub(TextSize::new(1)) - .unwrap_or(range.end()), - ); - self.trap.emit_location(self.label, label, start, end) - } - fn emit_assoc_item(&mut self, node: ast::AssocItem) -> Label { - match node { - ast::AssocItem::Const(inner) => self.emit_const(inner).into(), - ast::AssocItem::Fn(inner) => self.emit_fn(inner).into(), - ast::AssocItem::MacroCall(inner) => self.emit_macro_call(inner).into(), - ast::AssocItem::TypeAlias(inner) => self.emit_type_alias(inner).into(), - } - } - - fn emit_expr(&mut self, node: ast::Expr) -> Label { - match node { - ast::Expr::ArrayExpr(inner) => self.emit_array_expr(inner).into(), - ast::Expr::AsmExpr(inner) => self.emit_asm_expr(inner).into(), - ast::Expr::AwaitExpr(inner) => self.emit_await_expr(inner).into(), - ast::Expr::BecomeExpr(inner) => self.emit_become_expr(inner).into(), - ast::Expr::BinExpr(inner) => self.emit_bin_expr(inner).into(), - ast::Expr::BlockExpr(inner) => self.emit_block_expr(inner).into(), - ast::Expr::BreakExpr(inner) => self.emit_break_expr(inner).into(), - ast::Expr::CallExpr(inner) => self.emit_call_expr(inner).into(), - ast::Expr::CastExpr(inner) => self.emit_cast_expr(inner).into(), - ast::Expr::ClosureExpr(inner) => self.emit_closure_expr(inner).into(), - ast::Expr::ContinueExpr(inner) => self.emit_continue_expr(inner).into(), - ast::Expr::FieldExpr(inner) => self.emit_field_expr(inner).into(), - ast::Expr::ForExpr(inner) => self.emit_for_expr(inner).into(), - ast::Expr::FormatArgsExpr(inner) => self.emit_format_args_expr(inner).into(), - ast::Expr::IfExpr(inner) => self.emit_if_expr(inner).into(), - ast::Expr::IndexExpr(inner) => self.emit_index_expr(inner).into(), - ast::Expr::LetExpr(inner) => self.emit_let_expr(inner).into(), - ast::Expr::Literal(inner) => self.emit_literal(inner).into(), - ast::Expr::LoopExpr(inner) => self.emit_loop_expr(inner).into(), - ast::Expr::MacroExpr(inner) => self.emit_macro_expr(inner).into(), - ast::Expr::MatchExpr(inner) => self.emit_match_expr(inner).into(), - ast::Expr::MethodCallExpr(inner) => self.emit_method_call_expr(inner).into(), - ast::Expr::OffsetOfExpr(inner) => self.emit_offset_of_expr(inner).into(), - ast::Expr::ParenExpr(inner) => self.emit_paren_expr(inner).into(), - ast::Expr::PathExpr(inner) => self.emit_path_expr(inner).into(), - ast::Expr::PrefixExpr(inner) => self.emit_prefix_expr(inner).into(), - ast::Expr::RangeExpr(inner) => self.emit_range_expr(inner).into(), - ast::Expr::RecordExpr(inner) => self.emit_record_expr(inner).into(), - ast::Expr::RefExpr(inner) => self.emit_ref_expr(inner).into(), - ast::Expr::ReturnExpr(inner) => self.emit_return_expr(inner).into(), - ast::Expr::TryExpr(inner) => self.emit_try_expr(inner).into(), - ast::Expr::TupleExpr(inner) => self.emit_tuple_expr(inner).into(), - ast::Expr::UnderscoreExpr(inner) => self.emit_underscore_expr(inner).into(), - ast::Expr::WhileExpr(inner) => self.emit_while_expr(inner).into(), - ast::Expr::YeetExpr(inner) => self.emit_yeet_expr(inner).into(), - ast::Expr::YieldExpr(inner) => self.emit_yield_expr(inner).into(), - } - } - - fn emit_extern_item(&mut self, node: ast::ExternItem) -> Label { - match node { - ast::ExternItem::Fn(inner) => self.emit_fn(inner).into(), - ast::ExternItem::MacroCall(inner) => self.emit_macro_call(inner).into(), - ast::ExternItem::Static(inner) => self.emit_static(inner).into(), - ast::ExternItem::TypeAlias(inner) => self.emit_type_alias(inner).into(), - } - } - - fn emit_field_list(&mut self, node: ast::FieldList) -> Label { - match node { - ast::FieldList::RecordFieldList(inner) => self.emit_record_field_list(inner).into(), - ast::FieldList::TupleFieldList(inner) => self.emit_tuple_field_list(inner).into(), - } - } - - fn emit_generic_arg(&mut self, node: ast::GenericArg) -> Label { - match node { - ast::GenericArg::AssocTypeArg(inner) => self.emit_assoc_type_arg(inner).into(), - ast::GenericArg::ConstArg(inner) => self.emit_const_arg(inner).into(), - ast::GenericArg::LifetimeArg(inner) => self.emit_lifetime_arg(inner).into(), - ast::GenericArg::TypeArg(inner) => self.emit_type_arg(inner).into(), - } - } - - fn emit_generic_param(&mut self, node: ast::GenericParam) -> Label { - match node { - ast::GenericParam::ConstParam(inner) => self.emit_const_param(inner).into(), - ast::GenericParam::LifetimeParam(inner) => self.emit_lifetime_param(inner).into(), - ast::GenericParam::TypeParam(inner) => self.emit_type_param(inner).into(), - } - } - - fn emit_pat(&mut self, node: ast::Pat) -> Label { - match node { - ast::Pat::BoxPat(inner) => self.emit_box_pat(inner).into(), - ast::Pat::ConstBlockPat(inner) => self.emit_const_block_pat(inner).into(), - ast::Pat::IdentPat(inner) => self.emit_ident_pat(inner).into(), - ast::Pat::LiteralPat(inner) => self.emit_literal_pat(inner).into(), - ast::Pat::MacroPat(inner) => self.emit_macro_pat(inner).into(), - ast::Pat::OrPat(inner) => self.emit_or_pat(inner).into(), - ast::Pat::ParenPat(inner) => self.emit_paren_pat(inner).into(), - ast::Pat::PathPat(inner) => self.emit_path_pat(inner).into(), - ast::Pat::RangePat(inner) => self.emit_range_pat(inner).into(), - ast::Pat::RecordPat(inner) => self.emit_record_pat(inner).into(), - ast::Pat::RefPat(inner) => self.emit_ref_pat(inner).into(), - ast::Pat::RestPat(inner) => self.emit_rest_pat(inner).into(), - ast::Pat::SlicePat(inner) => self.emit_slice_pat(inner).into(), - ast::Pat::TuplePat(inner) => self.emit_tuple_pat(inner).into(), - ast::Pat::TupleStructPat(inner) => self.emit_tuple_struct_pat(inner).into(), - ast::Pat::WildcardPat(inner) => self.emit_wildcard_pat(inner).into(), - } - } - - fn emit_stmt(&mut self, node: ast::Stmt) -> Label { - match node { - ast::Stmt::ExprStmt(inner) => self.emit_expr_stmt(inner).into(), - ast::Stmt::Item(inner) => self.emit_item(inner).into(), - ast::Stmt::LetStmt(inner) => self.emit_let_stmt(inner).into(), - } - } - - fn emit_type(&mut self, node: ast::Type) -> Label { - match node { - ast::Type::ArrayType(inner) => self.emit_array_type(inner).into(), - ast::Type::DynTraitType(inner) => self.emit_dyn_trait_type(inner).into(), - ast::Type::FnPtrType(inner) => self.emit_fn_ptr_type(inner).into(), - ast::Type::ForType(inner) => self.emit_for_type(inner).into(), - ast::Type::ImplTraitType(inner) => self.emit_impl_trait_type(inner).into(), - ast::Type::InferType(inner) => self.emit_infer_type(inner).into(), - ast::Type::MacroType(inner) => self.emit_macro_type(inner).into(), - ast::Type::NeverType(inner) => self.emit_never_type(inner).into(), - ast::Type::ParenType(inner) => self.emit_paren_type(inner).into(), - ast::Type::PathType(inner) => self.emit_path_type(inner).into(), - ast::Type::PtrType(inner) => self.emit_ptr_type(inner).into(), - ast::Type::RefType(inner) => self.emit_ref_type(inner).into(), - ast::Type::SliceType(inner) => self.emit_slice_type(inner).into(), - ast::Type::TupleType(inner) => self.emit_tuple_type(inner).into(), - } - } - - fn emit_item(&mut self, node: ast::Item) -> Label { - match node { - ast::Item::Const(inner) => self.emit_const(inner).into(), - ast::Item::Enum(inner) => self.emit_enum(inner).into(), - ast::Item::ExternBlock(inner) => self.emit_extern_block(inner).into(), - ast::Item::ExternCrate(inner) => self.emit_extern_crate(inner).into(), - ast::Item::Fn(inner) => self.emit_fn(inner).into(), - ast::Item::Impl(inner) => self.emit_impl(inner).into(), - ast::Item::MacroCall(inner) => self.emit_macro_call(inner).into(), - ast::Item::MacroDef(inner) => self.emit_macro_def(inner).into(), - ast::Item::MacroRules(inner) => self.emit_macro_rules(inner).into(), - ast::Item::Module(inner) => self.emit_module(inner).into(), - ast::Item::Static(inner) => self.emit_static(inner).into(), - ast::Item::Struct(inner) => self.emit_struct(inner).into(), - ast::Item::Trait(inner) => self.emit_trait(inner).into(), - ast::Item::TraitAlias(inner) => self.emit_trait_alias(inner).into(), - ast::Item::TypeAlias(inner) => self.emit_type_alias(inner).into(), - ast::Item::Union(inner) => self.emit_union(inner).into(), - ast::Item::Use(inner) => self.emit_use(inner).into(), - } - } - - fn emit_abi(&mut self, node: ast::Abi) -> Label { - let abi_string = node.try_get_text(); - let label = self.trap.emit(generated::Abi { - id: TrapId::Star, - abi_string, - }); - self.emit_location(label, node); - label - } - - fn emit_arg_list(&mut self, node: ast::ArgList) -> Label { - let args = node.args().map(|x| self.emit_expr(x)).collect(); - let label = self.trap.emit(generated::ArgList { - id: TrapId::Star, - args, - }); - self.emit_location(label, node); - label - } - - fn emit_array_expr(&mut self, node: ast::ArrayExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let exprs = node.exprs().map(|x| self.emit_expr(x)).collect(); - let label = self.trap.emit(generated::ArrayExpr { - id: TrapId::Star, - attrs, - exprs, - }); - self.emit_location(label, node); - label - } - - fn emit_array_type(&mut self, node: ast::ArrayType) -> Label { - let const_arg = node.const_arg().map(|x| self.emit_const_arg(x)); - let ty = node.ty().map(|x| self.emit_type(x)); - let label = self.trap.emit(generated::ArrayType { - id: TrapId::Star, - const_arg, - ty, - }); - self.emit_location(label, node); - label - } - - fn emit_asm_expr(&mut self, node: ast::AsmExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let expr = node.expr().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::AsmExpr { - id: TrapId::Star, - attrs, - expr, - }); - self.emit_location(label, node); - label - } - - fn emit_assoc_item_list( - &mut self, - node: ast::AssocItemList, - ) -> Label { - let assoc_items = node - .assoc_items() - .map(|x| self.emit_assoc_item(x)) - .collect(); - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let label = self.trap.emit(generated::AssocItemList { - id: TrapId::Star, - assoc_items, - attrs, - }); - self.emit_location(label, node); - label - } - - fn emit_assoc_type_arg(&mut self, node: ast::AssocTypeArg) -> Label { - let const_arg = node.const_arg().map(|x| self.emit_const_arg(x)); - let generic_arg_list = node - .generic_arg_list() - .map(|x| self.emit_generic_arg_list(x)); - let name_ref = node.name_ref().map(|x| self.emit_name_ref(x)); - let param_list = node.param_list().map(|x| self.emit_param_list(x)); - let ret_type = node.ret_type().map(|x| self.emit_ret_type(x)); - let return_type_syntax = node - .return_type_syntax() - .map(|x| self.emit_return_type_syntax(x)); - let ty = node.ty().map(|x| self.emit_type(x)); - let type_bound_list = node.type_bound_list().map(|x| self.emit_type_bound_list(x)); - let label = self.trap.emit(generated::AssocTypeArg { - id: TrapId::Star, - const_arg, - generic_arg_list, - name_ref, - param_list, - ret_type, - return_type_syntax, - ty, - type_bound_list, - }); - self.emit_location(label, node); - label - } - - fn emit_attr(&mut self, node: ast::Attr) -> Label { - let meta = node.meta().map(|x| self.emit_meta(x)); - let label = self.trap.emit(generated::Attr { - id: TrapId::Star, - meta, - }); - self.emit_location(label, node); - label - } - - fn emit_await_expr(&mut self, node: ast::AwaitExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let expr = node.expr().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::AwaitExpr { - id: TrapId::Star, - attrs, - expr, - }); - self.emit_location(label, node); - label - } - - fn emit_become_expr(&mut self, node: ast::BecomeExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let expr = node.expr().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::BecomeExpr { - id: TrapId::Star, - attrs, - expr, - }); - self.emit_location(label, node); - label - } - - fn emit_bin_expr(&mut self, node: ast::BinExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let lhs = node.lhs().map(|x| self.emit_expr(x)); - let operator_name = node.try_get_text(); - let rhs = node.rhs().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::BinaryExpr { - id: TrapId::Star, - attrs, - lhs, - operator_name, - rhs, - }); - self.emit_location(label, node); - label - } - - fn emit_block_expr(&mut self, node: ast::BlockExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let label = node.label().map(|x| self.emit_label(x)); - let stmt_list = node.stmt_list().map(|x| self.emit_stmt_list(x)); - let label = self.trap.emit(generated::BlockExpr { - id: TrapId::Star, - attrs, - label, - stmt_list, - }); - self.emit_location(label, node); - label - } - - fn emit_box_pat(&mut self, node: ast::BoxPat) -> Label { - let pat = node.pat().map(|x| self.emit_pat(x)); - let label = self.trap.emit(generated::BoxPat { - id: TrapId::Star, - pat, - }); - self.emit_location(label, node); - label - } - - fn emit_break_expr(&mut self, node: ast::BreakExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let expr = node.expr().map(|x| self.emit_expr(x)); - let lifetime = node.lifetime().map(|x| self.emit_lifetime(x)); - let label = self.trap.emit(generated::BreakExpr { - id: TrapId::Star, - attrs, - expr, - lifetime, - }); - self.emit_location(label, node); - label - } - - fn emit_call_expr(&mut self, node: ast::CallExpr) -> Label { - let arg_list = node.arg_list().map(|x| self.emit_arg_list(x)); - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let expr = node.expr().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::CallExpr { - id: TrapId::Star, - arg_list, - attrs, - expr, - }); - self.emit_location(label, node); - label - } - - fn emit_cast_expr(&mut self, node: ast::CastExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let expr = node.expr().map(|x| self.emit_expr(x)); - let ty = node.ty().map(|x| self.emit_type(x)); - let label = self.trap.emit(generated::CastExpr { - id: TrapId::Star, - attrs, - expr, - ty, - }); - self.emit_location(label, node); - label - } - - fn emit_closure_binder(&mut self, node: ast::ClosureBinder) -> Label { - let generic_param_list = node - .generic_param_list() - .map(|x| self.emit_generic_param_list(x)); - let label = self.trap.emit(generated::ClosureBinder { - id: TrapId::Star, - generic_param_list, - }); - self.emit_location(label, node); - label - } - - fn emit_closure_expr(&mut self, node: ast::ClosureExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let body = node.body().map(|x| self.emit_expr(x)); - let closure_binder = node.closure_binder().map(|x| self.emit_closure_binder(x)); - let param_list = node.param_list().map(|x| self.emit_param_list(x)); - let ret_type = node.ret_type().map(|x| self.emit_ret_type(x)); - let label = self.trap.emit(generated::ClosureExpr { - id: TrapId::Star, - attrs, - body, - closure_binder, - param_list, - ret_type, - }); - self.emit_location(label, node); - label - } - - fn emit_const(&mut self, node: ast::Const) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let body = node.body().map(|x| self.emit_expr(x)); - let name = node.name().map(|x| self.emit_name(x)); - let ty = node.ty().map(|x| self.emit_type(x)); - let visibility = node.visibility().map(|x| self.emit_visibility(x)); - let label = self.trap.emit(generated::Const { - id: TrapId::Star, - attrs, - body, - name, - ty, - visibility, - }); - self.emit_location(label, node); - label - } - - fn emit_const_arg(&mut self, node: ast::ConstArg) -> Label { - let expr = node.expr().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::ConstArg { - id: TrapId::Star, - expr, - }); - self.emit_location(label, node); - label - } - - fn emit_const_block_pat( - &mut self, - node: ast::ConstBlockPat, - ) -> Label { - let block_expr = node.block_expr().map(|x| self.emit_block_expr(x)); - let label = self.trap.emit(generated::ConstBlockPat { - id: TrapId::Star, - block_expr, - }); - self.emit_location(label, node); - label - } - - fn emit_const_param(&mut self, node: ast::ConstParam) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let default_val = node.default_val().map(|x| self.emit_const_arg(x)); - let name = node.name().map(|x| self.emit_name(x)); - let ty = node.ty().map(|x| self.emit_type(x)); - let label = self.trap.emit(generated::ConstParam { - id: TrapId::Star, - attrs, - default_val, - name, - ty, - }); - self.emit_location(label, node); - label - } - - fn emit_continue_expr(&mut self, node: ast::ContinueExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let lifetime = node.lifetime().map(|x| self.emit_lifetime(x)); - let label = self.trap.emit(generated::ContinueExpr { - id: TrapId::Star, - attrs, - lifetime, - }); - self.emit_location(label, node); - label - } - - fn emit_dyn_trait_type(&mut self, node: ast::DynTraitType) -> Label { - let type_bound_list = node.type_bound_list().map(|x| self.emit_type_bound_list(x)); - let label = self.trap.emit(generated::DynTraitType { - id: TrapId::Star, - type_bound_list, - }); - self.emit_location(label, node); - label - } - - fn emit_enum(&mut self, node: ast::Enum) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let generic_param_list = node - .generic_param_list() - .map(|x| self.emit_generic_param_list(x)); - let name = node.name().map(|x| self.emit_name(x)); - let variant_list = node.variant_list().map(|x| self.emit_variant_list(x)); - let visibility = node.visibility().map(|x| self.emit_visibility(x)); - let where_clause = node.where_clause().map(|x| self.emit_where_clause(x)); - let label = self.trap.emit(generated::Enum { - id: TrapId::Star, - attrs, - generic_param_list, - name, - variant_list, - visibility, - where_clause, - }); - self.emit_location(label, node); - label - } - - fn emit_expr_stmt(&mut self, node: ast::ExprStmt) -> Label { - let expr = node.expr().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::ExprStmt { - id: TrapId::Star, - expr, - }); - self.emit_location(label, node); - label - } - - fn emit_extern_block(&mut self, node: ast::ExternBlock) -> Label { - let abi = node.abi().map(|x| self.emit_abi(x)); - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let extern_item_list = node - .extern_item_list() - .map(|x| self.emit_extern_item_list(x)); - let label = self.trap.emit(generated::ExternBlock { - id: TrapId::Star, - abi, - attrs, - extern_item_list, - }); - self.emit_location(label, node); - label - } - - fn emit_extern_crate(&mut self, node: ast::ExternCrate) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let name_ref = node.name_ref().map(|x| self.emit_name_ref(x)); - let rename = node.rename().map(|x| self.emit_rename(x)); - let visibility = node.visibility().map(|x| self.emit_visibility(x)); - let label = self.trap.emit(generated::ExternCrate { - id: TrapId::Star, - attrs, - name_ref, - rename, - visibility, - }); - self.emit_location(label, node); - label - } - - fn emit_extern_item_list( - &mut self, - node: ast::ExternItemList, - ) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let extern_items = node - .extern_items() - .map(|x| self.emit_extern_item(x)) - .collect(); - let label = self.trap.emit(generated::ExternItemList { - id: TrapId::Star, - attrs, - extern_items, - }); - self.emit_location(label, node); - label - } - - fn emit_field_expr(&mut self, node: ast::FieldExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let expr = node.expr().map(|x| self.emit_expr(x)); - let name_ref = node.name_ref().map(|x| self.emit_name_ref(x)); - let label = self.trap.emit(generated::FieldExpr { - id: TrapId::Star, - attrs, - expr, - name_ref, - }); - self.emit_location(label, node); - label - } - - fn emit_fn(&mut self, node: ast::Fn) -> Label { - let abi = node.abi().map(|x| self.emit_abi(x)); - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let body = node.body().map(|x| self.emit_block_expr(x)); - let generic_param_list = node - .generic_param_list() - .map(|x| self.emit_generic_param_list(x)); - let name = node.name().map(|x| self.emit_name(x)); - let param_list = node.param_list().map(|x| self.emit_param_list(x)); - let ret_type = node.ret_type().map(|x| self.emit_ret_type(x)); - let visibility = node.visibility().map(|x| self.emit_visibility(x)); - let where_clause = node.where_clause().map(|x| self.emit_where_clause(x)); - let label = self.trap.emit(generated::Function { - id: TrapId::Star, - abi, - attrs, - body, - generic_param_list, - name, - param_list, - ret_type, - visibility, - where_clause, - }); - self.emit_location(label, node); - label - } - - fn emit_fn_ptr_type(&mut self, node: ast::FnPtrType) -> Label { - let abi = node.abi().map(|x| self.emit_abi(x)); - let param_list = node.param_list().map(|x| self.emit_param_list(x)); - let ret_type = node.ret_type().map(|x| self.emit_ret_type(x)); - let label = self.trap.emit(generated::FnPtrType { - id: TrapId::Star, - abi, - param_list, - ret_type, - }); - self.emit_location(label, node); - label - } - - fn emit_for_expr(&mut self, node: ast::ForExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let iterable = node.iterable().map(|x| self.emit_expr(x)); - let label = node.label().map(|x| self.emit_label(x)); - let loop_body = node.loop_body().map(|x| self.emit_block_expr(x)); - let pat = node.pat().map(|x| self.emit_pat(x)); - let label = self.trap.emit(generated::ForExpr { - id: TrapId::Star, - attrs, - iterable, - label, - loop_body, - pat, - }); - self.emit_location(label, node); - label - } - - fn emit_for_type(&mut self, node: ast::ForType) -> Label { - let generic_param_list = node - .generic_param_list() - .map(|x| self.emit_generic_param_list(x)); - let ty = node.ty().map(|x| self.emit_type(x)); - let label = self.trap.emit(generated::ForType { - id: TrapId::Star, - generic_param_list, - ty, - }); - self.emit_location(label, node); - label - } - - fn emit_format_args_arg( - &mut self, - node: ast::FormatArgsArg, - ) -> Label { - let expr = node.expr().map(|x| self.emit_expr(x)); - let name = node.name().map(|x| self.emit_name(x)); - let label = self.trap.emit(generated::FormatArgsArg { - id: TrapId::Star, - expr, - name, - }); - self.emit_location(label, node); - label - } - - fn emit_format_args_expr( - &mut self, - node: ast::FormatArgsExpr, - ) -> Label { - let args = node.args().map(|x| self.emit_format_args_arg(x)).collect(); - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let template = node.template().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::FormatArgsExpr { - id: TrapId::Star, - args, - attrs, - template, - }); - self.emit_location(label, node); - label - } - - fn emit_generic_arg_list( - &mut self, - node: ast::GenericArgList, - ) -> Label { - let generic_args = node - .generic_args() - .map(|x| self.emit_generic_arg(x)) - .collect(); - let label = self.trap.emit(generated::GenericArgList { - id: TrapId::Star, - generic_args, - }); - self.emit_location(label, node); - label - } - - fn emit_generic_param_list( - &mut self, - node: ast::GenericParamList, - ) -> Label { - let generic_params = node - .generic_params() - .map(|x| self.emit_generic_param(x)) - .collect(); - let label = self.trap.emit(generated::GenericParamList { - id: TrapId::Star, - generic_params, - }); - self.emit_location(label, node); - label - } - - fn emit_ident_pat(&mut self, node: ast::IdentPat) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let name = node.name().map(|x| self.emit_name(x)); - let pat = node.pat().map(|x| self.emit_pat(x)); - let label = self.trap.emit(generated::IdentPat { - id: TrapId::Star, - attrs, - name, - pat, - }); - self.emit_location(label, node); - label - } - - fn emit_if_expr(&mut self, node: ast::IfExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let condition = node.condition().map(|x| self.emit_expr(x)); - let else_ = node.else_branch().map(|x| self.emit_else_branch(x)); - let then = node.then_branch().map(|x| self.emit_block_expr(x)); - let label = self.trap.emit(generated::IfExpr { - id: TrapId::Star, - attrs, - condition, - else_, - then, - }); - self.emit_location(label, node); - label - } - - fn emit_impl(&mut self, node: ast::Impl) -> Label { - let assoc_item_list = node.assoc_item_list().map(|x| self.emit_assoc_item_list(x)); - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let generic_param_list = node - .generic_param_list() - .map(|x| self.emit_generic_param_list(x)); - let self_ty = node.self_ty().map(|x| self.emit_type(x)); - let trait_ = node.trait_().map(|x| self.emit_type(x)); - let visibility = node.visibility().map(|x| self.emit_visibility(x)); - let where_clause = node.where_clause().map(|x| self.emit_where_clause(x)); - let label = self.trap.emit(generated::Impl { - id: TrapId::Star, - assoc_item_list, - attrs, - generic_param_list, - self_ty, - trait_, - visibility, - where_clause, - }); - self.emit_location(label, node); - label - } - - fn emit_impl_trait_type( - &mut self, - node: ast::ImplTraitType, - ) -> Label { - let type_bound_list = node.type_bound_list().map(|x| self.emit_type_bound_list(x)); - let label = self.trap.emit(generated::ImplTraitType { - id: TrapId::Star, - type_bound_list, - }); - self.emit_location(label, node); - label - } - - fn emit_index_expr(&mut self, node: ast::IndexExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let base = node.base().map(|x| self.emit_expr(x)); - let index = node.index().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::IndexExpr { - id: TrapId::Star, - attrs, - base, - index, - }); - self.emit_location(label, node); - label - } - - fn emit_infer_type(&mut self, node: ast::InferType) -> Label { - let label = self.trap.emit(generated::InferType { id: TrapId::Star }); - self.emit_location(label, node); - label - } - - fn emit_item_list(&mut self, node: ast::ItemList) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let items = node.items().map(|x| self.emit_item(x)).collect(); - let label = self.trap.emit(generated::ItemList { - id: TrapId::Star, - attrs, - items, - }); - self.emit_location(label, node); - label - } - - fn emit_label(&mut self, node: ast::Label) -> Label { - let lifetime = node.lifetime().map(|x| self.emit_lifetime(x)); - let label = self.trap.emit(generated::Label { - id: TrapId::Star, - lifetime, - }); - self.emit_location(label, node); - label - } - - fn emit_let_else(&mut self, node: ast::LetElse) -> Label { - let block_expr = node.block_expr().map(|x| self.emit_block_expr(x)); - let label = self.trap.emit(generated::LetElse { - id: TrapId::Star, - block_expr, - }); - self.emit_location(label, node); - label - } - - fn emit_let_expr(&mut self, node: ast::LetExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let expr = node.expr().map(|x| self.emit_expr(x)); - let pat = node.pat().map(|x| self.emit_pat(x)); - let label = self.trap.emit(generated::LetExpr { - id: TrapId::Star, - attrs, - expr, - pat, - }); - self.emit_location(label, node); - label - } - - fn emit_let_stmt(&mut self, node: ast::LetStmt) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let initializer = node.initializer().map(|x| self.emit_expr(x)); - let let_else = node.let_else().map(|x| self.emit_let_else(x)); - let pat = node.pat().map(|x| self.emit_pat(x)); - let ty = node.ty().map(|x| self.emit_type(x)); - let label = self.trap.emit(generated::LetStmt { - id: TrapId::Star, - attrs, - initializer, - let_else, - pat, - ty, - }); - self.emit_location(label, node); - label - } - - fn emit_lifetime(&mut self, node: ast::Lifetime) -> Label { - let text = node.try_get_text(); - let label = self.trap.emit(generated::Lifetime { - id: TrapId::Star, - text, - }); - self.emit_location(label, node); - label - } - - fn emit_lifetime_arg(&mut self, node: ast::LifetimeArg) -> Label { - let lifetime = node.lifetime().map(|x| self.emit_lifetime(x)); - let label = self.trap.emit(generated::LifetimeArg { - id: TrapId::Star, - lifetime, - }); - self.emit_location(label, node); - label - } - - fn emit_lifetime_param(&mut self, node: ast::LifetimeParam) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let lifetime = node.lifetime().map(|x| self.emit_lifetime(x)); - let type_bound_list = node.type_bound_list().map(|x| self.emit_type_bound_list(x)); - let label = self.trap.emit(generated::LifetimeParam { - id: TrapId::Star, - attrs, - lifetime, - type_bound_list, - }); - self.emit_location(label, node); - label - } - - fn emit_literal(&mut self, node: ast::Literal) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let text_value = node.try_get_text(); - let label = self.trap.emit(generated::LiteralExpr { - id: TrapId::Star, - attrs, - text_value, - }); - self.emit_location(label, node); - label - } - - fn emit_literal_pat(&mut self, node: ast::LiteralPat) -> Label { - let literal = node.literal().map(|x| self.emit_literal(x)); - let label = self.trap.emit(generated::LiteralPat { - id: TrapId::Star, - literal, - }); - self.emit_location(label, node); - label - } - - fn emit_loop_expr(&mut self, node: ast::LoopExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let label = node.label().map(|x| self.emit_label(x)); - let loop_body = node.loop_body().map(|x| self.emit_block_expr(x)); - let label = self.trap.emit(generated::LoopExpr { - id: TrapId::Star, - attrs, - label, - loop_body, - }); - self.emit_location(label, node); - label - } - - fn emit_macro_call(&mut self, node: ast::MacroCall) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let path = node.path().map(|x| self.emit_path(x)); - let token_tree = node.token_tree().map(|x| self.emit_token_tree(x)); - let label = self.trap.emit(generated::MacroCall { - id: TrapId::Star, - attrs, - path, - token_tree, - }); - self.emit_location(label, node); - label - } - - fn emit_macro_def(&mut self, node: ast::MacroDef) -> Label { - let args = node.args().map(|x| self.emit_token_tree(x)); - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let body = node.body().map(|x| self.emit_token_tree(x)); - let name = node.name().map(|x| self.emit_name(x)); - let visibility = node.visibility().map(|x| self.emit_visibility(x)); - let label = self.trap.emit(generated::MacroDef { - id: TrapId::Star, - args, - attrs, - body, - name, - visibility, - }); - self.emit_location(label, node); - label - } - - fn emit_macro_expr(&mut self, node: ast::MacroExpr) -> Label { - let macro_call = node.macro_call().map(|x| self.emit_macro_call(x)); - let label = self.trap.emit(generated::MacroExpr { - id: TrapId::Star, - macro_call, - }); - self.emit_location(label, node); - label - } - - fn emit_macro_pat(&mut self, node: ast::MacroPat) -> Label { - let macro_call = node.macro_call().map(|x| self.emit_macro_call(x)); - let label = self.trap.emit(generated::MacroPat { - id: TrapId::Star, - macro_call, - }); - self.emit_location(label, node); - label - } - - fn emit_macro_rules(&mut self, node: ast::MacroRules) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let name = node.name().map(|x| self.emit_name(x)); - let token_tree = node.token_tree().map(|x| self.emit_token_tree(x)); - let visibility = node.visibility().map(|x| self.emit_visibility(x)); - let label = self.trap.emit(generated::MacroRules { - id: TrapId::Star, - attrs, - name, - token_tree, - visibility, - }); - self.emit_location(label, node); - label - } - - fn emit_macro_type(&mut self, node: ast::MacroType) -> Label { - let macro_call = node.macro_call().map(|x| self.emit_macro_call(x)); - let label = self.trap.emit(generated::MacroType { - id: TrapId::Star, - macro_call, - }); - self.emit_location(label, node); - label - } - - fn emit_match_arm(&mut self, node: ast::MatchArm) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let expr = node.expr().map(|x| self.emit_expr(x)); - let guard = node.guard().map(|x| self.emit_match_guard(x)); - let pat = node.pat().map(|x| self.emit_pat(x)); - let label = self.trap.emit(generated::MatchArm { - id: TrapId::Star, - attrs, - expr, - guard, - pat, - }); - self.emit_location(label, node); - label - } - - fn emit_match_arm_list(&mut self, node: ast::MatchArmList) -> Label { - let arms = node.arms().map(|x| self.emit_match_arm(x)).collect(); - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let label = self.trap.emit(generated::MatchArmList { - id: TrapId::Star, - arms, - attrs, - }); - self.emit_location(label, node); - label - } - - fn emit_match_expr(&mut self, node: ast::MatchExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let expr = node.expr().map(|x| self.emit_expr(x)); - let match_arm_list = node.match_arm_list().map(|x| self.emit_match_arm_list(x)); - let label = self.trap.emit(generated::MatchExpr { - id: TrapId::Star, - attrs, - expr, - match_arm_list, - }); - self.emit_location(label, node); - label - } - - fn emit_match_guard(&mut self, node: ast::MatchGuard) -> Label { - let condition = node.condition().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::MatchGuard { - id: TrapId::Star, - condition, - }); - self.emit_location(label, node); - label - } - - fn emit_meta(&mut self, node: ast::Meta) -> Label { - let expr = node.expr().map(|x| self.emit_expr(x)); - let path = node.path().map(|x| self.emit_path(x)); - let token_tree = node.token_tree().map(|x| self.emit_token_tree(x)); - let label = self.trap.emit(generated::Meta { - id: TrapId::Star, - expr, - path, - token_tree, - }); - self.emit_location(label, node); - label - } - - fn emit_method_call_expr( - &mut self, - node: ast::MethodCallExpr, - ) -> Label { - let arg_list = node.arg_list().map(|x| self.emit_arg_list(x)); - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let generic_arg_list = node - .generic_arg_list() - .map(|x| self.emit_generic_arg_list(x)); - let name_ref = node.name_ref().map(|x| self.emit_name_ref(x)); - let receiver = node.receiver().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::MethodCallExpr { - id: TrapId::Star, - arg_list, - attrs, - generic_arg_list, - name_ref, - receiver, - }); - self.emit_location(label, node); - label - } - - fn emit_module(&mut self, node: ast::Module) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let item_list = node.item_list().map(|x| self.emit_item_list(x)); - let name = node.name().map(|x| self.emit_name(x)); - let visibility = node.visibility().map(|x| self.emit_visibility(x)); - let label = self.trap.emit(generated::Module { - id: TrapId::Star, - attrs, - item_list, - name, - visibility, - }); - self.emit_location(label, node); - label - } - - fn emit_name(&mut self, node: ast::Name) -> Label { - let text = node.try_get_text(); - let label = self.trap.emit(generated::Name { - id: TrapId::Star, - text, - }); - self.emit_location(label, node); - label - } - - fn emit_name_ref(&mut self, node: ast::NameRef) -> Label { - let text = node.try_get_text(); - let label = self.trap.emit(generated::NameRef { - id: TrapId::Star, - text, - }); - self.emit_location(label, node); - label - } - - fn emit_never_type(&mut self, node: ast::NeverType) -> Label { - let label = self.trap.emit(generated::NeverType { id: TrapId::Star }); - self.emit_location(label, node); - label - } - - fn emit_offset_of_expr(&mut self, node: ast::OffsetOfExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let fields = node.fields().map(|x| self.emit_name_ref(x)).collect(); - let ty = node.ty().map(|x| self.emit_type(x)); - let label = self.trap.emit(generated::OffsetOfExpr { - id: TrapId::Star, - attrs, - fields, - ty, - }); - self.emit_location(label, node); - label - } - - fn emit_or_pat(&mut self, node: ast::OrPat) -> Label { - let pats = node.pats().map(|x| self.emit_pat(x)).collect(); - let label = self.trap.emit(generated::OrPat { - id: TrapId::Star, - pats, - }); - self.emit_location(label, node); - label - } - - fn emit_param(&mut self, node: ast::Param) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let pat = node.pat().map(|x| self.emit_pat(x)); - let ty = node.ty().map(|x| self.emit_type(x)); - let label = self.trap.emit(generated::Param { - id: TrapId::Star, - attrs, - pat, - ty, - }); - self.emit_location(label, node); - label - } - - fn emit_param_list(&mut self, node: ast::ParamList) -> Label { - let params = node.params().map(|x| self.emit_param(x)).collect(); - let self_param = node.self_param().map(|x| self.emit_self_param(x)); - let label = self.trap.emit(generated::ParamList { - id: TrapId::Star, - params, - self_param, - }); - self.emit_location(label, node); - label - } - - fn emit_paren_expr(&mut self, node: ast::ParenExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let expr = node.expr().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::ParenExpr { - id: TrapId::Star, - attrs, - expr, - }); - self.emit_location(label, node); - label - } - - fn emit_paren_pat(&mut self, node: ast::ParenPat) -> Label { - let pat = node.pat().map(|x| self.emit_pat(x)); - let label = self.trap.emit(generated::ParenPat { - id: TrapId::Star, - pat, - }); - self.emit_location(label, node); - label - } - - fn emit_paren_type(&mut self, node: ast::ParenType) -> Label { - let ty = node.ty().map(|x| self.emit_type(x)); - let label = self.trap.emit(generated::ParenType { - id: TrapId::Star, - ty, - }); - self.emit_location(label, node); - label - } - - fn emit_path(&mut self, node: ast::Path) -> Label { - let qualifier = node.qualifier().map(|x| self.emit_path(x)); - let part = node.segment().map(|x| self.emit_path_segment(x)); - let label = self.trap.emit(generated::Path { - id: TrapId::Star, - qualifier, - part, - }); - self.emit_location(label, node); - label - } - - fn emit_path_expr(&mut self, node: ast::PathExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let path = node.path().map(|x| self.emit_path(x)); - let label = self.trap.emit(generated::PathExpr { - id: TrapId::Star, - attrs, - path, - }); - self.emit_location(label, node); - label - } - - fn emit_path_pat(&mut self, node: ast::PathPat) -> Label { - let path = node.path().map(|x| self.emit_path(x)); - let label = self.trap.emit(generated::PathPat { - id: TrapId::Star, - path, - }); - self.emit_location(label, node); - label - } - - fn emit_path_segment(&mut self, node: ast::PathSegment) -> Label { - let generic_arg_list = node - .generic_arg_list() - .map(|x| self.emit_generic_arg_list(x)); - let name_ref = node.name_ref().map(|x| self.emit_name_ref(x)); - let param_list = node.param_list().map(|x| self.emit_param_list(x)); - let path_type = node.path_type().map(|x| self.emit_path_type(x)); - let ret_type = node.ret_type().map(|x| self.emit_ret_type(x)); - let return_type_syntax = node - .return_type_syntax() - .map(|x| self.emit_return_type_syntax(x)); - let ty = node.ty().map(|x| self.emit_type(x)); - let label = self.trap.emit(generated::PathSegment { - id: TrapId::Star, - generic_arg_list, - name_ref, - param_list, - path_type, - ret_type, - return_type_syntax, - ty, - }); - self.emit_location(label, node); - label - } - - fn emit_path_type(&mut self, node: ast::PathType) -> Label { - let path = node.path().map(|x| self.emit_path(x)); - let label = self.trap.emit(generated::PathType { - id: TrapId::Star, - path, - }); - self.emit_location(label, node); - label - } - - fn emit_prefix_expr(&mut self, node: ast::PrefixExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let expr = node.expr().map(|x| self.emit_expr(x)); - let operator_name = node.try_get_text(); - let label = self.trap.emit(generated::PrefixExpr { - id: TrapId::Star, - attrs, - expr, - operator_name, - }); - self.emit_location(label, node); - label - } - - fn emit_ptr_type(&mut self, node: ast::PtrType) -> Label { - let ty = node.ty().map(|x| self.emit_type(x)); - let label = self.trap.emit(generated::PtrType { - id: TrapId::Star, - ty, - }); - self.emit_location(label, node); - label - } - - fn emit_range_expr(&mut self, node: ast::RangeExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let end = node.end().map(|x| self.emit_expr(x)); - let operator_name = node.try_get_text(); - let start = node.start().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::RangeExpr { - id: TrapId::Star, - attrs, - end, - operator_name, - start, - }); - self.emit_location(label, node); - label - } - - fn emit_range_pat(&mut self, node: ast::RangePat) -> Label { - let end = node.end().map(|x| self.emit_pat(x)); - let operator_name = node.try_get_text(); - let start = node.start().map(|x| self.emit_pat(x)); - let label = self.trap.emit(generated::RangePat { - id: TrapId::Star, - end, - operator_name, - start, - }); - self.emit_location(label, node); - label - } - - fn emit_record_expr(&mut self, node: ast::RecordExpr) -> Label { - let path = node.path().map(|x| self.emit_path(x)); - let record_expr_field_list = node - .record_expr_field_list() - .map(|x| self.emit_record_expr_field_list(x)); - let label = self.trap.emit(generated::RecordExpr { - id: TrapId::Star, - path, - record_expr_field_list, - }); - self.emit_location(label, node); - label - } - - fn emit_record_expr_field( - &mut self, - node: ast::RecordExprField, - ) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let expr = node.expr().map(|x| self.emit_expr(x)); - let name_ref = node.name_ref().map(|x| self.emit_name_ref(x)); - let label = self.trap.emit(generated::RecordExprField { - id: TrapId::Star, - attrs, - expr, - name_ref, - }); - self.emit_location(label, node); - label - } - - fn emit_record_expr_field_list( - &mut self, - node: ast::RecordExprFieldList, - ) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let fields = node - .fields() - .map(|x| self.emit_record_expr_field(x)) - .collect(); - let spread = node.spread().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::RecordExprFieldList { - id: TrapId::Star, - attrs, - fields, - spread, - }); - self.emit_location(label, node); - label - } - - fn emit_record_field(&mut self, node: ast::RecordField) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let name = node.name().map(|x| self.emit_name(x)); - let ty = node.ty().map(|x| self.emit_type(x)); - let visibility = node.visibility().map(|x| self.emit_visibility(x)); - let label = self.trap.emit(generated::RecordField { - id: TrapId::Star, - attrs, - name, - ty, - visibility, - }); - self.emit_location(label, node); - label - } - - fn emit_record_field_list( - &mut self, - node: ast::RecordFieldList, - ) -> Label { - let fields = node.fields().map(|x| self.emit_record_field(x)).collect(); - let label = self.trap.emit(generated::RecordFieldList { - id: TrapId::Star, - fields, - }); - self.emit_location(label, node); - label - } - - fn emit_record_pat(&mut self, node: ast::RecordPat) -> Label { - let path = node.path().map(|x| self.emit_path(x)); - let record_pat_field_list = node - .record_pat_field_list() - .map(|x| self.emit_record_pat_field_list(x)); - let label = self.trap.emit(generated::RecordPat { - id: TrapId::Star, - path, - record_pat_field_list, - }); - self.emit_location(label, node); - label - } - - fn emit_record_pat_field( - &mut self, - node: ast::RecordPatField, - ) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let name_ref = node.name_ref().map(|x| self.emit_name_ref(x)); - let pat = node.pat().map(|x| self.emit_pat(x)); - let label = self.trap.emit(generated::RecordPatField { - id: TrapId::Star, - attrs, - name_ref, - pat, - }); - self.emit_location(label, node); - label - } - - fn emit_record_pat_field_list( - &mut self, - node: ast::RecordPatFieldList, - ) -> Label { - let fields = node - .fields() - .map(|x| self.emit_record_pat_field(x)) - .collect(); - let rest_pat = node.rest_pat().map(|x| self.emit_rest_pat(x)); - let label = self.trap.emit(generated::RecordPatFieldList { - id: TrapId::Star, - fields, - rest_pat, - }); - self.emit_location(label, node); - label - } - - fn emit_ref_expr(&mut self, node: ast::RefExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let expr = node.expr().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::RefExpr { - id: TrapId::Star, - attrs, - expr, - }); - self.emit_location(label, node); - label - } - - fn emit_ref_pat(&mut self, node: ast::RefPat) -> Label { - let pat = node.pat().map(|x| self.emit_pat(x)); - let label = self.trap.emit(generated::RefPat { - id: TrapId::Star, - pat, - }); - self.emit_location(label, node); - label - } - - fn emit_ref_type(&mut self, node: ast::RefType) -> Label { - let lifetime = node.lifetime().map(|x| self.emit_lifetime(x)); - let ty = node.ty().map(|x| self.emit_type(x)); - let label = self.trap.emit(generated::RefType { - id: TrapId::Star, - lifetime, - ty, - }); - self.emit_location(label, node); - label - } - - fn emit_rename(&mut self, node: ast::Rename) -> Label { - let name = node.name().map(|x| self.emit_name(x)); - let label = self.trap.emit(generated::Rename { - id: TrapId::Star, - name, - }); - self.emit_location(label, node); - label - } - - fn emit_rest_pat(&mut self, node: ast::RestPat) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let label = self.trap.emit(generated::RestPat { - id: TrapId::Star, - attrs, - }); - self.emit_location(label, node); - label - } - - fn emit_ret_type(&mut self, node: ast::RetType) -> Label { - let ty = node.ty().map(|x| self.emit_type(x)); - let label = self.trap.emit(generated::RetType { - id: TrapId::Star, - ty, - }); - self.emit_location(label, node); - label - } - - fn emit_return_expr(&mut self, node: ast::ReturnExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let expr = node.expr().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::ReturnExpr { - id: TrapId::Star, - attrs, - expr, - }); - self.emit_location(label, node); - label - } - - fn emit_return_type_syntax( - &mut self, - node: ast::ReturnTypeSyntax, - ) -> Label { - let label = self - .trap - .emit(generated::ReturnTypeSyntax { id: TrapId::Star }); - self.emit_location(label, node); - label - } - - fn emit_self_param(&mut self, node: ast::SelfParam) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let lifetime = node.lifetime().map(|x| self.emit_lifetime(x)); - let name = node.name().map(|x| self.emit_name(x)); - let ty = node.ty().map(|x| self.emit_type(x)); - let label = self.trap.emit(generated::SelfParam { - id: TrapId::Star, - attrs, - lifetime, - name, - ty, - }); - self.emit_location(label, node); - label - } - - fn emit_slice_pat(&mut self, node: ast::SlicePat) -> Label { - let pats = node.pats().map(|x| self.emit_pat(x)).collect(); - let label = self.trap.emit(generated::SlicePat { - id: TrapId::Star, - pats, - }); - self.emit_location(label, node); - label - } - - fn emit_slice_type(&mut self, node: ast::SliceType) -> Label { - let ty = node.ty().map(|x| self.emit_type(x)); - let label = self.trap.emit(generated::SliceType { - id: TrapId::Star, - ty, - }); - self.emit_location(label, node); - label - } - - fn emit_source_file(&mut self, node: ast::SourceFile) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let items = node.items().map(|x| self.emit_item(x)).collect(); - let label = self.trap.emit(generated::SourceFile { - id: TrapId::Star, - attrs, - items, - }); - self.emit_location(label, node); - label - } - - fn emit_static(&mut self, node: ast::Static) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let body = node.body().map(|x| self.emit_expr(x)); - let name = node.name().map(|x| self.emit_name(x)); - let ty = node.ty().map(|x| self.emit_type(x)); - let visibility = node.visibility().map(|x| self.emit_visibility(x)); - let label = self.trap.emit(generated::Static { - id: TrapId::Star, - attrs, - body, - name, - ty, - visibility, - }); - self.emit_location(label, node); - label - } - - fn emit_stmt_list(&mut self, node: ast::StmtList) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let statements = node.statements().map(|x| self.emit_stmt(x)).collect(); - let tail_expr = node.tail_expr().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::StmtList { - id: TrapId::Star, - attrs, - statements, - tail_expr, - }); - self.emit_location(label, node); - label - } - - fn emit_struct(&mut self, node: ast::Struct) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let field_list = node.field_list().map(|x| self.emit_field_list(x)); - let generic_param_list = node - .generic_param_list() - .map(|x| self.emit_generic_param_list(x)); - let name = node.name().map(|x| self.emit_name(x)); - let visibility = node.visibility().map(|x| self.emit_visibility(x)); - let where_clause = node.where_clause().map(|x| self.emit_where_clause(x)); - let label = self.trap.emit(generated::Struct { - id: TrapId::Star, - attrs, - field_list, - generic_param_list, - name, - visibility, - where_clause, - }); - self.emit_location(label, node); - label - } - - fn emit_token_tree(&mut self, node: ast::TokenTree) -> Label { - let label = self.trap.emit(generated::TokenTree { id: TrapId::Star }); - self.emit_location(label, node); - label - } - - fn emit_trait(&mut self, node: ast::Trait) -> Label { - let assoc_item_list = node.assoc_item_list().map(|x| self.emit_assoc_item_list(x)); - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let generic_param_list = node - .generic_param_list() - .map(|x| self.emit_generic_param_list(x)); - let name = node.name().map(|x| self.emit_name(x)); - let type_bound_list = node.type_bound_list().map(|x| self.emit_type_bound_list(x)); - let visibility = node.visibility().map(|x| self.emit_visibility(x)); - let where_clause = node.where_clause().map(|x| self.emit_where_clause(x)); - let label = self.trap.emit(generated::Trait { - id: TrapId::Star, - assoc_item_list, - attrs, - generic_param_list, - name, - type_bound_list, - visibility, - where_clause, - }); - self.emit_location(label, node); - label - } - - fn emit_trait_alias(&mut self, node: ast::TraitAlias) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let generic_param_list = node - .generic_param_list() - .map(|x| self.emit_generic_param_list(x)); - let name = node.name().map(|x| self.emit_name(x)); - let type_bound_list = node.type_bound_list().map(|x| self.emit_type_bound_list(x)); - let visibility = node.visibility().map(|x| self.emit_visibility(x)); - let where_clause = node.where_clause().map(|x| self.emit_where_clause(x)); - let label = self.trap.emit(generated::TraitAlias { - id: TrapId::Star, - attrs, - generic_param_list, - name, - type_bound_list, - visibility, - where_clause, - }); - self.emit_location(label, node); - label - } - - fn emit_try_expr(&mut self, node: ast::TryExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let expr = node.expr().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::TryExpr { - id: TrapId::Star, - attrs, - expr, - }); - self.emit_location(label, node); - label - } - - fn emit_tuple_expr(&mut self, node: ast::TupleExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let fields = node.fields().map(|x| self.emit_expr(x)).collect(); - let label = self.trap.emit(generated::TupleExpr { - id: TrapId::Star, - attrs, - fields, - }); - self.emit_location(label, node); - label - } - - fn emit_tuple_field(&mut self, node: ast::TupleField) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let ty = node.ty().map(|x| self.emit_type(x)); - let visibility = node.visibility().map(|x| self.emit_visibility(x)); - let label = self.trap.emit(generated::TupleField { - id: TrapId::Star, - attrs, - ty, - visibility, - }); - self.emit_location(label, node); - label - } - - fn emit_tuple_field_list( - &mut self, - node: ast::TupleFieldList, - ) -> Label { - let fields = node.fields().map(|x| self.emit_tuple_field(x)).collect(); - let label = self.trap.emit(generated::TupleFieldList { - id: TrapId::Star, - fields, - }); - self.emit_location(label, node); - label - } - - fn emit_tuple_pat(&mut self, node: ast::TuplePat) -> Label { - let fields = node.fields().map(|x| self.emit_pat(x)).collect(); - let label = self.trap.emit(generated::TuplePat { - id: TrapId::Star, - fields, - }); - self.emit_location(label, node); - label - } - - fn emit_tuple_struct_pat( - &mut self, - node: ast::TupleStructPat, - ) -> Label { - let fields = node.fields().map(|x| self.emit_pat(x)).collect(); - let path = node.path().map(|x| self.emit_path(x)); - let label = self.trap.emit(generated::TupleStructPat { - id: TrapId::Star, - fields, - path, - }); - self.emit_location(label, node); - label - } - - fn emit_tuple_type(&mut self, node: ast::TupleType) -> Label { - let fields = node.fields().map(|x| self.emit_type(x)).collect(); - let label = self.trap.emit(generated::TupleType { - id: TrapId::Star, - fields, - }); - self.emit_location(label, node); - label - } - - fn emit_type_alias(&mut self, node: ast::TypeAlias) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let generic_param_list = node - .generic_param_list() - .map(|x| self.emit_generic_param_list(x)); - let name = node.name().map(|x| self.emit_name(x)); - let ty = node.ty().map(|x| self.emit_type(x)); - let type_bound_list = node.type_bound_list().map(|x| self.emit_type_bound_list(x)); - let visibility = node.visibility().map(|x| self.emit_visibility(x)); - let where_clause = node.where_clause().map(|x| self.emit_where_clause(x)); - let label = self.trap.emit(generated::TypeAlias { - id: TrapId::Star, - attrs, - generic_param_list, - name, - ty, - type_bound_list, - visibility, - where_clause, - }); - self.emit_location(label, node); - label - } - - fn emit_type_arg(&mut self, node: ast::TypeArg) -> Label { - let ty = node.ty().map(|x| self.emit_type(x)); - let label = self.trap.emit(generated::TypeArg { - id: TrapId::Star, - ty, - }); - self.emit_location(label, node); - label - } - - fn emit_type_bound(&mut self, node: ast::TypeBound) -> Label { - let generic_param_list = node - .generic_param_list() - .map(|x| self.emit_generic_param_list(x)); - let lifetime = node.lifetime().map(|x| self.emit_lifetime(x)); - let ty = node.ty().map(|x| self.emit_type(x)); - let label = self.trap.emit(generated::TypeBound { - id: TrapId::Star, - generic_param_list, - lifetime, - ty, - }); - self.emit_location(label, node); - label - } - - fn emit_type_bound_list( - &mut self, - node: ast::TypeBoundList, - ) -> Label { - let bounds = node.bounds().map(|x| self.emit_type_bound(x)).collect(); - let label = self.trap.emit(generated::TypeBoundList { - id: TrapId::Star, - bounds, - }); - self.emit_location(label, node); - label - } - - fn emit_type_param(&mut self, node: ast::TypeParam) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let default_type = node.default_type().map(|x| self.emit_type(x)); - let name = node.name().map(|x| self.emit_name(x)); - let type_bound_list = node.type_bound_list().map(|x| self.emit_type_bound_list(x)); - let label = self.trap.emit(generated::TypeParam { - id: TrapId::Star, - attrs, - default_type, - name, - type_bound_list, - }); - self.emit_location(label, node); - label - } - - fn emit_underscore_expr( - &mut self, - node: ast::UnderscoreExpr, - ) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let label = self.trap.emit(generated::UnderscoreExpr { - id: TrapId::Star, - attrs, - }); - self.emit_location(label, node); - label - } - - fn emit_union(&mut self, node: ast::Union) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let generic_param_list = node - .generic_param_list() - .map(|x| self.emit_generic_param_list(x)); - let name = node.name().map(|x| self.emit_name(x)); - let record_field_list = node - .record_field_list() - .map(|x| self.emit_record_field_list(x)); - let visibility = node.visibility().map(|x| self.emit_visibility(x)); - let where_clause = node.where_clause().map(|x| self.emit_where_clause(x)); - let label = self.trap.emit(generated::Union { - id: TrapId::Star, - attrs, - generic_param_list, - name, - record_field_list, - visibility, - where_clause, - }); - self.emit_location(label, node); - label - } - - fn emit_use(&mut self, node: ast::Use) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let use_tree = node.use_tree().map(|x| self.emit_use_tree(x)); - let visibility = node.visibility().map(|x| self.emit_visibility(x)); - let label = self.trap.emit(generated::Use { - id: TrapId::Star, - attrs, - use_tree, - visibility, - }); - self.emit_location(label, node); - label - } - - fn emit_use_tree(&mut self, node: ast::UseTree) -> Label { - let path = node.path().map(|x| self.emit_path(x)); - let rename = node.rename().map(|x| self.emit_rename(x)); - let use_tree_list = node.use_tree_list().map(|x| self.emit_use_tree_list(x)); - let label = self.trap.emit(generated::UseTree { - id: TrapId::Star, - path, - rename, - use_tree_list, - }); - self.emit_location(label, node); - label - } - - fn emit_use_tree_list(&mut self, node: ast::UseTreeList) -> Label { - let use_trees = node.use_trees().map(|x| self.emit_use_tree(x)).collect(); - let label = self.trap.emit(generated::UseTreeList { - id: TrapId::Star, - use_trees, - }); - self.emit_location(label, node); - label - } - - fn emit_variant(&mut self, node: ast::Variant) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let expr = node.expr().map(|x| self.emit_expr(x)); - let field_list = node.field_list().map(|x| self.emit_field_list(x)); - let name = node.name().map(|x| self.emit_name(x)); - let visibility = node.visibility().map(|x| self.emit_visibility(x)); - let label = self.trap.emit(generated::Variant { - id: TrapId::Star, - attrs, - expr, - field_list, - name, - visibility, - }); - self.emit_location(label, node); - label - } - - fn emit_variant_list(&mut self, node: ast::VariantList) -> Label { - let variants = node.variants().map(|x| self.emit_variant(x)).collect(); - let label = self.trap.emit(generated::VariantList { - id: TrapId::Star, - variants, - }); - self.emit_location(label, node); - label - } - - fn emit_visibility(&mut self, node: ast::Visibility) -> Label { - let path = node.path().map(|x| self.emit_path(x)); - let label = self.trap.emit(generated::Visibility { - id: TrapId::Star, - path, - }); - self.emit_location(label, node); - label - } - - fn emit_where_clause(&mut self, node: ast::WhereClause) -> Label { - let predicates = node.predicates().map(|x| self.emit_where_pred(x)).collect(); - let label = self.trap.emit(generated::WhereClause { - id: TrapId::Star, - predicates, - }); - self.emit_location(label, node); - label - } - - fn emit_where_pred(&mut self, node: ast::WherePred) -> Label { - let generic_param_list = node - .generic_param_list() - .map(|x| self.emit_generic_param_list(x)); - let lifetime = node.lifetime().map(|x| self.emit_lifetime(x)); - let ty = node.ty().map(|x| self.emit_type(x)); - let type_bound_list = node.type_bound_list().map(|x| self.emit_type_bound_list(x)); - let label = self.trap.emit(generated::WherePred { - id: TrapId::Star, - generic_param_list, - lifetime, - ty, - type_bound_list, - }); - self.emit_location(label, node); - label - } - - fn emit_while_expr(&mut self, node: ast::WhileExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let condition = node.condition().map(|x| self.emit_expr(x)); - let label = node.label().map(|x| self.emit_label(x)); - let loop_body = node.loop_body().map(|x| self.emit_block_expr(x)); - let label = self.trap.emit(generated::WhileExpr { - id: TrapId::Star, - attrs, - condition, - label, - loop_body, - }); - self.emit_location(label, node); - label - } - - fn emit_wildcard_pat(&mut self, node: ast::WildcardPat) -> Label { - let label = self.trap.emit(generated::WildcardPat { id: TrapId::Star }); - self.emit_location(label, node); - label - } - - fn emit_yeet_expr(&mut self, node: ast::YeetExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let expr = node.expr().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::YeetExpr { - id: TrapId::Star, - attrs, - expr, - }); - self.emit_location(label, node); - label - } - - fn emit_yield_expr(&mut self, node: ast::YieldExpr) -> Label { - let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); - let expr = node.expr().map(|x| self.emit_expr(x)); - let label = self.trap.emit(generated::YieldExpr { - id: TrapId::Star, - attrs, - expr, - }); - self.emit_location(label, node); - label - } -} +pub use base::Translator; diff --git a/rust/extractor/src/translate/.gitattributes b/rust/extractor/src/translate/.gitattributes new file mode 100644 index 000000000000..d408bf18300f --- /dev/null +++ b/rust/extractor/src/translate/.gitattributes @@ -0,0 +1 @@ +/generated.rs linguist-generated diff --git a/rust/extractor/src/translate/base.rs b/rust/extractor/src/translate/base.rs new file mode 100644 index 000000000000..063a59d8937e --- /dev/null +++ b/rust/extractor/src/translate/base.rs @@ -0,0 +1,107 @@ +use crate::trap::{DiagnosticSeverity, TrapFile}; +use crate::trap::{Label, TrapClass}; +use codeql_extractor::trap::{self}; +use ra_ap_ide_db::line_index::{LineCol, LineIndex}; +use ra_ap_syntax::ast::RangeItem; +use ra_ap_syntax::{ast, SyntaxError, TextRange}; +pub trait TextValue { + fn try_get_text(&self) -> Option; +} + +impl TextValue for ast::Lifetime { + fn try_get_text(&self) -> Option { + self.text().to_string().into() + } +} +impl TextValue for ast::Name { + fn try_get_text(&self) -> Option { + self.text().to_string().into() + } +} +impl TextValue for ast::Literal { + fn try_get_text(&self) -> Option { + self.token().text().to_string().into() + } +} +impl TextValue for ast::NameRef { + fn try_get_text(&self) -> Option { + self.text().to_string().into() + } +} +impl TextValue for ast::Abi { + fn try_get_text(&self) -> Option { + self.abi_string().map(|x| x.to_string()) + } +} + +impl TextValue for ast::BinExpr { + fn try_get_text(&self) -> Option { + self.op_token().map(|x| x.text().to_string()) + } +} +impl TextValue for ast::PrefixExpr { + fn try_get_text(&self) -> Option { + self.op_token().map(|x| x.text().to_string()) + } +} +impl TextValue for ast::RangeExpr { + fn try_get_text(&self) -> Option { + self.op_token().map(|x| x.text().to_string()) + } +} +impl TextValue for ast::RangePat { + fn try_get_text(&self) -> Option { + self.op_token().map(|x| x.text().to_string()) + } +} +pub struct Translator { + pub trap: TrapFile, + label: trap::Label, + line_index: LineIndex, +} + +impl Translator { + pub fn new(trap: TrapFile, label: trap::Label, line_index: LineIndex) -> Translator { + Translator { + trap, + label, + line_index, + } + } + pub fn location(&self, range: TextRange) -> (LineCol, LineCol) { + let start = self.line_index.line_col(range.start()); + let range_end = range.end(); + // QL end positions are inclusive, while TextRange offsets are exclusive and point at the position + // right after the last character of the range. We need to shift the end offset one character to the left to + // get the right inclusive QL position. Unfortunately, simply subtracting `1` from the end-offset may cause + // the offset to point in the middle of a mult-byte character, resulting in a `panic`. Therefore we use `try_line_col` + // with decreasing offsets to find the start of the last character included in the range. + for i in 1..4 { + if let Some(end) = range_end + .checked_sub(i.into()) + .and_then(|x| self.line_index.try_line_col(x)) + { + return (start, end); + } + } + let end = self.line_index.line_col(range_end); + (start, end) + } + pub fn emit_location(&mut self, label: Label, node: impl ast::AstNode) { + let (start, end) = self.location(node.syntax().text_range()); + self.trap.emit_location(self.label, label, start, end) + } + pub fn emit_parse_error(&mut self, path: &str, err: SyntaxError) { + let (start, end) = self.location(err.range()); + log::warn!("{}:{}:{}: {}", path, start.line + 1, start.col + 1, err); + let message = err.to_string(); + let location = self.trap.emit_location_label(self.label, start, end); + self.trap.emit_diagnostic( + DiagnosticSeverity::Warning, + "parse_error".to_owned(), + message.clone(), + message, + location, + ); + } +} diff --git a/rust/extractor/src/translate/generated.rs b/rust/extractor/src/translate/generated.rs new file mode 100644 index 000000000000..561bfbb1f0d4 --- /dev/null +++ b/rust/extractor/src/translate/generated.rs @@ -0,0 +1,2187 @@ +//! Generated by `cargo generate-schema`, do not edit by hand. + +use super::base::{TextValue, Translator}; +use crate::generated; +use crate::trap::{Label, TrapId}; +use ra_ap_syntax::ast; +use ra_ap_syntax::ast::{ + HasArgList, HasAttrs, HasGenericArgs, HasGenericParams, HasLoopBody, HasModuleItem, HasName, + HasTypeBounds, HasVisibility, RangeItem, +}; + +impl Translator { + fn emit_else_branch(&mut self, node: ast::ElseBranch) -> Label { + match node { + ast::ElseBranch::IfExpr(inner) => self.emit_if_expr(inner).into(), + ast::ElseBranch::Block(inner) => self.emit_block_expr(inner).into(), + } + } + + pub(crate) fn emit_assoc_item(&mut self, node: ast::AssocItem) -> Label { + match node { + ast::AssocItem::Const(inner) => self.emit_const(inner).into(), + ast::AssocItem::Fn(inner) => self.emit_fn(inner).into(), + ast::AssocItem::MacroCall(inner) => self.emit_macro_call(inner).into(), + ast::AssocItem::TypeAlias(inner) => self.emit_type_alias(inner).into(), + } + } + + pub(crate) fn emit_expr(&mut self, node: ast::Expr) -> Label { + match node { + ast::Expr::ArrayExpr(inner) => self.emit_array_expr(inner).into(), + ast::Expr::AsmExpr(inner) => self.emit_asm_expr(inner).into(), + ast::Expr::AwaitExpr(inner) => self.emit_await_expr(inner).into(), + ast::Expr::BecomeExpr(inner) => self.emit_become_expr(inner).into(), + ast::Expr::BinExpr(inner) => self.emit_bin_expr(inner).into(), + ast::Expr::BlockExpr(inner) => self.emit_block_expr(inner).into(), + ast::Expr::BreakExpr(inner) => self.emit_break_expr(inner).into(), + ast::Expr::CallExpr(inner) => self.emit_call_expr(inner).into(), + ast::Expr::CastExpr(inner) => self.emit_cast_expr(inner).into(), + ast::Expr::ClosureExpr(inner) => self.emit_closure_expr(inner).into(), + ast::Expr::ContinueExpr(inner) => self.emit_continue_expr(inner).into(), + ast::Expr::FieldExpr(inner) => self.emit_field_expr(inner).into(), + ast::Expr::ForExpr(inner) => self.emit_for_expr(inner).into(), + ast::Expr::FormatArgsExpr(inner) => self.emit_format_args_expr(inner).into(), + ast::Expr::IfExpr(inner) => self.emit_if_expr(inner).into(), + ast::Expr::IndexExpr(inner) => self.emit_index_expr(inner).into(), + ast::Expr::LetExpr(inner) => self.emit_let_expr(inner).into(), + ast::Expr::Literal(inner) => self.emit_literal(inner).into(), + ast::Expr::LoopExpr(inner) => self.emit_loop_expr(inner).into(), + ast::Expr::MacroExpr(inner) => self.emit_macro_expr(inner).into(), + ast::Expr::MatchExpr(inner) => self.emit_match_expr(inner).into(), + ast::Expr::MethodCallExpr(inner) => self.emit_method_call_expr(inner).into(), + ast::Expr::OffsetOfExpr(inner) => self.emit_offset_of_expr(inner).into(), + ast::Expr::ParenExpr(inner) => self.emit_paren_expr(inner).into(), + ast::Expr::PathExpr(inner) => self.emit_path_expr(inner).into(), + ast::Expr::PrefixExpr(inner) => self.emit_prefix_expr(inner).into(), + ast::Expr::RangeExpr(inner) => self.emit_range_expr(inner).into(), + ast::Expr::RecordExpr(inner) => self.emit_record_expr(inner).into(), + ast::Expr::RefExpr(inner) => self.emit_ref_expr(inner).into(), + ast::Expr::ReturnExpr(inner) => self.emit_return_expr(inner).into(), + ast::Expr::TryExpr(inner) => self.emit_try_expr(inner).into(), + ast::Expr::TupleExpr(inner) => self.emit_tuple_expr(inner).into(), + ast::Expr::UnderscoreExpr(inner) => self.emit_underscore_expr(inner).into(), + ast::Expr::WhileExpr(inner) => self.emit_while_expr(inner).into(), + ast::Expr::YeetExpr(inner) => self.emit_yeet_expr(inner).into(), + ast::Expr::YieldExpr(inner) => self.emit_yield_expr(inner).into(), + } + } + + pub(crate) fn emit_extern_item( + &mut self, + node: ast::ExternItem, + ) -> Label { + match node { + ast::ExternItem::Fn(inner) => self.emit_fn(inner).into(), + ast::ExternItem::MacroCall(inner) => self.emit_macro_call(inner).into(), + ast::ExternItem::Static(inner) => self.emit_static(inner).into(), + ast::ExternItem::TypeAlias(inner) => self.emit_type_alias(inner).into(), + } + } + + pub(crate) fn emit_field_list(&mut self, node: ast::FieldList) -> Label { + match node { + ast::FieldList::RecordFieldList(inner) => self.emit_record_field_list(inner).into(), + ast::FieldList::TupleFieldList(inner) => self.emit_tuple_field_list(inner).into(), + } + } + + pub(crate) fn emit_generic_arg( + &mut self, + node: ast::GenericArg, + ) -> Label { + match node { + ast::GenericArg::AssocTypeArg(inner) => self.emit_assoc_type_arg(inner).into(), + ast::GenericArg::ConstArg(inner) => self.emit_const_arg(inner).into(), + ast::GenericArg::LifetimeArg(inner) => self.emit_lifetime_arg(inner).into(), + ast::GenericArg::TypeArg(inner) => self.emit_type_arg(inner).into(), + } + } + + pub(crate) fn emit_generic_param( + &mut self, + node: ast::GenericParam, + ) -> Label { + match node { + ast::GenericParam::ConstParam(inner) => self.emit_const_param(inner).into(), + ast::GenericParam::LifetimeParam(inner) => self.emit_lifetime_param(inner).into(), + ast::GenericParam::TypeParam(inner) => self.emit_type_param(inner).into(), + } + } + + pub(crate) fn emit_pat(&mut self, node: ast::Pat) -> Label { + match node { + ast::Pat::BoxPat(inner) => self.emit_box_pat(inner).into(), + ast::Pat::ConstBlockPat(inner) => self.emit_const_block_pat(inner).into(), + ast::Pat::IdentPat(inner) => self.emit_ident_pat(inner).into(), + ast::Pat::LiteralPat(inner) => self.emit_literal_pat(inner).into(), + ast::Pat::MacroPat(inner) => self.emit_macro_pat(inner).into(), + ast::Pat::OrPat(inner) => self.emit_or_pat(inner).into(), + ast::Pat::ParenPat(inner) => self.emit_paren_pat(inner).into(), + ast::Pat::PathPat(inner) => self.emit_path_pat(inner).into(), + ast::Pat::RangePat(inner) => self.emit_range_pat(inner).into(), + ast::Pat::RecordPat(inner) => self.emit_record_pat(inner).into(), + ast::Pat::RefPat(inner) => self.emit_ref_pat(inner).into(), + ast::Pat::RestPat(inner) => self.emit_rest_pat(inner).into(), + ast::Pat::SlicePat(inner) => self.emit_slice_pat(inner).into(), + ast::Pat::TuplePat(inner) => self.emit_tuple_pat(inner).into(), + ast::Pat::TupleStructPat(inner) => self.emit_tuple_struct_pat(inner).into(), + ast::Pat::WildcardPat(inner) => self.emit_wildcard_pat(inner).into(), + } + } + + pub(crate) fn emit_stmt(&mut self, node: ast::Stmt) -> Label { + match node { + ast::Stmt::ExprStmt(inner) => self.emit_expr_stmt(inner).into(), + ast::Stmt::Item(inner) => self.emit_item(inner).into(), + ast::Stmt::LetStmt(inner) => self.emit_let_stmt(inner).into(), + } + } + + pub(crate) fn emit_type(&mut self, node: ast::Type) -> Label { + match node { + ast::Type::ArrayType(inner) => self.emit_array_type(inner).into(), + ast::Type::DynTraitType(inner) => self.emit_dyn_trait_type(inner).into(), + ast::Type::FnPtrType(inner) => self.emit_fn_ptr_type(inner).into(), + ast::Type::ForType(inner) => self.emit_for_type(inner).into(), + ast::Type::ImplTraitType(inner) => self.emit_impl_trait_type(inner).into(), + ast::Type::InferType(inner) => self.emit_infer_type(inner).into(), + ast::Type::MacroType(inner) => self.emit_macro_type(inner).into(), + ast::Type::NeverType(inner) => self.emit_never_type(inner).into(), + ast::Type::ParenType(inner) => self.emit_paren_type(inner).into(), + ast::Type::PathType(inner) => self.emit_path_type(inner).into(), + ast::Type::PtrType(inner) => self.emit_ptr_type(inner).into(), + ast::Type::RefType(inner) => self.emit_ref_type(inner).into(), + ast::Type::SliceType(inner) => self.emit_slice_type(inner).into(), + ast::Type::TupleType(inner) => self.emit_tuple_type(inner).into(), + } + } + + pub(crate) fn emit_item(&mut self, node: ast::Item) -> Label { + match node { + ast::Item::Const(inner) => self.emit_const(inner).into(), + ast::Item::Enum(inner) => self.emit_enum(inner).into(), + ast::Item::ExternBlock(inner) => self.emit_extern_block(inner).into(), + ast::Item::ExternCrate(inner) => self.emit_extern_crate(inner).into(), + ast::Item::Fn(inner) => self.emit_fn(inner).into(), + ast::Item::Impl(inner) => self.emit_impl(inner).into(), + ast::Item::MacroCall(inner) => self.emit_macro_call(inner).into(), + ast::Item::MacroDef(inner) => self.emit_macro_def(inner).into(), + ast::Item::MacroRules(inner) => self.emit_macro_rules(inner).into(), + ast::Item::Module(inner) => self.emit_module(inner).into(), + ast::Item::Static(inner) => self.emit_static(inner).into(), + ast::Item::Struct(inner) => self.emit_struct(inner).into(), + ast::Item::Trait(inner) => self.emit_trait(inner).into(), + ast::Item::TraitAlias(inner) => self.emit_trait_alias(inner).into(), + ast::Item::TypeAlias(inner) => self.emit_type_alias(inner).into(), + ast::Item::Union(inner) => self.emit_union(inner).into(), + ast::Item::Use(inner) => self.emit_use(inner).into(), + } + } + + pub(crate) fn emit_abi(&mut self, node: ast::Abi) -> Label { + let abi_string = node.try_get_text(); + let label = self.trap.emit(generated::Abi { + id: TrapId::Star, + abi_string, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_arg_list(&mut self, node: ast::ArgList) -> Label { + let args = node.args().map(|x| self.emit_expr(x)).collect(); + let label = self.trap.emit(generated::ArgList { + id: TrapId::Star, + args, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_array_expr(&mut self, node: ast::ArrayExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let exprs = node.exprs().map(|x| self.emit_expr(x)).collect(); + let label = self.trap.emit(generated::ArrayExpr { + id: TrapId::Star, + attrs, + exprs, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_array_type(&mut self, node: ast::ArrayType) -> Label { + let const_arg = node.const_arg().map(|x| self.emit_const_arg(x)); + let ty = node.ty().map(|x| self.emit_type(x)); + let label = self.trap.emit(generated::ArrayType { + id: TrapId::Star, + const_arg, + ty, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_asm_expr(&mut self, node: ast::AsmExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let expr = node.expr().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::AsmExpr { + id: TrapId::Star, + attrs, + expr, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_assoc_item_list( + &mut self, + node: ast::AssocItemList, + ) -> Label { + let assoc_items = node + .assoc_items() + .map(|x| self.emit_assoc_item(x)) + .collect(); + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let label = self.trap.emit(generated::AssocItemList { + id: TrapId::Star, + assoc_items, + attrs, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_assoc_type_arg( + &mut self, + node: ast::AssocTypeArg, + ) -> Label { + let const_arg = node.const_arg().map(|x| self.emit_const_arg(x)); + let generic_arg_list = node + .generic_arg_list() + .map(|x| self.emit_generic_arg_list(x)); + let name_ref = node.name_ref().map(|x| self.emit_name_ref(x)); + let param_list = node.param_list().map(|x| self.emit_param_list(x)); + let ret_type = node.ret_type().map(|x| self.emit_ret_type(x)); + let return_type_syntax = node + .return_type_syntax() + .map(|x| self.emit_return_type_syntax(x)); + let ty = node.ty().map(|x| self.emit_type(x)); + let type_bound_list = node.type_bound_list().map(|x| self.emit_type_bound_list(x)); + let label = self.trap.emit(generated::AssocTypeArg { + id: TrapId::Star, + const_arg, + generic_arg_list, + name_ref, + param_list, + ret_type, + return_type_syntax, + ty, + type_bound_list, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_attr(&mut self, node: ast::Attr) -> Label { + let meta = node.meta().map(|x| self.emit_meta(x)); + let label = self.trap.emit(generated::Attr { + id: TrapId::Star, + meta, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_await_expr(&mut self, node: ast::AwaitExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let expr = node.expr().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::AwaitExpr { + id: TrapId::Star, + attrs, + expr, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_become_expr( + &mut self, + node: ast::BecomeExpr, + ) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let expr = node.expr().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::BecomeExpr { + id: TrapId::Star, + attrs, + expr, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_bin_expr(&mut self, node: ast::BinExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let lhs = node.lhs().map(|x| self.emit_expr(x)); + let operator_name = node.try_get_text(); + let rhs = node.rhs().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::BinaryExpr { + id: TrapId::Star, + attrs, + lhs, + operator_name, + rhs, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_block_expr(&mut self, node: ast::BlockExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let label = node.label().map(|x| self.emit_label(x)); + let stmt_list = node.stmt_list().map(|x| self.emit_stmt_list(x)); + let label = self.trap.emit(generated::BlockExpr { + id: TrapId::Star, + attrs, + label, + stmt_list, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_box_pat(&mut self, node: ast::BoxPat) -> Label { + let pat = node.pat().map(|x| self.emit_pat(x)); + let label = self.trap.emit(generated::BoxPat { + id: TrapId::Star, + pat, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_break_expr(&mut self, node: ast::BreakExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let expr = node.expr().map(|x| self.emit_expr(x)); + let lifetime = node.lifetime().map(|x| self.emit_lifetime(x)); + let label = self.trap.emit(generated::BreakExpr { + id: TrapId::Star, + attrs, + expr, + lifetime, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_call_expr(&mut self, node: ast::CallExpr) -> Label { + let arg_list = node.arg_list().map(|x| self.emit_arg_list(x)); + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let expr = node.expr().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::CallExpr { + id: TrapId::Star, + arg_list, + attrs, + expr, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_cast_expr(&mut self, node: ast::CastExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let expr = node.expr().map(|x| self.emit_expr(x)); + let ty = node.ty().map(|x| self.emit_type(x)); + let label = self.trap.emit(generated::CastExpr { + id: TrapId::Star, + attrs, + expr, + ty, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_closure_binder( + &mut self, + node: ast::ClosureBinder, + ) -> Label { + let generic_param_list = node + .generic_param_list() + .map(|x| self.emit_generic_param_list(x)); + let label = self.trap.emit(generated::ClosureBinder { + id: TrapId::Star, + generic_param_list, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_closure_expr( + &mut self, + node: ast::ClosureExpr, + ) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let body = node.body().map(|x| self.emit_expr(x)); + let closure_binder = node.closure_binder().map(|x| self.emit_closure_binder(x)); + let param_list = node.param_list().map(|x| self.emit_param_list(x)); + let ret_type = node.ret_type().map(|x| self.emit_ret_type(x)); + let label = self.trap.emit(generated::ClosureExpr { + id: TrapId::Star, + attrs, + body, + closure_binder, + param_list, + ret_type, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_const(&mut self, node: ast::Const) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let body = node.body().map(|x| self.emit_expr(x)); + let name = node.name().map(|x| self.emit_name(x)); + let ty = node.ty().map(|x| self.emit_type(x)); + let visibility = node.visibility().map(|x| self.emit_visibility(x)); + let label = self.trap.emit(generated::Const { + id: TrapId::Star, + attrs, + body, + name, + ty, + visibility, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_const_arg(&mut self, node: ast::ConstArg) -> Label { + let expr = node.expr().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::ConstArg { + id: TrapId::Star, + expr, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_const_block_pat( + &mut self, + node: ast::ConstBlockPat, + ) -> Label { + let block_expr = node.block_expr().map(|x| self.emit_block_expr(x)); + let label = self.trap.emit(generated::ConstBlockPat { + id: TrapId::Star, + block_expr, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_const_param( + &mut self, + node: ast::ConstParam, + ) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let default_val = node.default_val().map(|x| self.emit_const_arg(x)); + let name = node.name().map(|x| self.emit_name(x)); + let ty = node.ty().map(|x| self.emit_type(x)); + let label = self.trap.emit(generated::ConstParam { + id: TrapId::Star, + attrs, + default_val, + name, + ty, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_continue_expr( + &mut self, + node: ast::ContinueExpr, + ) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let lifetime = node.lifetime().map(|x| self.emit_lifetime(x)); + let label = self.trap.emit(generated::ContinueExpr { + id: TrapId::Star, + attrs, + lifetime, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_dyn_trait_type( + &mut self, + node: ast::DynTraitType, + ) -> Label { + let type_bound_list = node.type_bound_list().map(|x| self.emit_type_bound_list(x)); + let label = self.trap.emit(generated::DynTraitType { + id: TrapId::Star, + type_bound_list, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_enum(&mut self, node: ast::Enum) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let generic_param_list = node + .generic_param_list() + .map(|x| self.emit_generic_param_list(x)); + let name = node.name().map(|x| self.emit_name(x)); + let variant_list = node.variant_list().map(|x| self.emit_variant_list(x)); + let visibility = node.visibility().map(|x| self.emit_visibility(x)); + let where_clause = node.where_clause().map(|x| self.emit_where_clause(x)); + let label = self.trap.emit(generated::Enum { + id: TrapId::Star, + attrs, + generic_param_list, + name, + variant_list, + visibility, + where_clause, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_expr_stmt(&mut self, node: ast::ExprStmt) -> Label { + let expr = node.expr().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::ExprStmt { + id: TrapId::Star, + expr, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_extern_block( + &mut self, + node: ast::ExternBlock, + ) -> Label { + let abi = node.abi().map(|x| self.emit_abi(x)); + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let extern_item_list = node + .extern_item_list() + .map(|x| self.emit_extern_item_list(x)); + let label = self.trap.emit(generated::ExternBlock { + id: TrapId::Star, + abi, + attrs, + extern_item_list, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_extern_crate( + &mut self, + node: ast::ExternCrate, + ) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let name_ref = node.name_ref().map(|x| self.emit_name_ref(x)); + let rename = node.rename().map(|x| self.emit_rename(x)); + let visibility = node.visibility().map(|x| self.emit_visibility(x)); + let label = self.trap.emit(generated::ExternCrate { + id: TrapId::Star, + attrs, + name_ref, + rename, + visibility, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_extern_item_list( + &mut self, + node: ast::ExternItemList, + ) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let extern_items = node + .extern_items() + .map(|x| self.emit_extern_item(x)) + .collect(); + let label = self.trap.emit(generated::ExternItemList { + id: TrapId::Star, + attrs, + extern_items, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_field_expr(&mut self, node: ast::FieldExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let expr = node.expr().map(|x| self.emit_expr(x)); + let name_ref = node.name_ref().map(|x| self.emit_name_ref(x)); + let label = self.trap.emit(generated::FieldExpr { + id: TrapId::Star, + attrs, + expr, + name_ref, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_fn(&mut self, node: ast::Fn) -> Label { + let abi = node.abi().map(|x| self.emit_abi(x)); + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let body = node.body().map(|x| self.emit_block_expr(x)); + let generic_param_list = node + .generic_param_list() + .map(|x| self.emit_generic_param_list(x)); + let name = node.name().map(|x| self.emit_name(x)); + let param_list = node.param_list().map(|x| self.emit_param_list(x)); + let ret_type = node.ret_type().map(|x| self.emit_ret_type(x)); + let visibility = node.visibility().map(|x| self.emit_visibility(x)); + let where_clause = node.where_clause().map(|x| self.emit_where_clause(x)); + let label = self.trap.emit(generated::Function { + id: TrapId::Star, + abi, + attrs, + body, + generic_param_list, + name, + param_list, + ret_type, + visibility, + where_clause, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_fn_ptr_type(&mut self, node: ast::FnPtrType) -> Label { + let abi = node.abi().map(|x| self.emit_abi(x)); + let param_list = node.param_list().map(|x| self.emit_param_list(x)); + let ret_type = node.ret_type().map(|x| self.emit_ret_type(x)); + let label = self.trap.emit(generated::FnPtrType { + id: TrapId::Star, + abi, + param_list, + ret_type, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_for_expr(&mut self, node: ast::ForExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let iterable = node.iterable().map(|x| self.emit_expr(x)); + let label = node.label().map(|x| self.emit_label(x)); + let loop_body = node.loop_body().map(|x| self.emit_block_expr(x)); + let pat = node.pat().map(|x| self.emit_pat(x)); + let label = self.trap.emit(generated::ForExpr { + id: TrapId::Star, + attrs, + iterable, + label, + loop_body, + pat, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_for_type(&mut self, node: ast::ForType) -> Label { + let generic_param_list = node + .generic_param_list() + .map(|x| self.emit_generic_param_list(x)); + let ty = node.ty().map(|x| self.emit_type(x)); + let label = self.trap.emit(generated::ForType { + id: TrapId::Star, + generic_param_list, + ty, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_format_args_arg( + &mut self, + node: ast::FormatArgsArg, + ) -> Label { + let expr = node.expr().map(|x| self.emit_expr(x)); + let name = node.name().map(|x| self.emit_name(x)); + let label = self.trap.emit(generated::FormatArgsArg { + id: TrapId::Star, + expr, + name, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_format_args_expr( + &mut self, + node: ast::FormatArgsExpr, + ) -> Label { + let args = node.args().map(|x| self.emit_format_args_arg(x)).collect(); + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let template = node.template().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::FormatArgsExpr { + id: TrapId::Star, + args, + attrs, + template, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_generic_arg_list( + &mut self, + node: ast::GenericArgList, + ) -> Label { + let generic_args = node + .generic_args() + .map(|x| self.emit_generic_arg(x)) + .collect(); + let label = self.trap.emit(generated::GenericArgList { + id: TrapId::Star, + generic_args, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_generic_param_list( + &mut self, + node: ast::GenericParamList, + ) -> Label { + let generic_params = node + .generic_params() + .map(|x| self.emit_generic_param(x)) + .collect(); + let label = self.trap.emit(generated::GenericParamList { + id: TrapId::Star, + generic_params, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_ident_pat(&mut self, node: ast::IdentPat) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let name = node.name().map(|x| self.emit_name(x)); + let pat = node.pat().map(|x| self.emit_pat(x)); + let label = self.trap.emit(generated::IdentPat { + id: TrapId::Star, + attrs, + name, + pat, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_if_expr(&mut self, node: ast::IfExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let condition = node.condition().map(|x| self.emit_expr(x)); + let else_ = node.else_branch().map(|x| self.emit_else_branch(x)); + let then = node.then_branch().map(|x| self.emit_block_expr(x)); + let label = self.trap.emit(generated::IfExpr { + id: TrapId::Star, + attrs, + condition, + else_, + then, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_impl(&mut self, node: ast::Impl) -> Label { + let assoc_item_list = node.assoc_item_list().map(|x| self.emit_assoc_item_list(x)); + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let generic_param_list = node + .generic_param_list() + .map(|x| self.emit_generic_param_list(x)); + let self_ty = node.self_ty().map(|x| self.emit_type(x)); + let trait_ = node.trait_().map(|x| self.emit_type(x)); + let visibility = node.visibility().map(|x| self.emit_visibility(x)); + let where_clause = node.where_clause().map(|x| self.emit_where_clause(x)); + let label = self.trap.emit(generated::Impl { + id: TrapId::Star, + assoc_item_list, + attrs, + generic_param_list, + self_ty, + trait_, + visibility, + where_clause, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_impl_trait_type( + &mut self, + node: ast::ImplTraitType, + ) -> Label { + let type_bound_list = node.type_bound_list().map(|x| self.emit_type_bound_list(x)); + let label = self.trap.emit(generated::ImplTraitType { + id: TrapId::Star, + type_bound_list, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_index_expr(&mut self, node: ast::IndexExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let base = node.base().map(|x| self.emit_expr(x)); + let index = node.index().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::IndexExpr { + id: TrapId::Star, + attrs, + base, + index, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_infer_type(&mut self, node: ast::InferType) -> Label { + let label = self.trap.emit(generated::InferType { id: TrapId::Star }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_item_list(&mut self, node: ast::ItemList) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let items = node.items().map(|x| self.emit_item(x)).collect(); + let label = self.trap.emit(generated::ItemList { + id: TrapId::Star, + attrs, + items, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_label(&mut self, node: ast::Label) -> Label { + let lifetime = node.lifetime().map(|x| self.emit_lifetime(x)); + let label = self.trap.emit(generated::Label { + id: TrapId::Star, + lifetime, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_let_else(&mut self, node: ast::LetElse) -> Label { + let block_expr = node.block_expr().map(|x| self.emit_block_expr(x)); + let label = self.trap.emit(generated::LetElse { + id: TrapId::Star, + block_expr, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_let_expr(&mut self, node: ast::LetExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let expr = node.expr().map(|x| self.emit_expr(x)); + let pat = node.pat().map(|x| self.emit_pat(x)); + let label = self.trap.emit(generated::LetExpr { + id: TrapId::Star, + attrs, + expr, + pat, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_let_stmt(&mut self, node: ast::LetStmt) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let initializer = node.initializer().map(|x| self.emit_expr(x)); + let let_else = node.let_else().map(|x| self.emit_let_else(x)); + let pat = node.pat().map(|x| self.emit_pat(x)); + let ty = node.ty().map(|x| self.emit_type(x)); + let label = self.trap.emit(generated::LetStmt { + id: TrapId::Star, + attrs, + initializer, + let_else, + pat, + ty, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_lifetime(&mut self, node: ast::Lifetime) -> Label { + let text = node.try_get_text(); + let label = self.trap.emit(generated::Lifetime { + id: TrapId::Star, + text, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_lifetime_arg( + &mut self, + node: ast::LifetimeArg, + ) -> Label { + let lifetime = node.lifetime().map(|x| self.emit_lifetime(x)); + let label = self.trap.emit(generated::LifetimeArg { + id: TrapId::Star, + lifetime, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_lifetime_param( + &mut self, + node: ast::LifetimeParam, + ) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let lifetime = node.lifetime().map(|x| self.emit_lifetime(x)); + let type_bound_list = node.type_bound_list().map(|x| self.emit_type_bound_list(x)); + let label = self.trap.emit(generated::LifetimeParam { + id: TrapId::Star, + attrs, + lifetime, + type_bound_list, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_literal(&mut self, node: ast::Literal) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let text_value = node.try_get_text(); + let label = self.trap.emit(generated::LiteralExpr { + id: TrapId::Star, + attrs, + text_value, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_literal_pat( + &mut self, + node: ast::LiteralPat, + ) -> Label { + let literal = node.literal().map(|x| self.emit_literal(x)); + let label = self.trap.emit(generated::LiteralPat { + id: TrapId::Star, + literal, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_loop_expr(&mut self, node: ast::LoopExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let label = node.label().map(|x| self.emit_label(x)); + let loop_body = node.loop_body().map(|x| self.emit_block_expr(x)); + let label = self.trap.emit(generated::LoopExpr { + id: TrapId::Star, + attrs, + label, + loop_body, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_macro_call(&mut self, node: ast::MacroCall) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let path = node.path().map(|x| self.emit_path(x)); + let token_tree = node.token_tree().map(|x| self.emit_token_tree(x)); + let label = self.trap.emit(generated::MacroCall { + id: TrapId::Star, + attrs, + path, + token_tree, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_macro_def(&mut self, node: ast::MacroDef) -> Label { + let args = node.args().map(|x| self.emit_token_tree(x)); + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let body = node.body().map(|x| self.emit_token_tree(x)); + let name = node.name().map(|x| self.emit_name(x)); + let visibility = node.visibility().map(|x| self.emit_visibility(x)); + let label = self.trap.emit(generated::MacroDef { + id: TrapId::Star, + args, + attrs, + body, + name, + visibility, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_macro_expr(&mut self, node: ast::MacroExpr) -> Label { + let macro_call = node.macro_call().map(|x| self.emit_macro_call(x)); + let label = self.trap.emit(generated::MacroExpr { + id: TrapId::Star, + macro_call, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_macro_pat(&mut self, node: ast::MacroPat) -> Label { + let macro_call = node.macro_call().map(|x| self.emit_macro_call(x)); + let label = self.trap.emit(generated::MacroPat { + id: TrapId::Star, + macro_call, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_macro_rules( + &mut self, + node: ast::MacroRules, + ) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let name = node.name().map(|x| self.emit_name(x)); + let token_tree = node.token_tree().map(|x| self.emit_token_tree(x)); + let visibility = node.visibility().map(|x| self.emit_visibility(x)); + let label = self.trap.emit(generated::MacroRules { + id: TrapId::Star, + attrs, + name, + token_tree, + visibility, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_macro_type(&mut self, node: ast::MacroType) -> Label { + let macro_call = node.macro_call().map(|x| self.emit_macro_call(x)); + let label = self.trap.emit(generated::MacroType { + id: TrapId::Star, + macro_call, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_match_arm(&mut self, node: ast::MatchArm) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let expr = node.expr().map(|x| self.emit_expr(x)); + let guard = node.guard().map(|x| self.emit_match_guard(x)); + let pat = node.pat().map(|x| self.emit_pat(x)); + let label = self.trap.emit(generated::MatchArm { + id: TrapId::Star, + attrs, + expr, + guard, + pat, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_match_arm_list( + &mut self, + node: ast::MatchArmList, + ) -> Label { + let arms = node.arms().map(|x| self.emit_match_arm(x)).collect(); + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let label = self.trap.emit(generated::MatchArmList { + id: TrapId::Star, + arms, + attrs, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_match_expr(&mut self, node: ast::MatchExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let expr = node.expr().map(|x| self.emit_expr(x)); + let match_arm_list = node.match_arm_list().map(|x| self.emit_match_arm_list(x)); + let label = self.trap.emit(generated::MatchExpr { + id: TrapId::Star, + attrs, + expr, + match_arm_list, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_match_guard( + &mut self, + node: ast::MatchGuard, + ) -> Label { + let condition = node.condition().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::MatchGuard { + id: TrapId::Star, + condition, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_meta(&mut self, node: ast::Meta) -> Label { + let expr = node.expr().map(|x| self.emit_expr(x)); + let path = node.path().map(|x| self.emit_path(x)); + let token_tree = node.token_tree().map(|x| self.emit_token_tree(x)); + let label = self.trap.emit(generated::Meta { + id: TrapId::Star, + expr, + path, + token_tree, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_method_call_expr( + &mut self, + node: ast::MethodCallExpr, + ) -> Label { + let arg_list = node.arg_list().map(|x| self.emit_arg_list(x)); + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let generic_arg_list = node + .generic_arg_list() + .map(|x| self.emit_generic_arg_list(x)); + let name_ref = node.name_ref().map(|x| self.emit_name_ref(x)); + let receiver = node.receiver().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::MethodCallExpr { + id: TrapId::Star, + arg_list, + attrs, + generic_arg_list, + name_ref, + receiver, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_module(&mut self, node: ast::Module) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let item_list = node.item_list().map(|x| self.emit_item_list(x)); + let name = node.name().map(|x| self.emit_name(x)); + let visibility = node.visibility().map(|x| self.emit_visibility(x)); + let label = self.trap.emit(generated::Module { + id: TrapId::Star, + attrs, + item_list, + name, + visibility, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_name(&mut self, node: ast::Name) -> Label { + let text = node.try_get_text(); + let label = self.trap.emit(generated::Name { + id: TrapId::Star, + text, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_name_ref(&mut self, node: ast::NameRef) -> Label { + let text = node.try_get_text(); + let label = self.trap.emit(generated::NameRef { + id: TrapId::Star, + text, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_never_type(&mut self, node: ast::NeverType) -> Label { + let label = self.trap.emit(generated::NeverType { id: TrapId::Star }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_offset_of_expr( + &mut self, + node: ast::OffsetOfExpr, + ) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let fields = node.fields().map(|x| self.emit_name_ref(x)).collect(); + let ty = node.ty().map(|x| self.emit_type(x)); + let label = self.trap.emit(generated::OffsetOfExpr { + id: TrapId::Star, + attrs, + fields, + ty, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_or_pat(&mut self, node: ast::OrPat) -> Label { + let pats = node.pats().map(|x| self.emit_pat(x)).collect(); + let label = self.trap.emit(generated::OrPat { + id: TrapId::Star, + pats, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_param(&mut self, node: ast::Param) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let pat = node.pat().map(|x| self.emit_pat(x)); + let ty = node.ty().map(|x| self.emit_type(x)); + let label = self.trap.emit(generated::Param { + id: TrapId::Star, + attrs, + pat, + ty, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_param_list(&mut self, node: ast::ParamList) -> Label { + let params = node.params().map(|x| self.emit_param(x)).collect(); + let self_param = node.self_param().map(|x| self.emit_self_param(x)); + let label = self.trap.emit(generated::ParamList { + id: TrapId::Star, + params, + self_param, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_paren_expr(&mut self, node: ast::ParenExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let expr = node.expr().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::ParenExpr { + id: TrapId::Star, + attrs, + expr, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_paren_pat(&mut self, node: ast::ParenPat) -> Label { + let pat = node.pat().map(|x| self.emit_pat(x)); + let label = self.trap.emit(generated::ParenPat { + id: TrapId::Star, + pat, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_paren_type(&mut self, node: ast::ParenType) -> Label { + let ty = node.ty().map(|x| self.emit_type(x)); + let label = self.trap.emit(generated::ParenType { + id: TrapId::Star, + ty, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_path(&mut self, node: ast::Path) -> Label { + let qualifier = node.qualifier().map(|x| self.emit_path(x)); + let part = node.segment().map(|x| self.emit_path_segment(x)); + let label = self.trap.emit(generated::Path { + id: TrapId::Star, + qualifier, + part, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_path_expr(&mut self, node: ast::PathExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let path = node.path().map(|x| self.emit_path(x)); + let label = self.trap.emit(generated::PathExpr { + id: TrapId::Star, + attrs, + path, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_path_pat(&mut self, node: ast::PathPat) -> Label { + let path = node.path().map(|x| self.emit_path(x)); + let label = self.trap.emit(generated::PathPat { + id: TrapId::Star, + path, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_path_segment( + &mut self, + node: ast::PathSegment, + ) -> Label { + let generic_arg_list = node + .generic_arg_list() + .map(|x| self.emit_generic_arg_list(x)); + let name_ref = node.name_ref().map(|x| self.emit_name_ref(x)); + let param_list = node.param_list().map(|x| self.emit_param_list(x)); + let path_type = node.path_type().map(|x| self.emit_path_type(x)); + let ret_type = node.ret_type().map(|x| self.emit_ret_type(x)); + let return_type_syntax = node + .return_type_syntax() + .map(|x| self.emit_return_type_syntax(x)); + let ty = node.ty().map(|x| self.emit_type(x)); + let label = self.trap.emit(generated::PathSegment { + id: TrapId::Star, + generic_arg_list, + name_ref, + param_list, + path_type, + ret_type, + return_type_syntax, + ty, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_path_type(&mut self, node: ast::PathType) -> Label { + let path = node.path().map(|x| self.emit_path(x)); + let label = self.trap.emit(generated::PathType { + id: TrapId::Star, + path, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_prefix_expr( + &mut self, + node: ast::PrefixExpr, + ) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let expr = node.expr().map(|x| self.emit_expr(x)); + let operator_name = node.try_get_text(); + let label = self.trap.emit(generated::PrefixExpr { + id: TrapId::Star, + attrs, + expr, + operator_name, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_ptr_type(&mut self, node: ast::PtrType) -> Label { + let ty = node.ty().map(|x| self.emit_type(x)); + let label = self.trap.emit(generated::PtrType { + id: TrapId::Star, + ty, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_range_expr(&mut self, node: ast::RangeExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let end = node.end().map(|x| self.emit_expr(x)); + let operator_name = node.try_get_text(); + let start = node.start().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::RangeExpr { + id: TrapId::Star, + attrs, + end, + operator_name, + start, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_range_pat(&mut self, node: ast::RangePat) -> Label { + let end = node.end().map(|x| self.emit_pat(x)); + let operator_name = node.try_get_text(); + let start = node.start().map(|x| self.emit_pat(x)); + let label = self.trap.emit(generated::RangePat { + id: TrapId::Star, + end, + operator_name, + start, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_record_expr( + &mut self, + node: ast::RecordExpr, + ) -> Label { + let path = node.path().map(|x| self.emit_path(x)); + let record_expr_field_list = node + .record_expr_field_list() + .map(|x| self.emit_record_expr_field_list(x)); + let label = self.trap.emit(generated::RecordExpr { + id: TrapId::Star, + path, + record_expr_field_list, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_record_expr_field( + &mut self, + node: ast::RecordExprField, + ) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let expr = node.expr().map(|x| self.emit_expr(x)); + let name_ref = node.name_ref().map(|x| self.emit_name_ref(x)); + let label = self.trap.emit(generated::RecordExprField { + id: TrapId::Star, + attrs, + expr, + name_ref, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_record_expr_field_list( + &mut self, + node: ast::RecordExprFieldList, + ) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let fields = node + .fields() + .map(|x| self.emit_record_expr_field(x)) + .collect(); + let spread = node.spread().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::RecordExprFieldList { + id: TrapId::Star, + attrs, + fields, + spread, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_record_field( + &mut self, + node: ast::RecordField, + ) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let name = node.name().map(|x| self.emit_name(x)); + let ty = node.ty().map(|x| self.emit_type(x)); + let visibility = node.visibility().map(|x| self.emit_visibility(x)); + let label = self.trap.emit(generated::RecordField { + id: TrapId::Star, + attrs, + name, + ty, + visibility, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_record_field_list( + &mut self, + node: ast::RecordFieldList, + ) -> Label { + let fields = node.fields().map(|x| self.emit_record_field(x)).collect(); + let label = self.trap.emit(generated::RecordFieldList { + id: TrapId::Star, + fields, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_record_pat(&mut self, node: ast::RecordPat) -> Label { + let path = node.path().map(|x| self.emit_path(x)); + let record_pat_field_list = node + .record_pat_field_list() + .map(|x| self.emit_record_pat_field_list(x)); + let label = self.trap.emit(generated::RecordPat { + id: TrapId::Star, + path, + record_pat_field_list, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_record_pat_field( + &mut self, + node: ast::RecordPatField, + ) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let name_ref = node.name_ref().map(|x| self.emit_name_ref(x)); + let pat = node.pat().map(|x| self.emit_pat(x)); + let label = self.trap.emit(generated::RecordPatField { + id: TrapId::Star, + attrs, + name_ref, + pat, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_record_pat_field_list( + &mut self, + node: ast::RecordPatFieldList, + ) -> Label { + let fields = node + .fields() + .map(|x| self.emit_record_pat_field(x)) + .collect(); + let rest_pat = node.rest_pat().map(|x| self.emit_rest_pat(x)); + let label = self.trap.emit(generated::RecordPatFieldList { + id: TrapId::Star, + fields, + rest_pat, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_ref_expr(&mut self, node: ast::RefExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let expr = node.expr().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::RefExpr { + id: TrapId::Star, + attrs, + expr, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_ref_pat(&mut self, node: ast::RefPat) -> Label { + let pat = node.pat().map(|x| self.emit_pat(x)); + let label = self.trap.emit(generated::RefPat { + id: TrapId::Star, + pat, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_ref_type(&mut self, node: ast::RefType) -> Label { + let lifetime = node.lifetime().map(|x| self.emit_lifetime(x)); + let ty = node.ty().map(|x| self.emit_type(x)); + let label = self.trap.emit(generated::RefType { + id: TrapId::Star, + lifetime, + ty, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_rename(&mut self, node: ast::Rename) -> Label { + let name = node.name().map(|x| self.emit_name(x)); + let label = self.trap.emit(generated::Rename { + id: TrapId::Star, + name, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_rest_pat(&mut self, node: ast::RestPat) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let label = self.trap.emit(generated::RestPat { + id: TrapId::Star, + attrs, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_ret_type(&mut self, node: ast::RetType) -> Label { + let ty = node.ty().map(|x| self.emit_type(x)); + let label = self.trap.emit(generated::RetType { + id: TrapId::Star, + ty, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_return_expr( + &mut self, + node: ast::ReturnExpr, + ) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let expr = node.expr().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::ReturnExpr { + id: TrapId::Star, + attrs, + expr, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_return_type_syntax( + &mut self, + node: ast::ReturnTypeSyntax, + ) -> Label { + let label = self + .trap + .emit(generated::ReturnTypeSyntax { id: TrapId::Star }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_self_param(&mut self, node: ast::SelfParam) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let lifetime = node.lifetime().map(|x| self.emit_lifetime(x)); + let name = node.name().map(|x| self.emit_name(x)); + let ty = node.ty().map(|x| self.emit_type(x)); + let label = self.trap.emit(generated::SelfParam { + id: TrapId::Star, + attrs, + lifetime, + name, + ty, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_slice_pat(&mut self, node: ast::SlicePat) -> Label { + let pats = node.pats().map(|x| self.emit_pat(x)).collect(); + let label = self.trap.emit(generated::SlicePat { + id: TrapId::Star, + pats, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_slice_type(&mut self, node: ast::SliceType) -> Label { + let ty = node.ty().map(|x| self.emit_type(x)); + let label = self.trap.emit(generated::SliceType { + id: TrapId::Star, + ty, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_source_file( + &mut self, + node: ast::SourceFile, + ) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let items = node.items().map(|x| self.emit_item(x)).collect(); + let label = self.trap.emit(generated::SourceFile { + id: TrapId::Star, + attrs, + items, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_static(&mut self, node: ast::Static) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let body = node.body().map(|x| self.emit_expr(x)); + let name = node.name().map(|x| self.emit_name(x)); + let ty = node.ty().map(|x| self.emit_type(x)); + let visibility = node.visibility().map(|x| self.emit_visibility(x)); + let label = self.trap.emit(generated::Static { + id: TrapId::Star, + attrs, + body, + name, + ty, + visibility, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_stmt_list(&mut self, node: ast::StmtList) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let statements = node.statements().map(|x| self.emit_stmt(x)).collect(); + let tail_expr = node.tail_expr().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::StmtList { + id: TrapId::Star, + attrs, + statements, + tail_expr, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_struct(&mut self, node: ast::Struct) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let field_list = node.field_list().map(|x| self.emit_field_list(x)); + let generic_param_list = node + .generic_param_list() + .map(|x| self.emit_generic_param_list(x)); + let name = node.name().map(|x| self.emit_name(x)); + let visibility = node.visibility().map(|x| self.emit_visibility(x)); + let where_clause = node.where_clause().map(|x| self.emit_where_clause(x)); + let label = self.trap.emit(generated::Struct { + id: TrapId::Star, + attrs, + field_list, + generic_param_list, + name, + visibility, + where_clause, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_token_tree(&mut self, node: ast::TokenTree) -> Label { + let label = self.trap.emit(generated::TokenTree { id: TrapId::Star }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_trait(&mut self, node: ast::Trait) -> Label { + let assoc_item_list = node.assoc_item_list().map(|x| self.emit_assoc_item_list(x)); + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let generic_param_list = node + .generic_param_list() + .map(|x| self.emit_generic_param_list(x)); + let name = node.name().map(|x| self.emit_name(x)); + let type_bound_list = node.type_bound_list().map(|x| self.emit_type_bound_list(x)); + let visibility = node.visibility().map(|x| self.emit_visibility(x)); + let where_clause = node.where_clause().map(|x| self.emit_where_clause(x)); + let label = self.trap.emit(generated::Trait { + id: TrapId::Star, + assoc_item_list, + attrs, + generic_param_list, + name, + type_bound_list, + visibility, + where_clause, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_trait_alias( + &mut self, + node: ast::TraitAlias, + ) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let generic_param_list = node + .generic_param_list() + .map(|x| self.emit_generic_param_list(x)); + let name = node.name().map(|x| self.emit_name(x)); + let type_bound_list = node.type_bound_list().map(|x| self.emit_type_bound_list(x)); + let visibility = node.visibility().map(|x| self.emit_visibility(x)); + let where_clause = node.where_clause().map(|x| self.emit_where_clause(x)); + let label = self.trap.emit(generated::TraitAlias { + id: TrapId::Star, + attrs, + generic_param_list, + name, + type_bound_list, + visibility, + where_clause, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_try_expr(&mut self, node: ast::TryExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let expr = node.expr().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::TryExpr { + id: TrapId::Star, + attrs, + expr, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_tuple_expr(&mut self, node: ast::TupleExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let fields = node.fields().map(|x| self.emit_expr(x)).collect(); + let label = self.trap.emit(generated::TupleExpr { + id: TrapId::Star, + attrs, + fields, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_tuple_field( + &mut self, + node: ast::TupleField, + ) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let ty = node.ty().map(|x| self.emit_type(x)); + let visibility = node.visibility().map(|x| self.emit_visibility(x)); + let label = self.trap.emit(generated::TupleField { + id: TrapId::Star, + attrs, + ty, + visibility, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_tuple_field_list( + &mut self, + node: ast::TupleFieldList, + ) -> Label { + let fields = node.fields().map(|x| self.emit_tuple_field(x)).collect(); + let label = self.trap.emit(generated::TupleFieldList { + id: TrapId::Star, + fields, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_tuple_pat(&mut self, node: ast::TuplePat) -> Label { + let fields = node.fields().map(|x| self.emit_pat(x)).collect(); + let label = self.trap.emit(generated::TuplePat { + id: TrapId::Star, + fields, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_tuple_struct_pat( + &mut self, + node: ast::TupleStructPat, + ) -> Label { + let fields = node.fields().map(|x| self.emit_pat(x)).collect(); + let path = node.path().map(|x| self.emit_path(x)); + let label = self.trap.emit(generated::TupleStructPat { + id: TrapId::Star, + fields, + path, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_tuple_type(&mut self, node: ast::TupleType) -> Label { + let fields = node.fields().map(|x| self.emit_type(x)).collect(); + let label = self.trap.emit(generated::TupleType { + id: TrapId::Star, + fields, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_type_alias(&mut self, node: ast::TypeAlias) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let generic_param_list = node + .generic_param_list() + .map(|x| self.emit_generic_param_list(x)); + let name = node.name().map(|x| self.emit_name(x)); + let ty = node.ty().map(|x| self.emit_type(x)); + let type_bound_list = node.type_bound_list().map(|x| self.emit_type_bound_list(x)); + let visibility = node.visibility().map(|x| self.emit_visibility(x)); + let where_clause = node.where_clause().map(|x| self.emit_where_clause(x)); + let label = self.trap.emit(generated::TypeAlias { + id: TrapId::Star, + attrs, + generic_param_list, + name, + ty, + type_bound_list, + visibility, + where_clause, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_type_arg(&mut self, node: ast::TypeArg) -> Label { + let ty = node.ty().map(|x| self.emit_type(x)); + let label = self.trap.emit(generated::TypeArg { + id: TrapId::Star, + ty, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_type_bound(&mut self, node: ast::TypeBound) -> Label { + let generic_param_list = node + .generic_param_list() + .map(|x| self.emit_generic_param_list(x)); + let lifetime = node.lifetime().map(|x| self.emit_lifetime(x)); + let ty = node.ty().map(|x| self.emit_type(x)); + let label = self.trap.emit(generated::TypeBound { + id: TrapId::Star, + generic_param_list, + lifetime, + ty, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_type_bound_list( + &mut self, + node: ast::TypeBoundList, + ) -> Label { + let bounds = node.bounds().map(|x| self.emit_type_bound(x)).collect(); + let label = self.trap.emit(generated::TypeBoundList { + id: TrapId::Star, + bounds, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_type_param(&mut self, node: ast::TypeParam) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let default_type = node.default_type().map(|x| self.emit_type(x)); + let name = node.name().map(|x| self.emit_name(x)); + let type_bound_list = node.type_bound_list().map(|x| self.emit_type_bound_list(x)); + let label = self.trap.emit(generated::TypeParam { + id: TrapId::Star, + attrs, + default_type, + name, + type_bound_list, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_underscore_expr( + &mut self, + node: ast::UnderscoreExpr, + ) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let label = self.trap.emit(generated::UnderscoreExpr { + id: TrapId::Star, + attrs, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_union(&mut self, node: ast::Union) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let generic_param_list = node + .generic_param_list() + .map(|x| self.emit_generic_param_list(x)); + let name = node.name().map(|x| self.emit_name(x)); + let record_field_list = node + .record_field_list() + .map(|x| self.emit_record_field_list(x)); + let visibility = node.visibility().map(|x| self.emit_visibility(x)); + let where_clause = node.where_clause().map(|x| self.emit_where_clause(x)); + let label = self.trap.emit(generated::Union { + id: TrapId::Star, + attrs, + generic_param_list, + name, + record_field_list, + visibility, + where_clause, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_use(&mut self, node: ast::Use) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let use_tree = node.use_tree().map(|x| self.emit_use_tree(x)); + let visibility = node.visibility().map(|x| self.emit_visibility(x)); + let label = self.trap.emit(generated::Use { + id: TrapId::Star, + attrs, + use_tree, + visibility, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_use_tree(&mut self, node: ast::UseTree) -> Label { + let path = node.path().map(|x| self.emit_path(x)); + let rename = node.rename().map(|x| self.emit_rename(x)); + let use_tree_list = node.use_tree_list().map(|x| self.emit_use_tree_list(x)); + let label = self.trap.emit(generated::UseTree { + id: TrapId::Star, + path, + rename, + use_tree_list, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_use_tree_list( + &mut self, + node: ast::UseTreeList, + ) -> Label { + let use_trees = node.use_trees().map(|x| self.emit_use_tree(x)).collect(); + let label = self.trap.emit(generated::UseTreeList { + id: TrapId::Star, + use_trees, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_variant(&mut self, node: ast::Variant) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let expr = node.expr().map(|x| self.emit_expr(x)); + let field_list = node.field_list().map(|x| self.emit_field_list(x)); + let name = node.name().map(|x| self.emit_name(x)); + let visibility = node.visibility().map(|x| self.emit_visibility(x)); + let label = self.trap.emit(generated::Variant { + id: TrapId::Star, + attrs, + expr, + field_list, + name, + visibility, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_variant_list( + &mut self, + node: ast::VariantList, + ) -> Label { + let variants = node.variants().map(|x| self.emit_variant(x)).collect(); + let label = self.trap.emit(generated::VariantList { + id: TrapId::Star, + variants, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_visibility( + &mut self, + node: ast::Visibility, + ) -> Label { + let path = node.path().map(|x| self.emit_path(x)); + let label = self.trap.emit(generated::Visibility { + id: TrapId::Star, + path, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_where_clause( + &mut self, + node: ast::WhereClause, + ) -> Label { + let predicates = node.predicates().map(|x| self.emit_where_pred(x)).collect(); + let label = self.trap.emit(generated::WhereClause { + id: TrapId::Star, + predicates, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_where_pred(&mut self, node: ast::WherePred) -> Label { + let generic_param_list = node + .generic_param_list() + .map(|x| self.emit_generic_param_list(x)); + let lifetime = node.lifetime().map(|x| self.emit_lifetime(x)); + let ty = node.ty().map(|x| self.emit_type(x)); + let type_bound_list = node.type_bound_list().map(|x| self.emit_type_bound_list(x)); + let label = self.trap.emit(generated::WherePred { + id: TrapId::Star, + generic_param_list, + lifetime, + ty, + type_bound_list, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_while_expr(&mut self, node: ast::WhileExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let condition = node.condition().map(|x| self.emit_expr(x)); + let label = node.label().map(|x| self.emit_label(x)); + let loop_body = node.loop_body().map(|x| self.emit_block_expr(x)); + let label = self.trap.emit(generated::WhileExpr { + id: TrapId::Star, + attrs, + condition, + label, + loop_body, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_wildcard_pat( + &mut self, + node: ast::WildcardPat, + ) -> Label { + let label = self.trap.emit(generated::WildcardPat { id: TrapId::Star }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_yeet_expr(&mut self, node: ast::YeetExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let expr = node.expr().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::YeetExpr { + id: TrapId::Star, + attrs, + expr, + }); + self.emit_location(label, node); + label + } + + pub(crate) fn emit_yield_expr(&mut self, node: ast::YieldExpr) -> Label { + let attrs = node.attrs().map(|x| self.emit_attr(x)).collect(); + let expr = node.expr().map(|x| self.emit_expr(x)); + let label = self.trap.emit(generated::YieldExpr { + id: TrapId::Star, + attrs, + expr, + }); + self.emit_location(label, node); + label + } +} diff --git a/rust/extractor/src/trap.rs b/rust/extractor/src/trap.rs index 6ad1742557dc..0d549ea4dc7a 100644 --- a/rust/extractor/src/trap.rs +++ b/rust/extractor/src/trap.rs @@ -128,19 +128,25 @@ pub struct TrapFile { compression: Compression, } +#[derive(Copy, Clone)] +pub enum DiagnosticSeverity { + Debug = 10, + Info = 20, + Warning = 30, + Error = 40, +} impl TrapFile { - pub fn emit_location( + pub fn emit_location_label( &mut self, file_label: UntypedLabel, - entity_label: Label, start: LineCol, end: LineCol, - ) { + ) -> UntypedLabel { let start_line = 1 + start.line as usize; let start_column = 1 + start.col as usize; let end_line = 1 + end.line as usize; let end_column = 1 + end.col as usize; - let location_label = extractor::location_label( + extractor::location_label( &mut self.writer, trap::Location { file_label, @@ -149,13 +155,43 @@ impl TrapFile { end_line, end_column, }, - ); + ) + } + pub fn emit_location( + &mut self, + file_label: UntypedLabel, + entity_label: Label, + start: LineCol, + end: LineCol, + ) { + let location_label = self.emit_location_label(file_label, start, end); self.writer.add_tuple( "locatable_locations", vec![entity_label.into(), location_label.into()], ); } + pub fn emit_diagnostic( + &mut self, + severity: DiagnosticSeverity, + error_tag: String, + error_message: String, + full_error_message: String, + location: UntypedLabel, + ) { + let label = self.writer.fresh_id(); + self.writer.add_tuple( + "diagnostics", + vec![ + trap::Arg::Label(label), + trap::Arg::Int(severity as usize), + trap::Arg::String(error_tag), + trap::Arg::String(error_message), + trap::Arg::String(full_error_message), + trap::Arg::Label(location), + ], + ); + } pub fn emit_file(&mut self, absolute_path: &Path) -> trap::Label { extractor::populate_file(&mut self.writer, absolute_path) } diff --git a/rust/generate-schema/src/main.rs b/rust/generate-schema/src/main.rs index 084faa51039e..956e2b1c0422 100644 --- a/rust/generate-schema/src/main.rs +++ b/rust/generate-schema/src/main.rs @@ -53,6 +53,10 @@ fn write_schema( super_types: BTreeMap>, ) -> std::io::Result { let mut buf: Vec = Vec::new(); + writeln!( + buf, + "# Generated by `cargo generate-schema`, do not edit by hand.\n" + )?; writeln!(buf, "from .prelude import *\n")?; for node in &grammar.enums { @@ -402,14 +406,33 @@ fn get_fields(node: &AstNodeSrc) -> Vec { fn write_extractor(grammar: &AstSrc) -> std::io::Result { let mut buf: Vec = Vec::new(); + writeln!( + buf, + "//! Generated by `cargo generate-schema`, do not edit by hand.\n +use crate::generated; +use super::base::{{TextValue, Translator}}; +use crate::trap::{{Label, TrapId}}; +use ra_ap_syntax::ast; +use ra_ap_syntax::ast::{{ + HasArgList, HasAttrs, HasGenericArgs, HasGenericParams, HasLoopBody, HasModuleItem, HasName, + HasTypeBounds, HasVisibility, RangeItem, +}}; +impl Translator {{ + fn emit_else_branch(&mut self, node: ast::ElseBranch) -> Label {{ + match node {{ + ast::ElseBranch::IfExpr(inner) => self.emit_if_expr(inner).into(), + ast::ElseBranch::Block(inner) => self.emit_block_expr(inner).into(), + }} + }}\n" + )?; for node in &grammar.enums { let type_name = &node.name; let class_name = class_name(&node.name); writeln!( buf, - " fn emit_{}(&mut self, node: ast::{}) -> Label {{", + " pub(crate) fn emit_{}(&mut self, node: ast::{}) -> Label {{", to_lower_snake_case(type_name), type_name, class_name @@ -434,7 +457,7 @@ fn write_extractor(grammar: &AstSrc) -> std::io::Result { writeln!( buf, - " fn emit_{}(&mut self, node: ast::{}) -> Label {{", + " pub(crate) fn emit_{}(&mut self, node: ast::{}) -> Label {{", to_lower_snake_case(type_name), type_name, class_name @@ -491,6 +514,7 @@ fn write_extractor(grammar: &AstSrc) -> std::io::Result { writeln!(buf, " }}\n")?; } + writeln!(buf, "}}")?; Ok(String::from_utf8_lossy(&buf).into_owned()) } @@ -523,13 +547,21 @@ fn main() -> std::io::Result<()> { }); let schema = write_schema(&grammar, super_types)?; let schema_path = PathBuf::from("../schema/ast.py"); - let extractor = write_extractor(&grammar)?; - print!("{}", extractor); codegen::ensure_file_contents( crate::flags::CodegenType::Grammar, &schema_path, &schema, false, ); + + let extractor = write_extractor(&grammar)?; + let extractor_path = PathBuf::from("../extractor/src/translate/generated.rs"); + codegen::ensure_file_contents( + crate::flags::CodegenType::Grammar, + &extractor_path, + &extractor, + false, + ); + Ok(()) } diff --git a/rust/ql/.generated.list b/rust/ql/.generated.list index 0d4ebbc8fe3b..c6ea61cfc834 100644 --- a/rust/ql/.generated.list +++ b/rust/ql/.generated.list @@ -176,7 +176,6 @@ lib/codeql/rust/elements/internal/AwaitExprImpl.qll 97eb9abc0f30ead9385f31c87b46 lib/codeql/rust/elements/internal/BecomeExprConstructor.qll ba073aaa256cb8827a0307c3128d50f62b11aac0b1f324e48c95f30351a9b942 3a787ded505c3158fa4f4923f66e8ecdcb7b5f86f27f64c5412dc32dca031f18 lib/codeql/rust/elements/internal/BecomeExprImpl.qll 8522410257ca9ff09e5314c3a39fba02f6ba18e1d4349b91f8823586317f3e47 073a877a6d72c5b762aac64cdd843fd2872aaefb9e264fb90eac8c25753a6e07 lib/codeql/rust/elements/internal/BinaryExprConstructor.qll 7f9b17757f78b9fb7c46e21d2040a77fa50083bef4911c8464991c3d1ad91d87 a59390cd8e896c0bfbdc9ba0674e06d980ffcefa710fbc9886be52ed427e9717 -lib/codeql/rust/elements/internal/BinaryExprImpl.qll 6e22b183edc36083c45a03a600da6ea995563268ecdcdd4980b612fb8c3e7d33 7d8f32500f1edf8e9b8a725a640605e2ecfd88f21ad09d10f81b0ac18f27360d lib/codeql/rust/elements/internal/BlockExprConstructor.qll 438337c807645e98a01440f3f4610d68b0567ba15c8f51dc43bf5a30c9af3696 48ce7a546910c884619762349b8ada9836284f8008298fdb0070a38f7ddf25a0 lib/codeql/rust/elements/internal/BlockExprImpl.qll 36ac09e4a6eeeec22919b62b1d004bdb5bb2527e67932c308aec383a770768d6 3b4b2a2014f6fe075c63a2d633b297566b548ef2e4343cadf067a9edbcadc876 lib/codeql/rust/elements/internal/BoxPatConstructor.qll 153f110ba25fd6c889092bfd16f73bb610fa60d6e0c8965d5f44d2446fcd48a2 9324cf0d8aa29945551bf8ab64801d598f57aab8cd4e19bcd4e9ef8a4a4e06eb @@ -287,7 +286,6 @@ lib/codeql/rust/elements/internal/MatchArmImpl.qll 065dff16fc70b51924eb4db57be12 lib/codeql/rust/elements/internal/MatchArmListConstructor.qll 8bc5ac978fe1158ef70d0ac06bdad9e02aadd657decb64abcc4ea03f6715a87a 4604ab0e524d0de6e19c16711b713f2090c95a8708909816a2b046f1bd83fe24 lib/codeql/rust/elements/internal/MatchArmListImpl.qll 896c6f1650e7ceb60d0b3d90e2b95fe7f8dc529203ddfec58edb063fa9b2871f a668fed1eb68806abfb021913786168d124de47b25da470e7b57f56bf8556891 lib/codeql/rust/elements/internal/MatchExprConstructor.qll 0355ca543a0f9ad56697bc2e1e2511fa3f233bc1f6344d9e1c2369106901c696 78622807a1c4bff61b751c715639510146c7a713e0c4f63246e9a2cf302f4875 -lib/codeql/rust/elements/internal/MatchExprImpl.qll 2f933805bbe6f2676501c1c72ce1dbcffb0acff34883fa7b423b1a20eaf58afb 56f1c727f327717afc48c1dc505241d56c46e84094395ca32a33824cf64ebdce lib/codeql/rust/elements/internal/MatchGuardConstructor.qll d4cae02d2902fe8d3cb6b9c2796137863f41f55840f6623935a1c99df43f28d8 0c89f2ca71a2fd5a3f365291e784cb779e34ba0542d9285515e1856424cec60d lib/codeql/rust/elements/internal/MatchGuardImpl.qll 77453be572769507e6515e622e6c874a875464c2ade8bcd89ef447bdc4649062 86cdf08b0ac5ff9a865ab52eae535d8c4e7d341bc79d422e123af5b8f593ad22 lib/codeql/rust/elements/internal/MetaConstructor.qll 49ab9aafdcab7785fc5fc9fb8f7c5bb0ae76cf85d0d259c4b3ac4b0eccbbeb56 bc11aef22661077e398b6ca75e3701fd8d0ac94a0e96dc556a6f6de4089d8b8c @@ -330,7 +328,6 @@ lib/codeql/rust/elements/internal/PathSegmentImpl.qll f8679dc63f0d71d412c3e1ce76 lib/codeql/rust/elements/internal/PathTypeConstructor.qll 8949742c7ab7fcfa3a3f6469e87355a6888931ab9ac7a6a07d2bd51e3fdf8283 fb1a402e94e9a1f33b7757338d7e95b107933339615a4fe86de33e41206dd94a lib/codeql/rust/elements/internal/PathTypeImpl.qll 0e3b85df054d1194505796e457ee31a8dac2a2a77284c077cbf1a3bfc179294e c198d4fdf8d1d55f1cf57685a9ad2adf88cc2d6d4f84bafa1e9f039192761399 lib/codeql/rust/elements/internal/PrefixExprConstructor.qll 90c50b0df2d4b4cbf5e2b7d67a9d243a1af9bfff660b7a70d8b9c7859c28bca7 1a1b5ea1f06ed8d41a658c872e8e1915c241a7c799c691df81b9a7b55d8f2f1e -lib/codeql/rust/elements/internal/PrefixExprImpl.qll f3c6a88cead13fb88f5be170123e9d5fc0819e6626602c42d38e756ef5a46213 e5cd78e6a77484e164334befd533d52e4de00c0c3b30dd2fa03f412f669cf369 lib/codeql/rust/elements/internal/PtrTypeConstructor.qll ee3c4326ea3f198d2537a914dd6eb51d0cf247310f037e13e87632fbd6cfb50a 3814218b5271f3c6c45b52082cca2a3250a2573abced43fe53e1b4145374afe3 lib/codeql/rust/elements/internal/PtrTypeImpl.qll ff4283ffab39b4a3c0e55e7d655dfdb846171cde0907bf1f893c86b35d2c1135 e54d3a6fb0b5a1484f00fd5a4631455902bab80642c3bb076e538ddcc29a85a4 lib/codeql/rust/elements/internal/RangeExprConstructor.qll a0aa90a1c38c5deea56475399016afae2a00a858b961fbbab8ddeb3bc6a08103 0ddf1bcf28aafc56d7334e6138fb268f9b36a429e4cbdd982cd8384e0644076b diff --git a/rust/ql/.gitattributes b/rust/ql/.gitattributes index 8c303421256b..6f1e154b8be8 100644 --- a/rust/ql/.gitattributes +++ b/rust/ql/.gitattributes @@ -178,7 +178,6 @@ /lib/codeql/rust/elements/internal/BecomeExprConstructor.qll linguist-generated /lib/codeql/rust/elements/internal/BecomeExprImpl.qll linguist-generated /lib/codeql/rust/elements/internal/BinaryExprConstructor.qll linguist-generated -/lib/codeql/rust/elements/internal/BinaryExprImpl.qll linguist-generated /lib/codeql/rust/elements/internal/BlockExprConstructor.qll linguist-generated /lib/codeql/rust/elements/internal/BlockExprImpl.qll linguist-generated /lib/codeql/rust/elements/internal/BoxPatConstructor.qll linguist-generated @@ -289,7 +288,6 @@ /lib/codeql/rust/elements/internal/MatchArmListConstructor.qll linguist-generated /lib/codeql/rust/elements/internal/MatchArmListImpl.qll linguist-generated /lib/codeql/rust/elements/internal/MatchExprConstructor.qll linguist-generated -/lib/codeql/rust/elements/internal/MatchExprImpl.qll linguist-generated /lib/codeql/rust/elements/internal/MatchGuardConstructor.qll linguist-generated /lib/codeql/rust/elements/internal/MatchGuardImpl.qll linguist-generated /lib/codeql/rust/elements/internal/MetaConstructor.qll linguist-generated @@ -332,7 +330,6 @@ /lib/codeql/rust/elements/internal/PathTypeConstructor.qll linguist-generated /lib/codeql/rust/elements/internal/PathTypeImpl.qll linguist-generated /lib/codeql/rust/elements/internal/PrefixExprConstructor.qll linguist-generated -/lib/codeql/rust/elements/internal/PrefixExprImpl.qll linguist-generated /lib/codeql/rust/elements/internal/PtrTypeConstructor.qll linguist-generated /lib/codeql/rust/elements/internal/PtrTypeImpl.qll linguist-generated /lib/codeql/rust/elements/internal/RangeExprConstructor.qll linguist-generated diff --git a/rust/ql/consistency-queries/CfgConsistency.ql b/rust/ql/consistency-queries/CfgConsistency.ql new file mode 100644 index 000000000000..6bcf8d88201c --- /dev/null +++ b/rust/ql/consistency-queries/CfgConsistency.ql @@ -0,0 +1,19 @@ +import rust +import codeql.rust.controlflow.internal.ControlFlowGraphImpl::Consistency +import codeql.rust.controlflow.internal.ControlFlowGraphImpl as CfgImpl +import codeql.rust.controlflow.internal.Completion + +/** + * All `Expr` nodes are `PostOrderTree`s + */ +query predicate nonPostOrderExpr(Expr e, string cls) { + cls = e.getPrimaryQlClasses() and + not e instanceof LetExpr and + not e instanceof LogicalAndExpr and // todo + not e instanceof LogicalOrExpr and + exists(AstNode last, Completion c | + CfgImpl::last(e, last, c) and + last != e and + c instanceof NormalCompletion + ) +} diff --git a/rust/ql/consistency-queries/Placeholder.ql b/rust/ql/consistency-queries/Placeholder.ql deleted file mode 100644 index 8e8965e4052a..000000000000 --- a/rust/ql/consistency-queries/Placeholder.ql +++ /dev/null @@ -1,3 +0,0 @@ -from boolean b -where b = true and b = false -select b diff --git a/rust/ql/lib/codeql/rust/Diagnostics.qll b/rust/ql/lib/codeql/rust/Diagnostics.qll new file mode 100644 index 000000000000..5902bb594141 --- /dev/null +++ b/rust/ql/lib/codeql/rust/Diagnostics.qll @@ -0,0 +1,54 @@ +/** Provides classes relating to extraction diagnostics. */ + +private import codeql.Locations + +/** A diagnostic emitted during extraction, such as a parse error */ +class Diagnostic extends @diagnostic { + int severity; + string tag; + string message; + string fullMessage; + Location location; + + Diagnostic() { diagnostics(this, severity, tag, message, fullMessage, location) } + + /** + * Gets the numerical severity level associated with this diagnostic. + */ + int getSeverity() { result = severity } + + /** Gets a string representation of the severity of this diagnostic. */ + string getSeverityText() { + severity = 10 and result = "Debug" + or + severity = 20 and result = "Info" + or + severity = 30 and result = "Warning" + or + severity = 40 and result = "Error" + } + + /** Gets the error code associated with this diagnostic, e.g. parse_error. */ + string getTag() { result = tag } + + /** + * Gets the error message text associated with this diagnostic. + */ + string getMessage() { result = message } + + /** + * Gets the full error message text associated with this diagnostic. + */ + string getFullMessage() { result = fullMessage } + + /** Gets the source location of this diagnostic. */ + Location getLocation() { result = location } + + /** Gets a textual representation of this diagnostic. */ + string toString() { result = this.getMessage() } +} + +/** A diagnostic relating to a particular error in extracting a file. */ +class ExtractionError extends Diagnostic { + ExtractionError() { this.getTag() = "parse_error" } +} diff --git a/rust/ql/lib/codeql/rust/controlflow/ControlFlowGraph.qll b/rust/ql/lib/codeql/rust/controlflow/ControlFlowGraph.qll index e8e6e5f98c9d..18159ccea748 100644 --- a/rust/ql/lib/codeql/rust/controlflow/ControlFlowGraph.qll +++ b/rust/ql/lib/codeql/rust/controlflow/ControlFlowGraph.qll @@ -9,6 +9,20 @@ private import BasicBlocks final class CfgScope = Scope::CfgScope; +final class SuccessorType = SuccessorTypeImpl; + +final class NormalSuccessor = NormalSuccessorImpl; + +final class ConditionalSuccessor = ConditionalSuccessorImpl; + +final class BooleanSuccessor = BooleanSuccessorImpl; + +final class MatchSuccessor = MatchSuccessorImpl; + +final class LoopJumpSuccessor = LoopJumpSuccessorImpl; + +final class ReturnSuccessor = ReturnSuccessorImpl; + /** * A control flow node. * diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll index 99b36e10c847..2e168c0abd54 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll @@ -3,7 +3,7 @@ private import codeql.rust.controlflow.ControlFlowGraph private import rust private import SuccessorType -private newtype TCompletion = +newtype TCompletion = TSimpleCompletion() or TBooleanCompletion(Boolean b) or TMatchCompletion(Boolean isMatch) or diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index bde6ecdc6631..41a47f172c65 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -1,11 +1,10 @@ private import rust import codeql.controlflow.Cfg import Completion -import codeql.controlflow.Cfg -private import SuccessorType as ST private import Scope as Scope +private import codeql.rust.controlflow.ControlFlowGraph as Cfg -module CfgInput implements InputSig { +private module CfgInput implements InputSig { private import rust as Rust private import Completion as C private import Splitting as S @@ -29,7 +28,7 @@ module CfgInput implements InputSig { class Split = S::Split; - class SuccessorType = ST::SuccessorType; + class SuccessorType = Cfg::SuccessorType; /** Gets a successor type that matches completion `c`. */ SuccessorType getAMatchingSuccessorType(Completion c) { result = c.getAMatchingSuccessorType() } @@ -37,13 +36,13 @@ module CfgInput implements InputSig { /** * Hold if `c` represents simple (normal) evaluation of a statement or an expression. */ - predicate successorTypeIsSimple(SuccessorType t) { t instanceof ST::NormalSuccessor } + predicate successorTypeIsSimple(SuccessorType t) { t instanceof Cfg::NormalSuccessor } /** Holds if `t` is an abnormal exit type out of a CFG scope. */ predicate isAbnormalExitType(SuccessorType t) { none() } /** Hold if `t` represents a conditional successor type. */ - predicate successorTypeIsCondition(SuccessorType t) { t instanceof ST::BooleanSuccessor } + predicate successorTypeIsCondition(SuccessorType t) { t instanceof Cfg::BooleanSuccessor } /** Gets the maximum number of splits allowed for a given node. */ int maxSplits() { result = 0 } @@ -74,7 +73,7 @@ class BecomeExprTree extends StandardPostOrderTree instanceof BecomeExpr { } class BinaryOpExprTree extends StandardPostOrderTree instanceof BinaryExpr { - BinaryOpExprTree() { super.getOperatorName() != "&&" and super.getOperatorName() != "||" } + BinaryOpExprTree() { not this instanceof BinaryLogicalOperation } override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getLhs() @@ -83,61 +82,53 @@ class BinaryOpExprTree extends StandardPostOrderTree instanceof BinaryExpr { } } -class LogicalOrBinaryOpExprTree extends PreOrderTree instanceof BinaryExpr { - LogicalOrBinaryOpExprTree() { super.getOperatorName() = "||" } - - final override predicate propagatesAbnormal(AstNode child) { - child = [super.getRhs(), super.getLhs()] - } +class LogicalOrBinaryOpExprTree extends PreOrderTree, LogicalOrExpr { + final override predicate propagatesAbnormal(AstNode child) { child = this.getAnOperand() } override predicate succ(AstNode pred, AstNode succ, Completion c) { // Edge to the first node in the lhs pred = this and - first(super.getLhs(), succ) and + first(this.getLhs(), succ) and completionIsSimple(c) or // Edge from the last node in the lhs to the first node in the rhs - last(super.getLhs(), pred, c) and - first(super.getRhs(), succ) and + last(this.getLhs(), pred, c) and + first(this.getRhs(), succ) and c.(BooleanCompletion).failed() } override predicate last(AstNode node, Completion c) { // Lhs. as the last node - last(super.getLhs(), node, c) and + last(this.getLhs(), node, c) and c.(BooleanCompletion).succeeded() or // Rhs. as the last node - last(super.getRhs(), node, c) + last(this.getRhs(), node, c) } } -class LogicalAndBinaryOpExprTree extends PreOrderTree instanceof BinaryExpr { - LogicalAndBinaryOpExprTree() { super.getOperatorName() = "&&" } - - final override predicate propagatesAbnormal(AstNode child) { - child = [super.getRhs(), super.getLhs()] - } +class LogicalAndBinaryOpExprTree extends PreOrderTree, LogicalAndExpr { + final override predicate propagatesAbnormal(AstNode child) { child = this.getAnOperand() } override predicate succ(AstNode pred, AstNode succ, Completion c) { // Edge to the first node in the lhs pred = this and - first(super.getLhs(), succ) and + first(this.getLhs(), succ) and completionIsSimple(c) or // Edge from the last node in the lhs to the first node in the rhs - last(super.getLhs(), pred, c) and - first(super.getRhs(), succ) and + last(this.getLhs(), pred, c) and + first(this.getRhs(), succ) and c.(BooleanCompletion).succeeded() } override predicate last(AstNode node, Completion c) { // Lhs. as the last node - last(super.getLhs(), node, c) and + last(this.getLhs(), node, c) and c.(BooleanCompletion).failed() or // Rhs. as the last node - last(super.getRhs(), node, c) + last(this.getRhs(), node, c) } } @@ -357,24 +348,24 @@ class MatchArmTree extends ControlFlowTree instanceof MatchArm { class MatchExprTree extends PostOrderTree instanceof MatchExpr { override predicate propagatesAbnormal(AstNode child) { - child = [super.getExpr(), super.getMatchArmList().getAnArm().getExpr()] + child = [super.getExpr(), super.getAnArm().getExpr()] } override predicate first(AstNode node) { first(super.getExpr(), node) } override predicate succ(AstNode pred, AstNode succ, Completion c) { // Edge from the scrutinee to the first arm. - last(super.getExpr(), pred, c) and succ = super.getMatchArmList().getArm(0).getPat() + last(super.getExpr(), pred, c) and succ = super.getArm(0).getPat() or // Edge from a failed match/guard in one arm to the beginning of the next arm. exists(int i | - last(super.getMatchArmList().getArm(i), pred, c) and - first(super.getMatchArmList().getArm(i + 1), succ) and + last(super.getArm(i), pred, c) and + first(super.getArm(i + 1), succ) and c.(ConditionalCompletion).failed() ) or // Edge from the end of each arm to the match expression. - last(super.getMatchArmList().getArm(_), pred, c) and succ = this and completionIsNormal(c) + last(super.getArm(_).getExpr(), pred, c) and succ = this and completionIsNormal(c) } } @@ -387,6 +378,10 @@ class MethodCallExprTree extends StandardPostOrderTree instanceof MethodCallExpr class OffsetOfExprTree extends LeafTree instanceof OffsetOfExpr { } +class ParenExprTree extends StandardPostOrderTree, ParenExpr { + override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } +} + // This covers all patterns as they all extend `Pat` class PatExprTree extends LeafTree instanceof Pat { } diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll b/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll index f7743e7275e3..6bdd54c263dd 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll @@ -1,5 +1,6 @@ private import rust private import codeql.util.Boolean +private import Completion newtype TLoopJumpType = TContinueJump() or @@ -14,36 +15,34 @@ newtype TSuccessorType = TSuccessorSuccessor() or TBooleanSuccessor(Boolean b) or TMatchSuccessor(Boolean b) or - TLoopSuccessor(TLoopJumpType kind, TLabelType label) or + TLoopSuccessor(TLoopJumpType kind, TLabelType label) { exists(TLoopCompletion(kind, label)) } or TReturnSuccessor() /** The type of a control flow successor. */ -abstract private class SuccessorTypeImpl extends TSuccessorType { +abstract class SuccessorTypeImpl extends TSuccessorType { /** Gets a textual representation of successor type. */ abstract string toString(); } -final class SuccessorType = SuccessorTypeImpl; - /** A normal control flow successor. */ -final class NormalSuccessor extends SuccessorTypeImpl, TSuccessorSuccessor { - final override string toString() { result = "successor" } +class NormalSuccessorImpl extends SuccessorTypeImpl, TSuccessorSuccessor { + override string toString() { result = "successor" } } /** A conditional control flow successor. */ -abstract private class ConditionalSuccessor extends SuccessorTypeImpl { +abstract class ConditionalSuccessorImpl extends SuccessorTypeImpl { boolean value; bindingset[value] - ConditionalSuccessor() { any() } + ConditionalSuccessorImpl() { exists(value) } /** Gets the Boolean value of this successor. */ - final boolean getValue() { result = value } + boolean getValue() { result = value } } /** A Boolean control flow successor for a boolean conditon. */ -final class BooleanSuccessor extends ConditionalSuccessor, TBooleanSuccessor { - BooleanSuccessor() { this = TBooleanSuccessor(value) } +class BooleanSuccessorImpl extends ConditionalSuccessorImpl, TBooleanSuccessor { + BooleanSuccessorImpl() { this = TBooleanSuccessor(value) } override string toString() { result = this.getValue().toString() } } @@ -51,8 +50,8 @@ final class BooleanSuccessor extends ConditionalSuccessor, TBooleanSuccessor { /** * A control flow successor of a pattern match. */ -final class MatchSuccessor extends ConditionalSuccessor, TMatchSuccessor { - MatchSuccessor() { this = TMatchSuccessor(value) } +class MatchSuccessorImpl extends ConditionalSuccessorImpl, TMatchSuccessor { + MatchSuccessorImpl() { this = TMatchSuccessor(value) } override string toString() { if this.getValue() = true then result = "match" else result = "no-match" @@ -62,20 +61,20 @@ final class MatchSuccessor extends ConditionalSuccessor, TMatchSuccessor { /** * A control flow successor of a loop control flow expression, `continue` or `break`. */ -final class LoopJumpSuccessor extends SuccessorTypeImpl, TLoopSuccessor { - final private TLoopJumpType getKind() { this = TLoopSuccessor(result, _) } +class LoopJumpSuccessorImpl extends SuccessorTypeImpl, TLoopSuccessor { + private TLoopJumpType getKind() { this = TLoopSuccessor(result, _) } - final private TLabelType getLabelType() { this = TLoopSuccessor(_, result) } + private TLabelType getLabelType() { this = TLoopSuccessor(_, result) } - final predicate hasLabel() { this.getLabelType() = TLabel(_) } + predicate hasLabel() { this.getLabelType() = TLabel(_) } - final string getLabelName() { this = TLoopSuccessor(_, TLabel(result)) } + string getLabelName() { this = TLoopSuccessor(_, TLabel(result)) } - final predicate isContinue() { this.getKind() = TContinueJump() } + predicate isContinue() { this.getKind() = TContinueJump() } - final predicate isBreak() { this.getKind() = TBreakJump() } + predicate isBreak() { this.getKind() = TBreakJump() } - final override string toString() { + override string toString() { exists(string kind, string label | (if this.isContinue() then kind = "continue" else kind = "break") and (if this.hasLabel() then label = "(" + this.getLabelName() + ")" else label = "") and @@ -87,6 +86,6 @@ final class LoopJumpSuccessor extends SuccessorTypeImpl, TLoopSuccessor { /** * A `return` control flow successor. */ -final class ReturnSuccessor extends SuccessorTypeImpl, TReturnSuccessor { - final override string toString() { result = "return" } +class ReturnSuccessorImpl extends SuccessorTypeImpl, TReturnSuccessor { + override string toString() { result = "return" } } diff --git a/rust/ql/lib/codeql/rust/elements/LogicalOperation.qll b/rust/ql/lib/codeql/rust/elements/LogicalOperation.qll new file mode 100644 index 000000000000..fdbfb5d4613a --- /dev/null +++ b/rust/ql/lib/codeql/rust/elements/LogicalOperation.qll @@ -0,0 +1,33 @@ +private import codeql.rust.elements.Expr +private import codeql.rust.elements.BinaryExpr +private import codeql.rust.elements.PrefixExpr + +abstract private class LogicalOperationImpl extends Expr { + abstract Expr getAnOperand(); +} + +final class LogicalOperation = LogicalOperationImpl; + +abstract private class BinaryLogicalOperationImpl extends BinaryExpr, LogicalOperationImpl { + override Expr getAnOperand() { result = [this.getLhs(), this.getRhs()] } +} + +final class BinaryLogicalOperation = BinaryLogicalOperationImpl; + +final class LogicalAndExpr extends BinaryLogicalOperationImpl, BinaryExpr { + LogicalAndExpr() { this.getOperatorName() = "&&" } +} + +final class LogicalOrExpr extends BinaryLogicalOperationImpl { + LogicalOrExpr() { this.getOperatorName() = "||" } +} + +abstract private class UnaryLogicalOperationImpl extends PrefixExpr, LogicalOperationImpl { } + +final class UnaryLogicalOperation = UnaryLogicalOperationImpl; + +final class LogicalNotExpr extends UnaryLogicalOperationImpl { + LogicalNotExpr() { this.getOperatorName() = "!" } + + override Expr getAnOperand() { result = this.getExpr() } +} diff --git a/rust/ql/lib/codeql/rust/elements/internal/BinaryExprImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/BinaryExprImpl.qll index 10490787fc1c..101295e5dc84 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/BinaryExprImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/BinaryExprImpl.qll @@ -1,4 +1,3 @@ -// generated by codegen, remove this comment if you wish to edit this file /** * This module provides a hand-modifiable wrapper around the generated class `BinaryExpr`. * @@ -12,6 +11,7 @@ private import codeql.rust.elements.internal.generated.BinaryExpr * be referenced directly. */ module Impl { + // the following QLdoc is generated: if you need to edit it, do it in the schema file /** * A binary operation expression. For example: * ```rust @@ -22,5 +22,7 @@ module Impl { * x += y; * ``` */ - class BinaryExpr extends Generated::BinaryExpr { } + class BinaryExpr extends Generated::BinaryExpr { + override string toString() { result = "... " + this.getOperatorName() + " ..." } + } } diff --git a/rust/ql/lib/codeql/rust/elements/internal/MatchExprImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/MatchExprImpl.qll index fd2cb793ca81..ebb0b8510678 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/MatchExprImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/MatchExprImpl.qll @@ -1,4 +1,3 @@ -// generated by codegen, remove this comment if you wish to edit this file /** * This module provides a hand-modifiable wrapper around the generated class `MatchExpr`. * @@ -12,6 +11,7 @@ private import codeql.rust.elements.internal.generated.MatchExpr * be referenced directly. */ module Impl { + // the following QLdoc is generated: if you need to edit it, do it in the schema file /** * A match expression. For example: * ```rust @@ -27,5 +27,20 @@ module Impl { * } * ``` */ - class MatchExpr extends Generated::MatchExpr { } + class MatchExpr extends Generated::MatchExpr { + /** + * Gets the `index`th arm of this match expression. + */ + MatchArm getArm(int index) { result = this.getMatchArmList().getArm(index) } + + /** + * Gets any of the arms of this match expression. + */ + MatchArm getAnArm() { result = this.getArm(_) } + + /** + * Gets the number of arms of this match expression. + */ + int getNumberOfArms() { result = this.getMatchArmList().getNumberOfArms() } + } } diff --git a/rust/ql/lib/codeql/rust/elements/internal/PrefixExprImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/PrefixExprImpl.qll index f5878bac274e..51df8a764454 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/PrefixExprImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/PrefixExprImpl.qll @@ -1,4 +1,3 @@ -// generated by codegen, remove this comment if you wish to edit this file /** * This module provides a hand-modifiable wrapper around the generated class `PrefixExpr`. * @@ -12,6 +11,7 @@ private import codeql.rust.elements.internal.generated.PrefixExpr * be referenced directly. */ module Impl { + // the following QLdoc is generated: if you need to edit it, do it in the schema file /** * A unary operation expression. For example: * ```rust @@ -20,5 +20,7 @@ module Impl { * let z = *ptr * ``` */ - class PrefixExpr extends Generated::PrefixExpr { } + class PrefixExpr extends Generated::PrefixExpr { + override string toString() { result = this.getOperatorName() + " ..." } + } } diff --git a/rust/ql/lib/rust.qll b/rust/ql/lib/rust.qll index bdb9f3df374c..72d2bd5498d2 100644 --- a/rust/ql/lib/rust.qll +++ b/rust/ql/lib/rust.qll @@ -3,3 +3,4 @@ import codeql.rust.elements import codeql.Locations import codeql.files.FileSystem +import codeql.rust.elements.LogicalOperation diff --git a/rust/ql/src/queries/diagnostics/ExtractionErrors.ql b/rust/ql/src/queries/diagnostics/ExtractionErrors.ql new file mode 100644 index 000000000000..a04c4e618c41 --- /dev/null +++ b/rust/ql/src/queries/diagnostics/ExtractionErrors.ql @@ -0,0 +1,18 @@ +/** + * @name Extraction errors + * @description List all extraction errors for files in the source code directory. + * @kind diagnostic + * @id rust/diagnostics/extraction-errors + */ + +import codeql.rust.Diagnostics +import codeql.files.FileSystem + +/** Gets the SARIF severity to associate an error. */ +int getSeverity() { result = 2 } + +from ExtractionError error, File f +where + f = error.getLocation().getFile() and + exists(f.getRelativePath()) +select error, "Extraction failed in " + f + " with error " + error.getMessage(), getSeverity() diff --git a/rust/ql/src/queries/summary/NumberOfFilesExtractedWithErrors.ql b/rust/ql/src/queries/summary/NumberOfFilesExtractedWithErrors.ql new file mode 100644 index 000000000000..1af3f0f88ec0 --- /dev/null +++ b/rust/ql/src/queries/summary/NumberOfFilesExtractedWithErrors.ql @@ -0,0 +1,15 @@ +/** + * @id rust/summary/number-of-files-extracted-with-errors + * @name Total number of Rust files that were extracted with errors + * @description The total number of Rust files in the source code directory that + * were extracted, but where at least one extraction error occurred in the process. + * @kind metric + * @tags summary + */ + +import codeql.files.FileSystem +import codeql.rust.Diagnostics + +select count(File f | + exists(ExtractionError e | e.getLocation().getFile() = f) and exists(f.getRelativePath()) + ) diff --git a/rust/ql/src/queries/summary/NumberOfSuccessfullyExtractedFiles.ql b/rust/ql/src/queries/summary/NumberOfSuccessfullyExtractedFiles.ql new file mode 100644 index 000000000000..eb86577b4b80 --- /dev/null +++ b/rust/ql/src/queries/summary/NumberOfSuccessfullyExtractedFiles.ql @@ -0,0 +1,15 @@ +/** + * @id rust/summary/number-of-successfully-extracted-files + * @name Total number of Rust files that were extracted without error + * @description The total number of Rust files in the source code directory that + * were extracted without encountering any extraction errors. + * @kind metric + * @tags summary + */ + +import codeql.rust.Diagnostics +import codeql.files.FileSystem + +select count(File f | + not exists(ExtractionError e | e.getLocation().getFile() = f) and exists(f.getRelativePath()) + ) diff --git a/rust/ql/test/extractor-tests/generated/BinaryExpr/BinaryExpr.expected b/rust/ql/test/extractor-tests/generated/BinaryExpr/BinaryExpr.expected index 0c0061be3efc..2f7a47933b1c 100644 --- a/rust/ql/test/extractor-tests/generated/BinaryExpr/BinaryExpr.expected +++ b/rust/ql/test/extractor-tests/generated/BinaryExpr/BinaryExpr.expected @@ -1,5 +1,5 @@ -| gen_binary_expr.rs:5:5:5:9 | BinaryExpr | getNumberOfAttrs: | 0 | hasLhs: | yes | hasOperatorName: | yes | hasRhs: | yes | -| gen_binary_expr.rs:6:5:6:10 | BinaryExpr | getNumberOfAttrs: | 0 | hasLhs: | yes | hasOperatorName: | yes | hasRhs: | yes | -| gen_binary_expr.rs:7:5:7:10 | BinaryExpr | getNumberOfAttrs: | 0 | hasLhs: | yes | hasOperatorName: | yes | hasRhs: | yes | -| gen_binary_expr.rs:8:5:8:9 | BinaryExpr | getNumberOfAttrs: | 0 | hasLhs: | yes | hasOperatorName: | yes | hasRhs: | yes | -| gen_binary_expr.rs:9:5:9:10 | BinaryExpr | getNumberOfAttrs: | 0 | hasLhs: | yes | hasOperatorName: | yes | hasRhs: | yes | +| gen_binary_expr.rs:5:5:5:9 | ... + ... | getNumberOfAttrs: | 0 | hasLhs: | yes | hasOperatorName: | yes | hasRhs: | yes | +| gen_binary_expr.rs:6:5:6:10 | ... && ... | getNumberOfAttrs: | 0 | hasLhs: | yes | hasOperatorName: | yes | hasRhs: | yes | +| gen_binary_expr.rs:7:5:7:10 | ... <= ... | getNumberOfAttrs: | 0 | hasLhs: | yes | hasOperatorName: | yes | hasRhs: | yes | +| gen_binary_expr.rs:8:5:8:9 | ... = ... | getNumberOfAttrs: | 0 | hasLhs: | yes | hasOperatorName: | yes | hasRhs: | yes | +| gen_binary_expr.rs:9:5:9:10 | ... += ... | getNumberOfAttrs: | 0 | hasLhs: | yes | hasOperatorName: | yes | hasRhs: | yes | diff --git a/rust/ql/test/extractor-tests/generated/BinaryExpr/BinaryExpr_getLhs.expected b/rust/ql/test/extractor-tests/generated/BinaryExpr/BinaryExpr_getLhs.expected index 2eb8f6ef572d..1f51339f5a8f 100644 --- a/rust/ql/test/extractor-tests/generated/BinaryExpr/BinaryExpr_getLhs.expected +++ b/rust/ql/test/extractor-tests/generated/BinaryExpr/BinaryExpr_getLhs.expected @@ -1,5 +1,5 @@ -| gen_binary_expr.rs:5:5:5:9 | BinaryExpr | gen_binary_expr.rs:5:5:5:5 | PathExpr | -| gen_binary_expr.rs:6:5:6:10 | BinaryExpr | gen_binary_expr.rs:6:5:6:5 | PathExpr | -| gen_binary_expr.rs:7:5:7:10 | BinaryExpr | gen_binary_expr.rs:7:5:7:5 | PathExpr | -| gen_binary_expr.rs:8:5:8:9 | BinaryExpr | gen_binary_expr.rs:8:5:8:5 | PathExpr | -| gen_binary_expr.rs:9:5:9:10 | BinaryExpr | gen_binary_expr.rs:9:5:9:5 | PathExpr | +| gen_binary_expr.rs:5:5:5:9 | ... + ... | gen_binary_expr.rs:5:5:5:5 | PathExpr | +| gen_binary_expr.rs:6:5:6:10 | ... && ... | gen_binary_expr.rs:6:5:6:5 | PathExpr | +| gen_binary_expr.rs:7:5:7:10 | ... <= ... | gen_binary_expr.rs:7:5:7:5 | PathExpr | +| gen_binary_expr.rs:8:5:8:9 | ... = ... | gen_binary_expr.rs:8:5:8:5 | PathExpr | +| gen_binary_expr.rs:9:5:9:10 | ... += ... | gen_binary_expr.rs:9:5:9:5 | PathExpr | diff --git a/rust/ql/test/extractor-tests/generated/BinaryExpr/BinaryExpr_getOperatorName.expected b/rust/ql/test/extractor-tests/generated/BinaryExpr/BinaryExpr_getOperatorName.expected index 9f9e191f660a..e55ca0c63a05 100644 --- a/rust/ql/test/extractor-tests/generated/BinaryExpr/BinaryExpr_getOperatorName.expected +++ b/rust/ql/test/extractor-tests/generated/BinaryExpr/BinaryExpr_getOperatorName.expected @@ -1,5 +1,5 @@ -| gen_binary_expr.rs:5:5:5:9 | BinaryExpr | + | -| gen_binary_expr.rs:6:5:6:10 | BinaryExpr | && | -| gen_binary_expr.rs:7:5:7:10 | BinaryExpr | <= | -| gen_binary_expr.rs:8:5:8:9 | BinaryExpr | = | -| gen_binary_expr.rs:9:5:9:10 | BinaryExpr | += | +| gen_binary_expr.rs:5:5:5:9 | ... + ... | + | +| gen_binary_expr.rs:6:5:6:10 | ... && ... | && | +| gen_binary_expr.rs:7:5:7:10 | ... <= ... | <= | +| gen_binary_expr.rs:8:5:8:9 | ... = ... | = | +| gen_binary_expr.rs:9:5:9:10 | ... += ... | += | diff --git a/rust/ql/test/extractor-tests/generated/BinaryExpr/BinaryExpr_getRhs.expected b/rust/ql/test/extractor-tests/generated/BinaryExpr/BinaryExpr_getRhs.expected index 868bf4490b9d..4f0277f2b2f3 100644 --- a/rust/ql/test/extractor-tests/generated/BinaryExpr/BinaryExpr_getRhs.expected +++ b/rust/ql/test/extractor-tests/generated/BinaryExpr/BinaryExpr_getRhs.expected @@ -1,5 +1,5 @@ -| gen_binary_expr.rs:5:5:5:9 | BinaryExpr | gen_binary_expr.rs:5:9:5:9 | PathExpr | -| gen_binary_expr.rs:6:5:6:10 | BinaryExpr | gen_binary_expr.rs:6:10:6:10 | PathExpr | -| gen_binary_expr.rs:7:5:7:10 | BinaryExpr | gen_binary_expr.rs:7:10:7:10 | PathExpr | -| gen_binary_expr.rs:8:5:8:9 | BinaryExpr | gen_binary_expr.rs:8:9:8:9 | PathExpr | -| gen_binary_expr.rs:9:5:9:10 | BinaryExpr | gen_binary_expr.rs:9:10:9:10 | PathExpr | +| gen_binary_expr.rs:5:5:5:9 | ... + ... | gen_binary_expr.rs:5:9:5:9 | PathExpr | +| gen_binary_expr.rs:6:5:6:10 | ... && ... | gen_binary_expr.rs:6:10:6:10 | PathExpr | +| gen_binary_expr.rs:7:5:7:10 | ... <= ... | gen_binary_expr.rs:7:10:7:10 | PathExpr | +| gen_binary_expr.rs:8:5:8:9 | ... = ... | gen_binary_expr.rs:8:9:8:9 | PathExpr | +| gen_binary_expr.rs:9:5:9:10 | ... += ... | gen_binary_expr.rs:9:10:9:10 | PathExpr | diff --git a/rust/ql/test/extractor-tests/generated/ClosureExpr/ClosureExpr_getBody.expected b/rust/ql/test/extractor-tests/generated/ClosureExpr/ClosureExpr_getBody.expected index 3b16f320ced0..71bc3cccda3c 100644 --- a/rust/ql/test/extractor-tests/generated/ClosureExpr/ClosureExpr_getBody.expected +++ b/rust/ql/test/extractor-tests/generated/ClosureExpr/ClosureExpr_getBody.expected @@ -1,5 +1,5 @@ -| gen_closure_expr.rs:5:5:5:13 | ClosureExpr | gen_closure_expr.rs:5:9:5:13 | BinaryExpr | +| gen_closure_expr.rs:5:5:5:13 | ClosureExpr | gen_closure_expr.rs:5:9:5:13 | ... + ... | | gen_closure_expr.rs:6:5:6:34 | ClosureExpr | gen_closure_expr.rs:6:26:6:34 | BlockExpr | -| gen_closure_expr.rs:7:5:7:27 | ClosureExpr | gen_closure_expr.rs:7:23:7:27 | BinaryExpr | +| gen_closure_expr.rs:7:5:7:27 | ClosureExpr | gen_closure_expr.rs:7:23:7:27 | ... + ... | | gen_closure_expr.rs:8:6:9:15 | ClosureExpr | gen_closure_expr.rs:9:9:9:15 | YieldExpr | | gen_closure_expr.rs:10:6:11:23 | ClosureExpr | gen_closure_expr.rs:11:17:11:23 | YieldExpr | diff --git a/rust/ql/test/extractor-tests/generated/IfExpr/IfExpr_getCondition.expected b/rust/ql/test/extractor-tests/generated/IfExpr/IfExpr_getCondition.expected index 4a777a6f762f..7bdb262dd324 100644 --- a/rust/ql/test/extractor-tests/generated/IfExpr/IfExpr_getCondition.expected +++ b/rust/ql/test/extractor-tests/generated/IfExpr/IfExpr_getCondition.expected @@ -1,2 +1,2 @@ -| gen_if_expr.rs:5:5:7:5 | IfExpr | gen_if_expr.rs:5:8:5:14 | BinaryExpr | -| gen_if_expr.rs:8:13:12:5 | IfExpr | gen_if_expr.rs:8:16:8:20 | BinaryExpr | +| gen_if_expr.rs:5:5:7:5 | IfExpr | gen_if_expr.rs:5:8:5:14 | ... == ... | +| gen_if_expr.rs:8:13:12:5 | IfExpr | gen_if_expr.rs:8:16:8:20 | ... > ... | diff --git a/rust/ql/test/extractor-tests/generated/MatchArm/CONSISTENCY/CfgConsistency.expected b/rust/ql/test/extractor-tests/generated/MatchArm/CONSISTENCY/CfgConsistency.expected new file mode 100644 index 000000000000..e558c7c1c28d --- /dev/null +++ b/rust/ql/test/extractor-tests/generated/MatchArm/CONSISTENCY/CfgConsistency.expected @@ -0,0 +1,2 @@ +deadEnd +| gen_match_arm.rs:10:20:10:25 | ... != ... | diff --git a/rust/ql/test/extractor-tests/generated/MatchArm/MatchArm_getExpr.expected b/rust/ql/test/extractor-tests/generated/MatchArm/MatchArm_getExpr.expected index 82984cc9385e..f1779f7b3944 100644 --- a/rust/ql/test/extractor-tests/generated/MatchArm/MatchArm_getExpr.expected +++ b/rust/ql/test/extractor-tests/generated/MatchArm/MatchArm_getExpr.expected @@ -1,4 +1,4 @@ | gen_match_arm.rs:6:9:6:29 | MatchArm | gen_match_arm.rs:6:28:6:28 | PathExpr | | gen_match_arm.rs:7:9:7:26 | MatchArm | gen_match_arm.rs:7:25:7:25 | LiteralExpr | -| gen_match_arm.rs:10:9:10:35 | MatchArm | gen_match_arm.rs:10:30:10:34 | BinaryExpr | +| gen_match_arm.rs:10:9:10:35 | MatchArm | gen_match_arm.rs:10:30:10:34 | ... / ... | | gen_match_arm.rs:11:9:11:15 | MatchArm | gen_match_arm.rs:11:14:11:14 | LiteralExpr | diff --git a/rust/ql/test/extractor-tests/generated/MatchExpr/CONSISTENCY/CfgConsistency.expected b/rust/ql/test/extractor-tests/generated/MatchExpr/CONSISTENCY/CfgConsistency.expected new file mode 100644 index 000000000000..8d6730211c8e --- /dev/null +++ b/rust/ql/test/extractor-tests/generated/MatchExpr/CONSISTENCY/CfgConsistency.expected @@ -0,0 +1,2 @@ +deadEnd +| gen_match_expr.rs:10:20:10:25 | ... != ... | diff --git a/rust/ql/test/extractor-tests/generated/PrefixExpr/PrefixExpr.expected b/rust/ql/test/extractor-tests/generated/PrefixExpr/PrefixExpr.expected index 74b997454980..01ebd0f099ca 100644 --- a/rust/ql/test/extractor-tests/generated/PrefixExpr/PrefixExpr.expected +++ b/rust/ql/test/extractor-tests/generated/PrefixExpr/PrefixExpr.expected @@ -1,3 +1,3 @@ -| gen_prefix_expr.rs:5:13:5:15 | PrefixExpr | getNumberOfAttrs: | 0 | hasExpr: | yes | hasOperatorName: | yes | -| gen_prefix_expr.rs:6:13:6:17 | PrefixExpr | getNumberOfAttrs: | 0 | hasExpr: | yes | hasOperatorName: | yes | -| gen_prefix_expr.rs:7:13:7:16 | PrefixExpr | getNumberOfAttrs: | 0 | hasExpr: | yes | hasOperatorName: | yes | +| gen_prefix_expr.rs:5:13:5:15 | - ... | getNumberOfAttrs: | 0 | hasExpr: | yes | hasOperatorName: | yes | +| gen_prefix_expr.rs:6:13:6:17 | ! ... | getNumberOfAttrs: | 0 | hasExpr: | yes | hasOperatorName: | yes | +| gen_prefix_expr.rs:7:13:7:16 | * ... | getNumberOfAttrs: | 0 | hasExpr: | yes | hasOperatorName: | yes | diff --git a/rust/ql/test/extractor-tests/generated/PrefixExpr/PrefixExpr_getExpr.expected b/rust/ql/test/extractor-tests/generated/PrefixExpr/PrefixExpr_getExpr.expected index 8ba21b74a778..d0ee1d8ce2b2 100644 --- a/rust/ql/test/extractor-tests/generated/PrefixExpr/PrefixExpr_getExpr.expected +++ b/rust/ql/test/extractor-tests/generated/PrefixExpr/PrefixExpr_getExpr.expected @@ -1,3 +1,3 @@ -| gen_prefix_expr.rs:5:13:5:15 | PrefixExpr | gen_prefix_expr.rs:5:14:5:15 | LiteralExpr | -| gen_prefix_expr.rs:6:13:6:17 | PrefixExpr | gen_prefix_expr.rs:6:14:6:17 | LiteralExpr | -| gen_prefix_expr.rs:7:13:7:16 | PrefixExpr | gen_prefix_expr.rs:7:14:7:16 | PathExpr | +| gen_prefix_expr.rs:5:13:5:15 | - ... | gen_prefix_expr.rs:5:14:5:15 | LiteralExpr | +| gen_prefix_expr.rs:6:13:6:17 | ! ... | gen_prefix_expr.rs:6:14:6:17 | LiteralExpr | +| gen_prefix_expr.rs:7:13:7:16 | * ... | gen_prefix_expr.rs:7:14:7:16 | PathExpr | diff --git a/rust/ql/test/extractor-tests/generated/PrefixExpr/PrefixExpr_getOperatorName.expected b/rust/ql/test/extractor-tests/generated/PrefixExpr/PrefixExpr_getOperatorName.expected index a9b0fe4f73c8..0cee9c31bc3f 100644 --- a/rust/ql/test/extractor-tests/generated/PrefixExpr/PrefixExpr_getOperatorName.expected +++ b/rust/ql/test/extractor-tests/generated/PrefixExpr/PrefixExpr_getOperatorName.expected @@ -1,3 +1,3 @@ -| gen_prefix_expr.rs:5:13:5:15 | PrefixExpr | - | -| gen_prefix_expr.rs:6:13:6:17 | PrefixExpr | ! | -| gen_prefix_expr.rs:7:13:7:16 | PrefixExpr | * | +| gen_prefix_expr.rs:5:13:5:15 | - ... | - | +| gen_prefix_expr.rs:6:13:6:17 | ! ... | ! | +| gen_prefix_expr.rs:7:13:7:16 | * ... | * | diff --git a/rust/ql/test/extractor-tests/utf8/ast.expected b/rust/ql/test/extractor-tests/utf8/ast.expected new file mode 100644 index 000000000000..bf1fd078af80 --- /dev/null +++ b/rust/ql/test/extractor-tests/utf8/ast.expected @@ -0,0 +1,39 @@ +| lib.rs:1:1:3:22 | SourceFile | +| lib.rs:2:1:2:8 | Module | +| lib.rs:2:5:2:7 | Name | +| lib.rs:3:1:3:8 | Module | +| lib.rs:3:5:3:8 | Name | +| lib.rs:3:10:3:20 | NameRef | +| lib.rs:3:10:3:20 | Path | +| lib.rs:3:10:3:20 | PathSegment | +| lib.rs:3:10:3:21 | MacroCall | +| utf8-identifiers.rs:1:1:4:6 | foo | +| utf8-identifiers.rs:1:1:12:2 | SourceFile | +| utf8-identifiers.rs:1:4:1:6 | Name | +| utf8-identifiers.rs:1:7:4:1 | GenericParamList | +| utf8-identifiers.rs:2:5:2:6 | Lifetime | +| utf8-identifiers.rs:2:5:2:6 | LifetimeParam | +| utf8-identifiers.rs:3:5:3:5 | Name | +| utf8-identifiers.rs:3:5:3:5 | TypeParam | +| utf8-identifiers.rs:4:2:4:3 | ParamList | +| utf8-identifiers.rs:4:5:4:6 | BlockExpr | +| utf8-identifiers.rs:4:5:4:6 | StmtList | +| utf8-identifiers.rs:6:1:8:1 | Struct | +| utf8-identifiers.rs:6:8:6:8 | Name | +| utf8-identifiers.rs:6:10:8:1 | RecordFieldList | +| utf8-identifiers.rs:7:5:7:5 | Name | +| utf8-identifiers.rs:7:5:7:13 | RecordField | +| utf8-identifiers.rs:7:9:7:13 | NameRef | +| utf8-identifiers.rs:7:9:7:13 | Path | +| utf8-identifiers.rs:7:9:7:13 | PathSegment | +| utf8-identifiers.rs:7:9:7:13 | PathType | +| utf8-identifiers.rs:10:1:10:3 | Visibility | +| utf8-identifiers.rs:10:1:12:1 | main | +| utf8-identifiers.rs:10:8:10:11 | Name | +| utf8-identifiers.rs:10:12:10:13 | ParamList | +| utf8-identifiers.rs:10:15:12:1 | BlockExpr | +| utf8-identifiers.rs:10:15:12:1 | StmtList | +| utf8-identifiers.rs:11:5:11:24 | LetStmt | +| utf8-identifiers.rs:11:9:11:9 | IdentPat | +| utf8-identifiers.rs:11:9:11:9 | Name | +| utf8-identifiers.rs:11:14:11:23 | LiteralExpr | diff --git a/rust/ql/test/extractor-tests/utf8/ast.ql b/rust/ql/test/extractor-tests/utf8/ast.ql new file mode 100644 index 000000000000..420f7e94eb9a --- /dev/null +++ b/rust/ql/test/extractor-tests/utf8/ast.ql @@ -0,0 +1,3 @@ +import codeql.rust.elements + +select any(AstNode n) diff --git a/rust/ql/test/extractor-tests/utf8/utf8-identifiers.rs b/rust/ql/test/extractor-tests/utf8/utf8-identifiers.rs new file mode 100644 index 000000000000..579dc82ab5f0 --- /dev/null +++ b/rust/ql/test/extractor-tests/utf8/utf8-identifiers.rs @@ -0,0 +1,12 @@ +fn foo< + 'β, + γ +>() {} + +struct X { + δ: usize +} + +pub fn main() { + let α = 0.00001f64; +} diff --git a/rust/ql/test/library-tests/controlflow/CONSISTENCY/CfgConsistency.expected b/rust/ql/test/library-tests/controlflow/CONSISTENCY/CfgConsistency.expected new file mode 100644 index 000000000000..a457b59c6a5a --- /dev/null +++ b/rust/ql/test/library-tests/controlflow/CONSISTENCY/CfgConsistency.expected @@ -0,0 +1,3 @@ +deadEnd +| test.rs:124:28:124:33 | ... < ... | +| test.rs:139:30:141:9 | BlockExpr | diff --git a/rust/ql/test/library-tests/controlflow/Cfg.expected b/rust/ql/test/library-tests/controlflow/Cfg.expected index 87361682296c..5722456daa86 100644 --- a/rust/ql/test/library-tests/controlflow/Cfg.expected +++ b/rust/ql/test/library-tests/controlflow/Cfg.expected @@ -20,43 +20,43 @@ | test.rs:10:9:22:9 | LoopExpr | test.rs:23:9:23:20 | ExprStmt | | | test.rs:10:14:22:9 | BlockExpr | test.rs:11:13:11:24 | ExprStmt | | | test.rs:11:13:11:13 | PathExpr | test.rs:11:17:11:20 | PathExpr | | -| test.rs:11:13:11:23 | BinaryExpr | test.rs:12:13:14:13 | ExprStmt | | +| test.rs:11:13:11:23 | ... = ... | test.rs:12:13:14:13 | ExprStmt | | | test.rs:11:13:11:24 | ExprStmt | test.rs:11:13:11:13 | PathExpr | | | test.rs:11:17:11:20 | PathExpr | test.rs:11:22:11:22 | PathExpr | | -| test.rs:11:17:11:23 | CallExpr | test.rs:11:13:11:23 | BinaryExpr | | +| test.rs:11:17:11:23 | CallExpr | test.rs:11:13:11:23 | ... = ... | | | test.rs:11:22:11:22 | PathExpr | test.rs:11:17:11:23 | CallExpr | | | test.rs:12:13:14:13 | ExprStmt | test.rs:12:16:12:16 | PathExpr | | | test.rs:12:13:14:13 | IfExpr | test.rs:15:13:17:13 | ExprStmt | | | test.rs:12:16:12:16 | PathExpr | test.rs:12:20:12:24 | LiteralExpr | | -| test.rs:12:16:12:24 | BinaryExpr | test.rs:12:13:14:13 | IfExpr | false | -| test.rs:12:16:12:24 | BinaryExpr | test.rs:13:17:13:29 | ExprStmt | true | -| test.rs:12:20:12:24 | LiteralExpr | test.rs:12:16:12:24 | BinaryExpr | | +| test.rs:12:16:12:24 | ... > ... | test.rs:12:13:14:13 | IfExpr | false | +| test.rs:12:16:12:24 | ... > ... | test.rs:13:17:13:29 | ExprStmt | true | +| test.rs:12:20:12:24 | LiteralExpr | test.rs:12:16:12:24 | ... > ... | | | test.rs:13:17:13:28 | ReturnExpr | test.rs:8:5:24:5 | exit test_break_and_continue (normal) | return | | test.rs:13:17:13:29 | ExprStmt | test.rs:13:24:13:28 | LiteralExpr | | | test.rs:13:24:13:28 | LiteralExpr | test.rs:13:17:13:28 | ReturnExpr | | | test.rs:15:13:17:13 | ExprStmt | test.rs:15:16:15:16 | PathExpr | | | test.rs:15:13:17:13 | IfExpr | test.rs:18:13:20:13 | ExprStmt | | | test.rs:15:16:15:16 | PathExpr | test.rs:15:21:15:21 | LiteralExpr | | -| test.rs:15:16:15:21 | BinaryExpr | test.rs:15:13:17:13 | IfExpr | false | -| test.rs:15:16:15:21 | BinaryExpr | test.rs:16:17:16:22 | ExprStmt | true | -| test.rs:15:21:15:21 | LiteralExpr | test.rs:15:16:15:21 | BinaryExpr | | +| test.rs:15:16:15:21 | ... == ... | test.rs:15:13:17:13 | IfExpr | false | +| test.rs:15:16:15:21 | ... == ... | test.rs:16:17:16:22 | ExprStmt | true | +| test.rs:15:21:15:21 | LiteralExpr | test.rs:15:16:15:21 | ... == ... | | | test.rs:16:17:16:21 | BreakExpr | test.rs:10:9:22:9 | LoopExpr | break | | test.rs:16:17:16:22 | ExprStmt | test.rs:16:17:16:21 | BreakExpr | | | test.rs:18:13:20:13 | ExprStmt | test.rs:18:16:18:16 | PathExpr | | | test.rs:18:13:20:13 | IfExpr | test.rs:21:13:21:13 | PathExpr | | | test.rs:18:16:18:16 | PathExpr | test.rs:18:20:18:20 | LiteralExpr | | -| test.rs:18:16:18:20 | BinaryExpr | test.rs:18:25:18:25 | LiteralExpr | | -| test.rs:18:16:18:25 | BinaryExpr | test.rs:18:13:20:13 | IfExpr | false | -| test.rs:18:16:18:25 | BinaryExpr | test.rs:19:17:19:25 | ExprStmt | true | -| test.rs:18:20:18:20 | LiteralExpr | test.rs:18:16:18:20 | BinaryExpr | | -| test.rs:18:25:18:25 | LiteralExpr | test.rs:18:16:18:25 | BinaryExpr | | +| test.rs:18:16:18:20 | ... % ... | test.rs:18:25:18:25 | LiteralExpr | | +| test.rs:18:16:18:25 | ... != ... | test.rs:18:13:20:13 | IfExpr | false | +| test.rs:18:16:18:25 | ... != ... | test.rs:19:17:19:25 | ExprStmt | true | +| test.rs:18:20:18:20 | LiteralExpr | test.rs:18:16:18:20 | ... % ... | | +| test.rs:18:25:18:25 | LiteralExpr | test.rs:18:16:18:25 | ... != ... | | | test.rs:19:17:19:24 | ContinueExpr | test.rs:11:13:11:24 | ExprStmt | continue | | test.rs:19:17:19:25 | ExprStmt | test.rs:19:17:19:24 | ContinueExpr | | | test.rs:21:13:21:13 | PathExpr | test.rs:21:17:21:17 | PathExpr | | -| test.rs:21:13:21:21 | BinaryExpr | test.rs:10:14:22:9 | BlockExpr | | +| test.rs:21:13:21:21 | ... = ... | test.rs:10:14:22:9 | BlockExpr | | | test.rs:21:17:21:17 | PathExpr | test.rs:21:21:21:21 | LiteralExpr | | -| test.rs:21:17:21:21 | BinaryExpr | test.rs:21:13:21:21 | BinaryExpr | | -| test.rs:21:21:21:21 | LiteralExpr | test.rs:21:17:21:21 | BinaryExpr | | +| test.rs:21:17:21:21 | ... / ... | test.rs:21:13:21:21 | ... = ... | | +| test.rs:21:21:21:21 | LiteralExpr | test.rs:21:17:21:21 | ... / ... | | | test.rs:23:9:23:19 | ReturnExpr | test.rs:8:5:24:5 | exit test_break_and_continue (normal) | return | | test.rs:23:9:23:20 | ExprStmt | test.rs:23:16:23:19 | LiteralExpr | | | test.rs:23:16:23:19 | LiteralExpr | test.rs:23:9:23:19 | ReturnExpr | | @@ -106,8 +106,8 @@ | test.rs:56:19:56:27 | enter ClosureExpr | test.rs:56:23:56:23 | PathExpr | | | test.rs:56:19:56:27 | exit ClosureExpr (normal) | test.rs:56:19:56:27 | exit ClosureExpr | | | test.rs:56:23:56:23 | PathExpr | test.rs:56:27:56:27 | LiteralExpr | | -| test.rs:56:23:56:27 | BinaryExpr | test.rs:56:19:56:27 | exit ClosureExpr (normal) | | -| test.rs:56:27:56:27 | LiteralExpr | test.rs:56:23:56:27 | BinaryExpr | | +| test.rs:56:23:56:27 | ... + ... | test.rs:56:19:56:27 | exit ClosureExpr (normal) | | +| test.rs:56:27:56:27 | LiteralExpr | test.rs:56:23:56:27 | ... + ... | | | test.rs:57:5:57:11 | PathExpr | test.rs:57:13:57:19 | PathExpr | | | test.rs:57:5:57:23 | CallExpr | test.rs:55:40:58:1 | BlockExpr | | | test.rs:57:13:57:19 | PathExpr | test.rs:57:21:57:21 | PathExpr | | @@ -118,15 +118,15 @@ | test.rs:62:36:68:5 | BlockExpr | test.rs:62:5:68:5 | exit test_if_else (normal) | | | test.rs:63:9:67:9 | IfExpr | test.rs:62:36:68:5 | BlockExpr | | | test.rs:63:12:63:12 | PathExpr | test.rs:63:17:63:17 | LiteralExpr | | -| test.rs:63:12:63:17 | BinaryExpr | test.rs:64:13:64:13 | LiteralExpr | true | -| test.rs:63:12:63:17 | BinaryExpr | test.rs:66:13:66:13 | PathExpr | false | -| test.rs:63:17:63:17 | LiteralExpr | test.rs:63:12:63:17 | BinaryExpr | | +| test.rs:63:12:63:17 | ... <= ... | test.rs:64:13:64:13 | LiteralExpr | true | +| test.rs:63:12:63:17 | ... <= ... | test.rs:66:13:66:13 | PathExpr | false | +| test.rs:63:17:63:17 | LiteralExpr | test.rs:63:12:63:17 | ... <= ... | | | test.rs:63:19:65:9 | BlockExpr | test.rs:63:9:67:9 | IfExpr | | | test.rs:64:13:64:13 | LiteralExpr | test.rs:63:19:65:9 | BlockExpr | | | test.rs:65:16:67:9 | BlockExpr | test.rs:63:9:67:9 | IfExpr | | | test.rs:66:13:66:13 | PathExpr | test.rs:66:17:66:17 | LiteralExpr | | -| test.rs:66:13:66:17 | BinaryExpr | test.rs:65:16:67:9 | BlockExpr | | -| test.rs:66:17:66:17 | LiteralExpr | test.rs:66:13:66:17 | BinaryExpr | | +| test.rs:66:13:66:17 | ... - ... | test.rs:65:16:67:9 | BlockExpr | | +| test.rs:66:17:66:17 | LiteralExpr | test.rs:66:13:66:17 | ... - ... | | | test.rs:70:5:76:5 | enter test_if_let_else | test.rs:71:12:71:26 | LetExpr | | | test.rs:70:5:76:5 | exit test_if_let_else (normal) | test.rs:70:5:76:5 | exit test_if_let_else | | | test.rs:70:48:76:5 | BlockExpr | test.rs:70:5:76:5 | exit test_if_let_else (normal) | | @@ -149,15 +149,56 @@ | test.rs:79:28:81:9 | BlockExpr | test.rs:79:9:81:9 | IfExpr | | | test.rs:80:13:80:13 | PathExpr | test.rs:79:28:81:9 | BlockExpr | | | test.rs:82:9:82:9 | LiteralExpr | test.rs:78:43:83:5 | BlockExpr | | +| test.rs:85:5:91:5 | enter test_nested_if | test.rs:86:16:86:16 | PathExpr | | +| test.rs:85:5:91:5 | exit test_nested_if (normal) | test.rs:85:5:91:5 | exit test_nested_if | | +| test.rs:85:38:91:5 | BlockExpr | test.rs:85:5:91:5 | exit test_nested_if (normal) | | +| test.rs:86:9:90:9 | IfExpr | test.rs:85:38:91:5 | BlockExpr | | +| test.rs:86:12:86:48 | ParenExpr | test.rs:87:13:87:13 | LiteralExpr | true | +| test.rs:86:12:86:48 | ParenExpr | test.rs:89:13:89:13 | LiteralExpr | false | +| test.rs:86:13:86:47 | IfExpr | test.rs:86:12:86:48 | ParenExpr | | +| test.rs:86:16:86:16 | PathExpr | test.rs:86:20:86:20 | LiteralExpr | | +| test.rs:86:16:86:20 | ... < ... | test.rs:86:24:86:24 | PathExpr | true | +| test.rs:86:16:86:20 | ... < ... | test.rs:86:41:86:41 | PathExpr | false | +| test.rs:86:20:86:20 | LiteralExpr | test.rs:86:16:86:20 | ... < ... | | +| test.rs:86:22:86:32 | BlockExpr | test.rs:86:13:86:47 | IfExpr | | +| test.rs:86:24:86:24 | PathExpr | test.rs:86:29:86:30 | LiteralExpr | | +| test.rs:86:24:86:30 | ... < ... | test.rs:86:22:86:32 | BlockExpr | | +| test.rs:86:28:86:30 | - ... | test.rs:86:24:86:30 | ... < ... | | +| test.rs:86:29:86:30 | LiteralExpr | test.rs:86:28:86:30 | - ... | | +| test.rs:86:39:86:47 | BlockExpr | test.rs:86:13:86:47 | IfExpr | | +| test.rs:86:41:86:41 | PathExpr | test.rs:86:45:86:46 | LiteralExpr | | +| test.rs:86:41:86:46 | ... > ... | test.rs:86:39:86:47 | BlockExpr | | +| test.rs:86:45:86:46 | LiteralExpr | test.rs:86:41:86:46 | ... > ... | | +| test.rs:86:50:88:9 | BlockExpr | test.rs:86:9:90:9 | IfExpr | | +| test.rs:87:13:87:13 | LiteralExpr | test.rs:86:50:88:9 | BlockExpr | | +| test.rs:88:16:90:9 | BlockExpr | test.rs:86:9:90:9 | IfExpr | | +| test.rs:89:13:89:13 | LiteralExpr | test.rs:88:16:90:9 | BlockExpr | | +| test.rs:93:5:99:5 | enter test_nested_if_match | test.rs:94:19:94:19 | PathExpr | | +| test.rs:93:5:99:5 | exit test_nested_if_match (normal) | test.rs:93:5:99:5 | exit test_nested_if_match | | +| test.rs:93:44:99:5 | BlockExpr | test.rs:93:5:99:5 | exit test_nested_if_match (normal) | | +| test.rs:94:9:98:9 | IfExpr | test.rs:93:44:99:5 | BlockExpr | | +| test.rs:94:12:94:46 | ParenExpr | test.rs:95:13:95:13 | LiteralExpr | true | +| test.rs:94:12:94:46 | ParenExpr | test.rs:97:13:97:13 | LiteralExpr | false | +| test.rs:94:13:94:45 | MatchExpr | test.rs:94:12:94:46 | ParenExpr | | +| test.rs:94:19:94:19 | PathExpr | test.rs:94:23:94:23 | LiteralPat | | +| test.rs:94:23:94:23 | LiteralPat | test.rs:94:28:94:31 | LiteralExpr | match | +| test.rs:94:23:94:23 | LiteralPat | test.rs:94:34:94:34 | WildcardPat | no-match | +| test.rs:94:28:94:31 | LiteralExpr | test.rs:94:13:94:45 | MatchExpr | | +| test.rs:94:34:94:34 | WildcardPat | test.rs:94:39:94:43 | LiteralExpr | match | +| test.rs:94:39:94:43 | LiteralExpr | test.rs:94:13:94:45 | MatchExpr | | +| test.rs:94:48:96:9 | BlockExpr | test.rs:94:9:98:9 | IfExpr | | +| test.rs:95:13:95:13 | LiteralExpr | test.rs:94:48:96:9 | BlockExpr | | +| test.rs:96:16:98:9 | BlockExpr | test.rs:94:9:98:9 | IfExpr | | +| test.rs:97:13:97:13 | LiteralExpr | test.rs:96:16:98:9 | BlockExpr | | | test.rs:105:5:108:5 | enter test_and_operator | test.rs:106:9:106:28 | LetStmt | | | test.rs:105:5:108:5 | exit test_and_operator (normal) | test.rs:105:5:108:5 | exit test_and_operator | | | test.rs:105:61:108:5 | BlockExpr | test.rs:105:5:108:5 | exit test_and_operator (normal) | | -| test.rs:106:9:106:28 | LetStmt | test.rs:106:17:106:27 | BinaryExpr | | +| test.rs:106:9:106:28 | LetStmt | test.rs:106:17:106:27 | ... && ... | | | test.rs:106:13:106:13 | IdentPat | test.rs:107:9:107:9 | PathExpr | match, no-match | | test.rs:106:17:106:17 | PathExpr | test.rs:106:13:106:13 | IdentPat | false | | test.rs:106:17:106:17 | PathExpr | test.rs:106:22:106:22 | PathExpr | true | -| test.rs:106:17:106:22 | BinaryExpr | test.rs:106:17:106:17 | PathExpr | | -| test.rs:106:17:106:27 | BinaryExpr | test.rs:106:17:106:22 | BinaryExpr | | +| test.rs:106:17:106:22 | ... && ... | test.rs:106:17:106:17 | PathExpr | | +| test.rs:106:17:106:27 | ... && ... | test.rs:106:17:106:22 | ... && ... | | | test.rs:106:22:106:22 | PathExpr | test.rs:106:13:106:13 | IdentPat | false | | test.rs:106:22:106:22 | PathExpr | test.rs:106:27:106:27 | PathExpr | true | | test.rs:106:27:106:27 | PathExpr | test.rs:106:13:106:13 | IdentPat | | @@ -165,12 +206,12 @@ | test.rs:110:5:113:5 | enter test_or_operator | test.rs:111:9:111:28 | LetStmt | | | test.rs:110:5:113:5 | exit test_or_operator (normal) | test.rs:110:5:113:5 | exit test_or_operator | | | test.rs:110:60:113:5 | BlockExpr | test.rs:110:5:113:5 | exit test_or_operator (normal) | | -| test.rs:111:9:111:28 | LetStmt | test.rs:111:17:111:27 | BinaryExpr | | +| test.rs:111:9:111:28 | LetStmt | test.rs:111:17:111:27 | ... \|\| ... | | | test.rs:111:13:111:13 | IdentPat | test.rs:112:9:112:9 | PathExpr | match, no-match | | test.rs:111:17:111:17 | PathExpr | test.rs:111:13:111:13 | IdentPat | true | | test.rs:111:17:111:17 | PathExpr | test.rs:111:22:111:22 | PathExpr | false | -| test.rs:111:17:111:22 | BinaryExpr | test.rs:111:17:111:17 | PathExpr | | -| test.rs:111:17:111:27 | BinaryExpr | test.rs:111:17:111:22 | BinaryExpr | | +| test.rs:111:17:111:22 | ... \|\| ... | test.rs:111:17:111:17 | PathExpr | | +| test.rs:111:17:111:27 | ... \|\| ... | test.rs:111:17:111:22 | ... \|\| ... | | | test.rs:111:22:111:22 | PathExpr | test.rs:111:13:111:13 | IdentPat | true | | test.rs:111:22:111:22 | PathExpr | test.rs:111:27:111:27 | PathExpr | false | | test.rs:111:27:111:27 | PathExpr | test.rs:111:13:111:13 | IdentPat | | @@ -178,27 +219,31 @@ | test.rs:115:5:118:5 | enter test_or_operator_2 | test.rs:116:9:116:36 | LetStmt | | | test.rs:115:5:118:5 | exit test_or_operator_2 (normal) | test.rs:115:5:118:5 | exit test_or_operator_2 | | | test.rs:115:61:118:5 | BlockExpr | test.rs:115:5:118:5 | exit test_or_operator_2 (normal) | | -| test.rs:116:9:116:36 | LetStmt | test.rs:116:17:116:35 | BinaryExpr | | +| test.rs:116:9:116:36 | LetStmt | test.rs:116:17:116:35 | ... \|\| ... | | | test.rs:116:13:116:13 | IdentPat | test.rs:117:9:117:9 | PathExpr | match, no-match | | test.rs:116:17:116:17 | PathExpr | test.rs:116:13:116:13 | IdentPat | true | -| test.rs:116:17:116:30 | BinaryExpr | test.rs:116:17:116:17 | PathExpr | | -| test.rs:116:17:116:35 | BinaryExpr | test.rs:116:17:116:30 | BinaryExpr | | +| test.rs:116:17:116:17 | PathExpr | test.rs:116:23:116:23 | PathExpr | false | +| test.rs:116:17:116:30 | ... \|\| ... | test.rs:116:17:116:17 | PathExpr | | +| test.rs:116:17:116:35 | ... \|\| ... | test.rs:116:17:116:30 | ... \|\| ... | | +| test.rs:116:22:116:30 | ParenExpr | test.rs:116:13:116:13 | IdentPat | true | +| test.rs:116:22:116:30 | ParenExpr | test.rs:116:35:116:35 | PathExpr | false | +| test.rs:116:23:116:23 | PathExpr | test.rs:116:28:116:29 | LiteralExpr | | +| test.rs:116:23:116:29 | ... == ... | test.rs:116:22:116:30 | ParenExpr | | +| test.rs:116:28:116:29 | LiteralExpr | test.rs:116:23:116:29 | ... == ... | | +| test.rs:116:35:116:35 | PathExpr | test.rs:116:13:116:13 | IdentPat | | | test.rs:117:9:117:9 | PathExpr | test.rs:115:61:118:5 | BlockExpr | | | test.rs:122:1:128:1 | enter test_match | test.rs:123:11:123:21 | PathExpr | | | test.rs:122:1:128:1 | exit test_match (normal) | test.rs:122:1:128:1 | exit test_match | | | test.rs:122:44:128:1 | BlockExpr | test.rs:122:1:128:1 | exit test_match (normal) | | | test.rs:123:5:127:5 | MatchExpr | test.rs:122:44:128:1 | BlockExpr | | | test.rs:123:11:123:21 | PathExpr | test.rs:124:9:124:23 | TupleStructPat | | -| test.rs:124:9:124:23 | TupleStructPat | test.rs:123:5:127:5 | MatchExpr | no-match | | test.rs:124:9:124:23 | TupleStructPat | test.rs:124:28:124:28 | PathExpr | match | | test.rs:124:9:124:23 | TupleStructPat | test.rs:125:9:125:23 | TupleStructPat | no-match | | test.rs:124:28:124:28 | PathExpr | test.rs:124:32:124:33 | LiteralExpr | | -| test.rs:124:32:124:33 | LiteralExpr | test.rs:124:28:124:33 | BinaryExpr | | -| test.rs:125:9:125:23 | TupleStructPat | test.rs:123:5:127:5 | MatchExpr | no-match | +| test.rs:124:32:124:33 | LiteralExpr | test.rs:124:28:124:33 | ... < ... | | | test.rs:125:9:125:23 | TupleStructPat | test.rs:125:28:125:28 | PathExpr | match | | test.rs:125:9:125:23 | TupleStructPat | test.rs:126:9:126:20 | PathPat | no-match | | test.rs:125:28:125:28 | PathExpr | test.rs:123:5:127:5 | MatchExpr | | -| test.rs:126:9:126:20 | PathPat | test.rs:123:5:127:5 | MatchExpr | no-match | | test.rs:126:9:126:20 | PathPat | test.rs:126:25:126:25 | LiteralExpr | match | | test.rs:126:25:126:25 | LiteralExpr | test.rs:123:5:127:5 | MatchExpr | | | test.rs:131:5:136:5 | enter test_infinite_loop | test.rs:132:9:134:9 | ExprStmt | | diff --git a/rust/ql/test/query-tests/diagnostics/ExtractionErrors.expected b/rust/ql/test/query-tests/diagnostics/ExtractionErrors.expected new file mode 100644 index 000000000000..b6aaf7b6d373 --- /dev/null +++ b/rust/ql/test/query-tests/diagnostics/ExtractionErrors.expected @@ -0,0 +1,6 @@ +| does_not_compile.rs:2:6:2:5 | expected SEMICOLON | Extraction failed in does_not_compile.rs with error expected SEMICOLON | 2 | +| does_not_compile.rs:2:9:2:8 | expected SEMICOLON | Extraction failed in does_not_compile.rs with error expected SEMICOLON | 2 | +| does_not_compile.rs:2:13:2:12 | expected SEMICOLON | Extraction failed in does_not_compile.rs with error expected SEMICOLON | 2 | +| does_not_compile.rs:2:21:2:20 | expected SEMICOLON | Extraction failed in does_not_compile.rs with error expected SEMICOLON | 2 | +| does_not_compile.rs:2:26:2:25 | expected SEMICOLON | Extraction failed in does_not_compile.rs with error expected SEMICOLON | 2 | +| does_not_compile.rs:2:32:2:31 | expected field name or number | Extraction failed in does_not_compile.rs with error expected field name or number | 2 | diff --git a/rust/ql/test/query-tests/diagnostics/ExtractionErrors.qlref b/rust/ql/test/query-tests/diagnostics/ExtractionErrors.qlref new file mode 100644 index 000000000000..ffbdb0a7b1b5 --- /dev/null +++ b/rust/ql/test/query-tests/diagnostics/ExtractionErrors.qlref @@ -0,0 +1 @@ +queries/diagnostics/ExtractionErrors.ql \ No newline at end of file diff --git a/rust/schema/.gitattributes b/rust/schema/.gitattributes new file mode 100644 index 000000000000..515346ca14c5 --- /dev/null +++ b/rust/schema/.gitattributes @@ -0,0 +1 @@ +/ast.py linguist-generated diff --git a/rust/schema/ast.py b/rust/schema/ast.py index 671f89473344..13eb54e7acf3 100644 --- a/rust/schema/ast.py +++ b/rust/schema/ast.py @@ -1,3 +1,5 @@ +# Generated by `cargo generate-schema`, do not edit by hand. + from .prelude import * class AssocItem(AstNode): diff --git a/shared/controlflow/codeql/controlflow/Cfg.qll b/shared/controlflow/codeql/controlflow/Cfg.qll index 0bd857e91c0e..aa7a072e4cbb 100644 --- a/shared/controlflow/codeql/controlflow/Cfg.qll +++ b/shared/controlflow/codeql/controlflow/Cfg.qll @@ -1273,8 +1273,14 @@ module Make Input> { string getOrderDisambiguation() { result = "" } } - import TestOutput - import Mermaid + private module Output = TestOutput; + + import Output::Mermaid + + query predicate edges(RelevantNode pred, RelevantNode succ, string attr, string val) { + attr = "semmle.label" and + Output::edges(pred, succ, val) + } } /** Provides a set of consistency queries. */ @@ -1380,5 +1386,10 @@ module Make Input> { ord = sk.getListOrder() and strictcount(sk.getListOrder()) > 1 } + + query predicate multipleToString(Node n, string s) { + s = strictconcat(n.toString(), ",") and + strictcount(n.toString()) > 1 + } } } diff --git a/shared/dataflow/codeql/dataflow/DataFlow.qll b/shared/dataflow/codeql/dataflow/DataFlow.qll index 6e4921521b1a..01bd0e5ea963 100644 --- a/shared/dataflow/codeql/dataflow/DataFlow.qll +++ b/shared/dataflow/codeql/dataflow/DataFlow.qll @@ -431,6 +431,17 @@ module Configs Lang> { * is not visualized (as it is in a `path-problem` query). */ default predicate includeHiddenNodes() { none() } + + /** + * Holds if sources and sinks should be filtered to only include those that + * may lead to a flow path with either a source or a sink in the location + * range given by `AlertFiltering`. This only has an effect when running + * in diff-informed incremental mode. + * + * This flag should only be applied to flow configurations whose results + * are used directly in a query result. + */ + default predicate observeDiffInformedIncrementalMode() { none() } } /** An input configuration for data flow using flow state. */ @@ -547,6 +558,17 @@ module Configs Lang> { * is not visualized (as it is in a `path-problem` query). */ default predicate includeHiddenNodes() { none() } + + /** + * Holds if sources and sinks should be filtered to only include those that + * may lead to a flow path with either a source or a sink in the location + * range given by `AlertFiltering`. This only has an effect when running + * in diff-informed incremental mode. + * + * This flag should only be applied to flow configurations whose results + * are used directly in a query result. + */ + default predicate observeDiffInformedIncrementalMode() { none() } } } diff --git a/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll b/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll index ef6861ec921a..1bebea93c486 100644 --- a/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll +++ b/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll @@ -124,6 +124,17 @@ module MakeImpl Lang> { * is not visualized (as it is in a `path-problem` query). */ predicate includeHiddenNodes(); + + /** + * Holds if sources and sinks should be filtered to only include those that + * may lead to a flow path with either a source or a sink in the location + * range given by `AlertFiltering`. This only has an effect when running + * in diff-informed incremental mode. + * + * This flag should only be applied to flow configurations whose results + * are used directly in a query result. + */ + predicate observeDiffInformedIncrementalMode(); } /** @@ -153,104 +164,75 @@ module MakeImpl Lang> { module Impl { private class FlowState = Config::FlowState; - private newtype TNodeEx = - TNodeNormal(Node n) or - TNodeImplicitRead(Node n, boolean hasRead) { - Config::allowImplicitRead(n, _) and hasRead = [false, true] - } or - TParamReturnNode(ParameterNode p, SndLevelScopeOption scope) { - paramReturnNode(_, p, scope, _) - } - - private class NodeEx extends TNodeEx { - string toString() { - result = this.asNode().toString() - or - exists(Node n | this.isImplicitReadNode(n, _) | result = n.toString() + " [Ext]") - or - result = this.asParamReturnNode().toString() + " [Return]" - } + private module SourceSinkFiltering { + private import codeql.util.AlertFiltering - Node asNode() { this = TNodeNormal(result) } - - /** Gets the corresponding Node if this is a normal node or its post-implicit read node. */ - Node asNodeOrImplicitRead() { - this = TNodeNormal(result) or this = TNodeImplicitRead(result, true) - } - - predicate isImplicitReadNode(Node n, boolean hasRead) { this = TNodeImplicitRead(n, hasRead) } - - ParameterNode asParamReturnNode() { this = TParamReturnNode(result, _) } - - Node projectToNode() { - this = TNodeNormal(result) or - this = TNodeImplicitRead(result, _) or - this = TParamReturnNode(result, _) - } + private module AlertFiltering = AlertFilteringImpl; pragma[nomagic] - private DataFlowCallable getEnclosingCallable0() { - nodeEnclosingCallable(this.projectToNode(), result) - } - - pragma[inline] - DataFlowCallable getEnclosingCallable() { - pragma[only_bind_out](this).getEnclosingCallable0() = pragma[only_bind_into](result) + private predicate isFilteredSource(Node source) { + Config::isSource(source, _) and + if Config::observeDiffInformedIncrementalMode() + then AlertFiltering::filterByLocation(source.getLocation()) + else any() } pragma[nomagic] - private DataFlowType getDataFlowType0() { - nodeDataFlowType(this.asNode(), result) - or - nodeDataFlowType(this.asParamReturnNode(), result) - } - - pragma[inline] - DataFlowType getDataFlowType() { - pragma[only_bind_out](this).getDataFlowType0() = pragma[only_bind_into](result) + private predicate isFilteredSink(Node sink) { + ( + Config::isSink(sink, _) or + Config::isSink(sink) + ) and + if Config::observeDiffInformedIncrementalMode() + then AlertFiltering::filterByLocation(sink.getLocation()) + else any() } - Location getLocation() { result = this.projectToNode().getLocation() } - } + private predicate hasFilteredSource() { isFilteredSource(_) } - private class ArgNodeEx extends NodeEx { - ArgNodeEx() { this.asNode() instanceof ArgNode } + private predicate hasFilteredSink() { isFilteredSink(_) } - DataFlowCall getCall() { this.asNode().(ArgNode).argumentOf(result, _) } - } - - private class ParamNodeEx extends NodeEx { - ParamNodeEx() { this.asNode() instanceof ParamNode } - - predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { - this.asNode().(ParamNode).isParameterOf(c, pos) + predicate isRelevantSource(Node source, FlowState state) { + // If there are filtered sinks, we need to pass through all sources to preserve all alerts + // with filtered sinks. Otherwise the only alerts of interest are those with filtered + // sources, so we can perform the source filtering right here. + Config::isSource(source, state) and + ( + isFilteredSource(source) or + hasFilteredSink() + ) } - ParameterPosition getPosition() { this.isParameterOf(_, result) } - } - - /** - * A node from which flow can return to the caller. This is either a regular - * `ReturnNode` or a synthesized node for flow out via a parameter. - */ - private class RetNodeEx extends NodeEx { - private ReturnPosition pos; - - RetNodeEx() { - pos = getValueReturnPosition(this.asNode()) or - pos = getParamReturnPosition(_, this.asParamReturnNode()) + predicate isRelevantSink(Node sink, FlowState state) { + // If there are filtered sources, we need to pass through all sinks to preserve all alerts + // with filtered sources. Otherwise the only alerts of interest are those with filtered + // sinks, so we can perform the sink filtering right here. + Config::isSink(sink, state) and + ( + isFilteredSink(sink) or + hasFilteredSource() + ) } - ReturnPosition getReturnPosition() { result = pos } - - ReturnKindExt getKind() { result = pos.getKind() } + predicate isRelevantSink(Node sink) { + // If there are filtered sources, we need to pass through all sinks to preserve all alerts + // with filtered sources. Otherwise the only alerts of interest are those with filtered + // sinks, so we can perform the sink filtering right here. + Config::isSink(sink) and + ( + isFilteredSink(sink) or + hasFilteredSource() + ) + } } + private import SourceSinkFiltering + private predicate inBarrier(NodeEx node) { exists(Node n | node.asNode() = n and Config::isBarrierIn(n) and - Config::isSource(n, _) + isRelevantSource(n, _) ) } @@ -259,7 +241,7 @@ module MakeImpl Lang> { exists(Node n | node.asNode() = n and Config::isBarrierIn(n, state) and - Config::isSource(n, state) + isRelevantSource(n, state) ) } @@ -268,9 +250,9 @@ module MakeImpl Lang> { node.asNodeOrImplicitRead() = n and Config::isBarrierOut(n) | - Config::isSink(n, _) + isRelevantSink(n, _) or - Config::isSink(n) + isRelevantSink(n) ) } @@ -280,9 +262,9 @@ module MakeImpl Lang> { node.asNodeOrImplicitRead() = n and Config::isBarrierOut(n, state) | - Config::isSink(n, state) + isRelevantSink(n, state) or - Config::isSink(n) + isRelevantSink(n) ) } @@ -292,11 +274,11 @@ module MakeImpl Lang> { Config::isBarrier(n) or Config::isBarrierIn(n) and - not Config::isSource(n, _) + not isRelevantSource(n, _) or Config::isBarrierOut(n) and - not Config::isSink(n, _) and - not Config::isSink(n) + not isRelevantSink(n, _) and + not isRelevantSink(n) ) } @@ -306,24 +288,24 @@ module MakeImpl Lang> { Config::isBarrier(n, state) or Config::isBarrierIn(n, state) and - not Config::isSource(n, state) + not isRelevantSource(n, state) or Config::isBarrierOut(n, state) and - not Config::isSink(n, state) and - not Config::isSink(n) + not isRelevantSink(n, state) and + not isRelevantSink(n) ) } pragma[nomagic] private predicate sourceNode(NodeEx node, FlowState state) { - Config::isSource(node.asNode(), state) and + isRelevantSource(node.asNode(), state) and not fullBarrier(node) and not stateBarrier(node, state) } pragma[nomagic] private predicate sinkNodeWithState(NodeEx node, FlowState state) { - Config::isSink(node.asNodeOrImplicitRead(), state) and + isRelevantSink(node.asNodeOrImplicitRead(), state) and not fullBarrier(node) and not stateBarrier(node, state) } @@ -357,27 +339,8 @@ module MakeImpl Lang> { * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStepEx(NodeEx node1, NodeEx node2, string model) { - exists(Node n1, Node n2 | - node1.asNode() = n1 and - node2.asNode() = n2 and - simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2), model) and - stepFilter(node1, node2) - ) - or - exists(Node n | - node1.asNode() = n and - node2.isImplicitReadNode(n, false) and - not fullBarrier(node1) and - model = "" - ) - or - exists(Node n1, Node n2, SndLevelScopeOption scope | - node1.asNode() = n1 and - node2 = TParamReturnNode(n2, scope) and - paramReturnNode(pragma[only_bind_into](n1), pragma[only_bind_into](n2), - pragma[only_bind_into](scope), _) and - model = "" - ) + localFlowStepExImpl(node1, node2, model) and + stepFilter(node1, node2) } /** @@ -449,9 +412,13 @@ module MakeImpl Lang> { stepFilter(node1, node2) or exists(Node n | - node2.isImplicitReadNode(n, true) and - node1.isImplicitReadNode(n, _) and + node2.isImplicitReadNode(n) and Config::allowImplicitRead(n, c) + | + node1.asNode() = n and + not fullBarrier(node1) + or + node1.isImplicitReadNode(n) ) } @@ -727,9 +694,9 @@ module MakeImpl Lang> { } additional predicate sinkNode(NodeEx node, FlowState state) { - fwdFlow(node) and + fwdFlow(pragma[only_bind_into](node)) and fwdFlowState(state) and - Config::isSink(node.asNodeOrImplicitRead()) + isRelevantSink(node.asNodeOrImplicitRead()) or fwdFlow(node) and fwdFlowState(state) and @@ -1062,10 +1029,15 @@ module MakeImpl Lang> { bindingset[label1, label2] pragma[inline_late] private string mergeLabels(string label1, string label2) { - // Big-step, hidden nodes, and summaries all may need to merge labels. - // These cases are expected to involve at most one non-empty label, so - // we'll just discard the 2nd+ label for now. - if label1 = "" then result = label2 else result = label1 + if label2.matches("Sink:%") + then if label1 = "" then result = label2 else result = label1 + " " + label2 + else + // Big-step, hidden nodes, and summaries all may need to merge labels. + // These cases are expected to involve at most one non-empty label, so + // we'll just discard the 2nd+ label for now. + if label1 = "" + then result = label2 + else result = label1 } pragma[nomagic] @@ -2801,8 +2773,6 @@ module MakeImpl Lang> { } /** - * INTERNAL: Only for debugging. - * * Provides a graph representation of the data flow in this stage suitable for use in a `path-problem` query. */ additional module Graph { @@ -2835,14 +2805,50 @@ module MakeImpl Lang> { abstract PathNodeImpl getASuccessorImpl(string label); + pragma[nomagic] + PathNodeImpl getAnImplicitReadSuccessorAtSink(string label) { + exists(PathNodeMid readTarget | + result = this.getASuccessorImpl(_) and + localStep(this, readTarget, _) and + readTarget.getNodeEx().isImplicitReadNode(_) + | + // last implicit read, leaving the access path empty + result = readTarget.projectToSink(label) + or + // implicit read, leaving the access path non-empty + exists(result.getAnImplicitReadSuccessorAtSink(label)) and + result = readTarget + ) + } + private PathNodeImpl getASuccessorIfHidden(string label) { this.isHidden() and result = this.getASuccessorImpl(label) + or + result = this.getAnImplicitReadSuccessorAtSink(label) } private PathNodeImpl getASuccessorFromNonHidden(string label) { result = this.getASuccessorImpl(label) and - not this.isHidden() + not this.isHidden() and + // In cases like + // + // ``` + // x.Field = taint; + // Sink(x); + // ``` + // + // we only want the direct edge + // + // `[post update] x [Field]` -> `x` + // + // and not the two edges + // + // `[post update] x [Field]` -> `x [Field]` + // `x [Field]` -> `x` + // + // which the restriction below ensures. + not result = this.getAnImplicitReadSuccessorAtSink(_) or exists(string l1, string l2 | result = this.getASuccessorFromNonHidden(l1).getASuccessorIfHidden(l2) and @@ -2946,7 +2952,7 @@ module MakeImpl Lang> { NodeEx toNormalSinkNodeEx() { exists(Node n | pragma[only_bind_out](node.asNodeOrImplicitRead()) = n and - (Config::isSink(n) or Config::isSink(n, _)) and + (isRelevantSink(n) or isRelevantSink(n, _)) and result.asNode() = n ) } @@ -2963,18 +2969,15 @@ module MakeImpl Lang> { ) or // a final step to a sink - exists(string l2, string sinkmodel, string l2_ | - result = this.getSuccMid(l2).projectToSink(sinkmodel) and - if l2 = "" then l2_ = l2 else l2_ = l2 + " " + exists(string l2, string sinkLabel | + result = this.getSuccMid(l2).projectToSink(sinkLabel) | not this.isSourceWithLabel(_) and - if sinkmodel != "" then label = l2_ + "Sink:" + sinkmodel else label = l2 + label = mergeLabels(l2, sinkLabel) or exists(string l1 | this.isSourceWithLabel(l1) and - if sinkmodel != "" - then label = l1 + l2_ + "Sink:" + sinkmodel - else label = l1 + l2 + label = l1 + mergeLabels(l2, sinkLabel) ) ) } @@ -3040,11 +3043,14 @@ module MakeImpl Lang> { else any() } - PathNodeSink projectToSink(string model) { - this.isAtSink() and - sinkModel(node, model) and - result.getNodeEx() = this.toNormalSinkNodeEx() and - result.getState() = state + PathNodeSink projectToSink(string label) { + exists(string model | + this.isAtSink() and + sinkModel(node, model) and + result.getNodeEx() = this.toNormalSinkNodeEx() and + result.getState() = state and + if model != "" then label = "Sink:" + model else label = "" + ) } } @@ -3316,6 +3322,8 @@ module MakeImpl Lang> { private predicate localStepFromHidden(PathNodeImpl n1, PathNodeImpl n2) { n2 = localStep(n1) and n1.isHidden() + or + n2 = n1.getAnImplicitReadSuccessorAtSink(_) } bindingset[par, ret] @@ -4624,6 +4632,8 @@ module MakeImpl Lang> { */ predicate stageStats = Debug::stageStats/10; + private module Stage1alias = Stage1; + private module Stage2alias = Stage2; private module Stage3alias = Stage3; @@ -4633,11 +4643,13 @@ module MakeImpl Lang> { private module Stage5alias = Stage5; /** - * INTERNAL: Only for debugging. + * INTERNAL: Subject to change without notice. * * Contains references to individual pruning stages. */ - module Debug { + module Stages { + module Stage1 = Stage1alias; + module Stage2 = Stage2alias; module Stage3 = Stage3alias; @@ -4645,6 +4657,15 @@ module MakeImpl Lang> { module Stage4 = Stage4alias; module Stage5 = Stage5alias; + } + + /** + * INTERNAL: Only for debugging. + * + * Contains references to individual pruning stages and stage statistics. + */ + module Debug { + import Stages predicate stageStats1( int n, string stage, int nodes, int fields, int conscand, int states, int tuples, @@ -4793,15 +4814,15 @@ module MakeImpl Lang> { } private predicate interestingCallableSrc(DataFlowCallable c) { - exists(Node n | Config::isSource(n, _) and c = getNodeEnclosingCallable(n)) + exists(Node n | isRelevantSource(n, _) and c = getNodeEnclosingCallable(n)) or exists(DataFlowCallable mid | interestingCallableSrc(mid) and callableStep(mid, c)) } private predicate interestingCallableSink(DataFlowCallable c) { exists(Node n | c = getNodeEnclosingCallable(n) | - Config::isSink(n, _) or - Config::isSink(n) + isRelevantSink(n, _) or + isRelevantSink(n) ) or exists(DataFlowCallable mid | interestingCallableSink(mid) and callableStep(c, mid)) @@ -4828,7 +4849,7 @@ module MakeImpl Lang> { or exists(Node n | ce1 = TCallableSrc() and - Config::isSource(n, _) and + isRelevantSource(n, _) and ce2 = TCallable(getNodeEnclosingCallable(n)) ) or @@ -4836,8 +4857,8 @@ module MakeImpl Lang> { ce2 = TCallableSink() and ce1 = TCallable(getNodeEnclosingCallable(n)) | - Config::isSink(n, _) or - Config::isSink(n) + isRelevantSink(n, _) or + isRelevantSink(n) ) } @@ -4901,7 +4922,7 @@ module MakeImpl Lang> { private predicate revSinkNode(NodeEx node, FlowState state) { sinkNodeWithState(node, state) or - Config::isSink(node.asNodeOrImplicitRead()) and + isRelevantSink(node.asNodeOrImplicitRead()) and relevantState(state) and not fullBarrier(node) and not stateBarrier(node, state) diff --git a/shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll b/shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll index 8a82c7b570c5..81f9946126db 100644 --- a/shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll +++ b/shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll @@ -850,6 +850,85 @@ module MakeImplCommon Lang> { class SndLevelScopeOption = SndLevelScopeOption::Option; + final class NodeEx extends TNodeEx { + string toString() { + result = this.asNode().toString() + or + exists(Node n | this.isImplicitReadNode(n) | result = n.toString() + " [Ext]") + or + result = this.asParamReturnNode().toString() + " [Return]" + } + + Node asNode() { this = TNodeNormal(result) } + + /** Gets the corresponding Node if this is a normal node or its post-implicit read node. */ + Node asNodeOrImplicitRead() { this = TNodeNormal(result) or this = TNodeImplicitRead(result) } + + predicate isImplicitReadNode(Node n) { this = TNodeImplicitRead(n) } + + ParameterNode asParamReturnNode() { this = TParamReturnNode(result, _) } + + Node projectToNode() { + this = TNodeNormal(result) or + this = TNodeImplicitRead(result) or + this = TParamReturnNode(result, _) + } + + pragma[nomagic] + private DataFlowCallable getEnclosingCallable0() { + nodeEnclosingCallable(this.projectToNode(), result) + } + + pragma[inline] + DataFlowCallable getEnclosingCallable() { + pragma[only_bind_out](this).getEnclosingCallable0() = pragma[only_bind_into](result) + } + + pragma[nomagic] + private DataFlowType getDataFlowType0() { + nodeDataFlowType(this.asNode(), result) + or + nodeDataFlowType(this.asParamReturnNode(), result) + } + + pragma[inline] + DataFlowType getDataFlowType() { + pragma[only_bind_out](this).getDataFlowType0() = pragma[only_bind_into](result) + } + + Location getLocation() { result = this.projectToNode().getLocation() } + } + + final class ArgNodeEx extends NodeEx { + ArgNodeEx() { this.asNode() instanceof ArgNode } + + DataFlowCall getCall() { this.asNode().(ArgNode).argumentOf(result, _) } + } + + final class ParamNodeEx extends NodeEx { + ParamNodeEx() { this.asNode() instanceof ParamNode } + + predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { + this.asNode().(ParamNode).isParameterOf(c, pos) + } + + ParameterPosition getPosition() { this.isParameterOf(_, result) } + } + + /** + * A node from which flow can return to the caller. This is either a regular + * `ReturnNode` or a synthesized node for flow out via a parameter. + */ + final class RetNodeEx extends NodeEx { + private ReturnPosition pos; + + RetNodeEx() { pos = getReturnPositionEx(this) } + + ReturnPosition getReturnPosition() { result = pos } + + ReturnKindExt getKind() { result = pos.getKind() } + } + cached private module Cached { /** @@ -927,11 +1006,8 @@ module MakeImplCommon Lang> { ) } - cached - predicate valueReturnNode(ReturnNode n, ReturnKindExt k) { k = TValueReturn(n.getKind()) } - - cached - predicate paramReturnNode( + pragma[nomagic] + private predicate paramReturnNode( PostUpdateNode n, ParamNode p, SndLevelScopeOption scope, ReturnKindExt k ) { exists(ParameterPosition pos | @@ -1541,6 +1617,20 @@ module MakeImplCommon Lang> { class UnreachableSetOption = UnreachableSetOption::Option; + pragma[nomagic] + private predicate hasValueReturnKindIn(ReturnNode ret, ReturnKindExt kind, DataFlowCallable c) { + c = getNodeEnclosingCallable(ret) and + kind = TValueReturn(ret.getKind()) + } + + pragma[nomagic] + private predicate hasParamReturnKindIn( + PostUpdateNode n, ParamNode p, ReturnKindExt kind, DataFlowCallable c + ) { + c = getNodeEnclosingCallable(n) and + paramReturnNode(n, p, _, kind) + } + cached newtype TReturnPosition = TReturnPosition0(DataFlowCallable c, ReturnKindExt kind) { @@ -1549,6 +1639,22 @@ module MakeImplCommon Lang> { hasParamReturnKindIn(_, _, kind, c) } + cached + ReturnPosition getValueReturnPosition(ReturnNode ret) { + exists(ReturnKindExt kind, DataFlowCallable c | + hasValueReturnKindIn(ret, kind, c) and + result = TReturnPosition0(c, kind) + ) + } + + cached + ReturnPosition getParamReturnPosition(PostUpdateNode n, ParamNode p) { + exists(ReturnKindExt kind, DataFlowCallable c | + hasParamReturnKindIn(n, p, kind, c) and + result = TReturnPosition0(c, kind) + ) + } + cached newtype TLocalFlowCallContext = TAnyLocalCall() or @@ -1594,6 +1700,44 @@ module MakeImplCommon Lang> { newtype TApproxAccessPathFrontOption = TApproxAccessPathFrontNone() or TApproxAccessPathFrontSome(ApproxAccessPathFront apf) + + cached + newtype TNodeEx = + TNodeNormal(Node n) or + TNodeImplicitRead(Node n) or // will be restricted to nodes with actual implicit reads in `DataFlowImpl.qll` + TParamReturnNode(ParameterNode p, SndLevelScopeOption scope) { + paramReturnNode(_, p, scope, _) + } + + /** + * Holds if data can flow in one local step from `node1` to `node2`. + */ + cached + predicate localFlowStepExImpl(NodeEx node1, NodeEx node2, string model) { + exists(Node n1, Node n2 | + node1.asNode() = n1 and + node2.asNode() = n2 and + simpleLocalFlowStepExt(pragma[only_bind_into](n1), pragma[only_bind_into](n2), model) + ) + or + exists(Node n1, Node n2, SndLevelScopeOption scope | + node1.asNode() = n1 and + node2 = TParamReturnNode(n2, scope) and + paramReturnNode(pragma[only_bind_into](n1), pragma[only_bind_into](n2), + pragma[only_bind_into](scope), _) and + model = "" + ) + } + + cached + ReturnPosition getReturnPositionEx(NodeEx ret) { + result = getValueReturnPosition(ret.asNode()) + or + exists(ParamNode p | + ret = TParamReturnNode(p, _) and + result = getParamReturnPosition(_, p) + ) + } } bindingset[call, tgt] @@ -2177,36 +2321,6 @@ module MakeImplCommon Lang> { nodeDataFlowType(pragma[only_bind_out](n), pragma[only_bind_into](result)) } - pragma[nomagic] - private predicate hasValueReturnKindIn(ReturnNode ret, ReturnKindExt kind, DataFlowCallable c) { - c = getNodeEnclosingCallable(ret) and - valueReturnNode(ret, kind) - } - - pragma[nomagic] - private predicate hasParamReturnKindIn( - PostUpdateNode n, ParamNode p, ReturnKindExt kind, DataFlowCallable c - ) { - c = getNodeEnclosingCallable(n) and - paramReturnNode(n, p, _, kind) - } - - pragma[nomagic] - ReturnPosition getValueReturnPosition(ReturnNode ret) { - exists(ReturnKindExt kind, DataFlowCallable c | - hasValueReturnKindIn(ret, kind, c) and - result = TReturnPosition0(c, kind) - ) - } - - pragma[nomagic] - ReturnPosition getParamReturnPosition(PostUpdateNode n, ParamNode p) { - exists(ReturnKindExt kind, DataFlowCallable c | - hasParamReturnKindIn(n, p, kind, c) and - result = TReturnPosition0(c, kind) - ) - } - /** An optional Boolean value. */ class BooleanOption extends TBooleanOption { string toString() { diff --git a/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll b/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll index 86b79d4433a2..b0b8901e982e 100644 --- a/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll +++ b/shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll @@ -1775,7 +1775,7 @@ module Make< exists(ReturnNode ret, ValueReturnKind kind | c = "ReturnValue" and ret = node.asNode() and - valueReturnNode(ret, kind) and + kind.getKind() = ret.getKind() and kind.getKind() = getStandardReturnValueKind() and mid.asCallable() = getNodeEnclosingCallable(ret) ) diff --git a/shared/mad/codeql/mad/modelgenerator/internal/ModelGeneratorImpl.qll b/shared/mad/codeql/mad/modelgenerator/internal/ModelGeneratorImpl.qll new file mode 100644 index 000000000000..f668d80ef1fc --- /dev/null +++ b/shared/mad/codeql/mad/modelgenerator/internal/ModelGeneratorImpl.qll @@ -0,0 +1,939 @@ +/** + * INTERNAL: Do not use. + * + * Provides classes and predicates related to capturing summary, source, + * and sink models of the Standard or a 3rd party library. + */ + +private import codeql.dataflow.DataFlow +private import codeql.dataflow.TaintTracking as Tt +private import codeql.dataflow.internal.ContentDataFlowImpl +private import codeql.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon +private import codeql.util.Location +private import ModelPrinting + +/** + * Provides language-specific model generator parameters. + */ +signature module ModelGeneratorInputSig Lang> { + /** + * A Type. + */ + class Type; + + /** + * A Parameter. + */ + class Parameter; + + /** + * A Callable. + */ + class Callable { + /** + * Gets the number of parameters of this callable. + */ + int getNumberOfParameters(); + + /** + * Gets a string representation of this callable. + */ + string toString(); + } + + /** + * A node. + */ + class NodeExtended extends Lang::Node { + /** + * Gets the type of this node. + */ + Type getType(); + + /** + * Gets the enclosing callable of this node. + */ + Callable getEnclosingCallable(); + + /** + * Gets the enclosing callable of this node, when considered as an expression. + */ + Callable getAsExprEnclosingCallable(); + + /** + * Gets the parameter corresponding to this node, if any. + */ + Parameter asParameter(); + } + + /** + * A class of callables that are potentially relevant for generating summary or + * neutral models. + * + * In the Standard library and 3rd party libraries it is the callables (or callables that have a + * super implementation) that can be called from outside the library itself. + */ + class SummaryTargetApi extends Callable { + /** + * Gets the callable that a model will be lifted to. + * + * The lifted callable is relevant in terms of model + * generation (this is ensured by `liftedImpl`). + */ + Callable lift(); + + /** + * Holds if `this` is relevant in terms of model generation. + */ + predicate isRelevant(); + } + + /** + * A class of callables that are potentially relevant for generating source or + * sink models. + */ + class SourceOrSinkTargetApi extends Callable; + + /** + * A class of callables that are potentially relevant for generating source models. + */ + class SourceTargetApi extends SourceOrSinkTargetApi; + + /** + * A class of callables that are potentially relevant for generating sink models. + */ + class SinkTargetApi extends SourceOrSinkTargetApi; + + /** + * An instance parameter node. + */ + class InstanceParameterNode extends Lang::Node; + + /** + * Holds for type `t` for fields that are relevant as an intermediate + * read or write step in the data flow analysis. + * That is, flow through any data-flow node that does not have a relevant type + * will be excluded. + */ + predicate isRelevantType(Type t); + + /** + * Gets the underlying type of the content `c`. + */ + Type getUnderlyingContentType(Lang::ContentSet c); + + /** + * Gets the MaD string representation of the qualifier. + */ + string qualifierString(); + + /** + * Gets the MaD string representation of the parameter `p`. + */ + string parameterAccess(Parameter p); + + /** + * Gets the MaD string representation of the parameter `p` + * when used in content flow. + */ + string parameterContentAccess(Parameter p); + + /** + * Gets the MaD string representation of return through parameter at position + * `pos` of callable `c`. + */ + bindingset[c] + string paramReturnNodeAsOutput(Callable c, Lang::ParameterPosition p); + + /** + * Gets the MaD string representation of return through parameter at position + * `pos` of callable `c` when used in content flow. + */ + bindingset[c] + string paramReturnNodeAsContentOutput(Callable c, Lang::ParameterPosition pos); + + /** + * Gets the enclosing callable of `ret`. + */ + Callable returnNodeEnclosingCallable(Lang::Node node); + + /** + * Holds if `node` is an own instance access. + */ + predicate isOwnInstanceAccessNode(Lang::ReturnNode node); + + /** + * Holds if `node` is a sanitizer for sink model construction. + */ + predicate sinkModelSanitizer(Lang::Node node); + + /** + * Holds if `source` is an api entrypoint relevant for creating sink models. + */ + predicate apiSource(Lang::Node source); + + /** + * Gets the MaD input string representation of `source`. + */ + string getInputArgument(Lang::Node source); + + /** + * Holds if it is not relevant to generate a source model for `api`, even + * if flow is detected from a node within `source` to a sink within `api`. + */ + bindingset[sourceEnclosing, api] + predicate irrelevantSourceSinkApi(Callable sourceEnclosing, SourceTargetApi api); + + /** + * Holds if `kind` is a relevant sink kind for creating sink models. + */ + bindingset[kind] + predicate isRelevantSinkKind(string kind); + + /** + * Holds if `kind` is a relevant source kind for creating source models. + */ + bindingset[kind] + predicate isRelevantSourceKind(string kind); + + /** + * Holds if the the content `c` is a container. + */ + predicate containerContent(Lang::ContentSet c); + + /** + * Holds if there is a taint step from `node1` to `node2` in content flow. + */ + predicate isAdditionalContentFlowStep(Lang::Node nodeFrom, Lang::Node nodeTo); + + /** + * Holds if the content set `c` is field like. + */ + predicate isField(Lang::ContentSet c); + + /** + * Gets the MaD synthetic name string representation for the content set `c`, if any. + */ + string getSyntheticName(Lang::ContentSet c); + + /** + * Gets the MaD string representation of the content set `c`. + */ + string printContent(Lang::ContentSet c); + + /** + * Holds if it is irrelevant to generate models for `api` based on data flow analysis. + * + * This serves as an extra filter for the `relevant` predicate. + */ + predicate isUninterestingForDataFlowModels(Callable api); + + /** + * Holds if `namespace`, `type`, `extensible`, `name` and `parameters` are string representations + * for the corresponding MaD columns for `api`. + */ + predicate partialModel( + Callable api, string namespace, string type, string extensible, string name, string parameters + ); + + /** + * Holds if `node` is specified as a source with the given kind in a MaD flow + * model. + */ + predicate sourceNode(Lang::Node node, string kind); + + /** + * Holds if `node` is specified as a sink with the given kind in a MaD flow + * model. + */ + predicate sinkNode(Lang::Node node, string kind); +} + +module MakeModelGenerator< + LocationSig Location, InputSig Lang, Tt::InputSig TaintLang, + ModelGeneratorInputSig ModelGeneratorInput> +{ + private module DataFlow { + import Lang + import DataFlowMake + import DataFlowImplCommon::MakeImplCommon + } + + private import ModelGeneratorInput + private import Tt::TaintFlowMake as TaintTracking + + private module ModelPrintingLang implements ModelPrintingLangSig { + class Callable = ModelGeneratorInput::Callable; + + predicate partialModel = ModelGeneratorInput::partialModel/6; + } + + private import ModelPrintingImpl as Printing + + final private class NodeExtendedFinal = NodeExtended; + + /** + * A node from which flow can return to the caller. This is either a regular + * `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter. + */ + private class ReturnNodeExt extends NodeExtendedFinal { + private DataFlow::ReturnKindExt kind; + + ReturnNodeExt() { + kind = DataFlow::getValueReturnPosition(this).getKind() or + kind = DataFlow::getParamReturnPosition(this, _).getKind() + } + + /** + * Gets the kind of the return node. + */ + DataFlow::ReturnKindExt getKind() { result = kind } + } + + bindingset[c] + private signature string printCallableParamSig(Callable c, DataFlow::ParameterPosition p); + + private module PrintReturnNodeExt { + string getOutput(ReturnNodeExt node) { + node.getKind() instanceof DataFlow::ValueReturnKind and + result = "ReturnValue" + or + exists(DataFlow::ParameterPosition pos | + pos = node.getKind().(DataFlow::ParamUpdateReturnKind).getPosition() and + result = printCallableParam(returnNodeEnclosingCallable(node), pos) + ) + } + } + + string getOutput(ReturnNodeExt node) { + result = PrintReturnNodeExt::getOutput(node) + } + + final private class SummaryTargetApiFinal = SummaryTargetApi; + + class DataFlowSummaryTargetApi extends SummaryTargetApiFinal { + DataFlowSummaryTargetApi() { not isUninterestingForDataFlowModels(this) } + } + + class DataFlowSourceTargetApi = SourceTargetApi; + + class DataFlowSinkTargetApi = SinkTargetApi; + + private module ModelPrintingInput implements Printing::ModelPrintingSig { + class SummaryApi = DataFlowSummaryTargetApi; + + class SourceOrSinkApi = SourceOrSinkTargetApi; + + string getProvenance() { result = "df-generated" } + } + + module ModelPrinting = Printing::ModelPrinting; + + /** + * Holds if `c` is a relevant content kind, where the underlying type is relevant. + */ + private predicate isRelevantTypeInContent(DataFlow::ContentSet c) { + isRelevantType(getUnderlyingContentType(c)) + } + + /** + * Holds if data can flow from `node1` to `node2` either via a read or a write of an intermediate field `f`. + */ + private predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(DataFlow::ContentSet f | + DataFlow::readStep(node1, f, node2) and + // Partially restrict the content types used for intermediate steps. + (not exists(getUnderlyingContentType(f)) or isRelevantTypeInContent(f)) + ) + or + exists(DataFlow::ContentSet f | DataFlow::storeStep(node1, f, node2) | containerContent(f)) + } + + /** + * Holds if content `c` is either a field, a synthetic field or language specific + * content of a relevant type or a container like content. + */ + pragma[nomagic] + private predicate isRelevantContent0(DataFlow::ContentSet c) { + isRelevantTypeInContent(c) or + containerContent(c) + } + + /** + * Gets the MaD string representation of the parameter node `p`. + */ + string parameterNodeAsInput(DataFlow::ParameterNode p) { + result = parameterAccess(p.(NodeExtended).asParameter()) + or + result = qualifierString() and p instanceof InstanceParameterNode + } + + /** + * Gets the MaD input string representation of `source`. + */ + string asInputArgument(NodeExtended source) { result = getInputArgument(source) } + + /** + * Gets the summary model of `api`, if it follows the `fluent` programming pattern (returns `this`). + */ + private string captureQualifierFlow(DataFlowSummaryTargetApi api) { + exists(ReturnNodeExt ret | + api = returnNodeEnclosingCallable(ret) and + isOwnInstanceAccessNode(ret) + ) and + result = ModelPrinting::asLiftedValueModel(api, qualifierString(), "ReturnValue") + } + + private int accessPathLimit0() { result = 2 } + + private newtype TTaintState = + TTaintRead(int n) { n in [0 .. accessPathLimit0()] } or + TTaintStore(int n) { n in [1 .. accessPathLimit0()] } + + abstract private class TaintState extends TTaintState { + abstract string toString(); + } + + /** + * A FlowState representing a tainted read. + */ + private class TaintRead extends TaintState, TTaintRead { + private int step; + + TaintRead() { this = TTaintRead(step) } + + /** + * Gets the flow state step number. + */ + int getStep() { result = step } + + override string toString() { result = "TaintRead(" + step + ")" } + } + + /** + * A FlowState representing a tainted write. + */ + private class TaintStore extends TaintState, TTaintStore { + private int step; + + TaintStore() { this = TTaintStore(step) } + + /** + * Gets the flow state step number. + */ + int getStep() { result = step } + + override string toString() { result = "TaintStore(" + step + ")" } + } + + /** + * A data-flow configuration for tracking flow through APIs. + * The sources are the parameters of an API and the sinks are the return values (excluding `this`) and parameters. + * + * This can be used to generate Flow summaries for APIs from parameter to return. + */ + module PropagateFlowConfig implements DataFlow::StateConfigSig { + class FlowState = TaintState; + + predicate isSource(DataFlow::Node source, FlowState state) { + source instanceof DataFlow::ParameterNode and + source.(NodeExtended).getEnclosingCallable() instanceof DataFlowSummaryTargetApi and + state.(TaintRead).getStep() = 0 + } + + predicate isSink(DataFlow::Node sink, FlowState state) { + sink instanceof ReturnNodeExt and + not isOwnInstanceAccessNode(sink) and + not exists(captureQualifierFlow(sink.(NodeExtended).getAsExprEnclosingCallable())) and + (state instanceof TaintRead or state instanceof TaintStore) + } + + predicate isAdditionalFlowStep( + DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2 + ) { + exists(DataFlow::ContentSet c | + DataFlow::store(node1, c.getAStoreContent(), node2, _, _) and + isRelevantContent0(c) and + ( + state1 instanceof TaintRead and state2.(TaintStore).getStep() = 1 + or + state1.(TaintStore).getStep() + 1 = state2.(TaintStore).getStep() + ) + ) + or + exists(DataFlow::ContentSet c | + DataFlow::readStep(node1, c, node2) and + isRelevantContent0(c) and + state1.(TaintRead).getStep() + 1 = state2.(TaintRead).getStep() + ) + } + + predicate isBarrier(DataFlow::Node n) { + exists(Type t | t = n.(NodeExtended).getType() and not isRelevantType(t)) + } + + DataFlow::FlowFeature getAFeature() { + result instanceof DataFlow::FeatureEqualSourceSinkCallContext + } + } + + module PropagateFlow = TaintTracking::GlobalWithState; + + /** + * Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter. + */ + string captureThroughFlow0( + DataFlowSummaryTargetApi api, DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt + ) { + exists(string input, string output | + p.(NodeExtended).getEnclosingCallable() = api and + returnNodeExt.getEnclosingCallable() = api and + input = parameterNodeAsInput(p) and + output = getOutput(returnNodeExt) and + input != output and + result = ModelPrinting::asLiftedTaintModel(api, input, output) + ) + } + + /** + * Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter. + */ + private string captureThroughFlow(DataFlowSummaryTargetApi api) { + exists(DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt | + PropagateFlow::flow(p, returnNodeExt) and + result = captureThroughFlow0(api, p, returnNodeExt) + ) + } + + /** + * Gets the summary model(s) of `api`, if there is flow from parameters to the + * return value or parameter or if `api` is a fluent API. + */ + string captureFlow(DataFlowSummaryTargetApi api) { + result = captureQualifierFlow(api) or + result = captureThroughFlow(api) + } + + /** + * Gets the neutral summary model for `api`, if any. + * A neutral summary model is generated, if we are not generating + * a summary model that applies to `api`. + */ + string captureNoFlow(DataFlowSummaryTargetApi api) { + not exists(DataFlowSummaryTargetApi api0 | + exists(captureFlow(api0)) and api0.lift() = api.lift() + ) and + api.isRelevant() and + result = ModelPrinting::asNeutralSummaryModel(api) + } + + /** + * Provides classes and predicates related to capturing summary models + * based on content data flow. + */ + module ContentSensitive { + private import MakeImplContentDataFlow as ContentDataFlow + + private module PropagateContentFlowConfig implements ContentDataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + source instanceof DataFlow::ParameterNode and + source.(NodeExtended).getEnclosingCallable() instanceof DataFlowSummaryTargetApi + } + + predicate isSink(DataFlow::Node sink) { + sink.(ReturnNodeExt).getEnclosingCallable() instanceof DataFlowSummaryTargetApi + } + + predicate isAdditionalFlowStep = isAdditionalContentFlowStep/2; + + predicate isBarrier(DataFlow::Node n) { + exists(Type t | t = n.(NodeExtended).getType() and not isRelevantType(t)) + } + + int accessPathLimit() { result = 2 } + + predicate isRelevantContent(DataFlow::ContentSet s) { isRelevantContent0(s) } + + DataFlow::FlowFeature getAFeature() { + result instanceof DataFlow::FeatureEqualSourceSinkCallContext + } + } + + private module PropagateContentFlow = ContentDataFlow::Global; + + private string getContentOutput(ReturnNodeExt node) { + result = PrintReturnNodeExt::getOutput(node) + } + + /** + * Gets the MaD string representation of the parameter `p` + * when used in content flow. + */ + private string parameterNodeAsContentInput(DataFlow::ParameterNode p) { + result = parameterContentAccess(p.(NodeExtended).asParameter()) + or + result = qualifierString() and p instanceof InstanceParameterNode + } + + private string getContent(PropagateContentFlow::AccessPath ap, int i) { + exists(DataFlow::ContentSet head, PropagateContentFlow::AccessPath tail | + head = ap.getHead() and + tail = ap.getTail() + | + i = 0 and + result = "." + printContent(head) + or + i > 0 and result = getContent(tail, i - 1) + ) + } + + /** + * Gets the MaD string representation of a store step access path. + */ + private string printStoreAccessPath(PropagateContentFlow::AccessPath ap) { + result = concat(int i | | getContent(ap, i), "" order by i) + } + + /** + * Gets the MaD string representation of a read step access path. + */ + private string printReadAccessPath(PropagateContentFlow::AccessPath ap) { + result = concat(int i | | getContent(ap, i), "" order by i desc) + } + + /** + * Holds if the access path `ap` contains a field or synthetic field access. + */ + private predicate mentionsField(PropagateContentFlow::AccessPath ap) { + exists(DataFlow::ContentSet head, PropagateContentFlow::AccessPath tail | + head = ap.getHead() and + tail = ap.getTail() + | + mentionsField(tail) or isField(head) + ) + } + + private predicate apiFlow( + DataFlowSummaryTargetApi api, DataFlow::ParameterNode p, + PropagateContentFlow::AccessPath reads, ReturnNodeExt returnNodeExt, + PropagateContentFlow::AccessPath stores, boolean preservesValue + ) { + PropagateContentFlow::flow(p, reads, returnNodeExt, stores, preservesValue) and + returnNodeExt.getEnclosingCallable() = api and + p.(NodeExtended).getEnclosingCallable() = api + } + + /** + * A class of APIs relevant for modeling using content flow. + * The following heuristic is applied: + * Content flow is only relevant for an API, if + * #content flow <= 2 * #parameters + 3 + * If an API produces more content flow, it is likely that + * 1. Types are not sufficiently constrained leading to a combinatorial + * explosion in dispatch and thus in the generated summaries. + * 2. It is a reasonable approximation to use the non-content based flow + * detection instead, as reads and stores would use a significant + * part of an objects internal state. + */ + private class ContentDataFlowSummaryTargetApi extends DataFlowSummaryTargetApi { + ContentDataFlowSummaryTargetApi() { + count(string input, string output | + exists( + DataFlow::ParameterNode p, PropagateContentFlow::AccessPath reads, + ReturnNodeExt returnNodeExt, PropagateContentFlow::AccessPath stores + | + apiFlow(this, p, reads, returnNodeExt, stores, _) and + input = parameterNodeAsContentInput(p) + printReadAccessPath(reads) and + output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores) + ) + ) <= 2 * this.getNumberOfParameters() + 3 + } + } + + pragma[nomagic] + private predicate apiContentFlow( + ContentDataFlowSummaryTargetApi api, DataFlow::ParameterNode p, + PropagateContentFlow::AccessPath reads, ReturnNodeExt returnNodeExt, + PropagateContentFlow::AccessPath stores, boolean preservesValue + ) { + PropagateContentFlow::flow(p, reads, returnNodeExt, stores, preservesValue) and + returnNodeExt.getEnclosingCallable() = api and + p.(NodeExtended).getEnclosingCallable() = api + } + + /** + * Holds if any of the content sets in `path` translates into a synthetic field. + */ + private predicate hasSyntheticContent(PropagateContentFlow::AccessPath path) { + exists(PropagateContentFlow::AccessPath tail, DataFlow::ContentSet head | + head = path.getHead() and + tail = path.getTail() + | + exists(getSyntheticName(head)) or + hasSyntheticContent(tail) + ) + } + + /** + * A module containing predicates for validating access paths containing content sets + * that translates into synthetic fields, when used for generated summary models. + */ + private module AccessPathSyntheticValidation { + /** + * Holds if there exists an API that has content flow from `read` (on type `t1`) + * to `store` (on type `t2`). + */ + private predicate step( + Type t1, PropagateContentFlow::AccessPath read, Type t2, + PropagateContentFlow::AccessPath store + ) { + exists(DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt | + p.(NodeExtended).getType() = t1 and + returnNodeExt.getType() = t2 and + apiContentFlow(_, p, read, returnNodeExt, store, _) + ) + } + + /** + * Holds if there exists an API that has content flow from `read` (on type `t1`) + * to `store` (on type `t2`), where `read` does not have synthetic content and `store` does. + * + * Step A -> Synth. + */ + private predicate synthPathEntry( + Type t1, PropagateContentFlow::AccessPath read, Type t2, + PropagateContentFlow::AccessPath store + ) { + not hasSyntheticContent(read) and + hasSyntheticContent(store) and + step(t1, read, t2, store) + } + + /** + * Holds if there exists an API that has content flow from `read` (on type `t1`) + * to `store` (on type `t2`), where `read` has synthetic content + * and `store` does not. + * + * Step Synth -> A. + */ + private predicate synthPathExit( + Type t1, PropagateContentFlow::AccessPath read, Type t2, + PropagateContentFlow::AccessPath store + ) { + hasSyntheticContent(read) and + not hasSyntheticContent(store) and + step(t1, read, t2, store) + } + + /** + * Holds if there exists a path of steps from `read` to an exit. + * + * read ->* Synth -> A + */ + private predicate reachesSynthExit(Type t, PropagateContentFlow::AccessPath read) { + synthPathExit(t, read, _, _) + or + hasSyntheticContent(read) and + exists(PropagateContentFlow::AccessPath mid, Type midType | + hasSyntheticContent(mid) and + step(t, read, midType, mid) and + reachesSynthExit(midType, mid.reverse()) + ) + } + + /** + * Holds if there exists a path of steps from an entry to `store`. + * + * A -> Synth ->* store + */ + private predicate synthEntryReaches(Type t, PropagateContentFlow::AccessPath store) { + synthPathEntry(_, _, t, store) + or + hasSyntheticContent(store) and + exists(PropagateContentFlow::AccessPath mid, Type midType | + hasSyntheticContent(mid) and + step(midType, mid, t, store) and + synthEntryReaches(midType, mid.reverse()) + ) + } + + /** + * Holds if at least one of the access paths `read` (on type `t1`) and `store` (on type `t2`) + * contain content that will be translated into a synthetic field, when being used in + * a MaD summary model, and if there is a range of APIs, such that + * when chaining their flow access paths, there exists access paths `A` and `B` where + * A ->* read -> store ->* B and where `A` and `B` do not contain content that will + * be translated into a synthetic field. + * + * This is needed because we don't want to include summaries that reads from or + * stores into an "internal" synthetic field. + * + * Example: + * Assume we have a type `t` (in this case `t1` = `t2`) with methods `getX` and + * `setX`, which gets and sets a private field `X` on `t`. + * This would lead to the following content flows + * getX : Argument[this].SyntheticField[t.X] -> ReturnValue. + * setX : Argument[0] -> Argument[this].SyntheticField[t.X] + * As the reads and stores are on synthetic fields we should only make summaries + * if both of these methods exist. + */ + pragma[nomagic] + predicate acceptReadStore( + Type t1, PropagateContentFlow::AccessPath read, Type t2, + PropagateContentFlow::AccessPath store + ) { + synthPathEntry(t1, read, t2, store) and reachesSynthExit(t2, store.reverse()) + or + exists(PropagateContentFlow::AccessPath store0 | store0.reverse() = read | + synthEntryReaches(t1, store0) and synthPathExit(t1, read, t2, store) + or + synthEntryReaches(t1, store0) and + step(t1, read, t2, store) and + reachesSynthExit(t2, store.reverse()) + ) + } + } + + /** + * Holds, if the API `api` has relevant flow from `read` on `p` to `store` on `returnNodeExt`. + * Flow is considered relevant, + * 1. If `read` or `store` do not contain a content set that translates into a synthetic field. + * 2. If `read` or `store` contain a content set that translates into a synthetic field, and if + * the synthetic content is "live" on the relevant declaring type. + */ + private predicate apiRelevantContentFlow( + ContentDataFlowSummaryTargetApi api, DataFlow::ParameterNode p, + PropagateContentFlow::AccessPath read, ReturnNodeExt returnNodeExt, + PropagateContentFlow::AccessPath store, boolean preservesValue + ) { + apiContentFlow(api, p, read, returnNodeExt, store, preservesValue) and + ( + not hasSyntheticContent(read) and not hasSyntheticContent(store) + or + AccessPathSyntheticValidation::acceptReadStore(p.(NodeExtended).getType(), read, + returnNodeExt.getType(), store) + ) + } + + pragma[nomagic] + private predicate captureFlow0( + ContentDataFlowSummaryTargetApi api, string input, string output, boolean preservesValue, + boolean lift + ) { + exists( + DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt, + PropagateContentFlow::AccessPath reads, PropagateContentFlow::AccessPath stores + | + apiRelevantContentFlow(api, p, reads, returnNodeExt, stores, preservesValue) and + input = parameterNodeAsContentInput(p) + printReadAccessPath(reads) and + output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores) and + input != output and + (if mentionsField(reads) or mentionsField(stores) then lift = false else lift = true) + ) + } + + /** + * Gets the content based summary model(s) of the API `api` (if there is flow from a parameter to + * the return value or a parameter). + * + * Models are lifted to the best type in case the read and store access paths do not + * contain a field or synthetic field access. + */ + string captureFlow(ContentDataFlowSummaryTargetApi api) { + exists(string input, string output, boolean lift, boolean preservesValue | + captureFlow0(api, input, output, _, lift) and + preservesValue = max(boolean p | captureFlow0(api, input, output, p, lift)) and + result = ModelPrinting::asModel(api, input, output, preservesValue, lift) + ) + } + } + + /** + * A dataflow configuration used for finding new sources. + * The sources are the already known existing sources and the sinks are the API return nodes. + * + * This can be used to generate Source summaries for an API, if the API expose an already known source + * via its return (then the API itself becomes a source). + */ + module PropagateFromSourceConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + exists(string kind | + isRelevantSourceKind(kind) and + sourceNode(source, kind) + ) + } + + predicate isSink(DataFlow::Node sink) { + sink.(ReturnNodeExt).getEnclosingCallable() instanceof DataFlowSourceTargetApi + } + + DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSinkCallContext } + + predicate isBarrier(DataFlow::Node n) { + exists(Type t | t = n.(NodeExtended).getType() and not isRelevantType(t)) + } + + predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { + isRelevantTaintStep(node1, node2) + } + } + + private module PropagateFromSource = TaintTracking::Global; + + /** + * Gets the source model(s) of `api`, if there is flow from an existing known source to the return of `api`. + */ + string captureSource(DataFlowSourceTargetApi api) { + exists(NodeExtended source, ReturnNodeExt sink, string kind | + PropagateFromSource::flow(source, sink) and + sourceNode(source, kind) and + api = sink.getEnclosingCallable() and + not irrelevantSourceSinkApi(source.getEnclosingCallable(), api) and + result = ModelPrinting::asSourceModel(api, getOutput(sink), kind) + ) + } + + /** + * A dataflow configuration used for finding new sinks. + * The sources are the parameters of the API and the fields of the enclosing type. + * + * This can be used to generate Sink summaries for APIs, if the API propagates a parameter (or enclosing type field) + * into an existing known sink (then the API itself becomes a sink). + */ + module PropagateToSinkConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + apiSource(source) and + source.(NodeExtended).getEnclosingCallable() instanceof DataFlowSinkTargetApi + } + + predicate isSink(DataFlow::Node sink) { + exists(string kind | isRelevantSinkKind(kind) and sinkNode(sink, kind)) + } + + predicate isBarrier(DataFlow::Node node) { + exists(Type t | t = node.(NodeExtended).getType() and not isRelevantType(t)) + or + sinkModelSanitizer(node) + } + + DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext } + + predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { + isRelevantTaintStep(node1, node2) + } + } + + private module PropagateToSink = TaintTracking::Global; + + /** + * Gets the sink model(s) of `api`, if there is flow from a parameter to an existing known sink. + */ + string captureSink(DataFlowSinkTargetApi api) { + exists(NodeExtended src, NodeExtended sink, string kind | + PropagateToSink::flow(src, sink) and + sinkNode(sink, kind) and + api = src.getEnclosingCallable() and + result = ModelPrinting::asSinkModel(api, asInputArgument(src), kind) + ) + } +} diff --git a/shared/mad/codeql/mad/modelgenerator/ModelPrinting.qll b/shared/mad/codeql/mad/modelgenerator/internal/ModelPrinting.qll similarity index 100% rename from shared/mad/codeql/mad/modelgenerator/ModelPrinting.qll rename to shared/mad/codeql/mad/modelgenerator/internal/ModelPrinting.qll diff --git a/shared/mad/qlpack.yml b/shared/mad/qlpack.yml index 9933a7eef31b..e1bb442e4aee 100644 --- a/shared/mad/qlpack.yml +++ b/shared/mad/qlpack.yml @@ -4,4 +4,5 @@ groups: shared library: true dependencies: codeql/util: ${workspace} + codeql/dataflow: ${workspace} warnOnImplicitThis: true diff --git a/shared/util/codeql/util/AlertFiltering.qll b/shared/util/codeql/util/AlertFiltering.qll new file mode 100644 index 000000000000..d1778304b733 --- /dev/null +++ b/shared/util/codeql/util/AlertFiltering.qll @@ -0,0 +1,40 @@ +/** + * Provides the `restrictAlertsTo` extensible predicate to restrict alerts to specific source + * locations, and the `AlertFilteringImpl` parameterized module to apply the filtering. + */ + +private import codeql.util.Location + +/** + * Restricts alerts to a specific location in specific files. + * + * If this predicate is empty, accept all alerts. Otherwise, accept alerts only at the specified + * locations. Note that alert restrictions apply only to the start line of an alert (even if the + * alert location spans multiple lines) because alerts are displayed on their start lines. + * + * - filePath: Absolute path of the file to restrict alerts to. + * - startLine: Start line number (starting with 1, inclusive) to restrict alerts to. + * - endLine: End line number (starting with 1, inclusive) to restrict alerts to. + * + * If startLine and endLine are both 0, accept alerts anywhere in the file. + */ +extensible predicate restrictAlertsTo(string filePath, int startLine, int endLine); + +/** Module for applying alert location filtering. */ +module AlertFilteringImpl { + /** Applies alert filtering to the given location. */ + bindingset[location] + predicate filterByLocation(Location location) { + not restrictAlertsTo(_, _, _) + or + exists(string filePath, int startLine, int endLine | + restrictAlertsTo(filePath, startLine, endLine) + | + startLine = 0 and + endLine = 0 and + location.hasLocationInfo(filePath, _, _, _, _) + or + location.hasLocationInfo(filePath, [startLine .. endLine], _, _, _) + ) + } +} diff --git a/shared/util/ext/default-alert-filter.yml b/shared/util/ext/default-alert-filter.yml new file mode 100644 index 000000000000..0ae5a2f4eb5b --- /dev/null +++ b/shared/util/ext/default-alert-filter.yml @@ -0,0 +1,7 @@ +extensions: + + - addsTo: + pack: codeql/util + extensible: restrictAlertsTo + # Empty predicate means no restrictions on alert locations + data: [] diff --git a/shared/util/qlpack.yml b/shared/util/qlpack.yml index 2f5ab19dec43..2e46755f89fe 100644 --- a/shared/util/qlpack.yml +++ b/shared/util/qlpack.yml @@ -3,4 +3,6 @@ version: 1.0.9-dev groups: shared library: true dependencies: null +dataExtensions: + - ext/*.yml warnOnImplicitThis: true diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl1.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl1.qll index 359fa71744b4..ce964917e970 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl1.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl1.qll @@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig { FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } + + predicate observeDiffInformedIncrementalMode() { none() } } deprecated private import Impl as I diff --git a/swift/ql/test/library-tests/dataflow/taint/core/Taint.expected b/swift/ql/test/library-tests/dataflow/taint/core/Taint.expected index c1b219288812..70cf2d3eaf00 100644 --- a/swift/ql/test/library-tests/dataflow/taint/core/Taint.expected +++ b/swift/ql/test/library-tests/dataflow/taint/core/Taint.expected @@ -2,9 +2,7 @@ edges | conversions.swift:33:16:33:26 | call to sourceInt() | conversions.swift:33:12:33:27 | call to Self.init(_:) | provenance | | | conversions.swift:34:18:34:28 | call to sourceInt() | conversions.swift:34:12:34:29 | call to Self.init(_:) | provenance | | | conversions.swift:35:18:35:28 | call to sourceInt() | conversions.swift:35:12:35:29 | call to Float.init(_:) | provenance | | -| conversions.swift:36:12:36:30 | call to String.init(_:) [Collection element] | conversions.swift:36:12:36:30 | call to String.init(_:) | provenance | | | conversions.swift:36:19:36:29 | call to sourceInt() | conversions.swift:36:12:36:30 | call to String.init(_:) | provenance | | -| conversions.swift:36:19:36:29 | call to sourceInt() | conversions.swift:36:12:36:30 | call to String.init(_:) [Collection element] | provenance | | | conversions.swift:37:12:37:30 | call to String.init(_:) | conversions.swift:37:12:37:32 | .utf8 | provenance | | | conversions.swift:37:19:37:29 | call to sourceInt() | conversions.swift:37:12:37:30 | call to String.init(_:) | provenance | | | conversions.swift:39:12:39:30 | [...] [Collection element] | conversions.swift:40:12:40:12 | arr | provenance | | @@ -13,13 +11,11 @@ edges | conversions.swift:39:12:39:30 | [...] [Collection element] | conversions.swift:43:20:43:20 | arr [Collection element] | provenance | | | conversions.swift:39:19:39:29 | call to sourceInt() | conversions.swift:39:12:39:30 | [...] [Collection element] | provenance | | | conversions.swift:41:12:41:12 | arr [Collection element] | conversions.swift:41:12:41:17 | ...[...] | provenance | | -| conversions.swift:42:12:42:23 | call to Array.init(_:) [Collection element] | conversions.swift:42:12:42:23 | call to Array.init(_:) | provenance | | -| conversions.swift:42:20:42:20 | arr [Collection element] | conversions.swift:42:12:42:23 | call to Array.init(_:) [Collection element] | provenance | | +| conversions.swift:42:20:42:20 | arr [Collection element] | conversions.swift:42:12:42:23 | call to Array.init(_:) | provenance | | | conversions.swift:43:12:43:23 | call to Array.init(_:) [Collection element] | conversions.swift:43:12:43:26 | ...[...] | provenance | | | conversions.swift:43:20:43:20 | arr [Collection element] | conversions.swift:43:12:43:23 | call to Array.init(_:) [Collection element] | provenance | | -| conversions.swift:44:12:44:39 | call to Array.init(_:) [Collection element] | conversions.swift:44:12:44:39 | call to Array.init(_:) | provenance | | | conversions.swift:44:20:44:33 | call to sourceString() | conversions.swift:44:20:44:35 | .utf8 | provenance | | -| conversions.swift:44:20:44:35 | .utf8 | conversions.swift:44:12:44:39 | call to Array.init(_:) [Collection element] | provenance | | +| conversions.swift:44:20:44:35 | .utf8 | conversions.swift:44:12:44:39 | call to Array.init(_:) | provenance | | | conversions.swift:45:12:45:39 | call to Array.init(_:) [Collection element] | conversions.swift:45:12:45:42 | ...[...] | provenance | | | conversions.swift:45:20:45:33 | call to sourceString() | conversions.swift:45:20:45:35 | .utf8 | provenance | | | conversions.swift:45:20:45:35 | .utf8 | conversions.swift:45:12:45:39 | call to Array.init(_:) [Collection element] | provenance | | @@ -49,19 +45,13 @@ edges | conversions.swift:80:12:80:22 | call to sourceInt() | conversions.swift:80:12:80:24 | .bigEndian | provenance | | | conversions.swift:109:18:109:30 | call to sourceFloat() | conversions.swift:109:12:109:31 | call to Float.init(_:) | provenance | | | conversions.swift:110:18:110:30 | call to sourceFloat() | conversions.swift:110:12:110:31 | call to UInt8.init(_:) | provenance | | -| conversions.swift:111:12:111:32 | call to String.init(_:) [Collection element] | conversions.swift:111:12:111:32 | call to String.init(_:) | provenance | | | conversions.swift:111:19:111:31 | call to sourceFloat() | conversions.swift:111:12:111:32 | call to String.init(_:) | provenance | | -| conversions.swift:111:19:111:31 | call to sourceFloat() | conversions.swift:111:12:111:32 | call to String.init(_:) [Collection element] | provenance | | | conversions.swift:112:12:112:32 | call to String.init(_:) | conversions.swift:112:12:112:34 | .utf8 | provenance | | | conversions.swift:112:19:112:31 | call to sourceFloat() | conversions.swift:112:12:112:32 | call to String.init(_:) | provenance | | -| conversions.swift:113:12:113:34 | call to String.init(_:) [Collection element] | conversions.swift:113:12:113:34 | call to String.init(_:) | provenance | | | conversions.swift:113:19:113:33 | call to sourceFloat80() | conversions.swift:113:12:113:34 | call to String.init(_:) | provenance | | -| conversions.swift:113:19:113:33 | call to sourceFloat80() | conversions.swift:113:12:113:34 | call to String.init(_:) [Collection element] | provenance | | | conversions.swift:114:12:114:34 | call to String.init(_:) | conversions.swift:114:12:114:36 | .utf8 | provenance | | | conversions.swift:114:19:114:33 | call to sourceFloat80() | conversions.swift:114:12:114:34 | call to String.init(_:) | provenance | | -| conversions.swift:115:12:115:33 | call to String.init(_:) [Collection element] | conversions.swift:115:12:115:33 | call to String.init(_:) | provenance | | | conversions.swift:115:19:115:32 | call to sourceDouble() | conversions.swift:115:12:115:33 | call to String.init(_:) | provenance | | -| conversions.swift:115:19:115:32 | call to sourceDouble() | conversions.swift:115:12:115:33 | call to String.init(_:) [Collection element] | provenance | | | conversions.swift:116:12:116:33 | call to String.init(_:) | conversions.swift:116:12:116:35 | .utf8 | provenance | | | conversions.swift:116:19:116:32 | call to sourceDouble() | conversions.swift:116:12:116:33 | call to String.init(_:) | provenance | | | conversions.swift:118:18:118:30 | call to sourceFloat() | conversions.swift:118:12:118:31 | call to Float.init(_:) | provenance | | @@ -76,9 +66,7 @@ edges | conversions.swift:129:12:129:25 | call to sourceDouble() | conversions.swift:129:12:129:27 | .significand | provenance | | | conversions.swift:130:12:130:23 | call to sourceUInt() | conversions.swift:130:12:130:25 | .byteSwapped | provenance | | | conversions.swift:131:12:131:25 | call to sourceUInt64() | conversions.swift:131:12:131:27 | .byteSwapped | provenance | | -| conversions.swift:136:12:136:33 | call to String.init(_:) [Collection element] | conversions.swift:136:12:136:33 | call to String.init(_:) | provenance | | | conversions.swift:136:19:136:32 | call to sourceString() | conversions.swift:136:12:136:33 | call to String.init(_:) | provenance | | -| conversions.swift:136:19:136:32 | call to sourceString() | conversions.swift:136:12:136:33 | call to String.init(_:) [Collection element] | provenance | | | conversions.swift:144:12:144:35 | call to MyString.init(_:) | conversions.swift:144:12:144:35 | call to MyString.init(_:) [some:0] | provenance | | | conversions.swift:144:12:144:35 | call to MyString.init(_:) | conversions.swift:145:12:145:12 | ms2 | provenance | | | conversions.swift:144:12:144:35 | call to MyString.init(_:) | conversions.swift:146:12:146:16 | .description | provenance | | @@ -251,7 +239,6 @@ nodes | conversions.swift:35:12:35:29 | call to Float.init(_:) | semmle.label | call to Float.init(_:) | | conversions.swift:35:18:35:28 | call to sourceInt() | semmle.label | call to sourceInt() | | conversions.swift:36:12:36:30 | call to String.init(_:) | semmle.label | call to String.init(_:) | -| conversions.swift:36:12:36:30 | call to String.init(_:) [Collection element] | semmle.label | call to String.init(_:) [Collection element] | | conversions.swift:36:19:36:29 | call to sourceInt() | semmle.label | call to sourceInt() | | conversions.swift:37:12:37:30 | call to String.init(_:) | semmle.label | call to String.init(_:) | | conversions.swift:37:12:37:32 | .utf8 | semmle.label | .utf8 | @@ -262,13 +249,11 @@ nodes | conversions.swift:41:12:41:12 | arr [Collection element] | semmle.label | arr [Collection element] | | conversions.swift:41:12:41:17 | ...[...] | semmle.label | ...[...] | | conversions.swift:42:12:42:23 | call to Array.init(_:) | semmle.label | call to Array.init(_:) | -| conversions.swift:42:12:42:23 | call to Array.init(_:) [Collection element] | semmle.label | call to Array.init(_:) [Collection element] | | conversions.swift:42:20:42:20 | arr [Collection element] | semmle.label | arr [Collection element] | | conversions.swift:43:12:43:23 | call to Array.init(_:) [Collection element] | semmle.label | call to Array.init(_:) [Collection element] | | conversions.swift:43:12:43:26 | ...[...] | semmle.label | ...[...] | | conversions.swift:43:20:43:20 | arr [Collection element] | semmle.label | arr [Collection element] | | conversions.swift:44:12:44:39 | call to Array.init(_:) | semmle.label | call to Array.init(_:) | -| conversions.swift:44:12:44:39 | call to Array.init(_:) [Collection element] | semmle.label | call to Array.init(_:) [Collection element] | | conversions.swift:44:20:44:33 | call to sourceString() | semmle.label | call to sourceString() | | conversions.swift:44:20:44:35 | .utf8 | semmle.label | .utf8 | | conversions.swift:45:12:45:39 | call to Array.init(_:) [Collection element] | semmle.label | call to Array.init(_:) [Collection element] | @@ -321,19 +306,16 @@ nodes | conversions.swift:110:12:110:31 | call to UInt8.init(_:) | semmle.label | call to UInt8.init(_:) | | conversions.swift:110:18:110:30 | call to sourceFloat() | semmle.label | call to sourceFloat() | | conversions.swift:111:12:111:32 | call to String.init(_:) | semmle.label | call to String.init(_:) | -| conversions.swift:111:12:111:32 | call to String.init(_:) [Collection element] | semmle.label | call to String.init(_:) [Collection element] | | conversions.swift:111:19:111:31 | call to sourceFloat() | semmle.label | call to sourceFloat() | | conversions.swift:112:12:112:32 | call to String.init(_:) | semmle.label | call to String.init(_:) | | conversions.swift:112:12:112:34 | .utf8 | semmle.label | .utf8 | | conversions.swift:112:19:112:31 | call to sourceFloat() | semmle.label | call to sourceFloat() | | conversions.swift:113:12:113:34 | call to String.init(_:) | semmle.label | call to String.init(_:) | -| conversions.swift:113:12:113:34 | call to String.init(_:) [Collection element] | semmle.label | call to String.init(_:) [Collection element] | | conversions.swift:113:19:113:33 | call to sourceFloat80() | semmle.label | call to sourceFloat80() | | conversions.swift:114:12:114:34 | call to String.init(_:) | semmle.label | call to String.init(_:) | | conversions.swift:114:12:114:36 | .utf8 | semmle.label | .utf8 | | conversions.swift:114:19:114:33 | call to sourceFloat80() | semmle.label | call to sourceFloat80() | | conversions.swift:115:12:115:33 | call to String.init(_:) | semmle.label | call to String.init(_:) | -| conversions.swift:115:12:115:33 | call to String.init(_:) [Collection element] | semmle.label | call to String.init(_:) [Collection element] | | conversions.swift:115:19:115:32 | call to sourceDouble() | semmle.label | call to sourceDouble() | | conversions.swift:116:12:116:33 | call to String.init(_:) | semmle.label | call to String.init(_:) | | conversions.swift:116:12:116:35 | .utf8 | semmle.label | .utf8 | @@ -364,7 +346,6 @@ nodes | conversions.swift:131:12:131:27 | .byteSwapped | semmle.label | .byteSwapped | | conversions.swift:135:12:135:25 | call to sourceString() | semmle.label | call to sourceString() | | conversions.swift:136:12:136:33 | call to String.init(_:) | semmle.label | call to String.init(_:) | -| conversions.swift:136:12:136:33 | call to String.init(_:) [Collection element] | semmle.label | call to String.init(_:) [Collection element] | | conversions.swift:136:19:136:32 | call to sourceString() | semmle.label | call to sourceString() | | conversions.swift:144:12:144:35 | call to MyString.init(_:) | semmle.label | call to MyString.init(_:) | | conversions.swift:144:12:144:35 | call to MyString.init(_:) [some:0] | semmle.label | call to MyString.init(_:) [some:0] | diff --git a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index 0fe8ae7b8685..6e6b86231495 100644 --- a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -14,8 +14,7 @@ edges | CommandInjection.swift:75:40:75:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:75:8:75:12 | let ...? [some:0] | provenance | | | CommandInjection.swift:75:40:75:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:75:40:75:94 | call to String.init(contentsOf:) [some:0, some:0] | provenance | | | CommandInjection.swift:75:40:75:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:84:43:84:43 | userControlledString [some:0] | provenance | | -| CommandInjection.swift:81:2:81:2 | [post] task1 [arguments, Collection element] | CommandInjection.swift:81:2:81:2 | [post] task1 | provenance | | -| CommandInjection.swift:81:20:81:47 | [...] [Collection element] | CommandInjection.swift:81:2:81:2 | [post] task1 [arguments, Collection element] | provenance | | +| CommandInjection.swift:81:20:81:47 | [...] [Collection element] | CommandInjection.swift:81:2:81:2 | [post] task1 | provenance | | | CommandInjection.swift:81:27:81:27 | userControlledString | CommandInjection.swift:81:20:81:47 | [...] [Collection element] | provenance | | | CommandInjection.swift:84:5:84:9 | let ...? [some:0] | CommandInjection.swift:84:9:84:9 | validatedString | provenance | | | CommandInjection.swift:84:9:84:9 | validatedString | CommandInjection.swift:87:31:87:31 | validatedString | provenance | | @@ -26,12 +25,10 @@ edges | CommandInjection.swift:84:43:84:43 | userControlledString | CommandInjection.swift:84:27:84:63 | call to validateCommand(_:) [some:0] | provenance | | | CommandInjection.swift:84:43:84:43 | userControlledString [some:0] | CommandInjection.swift:64:22:64:33 | command [some:0] | provenance | | | CommandInjection.swift:84:43:84:43 | userControlledString [some:0] | CommandInjection.swift:84:27:84:63 | call to validateCommand(_:) [some:0] | provenance | | -| CommandInjection.swift:87:6:87:6 | [post] task2 [arguments, Collection element] | CommandInjection.swift:87:6:87:6 | [post] task2 | provenance | | -| CommandInjection.swift:87:24:87:46 | [...] [Collection element] | CommandInjection.swift:87:6:87:6 | [post] task2 [arguments, Collection element] | provenance | | +| CommandInjection.swift:87:24:87:46 | [...] [Collection element] | CommandInjection.swift:87:6:87:6 | [post] task2 | provenance | | | CommandInjection.swift:87:31:87:31 | validatedString | CommandInjection.swift:87:24:87:46 | [...] [Collection element] | provenance | | | CommandInjection.swift:99:20:99:40 | arguments [Collection element] | CommandInjection.swift:100:20:100:20 | arguments [Collection element] | provenance | | -| CommandInjection.swift:100:3:100:3 | [post] self [arguments, Collection element] | CommandInjection.swift:100:3:100:3 | [post] self | provenance | | -| CommandInjection.swift:100:20:100:20 | arguments [Collection element] | CommandInjection.swift:100:3:100:3 | [post] self [arguments, Collection element] | provenance | | +| CommandInjection.swift:100:20:100:20 | arguments [Collection element] | CommandInjection.swift:100:3:100:3 | [post] self | provenance | | | CommandInjection.swift:105:8:105:12 | let ...? [some:0] | CommandInjection.swift:105:12:105:12 | userControlledString | provenance | | | CommandInjection.swift:105:12:105:12 | userControlledString | CommandInjection.swift:120:36:120:36 | userControlledString | provenance | | | CommandInjection.swift:105:12:105:12 | userControlledString | CommandInjection.swift:121:28:121:28 | userControlledString | provenance | | @@ -73,55 +70,42 @@ edges | CommandInjection.swift:105:40:105:94 | call to String.init(contentsOf:) | CommandInjection.swift:164:33:164:33 | userControlledString | provenance | | | CommandInjection.swift:105:40:105:94 | call to String.init(contentsOf:) | CommandInjection.swift:166:57:166:57 | userControlledString | provenance | | | CommandInjection.swift:105:40:105:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:105:8:105:12 | let ...? [some:0] | provenance | | -| CommandInjection.swift:120:2:120:2 | [post] task3 [executableURL] | CommandInjection.swift:120:2:120:2 | [post] task3 | provenance | | | CommandInjection.swift:120:24:120:56 | call to URL.init(string:) [some:0] | CommandInjection.swift:120:24:120:57 | ...! | provenance | | -| CommandInjection.swift:120:24:120:57 | ...! | CommandInjection.swift:120:2:120:2 | [post] task3 [executableURL] | provenance | | +| CommandInjection.swift:120:24:120:57 | ...! | CommandInjection.swift:120:2:120:2 | [post] task3 | provenance | | | CommandInjection.swift:120:36:120:36 | userControlledString | CommandInjection.swift:120:24:120:56 | call to URL.init(string:) [some:0] | provenance | | -| CommandInjection.swift:121:2:121:2 | [post] task3 [arguments, Collection element] | CommandInjection.swift:121:2:121:2 | [post] task3 | provenance | | -| CommandInjection.swift:121:20:121:48 | [...] [Collection element] | CommandInjection.swift:121:2:121:2 | [post] task3 [arguments, Collection element] | provenance | | +| CommandInjection.swift:121:20:121:48 | [...] [Collection element] | CommandInjection.swift:121:2:121:2 | [post] task3 | provenance | | | CommandInjection.swift:121:28:121:28 | userControlledString | CommandInjection.swift:121:20:121:48 | [...] [Collection element] | provenance | | -| CommandInjection.swift:125:2:125:2 | [post] task4 [executableURL] | CommandInjection.swift:125:2:125:2 | [post] task4 | provenance | | -| CommandInjection.swift:125:24:125:65 | call to URL.init(fileURLWithPath:) | CommandInjection.swift:125:2:125:2 | [post] task4 [executableURL] | provenance | | +| CommandInjection.swift:125:24:125:65 | call to URL.init(fileURLWithPath:) | CommandInjection.swift:125:2:125:2 | [post] task4 | provenance | | | CommandInjection.swift:125:45:125:45 | userControlledString | CommandInjection.swift:125:24:125:65 | call to URL.init(fileURLWithPath:) | provenance | | -| CommandInjection.swift:126:2:126:2 | [post] task4 [executableURL] | CommandInjection.swift:126:2:126:2 | [post] task4 | provenance | | | CommandInjection.swift:126:24:126:56 | call to URL.init(string:) [some:0] | CommandInjection.swift:126:24:126:57 | ...! | provenance | | -| CommandInjection.swift:126:24:126:57 | ...! | CommandInjection.swift:126:2:126:2 | [post] task4 [executableURL] | provenance | | +| CommandInjection.swift:126:24:126:57 | ...! | CommandInjection.swift:126:2:126:2 | [post] task4 | provenance | | | CommandInjection.swift:126:36:126:36 | userControlledString | CommandInjection.swift:126:24:126:56 | call to URL.init(string:) [some:0] | provenance | | -| CommandInjection.swift:127:2:127:2 | [post] task4 [arguments, Collection element] | CommandInjection.swift:127:2:127:2 | [post] task4 | provenance | | -| CommandInjection.swift:127:20:127:56 | [...] [Collection element] | CommandInjection.swift:127:2:127:2 | [post] task4 [arguments, Collection element] | provenance | | +| CommandInjection.swift:127:20:127:56 | [...] [Collection element] | CommandInjection.swift:127:2:127:2 | [post] task4 | provenance | | | CommandInjection.swift:127:28:127:36 | ... .+(_:_:) ... | CommandInjection.swift:127:20:127:56 | [...] [Collection element] | provenance | | -| CommandInjection.swift:131:2:131:7 | [post] ...? [executableURL] | CommandInjection.swift:131:2:131:7 | [post] ...? | provenance | | -| CommandInjection.swift:131:25:131:66 | call to URL.init(fileURLWithPath:) | CommandInjection.swift:131:2:131:7 | [post] ...? [executableURL] | provenance | | +| CommandInjection.swift:131:25:131:66 | call to URL.init(fileURLWithPath:) | CommandInjection.swift:131:2:131:7 | [post] ...? | provenance | | | CommandInjection.swift:131:46:131:46 | userControlledString | CommandInjection.swift:131:25:131:66 | call to URL.init(fileURLWithPath:) | provenance | | -| CommandInjection.swift:132:2:132:7 | [post] ...? [arguments, Collection element] | CommandInjection.swift:132:2:132:7 | [post] ...? | provenance | | -| CommandInjection.swift:132:21:132:42 | [...] [Collection element] | CommandInjection.swift:132:2:132:7 | [post] ...? [arguments, Collection element] | provenance | | +| CommandInjection.swift:132:21:132:42 | [...] [Collection element] | CommandInjection.swift:132:2:132:7 | [post] ...? | provenance | | | CommandInjection.swift:132:22:132:22 | userControlledString | CommandInjection.swift:132:21:132:42 | [...] [Collection element] | provenance | | -| CommandInjection.swift:136:2:136:2 | [post] task6 [executableURL] | CommandInjection.swift:136:2:136:2 | [post] task6 | provenance | | -| CommandInjection.swift:136:24:136:65 | call to URL.init(fileURLWithPath:) | CommandInjection.swift:136:2:136:2 | [post] task6 [executableURL] | provenance | | +| CommandInjection.swift:136:24:136:65 | call to URL.init(fileURLWithPath:) | CommandInjection.swift:136:2:136:2 | [post] task6 | provenance | | | CommandInjection.swift:136:45:136:45 | userControlledString | CommandInjection.swift:136:24:136:65 | call to URL.init(fileURLWithPath:) | provenance | | -| CommandInjection.swift:137:2:137:2 | [post] task6 [executableURL] | CommandInjection.swift:137:2:137:2 | [post] task6 | provenance | | | CommandInjection.swift:137:24:137:56 | call to URL.init(string:) [some:0] | CommandInjection.swift:137:24:137:57 | ...! | provenance | | -| CommandInjection.swift:137:24:137:57 | ...! | CommandInjection.swift:137:2:137:2 | [post] task6 [executableURL] | provenance | | +| CommandInjection.swift:137:24:137:57 | ...! | CommandInjection.swift:137:2:137:2 | [post] task6 | provenance | | | CommandInjection.swift:137:36:137:36 | userControlledString | CommandInjection.swift:137:24:137:56 | call to URL.init(string:) [some:0] | provenance | | -| CommandInjection.swift:138:2:138:2 | [post] task6 [arguments, Collection element] | CommandInjection.swift:138:2:138:2 | [post] task6 | provenance | | -| CommandInjection.swift:138:20:138:41 | [...] [Collection element] | CommandInjection.swift:138:2:138:2 | [post] task6 [arguments, Collection element] | provenance | | +| CommandInjection.swift:138:20:138:41 | [...] [Collection element] | CommandInjection.swift:138:2:138:2 | [post] task6 | provenance | | | CommandInjection.swift:138:21:138:21 | userControlledString | CommandInjection.swift:138:20:138:41 | [...] [Collection element] | provenance | | | CommandInjection.swift:139:21:139:42 | [...] [Collection element] | CommandInjection.swift:99:20:99:40 | arguments [Collection element] | provenance | | | CommandInjection.swift:139:22:139:22 | userControlledString | CommandInjection.swift:139:21:139:42 | [...] [Collection element] | provenance | | -| CommandInjection.swift:151:67:151:95 | [...] [Collection element] | CommandInjection.swift:151:67:151:95 | [...] | provenance | | -| CommandInjection.swift:151:75:151:75 | userControlledString | CommandInjection.swift:151:67:151:95 | [...] [Collection element] | provenance | | +| CommandInjection.swift:151:75:151:75 | userControlledString | CommandInjection.swift:151:67:151:95 | [...] | provenance | | | CommandInjection.swift:154:23:154:55 | call to URL.init(string:) [some:0] | CommandInjection.swift:154:23:154:56 | ...! | provenance | | | CommandInjection.swift:154:35:154:35 | userControlledString | CommandInjection.swift:154:23:154:55 | call to URL.init(string:) [some:0] | provenance | | -| CommandInjection.swift:155:62:155:90 | [...] [Collection element] | CommandInjection.swift:155:62:155:90 | [...] | provenance | | -| CommandInjection.swift:155:70:155:70 | userControlledString | CommandInjection.swift:155:62:155:90 | [...] [Collection element] | provenance | | +| CommandInjection.swift:155:70:155:70 | userControlledString | CommandInjection.swift:155:62:155:90 | [...] | provenance | | | CommandInjection.swift:160:41:160:73 | call to URL.init(string:) [some:0] | CommandInjection.swift:160:41:160:74 | ...! | provenance | | | CommandInjection.swift:160:53:160:53 | userControlledString | CommandInjection.swift:160:41:160:73 | call to URL.init(string:) [some:0] | provenance | | | CommandInjection.swift:163:40:163:72 | call to URL.init(string:) [some:0] | CommandInjection.swift:163:40:163:73 | ...! | provenance | | | CommandInjection.swift:163:40:163:72 | call to URL.init(string:) [some:0] | CommandInjection.swift:163:40:163:73 | ...! | provenance | | | CommandInjection.swift:163:40:163:73 | ...! | file://:0:0:0:0 | url | provenance | | | CommandInjection.swift:163:52:163:52 | userControlledString | CommandInjection.swift:163:40:163:72 | call to URL.init(string:) [some:0] | provenance | | -| CommandInjection.swift:164:32:164:53 | [...] [Collection element] | CommandInjection.swift:164:32:164:53 | [...] | provenance | | -| CommandInjection.swift:164:33:164:33 | userControlledString | CommandInjection.swift:164:32:164:53 | [...] [Collection element] | provenance | | +| CommandInjection.swift:164:33:164:33 | userControlledString | CommandInjection.swift:164:32:164:53 | [...] | provenance | | | CommandInjection.swift:166:45:166:77 | call to URL.init(string:) [some:0] | CommandInjection.swift:166:45:166:78 | ...! | provenance | | | CommandInjection.swift:166:45:166:77 | call to URL.init(string:) [some:0] | CommandInjection.swift:166:45:166:78 | ...! | provenance | | | CommandInjection.swift:166:45:166:78 | ...! | file://:0:0:0:0 | url | provenance | | @@ -129,12 +113,9 @@ edges | CommandInjection.swift:193:3:193:3 | newValue [Collection element] | CommandInjection.swift:194:19:194:19 | newValue [Collection element] | provenance | | | CommandInjection.swift:193:3:193:3 | newValue [Collection element] | CommandInjection.swift:195:20:195:20 | newValue [Collection element] | provenance | | | CommandInjection.swift:193:3:193:3 | newValue [Collection element] | CommandInjection.swift:196:19:196:19 | newValue [Collection element] | provenance | | -| CommandInjection.swift:194:4:194:4 | [post] getter for .p1 [arguments, Collection element] | CommandInjection.swift:194:4:194:4 | [post] getter for .p1 | provenance | | -| CommandInjection.swift:194:19:194:19 | newValue [Collection element] | CommandInjection.swift:194:4:194:4 | [post] getter for .p1 [arguments, Collection element] | provenance | | -| CommandInjection.swift:195:4:195:6 | [post] ...! [arguments, Collection element] | CommandInjection.swift:195:4:195:6 | [post] ...! | provenance | | -| CommandInjection.swift:195:20:195:20 | newValue [Collection element] | CommandInjection.swift:195:4:195:6 | [post] ...! [arguments, Collection element] | provenance | | -| CommandInjection.swift:196:4:196:4 | [post] ...! [arguments, Collection element] | CommandInjection.swift:196:4:196:4 | [post] ...! | provenance | | -| CommandInjection.swift:196:19:196:19 | newValue [Collection element] | CommandInjection.swift:196:4:196:4 | [post] ...! [arguments, Collection element] | provenance | | +| CommandInjection.swift:194:19:194:19 | newValue [Collection element] | CommandInjection.swift:194:4:194:4 | [post] getter for .p1 | provenance | | +| CommandInjection.swift:195:20:195:20 | newValue [Collection element] | CommandInjection.swift:195:4:195:6 | [post] ...! | provenance | | +| CommandInjection.swift:196:19:196:19 | newValue [Collection element] | CommandInjection.swift:196:4:196:4 | [post] ...! | provenance | | | CommandInjection.swift:201:9:201:13 | let ...? [some:0] | CommandInjection.swift:201:13:201:13 | userControlledString | provenance | | | CommandInjection.swift:201:13:201:13 | userControlledString | CommandInjection.swift:205:19:205:19 | userControlledString | provenance | | | CommandInjection.swift:201:13:201:13 | userControlledString | CommandInjection.swift:211:31:211:31 | userControlledString | provenance | | @@ -146,23 +127,17 @@ edges | CommandInjection.swift:205:18:205:39 | [...] [Collection element] | CommandInjection.swift:208:19:208:19 | tainted1 [Collection element] | provenance | | | CommandInjection.swift:205:18:205:39 | [...] [Collection element] | CommandInjection.swift:209:18:209:18 | tainted1 [Collection element] | provenance | | | CommandInjection.swift:205:19:205:19 | userControlledString | CommandInjection.swift:205:18:205:39 | [...] [Collection element] | provenance | | -| CommandInjection.swift:207:3:207:3 | [post] getter for .p1 [arguments, Collection element] | CommandInjection.swift:207:3:207:3 | [post] getter for .p1 | provenance | | -| CommandInjection.swift:207:18:207:18 | tainted1 [Collection element] | CommandInjection.swift:207:3:207:3 | [post] getter for .p1 [arguments, Collection element] | provenance | | -| CommandInjection.swift:208:3:208:5 | [post] ...! [arguments, Collection element] | CommandInjection.swift:208:3:208:5 | [post] ...! | provenance | | -| CommandInjection.swift:208:19:208:19 | tainted1 [Collection element] | CommandInjection.swift:208:3:208:5 | [post] ...! [arguments, Collection element] | provenance | | -| CommandInjection.swift:209:3:209:3 | [post] ...! [arguments, Collection element] | CommandInjection.swift:209:3:209:3 | [post] ...! | provenance | | -| CommandInjection.swift:209:18:209:18 | tainted1 [Collection element] | CommandInjection.swift:209:3:209:3 | [post] ...! [arguments, Collection element] | provenance | | +| CommandInjection.swift:207:18:207:18 | tainted1 [Collection element] | CommandInjection.swift:207:3:207:3 | [post] getter for .p1 | provenance | | +| CommandInjection.swift:208:19:208:19 | tainted1 [Collection element] | CommandInjection.swift:208:3:208:5 | [post] ...! | provenance | | +| CommandInjection.swift:209:18:209:18 | tainted1 [Collection element] | CommandInjection.swift:209:3:209:3 | [post] ...! | provenance | | | CommandInjection.swift:211:30:211:51 | [...] [Collection element] | CommandInjection.swift:213:18:213:18 | tainted2 [Collection element] | provenance | | | CommandInjection.swift:211:30:211:51 | [...] [Collection element] | CommandInjection.swift:214:19:214:19 | tainted2 [Collection element] | provenance | | | CommandInjection.swift:211:30:211:51 | [...] [Collection element] | CommandInjection.swift:215:18:215:18 | tainted2 [Collection element] | provenance | | | CommandInjection.swift:211:30:211:51 | [...] [Collection element] | CommandInjection.swift:217:13:217:13 | tainted2 [Collection element] | provenance | | | CommandInjection.swift:211:31:211:31 | userControlledString | CommandInjection.swift:211:30:211:51 | [...] [Collection element] | provenance | | -| CommandInjection.swift:213:3:213:3 | [post] getter for .p1 [arguments, Collection element] | CommandInjection.swift:213:3:213:3 | [post] getter for .p1 | provenance | | -| CommandInjection.swift:213:18:213:18 | tainted2 [Collection element] | CommandInjection.swift:213:3:213:3 | [post] getter for .p1 [arguments, Collection element] | provenance | | -| CommandInjection.swift:214:3:214:5 | [post] ...! [arguments, Collection element] | CommandInjection.swift:214:3:214:5 | [post] ...! | provenance | | -| CommandInjection.swift:214:19:214:19 | tainted2 [Collection element] | CommandInjection.swift:214:3:214:5 | [post] ...! [arguments, Collection element] | provenance | | -| CommandInjection.swift:215:3:215:3 | [post] ...! [arguments, Collection element] | CommandInjection.swift:215:3:215:3 | [post] ...! | provenance | | -| CommandInjection.swift:215:18:215:18 | tainted2 [Collection element] | CommandInjection.swift:215:3:215:3 | [post] ...! [arguments, Collection element] | provenance | | +| CommandInjection.swift:213:18:213:18 | tainted2 [Collection element] | CommandInjection.swift:213:3:213:3 | [post] getter for .p1 | provenance | | +| CommandInjection.swift:214:19:214:19 | tainted2 [Collection element] | CommandInjection.swift:214:3:214:5 | [post] ...! | provenance | | +| CommandInjection.swift:215:18:215:18 | tainted2 [Collection element] | CommandInjection.swift:215:3:215:3 | [post] ...! | provenance | | | CommandInjection.swift:217:13:217:13 | tainted2 [Collection element] | CommandInjection.swift:193:3:193:3 | newValue [Collection element] | provenance | | | file://:0:0:0:0 | url | file://:0:0:0:0 | url | provenance | | | file://:0:0:0:0 | url | file://:0:0:0:0 | url | provenance | | @@ -180,7 +155,6 @@ nodes | CommandInjection.swift:75:40:75:94 | call to String.init(contentsOf:) [some:0, some:0] | semmle.label | call to String.init(contentsOf:) [some:0, some:0] | | CommandInjection.swift:75:40:75:94 | call to String.init(contentsOf:) [some:0] | semmle.label | call to String.init(contentsOf:) [some:0] | | CommandInjection.swift:81:2:81:2 | [post] task1 | semmle.label | [post] task1 | -| CommandInjection.swift:81:2:81:2 | [post] task1 [arguments, Collection element] | semmle.label | [post] task1 [arguments, Collection element] | | CommandInjection.swift:81:20:81:47 | [...] [Collection element] | semmle.label | [...] [Collection element] | | CommandInjection.swift:81:27:81:27 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:84:5:84:9 | let ...? [some:0] | semmle.label | let ...? [some:0] | @@ -190,71 +164,57 @@ nodes | CommandInjection.swift:84:43:84:43 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:84:43:84:43 | userControlledString [some:0] | semmle.label | userControlledString [some:0] | | CommandInjection.swift:87:6:87:6 | [post] task2 | semmle.label | [post] task2 | -| CommandInjection.swift:87:6:87:6 | [post] task2 [arguments, Collection element] | semmle.label | [post] task2 [arguments, Collection element] | | CommandInjection.swift:87:24:87:46 | [...] [Collection element] | semmle.label | [...] [Collection element] | | CommandInjection.swift:87:31:87:31 | validatedString | semmle.label | validatedString | | CommandInjection.swift:99:20:99:40 | arguments [Collection element] | semmle.label | arguments [Collection element] | | CommandInjection.swift:100:3:100:3 | [post] self | semmle.label | [post] self | -| CommandInjection.swift:100:3:100:3 | [post] self [arguments, Collection element] | semmle.label | [post] self [arguments, Collection element] | | CommandInjection.swift:100:20:100:20 | arguments [Collection element] | semmle.label | arguments [Collection element] | | CommandInjection.swift:105:8:105:12 | let ...? [some:0] | semmle.label | let ...? [some:0] | | CommandInjection.swift:105:12:105:12 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:105:40:105:94 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) | | CommandInjection.swift:105:40:105:94 | call to String.init(contentsOf:) [some:0] | semmle.label | call to String.init(contentsOf:) [some:0] | | CommandInjection.swift:120:2:120:2 | [post] task3 | semmle.label | [post] task3 | -| CommandInjection.swift:120:2:120:2 | [post] task3 [executableURL] | semmle.label | [post] task3 [executableURL] | | CommandInjection.swift:120:24:120:56 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | | CommandInjection.swift:120:24:120:57 | ...! | semmle.label | ...! | | CommandInjection.swift:120:36:120:36 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:121:2:121:2 | [post] task3 | semmle.label | [post] task3 | -| CommandInjection.swift:121:2:121:2 | [post] task3 [arguments, Collection element] | semmle.label | [post] task3 [arguments, Collection element] | | CommandInjection.swift:121:20:121:48 | [...] [Collection element] | semmle.label | [...] [Collection element] | | CommandInjection.swift:121:28:121:28 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:125:2:125:2 | [post] task4 | semmle.label | [post] task4 | -| CommandInjection.swift:125:2:125:2 | [post] task4 [executableURL] | semmle.label | [post] task4 [executableURL] | | CommandInjection.swift:125:24:125:65 | call to URL.init(fileURLWithPath:) | semmle.label | call to URL.init(fileURLWithPath:) | | CommandInjection.swift:125:45:125:45 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:126:2:126:2 | [post] task4 | semmle.label | [post] task4 | -| CommandInjection.swift:126:2:126:2 | [post] task4 [executableURL] | semmle.label | [post] task4 [executableURL] | | CommandInjection.swift:126:24:126:56 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | | CommandInjection.swift:126:24:126:57 | ...! | semmle.label | ...! | | CommandInjection.swift:126:36:126:36 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:127:2:127:2 | [post] task4 | semmle.label | [post] task4 | -| CommandInjection.swift:127:2:127:2 | [post] task4 [arguments, Collection element] | semmle.label | [post] task4 [arguments, Collection element] | | CommandInjection.swift:127:20:127:56 | [...] [Collection element] | semmle.label | [...] [Collection element] | | CommandInjection.swift:127:28:127:36 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | | CommandInjection.swift:131:2:131:7 | [post] ...? | semmle.label | [post] ...? | -| CommandInjection.swift:131:2:131:7 | [post] ...? [executableURL] | semmle.label | [post] ...? [executableURL] | | CommandInjection.swift:131:25:131:66 | call to URL.init(fileURLWithPath:) | semmle.label | call to URL.init(fileURLWithPath:) | | CommandInjection.swift:131:46:131:46 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:132:2:132:7 | [post] ...? | semmle.label | [post] ...? | -| CommandInjection.swift:132:2:132:7 | [post] ...? [arguments, Collection element] | semmle.label | [post] ...? [arguments, Collection element] | | CommandInjection.swift:132:21:132:42 | [...] [Collection element] | semmle.label | [...] [Collection element] | | CommandInjection.swift:132:22:132:22 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:136:2:136:2 | [post] task6 | semmle.label | [post] task6 | -| CommandInjection.swift:136:2:136:2 | [post] task6 [executableURL] | semmle.label | [post] task6 [executableURL] | | CommandInjection.swift:136:24:136:65 | call to URL.init(fileURLWithPath:) | semmle.label | call to URL.init(fileURLWithPath:) | | CommandInjection.swift:136:45:136:45 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:137:2:137:2 | [post] task6 | semmle.label | [post] task6 | -| CommandInjection.swift:137:2:137:2 | [post] task6 [executableURL] | semmle.label | [post] task6 [executableURL] | | CommandInjection.swift:137:24:137:56 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | | CommandInjection.swift:137:24:137:57 | ...! | semmle.label | ...! | | CommandInjection.swift:137:36:137:36 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:138:2:138:2 | [post] task6 | semmle.label | [post] task6 | -| CommandInjection.swift:138:2:138:2 | [post] task6 [arguments, Collection element] | semmle.label | [post] task6 [arguments, Collection element] | | CommandInjection.swift:138:20:138:41 | [...] [Collection element] | semmle.label | [...] [Collection element] | | CommandInjection.swift:138:21:138:21 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:139:21:139:42 | [...] [Collection element] | semmle.label | [...] [Collection element] | | CommandInjection.swift:139:22:139:22 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:150:42:150:42 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:151:67:151:95 | [...] | semmle.label | [...] | -| CommandInjection.swift:151:67:151:95 | [...] [Collection element] | semmle.label | [...] [Collection element] | | CommandInjection.swift:151:75:151:75 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:154:23:154:55 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | | CommandInjection.swift:154:23:154:56 | ...! | semmle.label | ...! | | CommandInjection.swift:154:35:154:35 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:155:62:155:90 | [...] | semmle.label | [...] | -| CommandInjection.swift:155:62:155:90 | [...] [Collection element] | semmle.label | [...] [Collection element] | | CommandInjection.swift:155:70:155:70 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:160:41:160:73 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | | CommandInjection.swift:160:41:160:74 | ...! | semmle.label | ...! | @@ -264,7 +224,6 @@ nodes | CommandInjection.swift:163:40:163:73 | ...! | semmle.label | ...! | | CommandInjection.swift:163:52:163:52 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:164:32:164:53 | [...] | semmle.label | [...] | -| CommandInjection.swift:164:32:164:53 | [...] [Collection element] | semmle.label | [...] [Collection element] | | CommandInjection.swift:164:33:164:33 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:166:45:166:77 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | | CommandInjection.swift:166:45:166:78 | ...! | semmle.label | ...! | @@ -272,13 +231,10 @@ nodes | CommandInjection.swift:166:57:166:57 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:193:3:193:3 | newValue [Collection element] | semmle.label | newValue [Collection element] | | CommandInjection.swift:194:4:194:4 | [post] getter for .p1 | semmle.label | [post] getter for .p1 | -| CommandInjection.swift:194:4:194:4 | [post] getter for .p1 [arguments, Collection element] | semmle.label | [post] getter for .p1 [arguments, Collection element] | | CommandInjection.swift:194:19:194:19 | newValue [Collection element] | semmle.label | newValue [Collection element] | | CommandInjection.swift:195:4:195:6 | [post] ...! | semmle.label | [post] ...! | -| CommandInjection.swift:195:4:195:6 | [post] ...! [arguments, Collection element] | semmle.label | [post] ...! [arguments, Collection element] | | CommandInjection.swift:195:20:195:20 | newValue [Collection element] | semmle.label | newValue [Collection element] | | CommandInjection.swift:196:4:196:4 | [post] ...! | semmle.label | [post] ...! | -| CommandInjection.swift:196:4:196:4 | [post] ...! [arguments, Collection element] | semmle.label | [post] ...! [arguments, Collection element] | | CommandInjection.swift:196:19:196:19 | newValue [Collection element] | semmle.label | newValue [Collection element] | | CommandInjection.swift:201:9:201:13 | let ...? [some:0] | semmle.label | let ...? [some:0] | | CommandInjection.swift:201:13:201:13 | userControlledString | semmle.label | userControlledString | @@ -287,24 +243,18 @@ nodes | CommandInjection.swift:205:18:205:39 | [...] [Collection element] | semmle.label | [...] [Collection element] | | CommandInjection.swift:205:19:205:19 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:207:3:207:3 | [post] getter for .p1 | semmle.label | [post] getter for .p1 | -| CommandInjection.swift:207:3:207:3 | [post] getter for .p1 [arguments, Collection element] | semmle.label | [post] getter for .p1 [arguments, Collection element] | | CommandInjection.swift:207:18:207:18 | tainted1 [Collection element] | semmle.label | tainted1 [Collection element] | | CommandInjection.swift:208:3:208:5 | [post] ...! | semmle.label | [post] ...! | -| CommandInjection.swift:208:3:208:5 | [post] ...! [arguments, Collection element] | semmle.label | [post] ...! [arguments, Collection element] | | CommandInjection.swift:208:19:208:19 | tainted1 [Collection element] | semmle.label | tainted1 [Collection element] | | CommandInjection.swift:209:3:209:3 | [post] ...! | semmle.label | [post] ...! | -| CommandInjection.swift:209:3:209:3 | [post] ...! [arguments, Collection element] | semmle.label | [post] ...! [arguments, Collection element] | | CommandInjection.swift:209:18:209:18 | tainted1 [Collection element] | semmle.label | tainted1 [Collection element] | | CommandInjection.swift:211:30:211:51 | [...] [Collection element] | semmle.label | [...] [Collection element] | | CommandInjection.swift:211:31:211:31 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:213:3:213:3 | [post] getter for .p1 | semmle.label | [post] getter for .p1 | -| CommandInjection.swift:213:3:213:3 | [post] getter for .p1 [arguments, Collection element] | semmle.label | [post] getter for .p1 [arguments, Collection element] | | CommandInjection.swift:213:18:213:18 | tainted2 [Collection element] | semmle.label | tainted2 [Collection element] | | CommandInjection.swift:214:3:214:5 | [post] ...! | semmle.label | [post] ...! | -| CommandInjection.swift:214:3:214:5 | [post] ...! [arguments, Collection element] | semmle.label | [post] ...! [arguments, Collection element] | | CommandInjection.swift:214:19:214:19 | tainted2 [Collection element] | semmle.label | tainted2 [Collection element] | | CommandInjection.swift:215:3:215:3 | [post] ...! | semmle.label | [post] ...! | -| CommandInjection.swift:215:3:215:3 | [post] ...! [arguments, Collection element] | semmle.label | [post] ...! [arguments, Collection element] | | CommandInjection.swift:215:18:215:18 | tainted2 [Collection element] | semmle.label | tainted2 [Collection element] | | CommandInjection.swift:217:13:217:13 | tainted2 [Collection element] | semmle.label | tainted2 [Collection element] | | file://:0:0:0:0 | url | semmle.label | url | diff --git a/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected b/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected index 83fb7d9c1fe8..204e2486cc2f 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected @@ -21,35 +21,23 @@ edges | SQLite.swift:153:20:153:20 | mobilePhoneNumber | SQLite.swift:153:20:153:20 | [...] [Collection element] | provenance | | | SQLite.swift:154:23:154:23 | [...] [Collection element] | SQLite.swift:154:23:154:23 | [...] | provenance | | | SQLite.swift:154:23:154:23 | mobilePhoneNumber | SQLite.swift:154:23:154:23 | [...] [Collection element] | provenance | | -| SQLite.swift:158:32:158:54 | [...] [Collection element] | SQLite.swift:158:32:158:54 | [...] | provenance | | -| SQLite.swift:158:33:158:33 | mobilePhoneNumber | SQLite.swift:158:32:158:54 | [...] [Collection element] | provenance | | -| SQLite.swift:159:28:159:50 | [...] [Collection element] | SQLite.swift:159:28:159:50 | [...] | provenance | | -| SQLite.swift:159:29:159:29 | mobilePhoneNumber | SQLite.swift:159:28:159:50 | [...] [Collection element] | provenance | | -| SQLite.swift:160:31:160:53 | [...] [Collection element] | SQLite.swift:160:31:160:53 | [...] | provenance | | -| SQLite.swift:160:32:160:32 | mobilePhoneNumber | SQLite.swift:160:31:160:53 | [...] [Collection element] | provenance | | -| SQLite.swift:163:21:163:43 | [...] [Collection element] | SQLite.swift:163:21:163:43 | [...] | provenance | | -| SQLite.swift:163:22:163:22 | mobilePhoneNumber | SQLite.swift:163:21:163:43 | [...] [Collection element] | provenance | | -| SQLite.swift:164:20:164:42 | [...] [Collection element] | SQLite.swift:164:20:164:42 | [...] | provenance | | -| SQLite.swift:164:21:164:21 | mobilePhoneNumber | SQLite.swift:164:20:164:42 | [...] [Collection element] | provenance | | -| SQLite.swift:165:23:165:45 | [...] [Collection element] | SQLite.swift:165:23:165:45 | [...] | provenance | | -| SQLite.swift:165:24:165:24 | mobilePhoneNumber | SQLite.swift:165:23:165:45 | [...] [Collection element] | provenance | | -| SQLite.swift:169:32:169:70 | [...] [Collection element, Tuple element at index 1] | SQLite.swift:169:32:169:70 | [...] | provenance | | -| SQLite.swift:169:43:169:53 | (...) [Tuple element at index 1] | SQLite.swift:169:32:169:70 | [...] [Collection element, Tuple element at index 1] | provenance | | +| SQLite.swift:158:33:158:33 | mobilePhoneNumber | SQLite.swift:158:32:158:54 | [...] | provenance | | +| SQLite.swift:159:29:159:29 | mobilePhoneNumber | SQLite.swift:159:28:159:50 | [...] | provenance | | +| SQLite.swift:160:32:160:32 | mobilePhoneNumber | SQLite.swift:160:31:160:53 | [...] | provenance | | +| SQLite.swift:163:22:163:22 | mobilePhoneNumber | SQLite.swift:163:21:163:43 | [...] | provenance | | +| SQLite.swift:164:21:164:21 | mobilePhoneNumber | SQLite.swift:164:20:164:42 | [...] | provenance | | +| SQLite.swift:165:24:165:24 | mobilePhoneNumber | SQLite.swift:165:23:165:45 | [...] | provenance | | +| SQLite.swift:169:43:169:53 | (...) [Tuple element at index 1] | SQLite.swift:169:32:169:70 | [...] | provenance | | | SQLite.swift:169:53:169:53 | mobilePhoneNumber | SQLite.swift:169:43:169:53 | (...) [Tuple element at index 1] | provenance | | -| SQLite.swift:170:28:170:66 | [...] [Collection element, Tuple element at index 1] | SQLite.swift:170:28:170:66 | [...] | provenance | | -| SQLite.swift:170:39:170:49 | (...) [Tuple element at index 1] | SQLite.swift:170:28:170:66 | [...] [Collection element, Tuple element at index 1] | provenance | | +| SQLite.swift:170:39:170:49 | (...) [Tuple element at index 1] | SQLite.swift:170:28:170:66 | [...] | provenance | | | SQLite.swift:170:49:170:49 | mobilePhoneNumber | SQLite.swift:170:39:170:49 | (...) [Tuple element at index 1] | provenance | | -| SQLite.swift:171:31:171:69 | [...] [Collection element, Tuple element at index 1] | SQLite.swift:171:31:171:69 | [...] | provenance | | -| SQLite.swift:171:42:171:52 | (...) [Tuple element at index 1] | SQLite.swift:171:31:171:69 | [...] [Collection element, Tuple element at index 1] | provenance | | +| SQLite.swift:171:42:171:52 | (...) [Tuple element at index 1] | SQLite.swift:171:31:171:69 | [...] | provenance | | | SQLite.swift:171:52:171:52 | mobilePhoneNumber | SQLite.swift:171:42:171:52 | (...) [Tuple element at index 1] | provenance | | -| SQLite.swift:174:21:174:59 | [...] [Collection element, Tuple element at index 1] | SQLite.swift:174:21:174:59 | [...] | provenance | | -| SQLite.swift:174:32:174:42 | (...) [Tuple element at index 1] | SQLite.swift:174:21:174:59 | [...] [Collection element, Tuple element at index 1] | provenance | | +| SQLite.swift:174:32:174:42 | (...) [Tuple element at index 1] | SQLite.swift:174:21:174:59 | [...] | provenance | | | SQLite.swift:174:42:174:42 | mobilePhoneNumber | SQLite.swift:174:32:174:42 | (...) [Tuple element at index 1] | provenance | | -| SQLite.swift:175:20:175:58 | [...] [Collection element, Tuple element at index 1] | SQLite.swift:175:20:175:58 | [...] | provenance | | -| SQLite.swift:175:31:175:41 | (...) [Tuple element at index 1] | SQLite.swift:175:20:175:58 | [...] [Collection element, Tuple element at index 1] | provenance | | +| SQLite.swift:175:31:175:41 | (...) [Tuple element at index 1] | SQLite.swift:175:20:175:58 | [...] | provenance | | | SQLite.swift:175:41:175:41 | mobilePhoneNumber | SQLite.swift:175:31:175:41 | (...) [Tuple element at index 1] | provenance | | -| SQLite.swift:176:23:176:61 | [...] [Collection element, Tuple element at index 1] | SQLite.swift:176:23:176:61 | [...] | provenance | | -| SQLite.swift:176:34:176:44 | (...) [Tuple element at index 1] | SQLite.swift:176:23:176:61 | [...] [Collection element, Tuple element at index 1] | provenance | | +| SQLite.swift:176:34:176:44 | (...) [Tuple element at index 1] | SQLite.swift:176:23:176:61 | [...] | provenance | | | SQLite.swift:176:44:176:44 | mobilePhoneNumber | SQLite.swift:176:34:176:44 | (...) [Tuple element at index 1] | provenance | | | SQLite.swift:186:40:186:54 | ... <-(_:_:) ... | SQLite.swift:186:40:186:54 | [...] [Collection element] | provenance | | | SQLite.swift:186:40:186:54 | [...] [Collection element] | SQLite.swift:186:40:186:54 | [...] | provenance | | @@ -87,264 +75,173 @@ edges | sqlite3_c_api.swift:42:69:42:69 | medicalNotes | sqlite3_c_api.swift:46:27:46:27 | insertQuery | provenance | | | sqlite3_c_api.swift:43:49:43:49 | medicalNotes | sqlite3_c_api.swift:47:27:47:27 | updateQuery | provenance | | | testCoreData2.swift:23:13:23:13 | value | file://:0:0:0:0 | value | provenance | | -| testCoreData2.swift:37:2:37:2 | [post] obj [myValue] | testCoreData2.swift:37:2:37:2 | [post] obj | provenance | | -| testCoreData2.swift:37:16:37:16 | bankAccountNo | testCoreData2.swift:37:2:37:2 | [post] obj [myValue] | provenance | | -| testCoreData2.swift:39:2:39:2 | [post] obj [myBankAccountNumber] | testCoreData2.swift:39:2:39:2 | [post] obj | provenance | | -| testCoreData2.swift:39:28:39:28 | bankAccountNo | testCoreData2.swift:39:2:39:2 | [post] obj [myBankAccountNumber] | provenance | | -| testCoreData2.swift:41:2:41:2 | [post] obj [myBankAccountNumber2] | testCoreData2.swift:41:2:41:2 | [post] obj | provenance | | -| testCoreData2.swift:41:29:41:29 | bankAccountNo | testCoreData2.swift:41:2:41:2 | [post] obj [myBankAccountNumber2] | provenance | | -| testCoreData2.swift:43:2:43:2 | [post] obj [notStoredBankAccountNumber] | testCoreData2.swift:43:2:43:2 | [post] obj | provenance | | +| testCoreData2.swift:37:16:37:16 | bankAccountNo | testCoreData2.swift:37:2:37:2 | [post] obj | provenance | | +| testCoreData2.swift:39:28:39:28 | bankAccountNo | testCoreData2.swift:39:2:39:2 | [post] obj | provenance | | +| testCoreData2.swift:41:29:41:29 | bankAccountNo | testCoreData2.swift:41:2:41:2 | [post] obj | provenance | | | testCoreData2.swift:43:35:43:35 | bankAccountNo | testCoreData2.swift:23:13:23:13 | value | provenance | | -| testCoreData2.swift:43:35:43:35 | bankAccountNo | testCoreData2.swift:43:2:43:2 | [post] obj [notStoredBankAccountNumber] | provenance | | -| testCoreData2.swift:46:2:46:10 | [post] ...? [myValue] | testCoreData2.swift:46:2:46:10 | [post] ...? | provenance | | -| testCoreData2.swift:46:22:46:22 | bankAccountNo | testCoreData2.swift:46:2:46:10 | [post] ...? [myValue] | provenance | | -| testCoreData2.swift:48:2:48:10 | [post] ...? [myBankAccountNumber] | testCoreData2.swift:48:2:48:10 | [post] ...? | provenance | | -| testCoreData2.swift:48:34:48:34 | bankAccountNo | testCoreData2.swift:48:2:48:10 | [post] ...? [myBankAccountNumber] | provenance | | -| testCoreData2.swift:50:2:50:10 | [post] ...? [myBankAccountNumber2] | testCoreData2.swift:50:2:50:10 | [post] ...? | provenance | | -| testCoreData2.swift:50:35:50:35 | bankAccountNo | testCoreData2.swift:50:2:50:10 | [post] ...? [myBankAccountNumber2] | provenance | | -| testCoreData2.swift:52:2:52:10 | [post] ...? [notStoredBankAccountNumber] | testCoreData2.swift:52:2:52:10 | [post] ...? | provenance | | +| testCoreData2.swift:43:35:43:35 | bankAccountNo | testCoreData2.swift:43:2:43:2 | [post] obj | provenance | | +| testCoreData2.swift:46:22:46:22 | bankAccountNo | testCoreData2.swift:46:2:46:10 | [post] ...? | provenance | | +| testCoreData2.swift:48:34:48:34 | bankAccountNo | testCoreData2.swift:48:2:48:10 | [post] ...? | provenance | | +| testCoreData2.swift:50:35:50:35 | bankAccountNo | testCoreData2.swift:50:2:50:10 | [post] ...? | provenance | | | testCoreData2.swift:52:41:52:41 | bankAccountNo | testCoreData2.swift:23:13:23:13 | value | provenance | | -| testCoreData2.swift:52:41:52:41 | bankAccountNo | testCoreData2.swift:52:2:52:10 | [post] ...? [notStoredBankAccountNumber] | provenance | | -| testCoreData2.swift:57:3:57:3 | [post] obj [myBankAccountNumber] | testCoreData2.swift:57:3:57:3 | [post] obj | provenance | | -| testCoreData2.swift:57:29:57:29 | bankAccountNo | testCoreData2.swift:57:3:57:3 | [post] obj [myBankAccountNumber] | provenance | | -| testCoreData2.swift:60:4:60:4 | [post] obj [myBankAccountNumber] | testCoreData2.swift:60:4:60:4 | [post] obj | provenance | | -| testCoreData2.swift:60:30:60:30 | bankAccountNo | testCoreData2.swift:60:4:60:4 | [post] obj [myBankAccountNumber] | provenance | | -| testCoreData2.swift:62:4:62:4 | [post] obj [myBankAccountNumber] | testCoreData2.swift:62:4:62:4 | [post] obj | provenance | | -| testCoreData2.swift:62:30:62:30 | bankAccountNo | testCoreData2.swift:62:4:62:4 | [post] obj [myBankAccountNumber] | provenance | | -| testCoreData2.swift:65:3:65:3 | [post] obj [myBankAccountNumber] | testCoreData2.swift:65:3:65:3 | [post] obj | provenance | | -| testCoreData2.swift:65:29:65:29 | bankAccountNo | testCoreData2.swift:65:3:65:3 | [post] obj [myBankAccountNumber] | provenance | | +| testCoreData2.swift:52:41:52:41 | bankAccountNo | testCoreData2.swift:52:2:52:10 | [post] ...? | provenance | | +| testCoreData2.swift:57:29:57:29 | bankAccountNo | testCoreData2.swift:57:3:57:3 | [post] obj | provenance | | +| testCoreData2.swift:60:30:60:30 | bankAccountNo | testCoreData2.swift:60:4:60:4 | [post] obj | provenance | | +| testCoreData2.swift:62:30:62:30 | bankAccountNo | testCoreData2.swift:62:4:62:4 | [post] obj | provenance | | +| testCoreData2.swift:65:29:65:29 | bankAccountNo | testCoreData2.swift:65:3:65:3 | [post] obj | provenance | | | testCoreData2.swift:70:9:70:9 | self | file://:0:0:0:0 | self | provenance | | | testCoreData2.swift:70:9:70:9 | self [value] | file://:0:0:0:0 | self [value] | provenance | | | testCoreData2.swift:70:9:70:9 | value | file://:0:0:0:0 | value | provenance | | | testCoreData2.swift:71:9:71:9 | self | file://:0:0:0:0 | self | provenance | | -| testCoreData2.swift:79:2:79:2 | [post] dbObj [myValue] | testCoreData2.swift:79:2:79:2 | [post] dbObj | provenance | | -| testCoreData2.swift:79:18:79:28 | .bankAccountNo | testCoreData2.swift:79:2:79:2 | [post] dbObj [myValue] | provenance | | -| testCoreData2.swift:80:2:80:2 | [post] dbObj [myValue] | testCoreData2.swift:80:2:80:2 | [post] dbObj | provenance | | -| testCoreData2.swift:80:18:80:28 | ...! | testCoreData2.swift:80:2:80:2 | [post] dbObj [myValue] | provenance | | +| testCoreData2.swift:79:18:79:28 | .bankAccountNo | testCoreData2.swift:79:2:79:2 | [post] dbObj | provenance | | +| testCoreData2.swift:80:18:80:28 | ...! | testCoreData2.swift:80:2:80:2 | [post] dbObj | provenance | | | testCoreData2.swift:80:18:80:28 | .bankAccountNo2 | testCoreData2.swift:80:18:80:28 | ...! | provenance | | -| testCoreData2.swift:82:2:82:2 | [post] dbObj [myValue] | testCoreData2.swift:82:2:82:2 | [post] dbObj | provenance | | | testCoreData2.swift:82:18:82:18 | bankAccountNo | testCoreData2.swift:70:9:70:9 | self | provenance | | | testCoreData2.swift:82:18:82:18 | bankAccountNo | testCoreData2.swift:82:18:82:32 | .value | provenance | Config | -| testCoreData2.swift:82:18:82:32 | .value | testCoreData2.swift:82:2:82:2 | [post] dbObj [myValue] | provenance | | -| testCoreData2.swift:83:2:83:2 | [post] dbObj [myValue] | testCoreData2.swift:83:2:83:2 | [post] dbObj | provenance | | +| testCoreData2.swift:82:18:82:32 | .value | testCoreData2.swift:82:2:82:2 | [post] dbObj | provenance | | | testCoreData2.swift:83:18:83:18 | bankAccountNo | testCoreData2.swift:71:9:71:9 | self | provenance | | | testCoreData2.swift:83:18:83:18 | bankAccountNo | testCoreData2.swift:83:18:83:32 | .value2 | provenance | Config | -| testCoreData2.swift:83:18:83:32 | ...! | testCoreData2.swift:83:2:83:2 | [post] dbObj [myValue] | provenance | | +| testCoreData2.swift:83:18:83:32 | ...! | testCoreData2.swift:83:2:83:2 | [post] dbObj | provenance | | | testCoreData2.swift:83:18:83:32 | .value2 | testCoreData2.swift:83:18:83:32 | ...! | provenance | | -| testCoreData2.swift:84:2:84:2 | [post] dbObj [myValue] | testCoreData2.swift:84:2:84:2 | [post] dbObj | provenance | | | testCoreData2.swift:84:18:84:18 | ...! | testCoreData2.swift:70:9:70:9 | self | provenance | | | testCoreData2.swift:84:18:84:18 | ...! | testCoreData2.swift:84:18:84:33 | .value | provenance | Config | | testCoreData2.swift:84:18:84:18 | bankAccountNo2 | testCoreData2.swift:84:18:84:18 | ...! | provenance | | -| testCoreData2.swift:84:18:84:33 | .value | testCoreData2.swift:84:2:84:2 | [post] dbObj [myValue] | provenance | | -| testCoreData2.swift:85:2:85:2 | [post] dbObj [myValue] | testCoreData2.swift:85:2:85:2 | [post] dbObj | provenance | | +| testCoreData2.swift:84:18:84:33 | .value | testCoreData2.swift:84:2:84:2 | [post] dbObj | provenance | | | testCoreData2.swift:85:18:85:18 | ...! | testCoreData2.swift:71:9:71:9 | self | provenance | | | testCoreData2.swift:85:18:85:18 | ...! | testCoreData2.swift:85:18:85:33 | .value2 | provenance | Config | | testCoreData2.swift:85:18:85:18 | bankAccountNo2 | testCoreData2.swift:85:18:85:18 | ...! | provenance | | -| testCoreData2.swift:85:18:85:33 | ...! | testCoreData2.swift:85:2:85:2 | [post] dbObj [myValue] | provenance | | +| testCoreData2.swift:85:18:85:33 | ...! | testCoreData2.swift:85:2:85:2 | [post] dbObj | provenance | | | testCoreData2.swift:85:18:85:33 | .value2 | testCoreData2.swift:85:18:85:33 | ...! | provenance | | -| testCoreData2.swift:87:2:87:10 | [post] ...? [myValue] | testCoreData2.swift:87:2:87:10 | [post] ...? | provenance | | -| testCoreData2.swift:87:22:87:32 | .bankAccountNo | testCoreData2.swift:87:2:87:10 | [post] ...? [myValue] | provenance | | -| testCoreData2.swift:88:2:88:10 | [post] ...? [myValue] | testCoreData2.swift:88:2:88:10 | [post] ...? | provenance | | +| testCoreData2.swift:87:22:87:32 | .bankAccountNo | testCoreData2.swift:87:2:87:10 | [post] ...? | provenance | | | testCoreData2.swift:88:22:88:22 | bankAccountNo | testCoreData2.swift:70:9:70:9 | self | provenance | | | testCoreData2.swift:88:22:88:22 | bankAccountNo | testCoreData2.swift:88:22:88:36 | .value | provenance | Config | -| testCoreData2.swift:88:22:88:36 | .value | testCoreData2.swift:88:2:88:10 | [post] ...? [myValue] | provenance | | -| testCoreData2.swift:89:2:89:10 | [post] ...? [myValue] | testCoreData2.swift:89:2:89:10 | [post] ...? | provenance | | +| testCoreData2.swift:88:22:88:36 | .value | testCoreData2.swift:88:2:88:10 | [post] ...? | provenance | | | testCoreData2.swift:89:22:89:22 | ...! | testCoreData2.swift:71:9:71:9 | self | provenance | | | testCoreData2.swift:89:22:89:22 | ...! | testCoreData2.swift:89:22:89:37 | .value2 | provenance | Config | | testCoreData2.swift:89:22:89:22 | bankAccountNo2 | testCoreData2.swift:89:22:89:22 | ...! | provenance | | -| testCoreData2.swift:89:22:89:37 | ...! | testCoreData2.swift:89:2:89:10 | [post] ...? [myValue] | provenance | | +| testCoreData2.swift:89:22:89:37 | ...! | testCoreData2.swift:89:2:89:10 | [post] ...? | provenance | | | testCoreData2.swift:89:22:89:37 | .value2 | testCoreData2.swift:89:22:89:37 | ...! | provenance | | | testCoreData2.swift:91:10:91:10 | bankAccountNo | testCoreData2.swift:92:10:92:10 | a | provenance | | | testCoreData2.swift:92:10:92:10 | a | testCoreData2.swift:70:9:70:9 | self | provenance | | | testCoreData2.swift:92:10:92:10 | a | testCoreData2.swift:92:10:92:12 | .value | provenance | Config | | testCoreData2.swift:92:10:92:12 | .value | testCoreData2.swift:93:18:93:18 | b | provenance | | -| testCoreData2.swift:93:2:93:2 | [post] dbObj [myValue] | testCoreData2.swift:93:2:93:2 | [post] dbObj | provenance | | -| testCoreData2.swift:93:18:93:18 | b | testCoreData2.swift:93:2:93:2 | [post] dbObj [myValue] | provenance | | +| testCoreData2.swift:93:18:93:18 | b | testCoreData2.swift:93:2:93:2 | [post] dbObj | provenance | | | testCoreData2.swift:95:10:95:10 | bankAccountNo | testCoreData2.swift:97:12:97:12 | c | provenance | | | testCoreData2.swift:97:2:97:2 | [post] d [value] | testCoreData2.swift:98:18:98:18 | d [value] | provenance | | | testCoreData2.swift:97:12:97:12 | c | testCoreData2.swift:70:9:70:9 | self | provenance | | | testCoreData2.swift:97:12:97:12 | c | testCoreData2.swift:97:12:97:14 | .value | provenance | Config | | testCoreData2.swift:97:12:97:14 | .value | testCoreData2.swift:70:9:70:9 | value | provenance | | | testCoreData2.swift:97:12:97:14 | .value | testCoreData2.swift:97:2:97:2 | [post] d [value] | provenance | | -| testCoreData2.swift:98:2:98:2 | [post] dbObj [myValue] | testCoreData2.swift:98:2:98:2 | [post] dbObj | provenance | | | testCoreData2.swift:98:18:98:18 | d [value] | testCoreData2.swift:70:9:70:9 | self [value] | provenance | | | testCoreData2.swift:98:18:98:18 | d [value] | testCoreData2.swift:98:18:98:20 | .value | provenance | | -| testCoreData2.swift:98:18:98:20 | .value | testCoreData2.swift:98:2:98:2 | [post] dbObj [myValue] | provenance | | +| testCoreData2.swift:98:18:98:20 | .value | testCoreData2.swift:98:2:98:2 | [post] dbObj | provenance | | | testCoreData2.swift:101:10:101:10 | bankAccountNo | testCoreData2.swift:103:13:103:13 | e | provenance | | | testCoreData2.swift:103:13:103:13 | e | testCoreData2.swift:104:18:104:18 | e | provenance | | -| testCoreData2.swift:104:2:104:2 | [post] dbObj [myValue] | testCoreData2.swift:104:2:104:2 | [post] dbObj | provenance | | | testCoreData2.swift:104:18:104:18 | e | testCoreData2.swift:70:9:70:9 | self | provenance | | | testCoreData2.swift:104:18:104:18 | e | testCoreData2.swift:104:18:104:20 | .value | provenance | Config | | testCoreData2.swift:104:18:104:18 | e | testCoreData2.swift:105:18:105:18 | e | provenance | | -| testCoreData2.swift:104:18:104:20 | .value | testCoreData2.swift:104:2:104:2 | [post] dbObj [myValue] | provenance | | -| testCoreData2.swift:105:2:105:2 | [post] dbObj [myValue] | testCoreData2.swift:105:2:105:2 | [post] dbObj | provenance | | +| testCoreData2.swift:104:18:104:20 | .value | testCoreData2.swift:104:2:104:2 | [post] dbObj | provenance | | | testCoreData2.swift:105:18:105:18 | e | testCoreData2.swift:71:9:71:9 | self | provenance | | | testCoreData2.swift:105:18:105:18 | e | testCoreData2.swift:105:18:105:20 | .value2 | provenance | Config | -| testCoreData2.swift:105:18:105:20 | ...! | testCoreData2.swift:105:2:105:2 | [post] dbObj [myValue] | provenance | | +| testCoreData2.swift:105:18:105:20 | ...! | testCoreData2.swift:105:2:105:2 | [post] dbObj | provenance | | | testCoreData2.swift:105:18:105:20 | .value2 | testCoreData2.swift:105:18:105:20 | ...! | provenance | | | testCoreData.swift:18:19:18:26 | value | testCoreData.swift:19:12:19:12 | value | provenance | | | testCoreData.swift:31:3:31:3 | newValue | testCoreData.swift:32:13:32:13 | newValue | provenance | | | testCoreData.swift:61:25:61:25 | password | testCoreData.swift:18:19:18:26 | value | provenance | | -| testCoreData.swift:64:2:64:2 | [post] obj [myValue] | testCoreData.swift:64:2:64:2 | [post] obj | provenance | | | testCoreData.swift:64:16:64:16 | password | testCoreData.swift:31:3:31:3 | newValue | provenance | | -| testCoreData.swift:64:16:64:16 | password | testCoreData.swift:64:2:64:2 | [post] obj [myValue] | provenance | | +| testCoreData.swift:64:16:64:16 | password | testCoreData.swift:64:2:64:2 | [post] obj | provenance | | | testCoreData.swift:77:24:77:24 | x | testCoreData.swift:78:15:78:15 | x | provenance | | | testCoreData.swift:80:10:80:22 | call to getPassword() | testCoreData.swift:81:15:81:15 | y | provenance | | | testCoreData.swift:91:10:91:10 | passwd | testCoreData.swift:95:15:95:15 | x | provenance | | | testCoreData.swift:92:10:92:10 | passwd | testCoreData.swift:96:15:96:15 | y | provenance | | | testCoreData.swift:93:10:93:10 | passwd | testCoreData.swift:97:15:97:15 | z | provenance | | -| testGRDB.swift:73:56:73:65 | [...] [Collection element] | testGRDB.swift:73:56:73:65 | [...] | provenance | | -| testGRDB.swift:73:57:73:57 | password | testGRDB.swift:73:56:73:65 | [...] [Collection element] | provenance | | -| testGRDB.swift:76:42:76:51 | [...] [Collection element] | testGRDB.swift:76:42:76:51 | [...] | provenance | | -| testGRDB.swift:76:43:76:43 | password | testGRDB.swift:76:42:76:51 | [...] [Collection element] | provenance | | -| testGRDB.swift:81:44:81:53 | [...] [Collection element] | testGRDB.swift:81:44:81:53 | [...] | provenance | | -| testGRDB.swift:81:45:81:45 | password | testGRDB.swift:81:44:81:53 | [...] [Collection element] | provenance | | -| testGRDB.swift:83:44:83:53 | [...] [Collection element] | testGRDB.swift:83:44:83:53 | [...] | provenance | | -| testGRDB.swift:83:45:83:45 | password | testGRDB.swift:83:44:83:53 | [...] [Collection element] | provenance | | -| testGRDB.swift:85:44:85:53 | [...] [Collection element] | testGRDB.swift:85:44:85:53 | [...] | provenance | | -| testGRDB.swift:85:45:85:45 | password | testGRDB.swift:85:44:85:53 | [...] [Collection element] | provenance | | -| testGRDB.swift:87:44:87:53 | [...] [Collection element] | testGRDB.swift:87:44:87:53 | [...] | provenance | | -| testGRDB.swift:87:45:87:45 | password | testGRDB.swift:87:44:87:53 | [...] [Collection element] | provenance | | -| testGRDB.swift:92:37:92:46 | [...] [Collection element] | testGRDB.swift:92:37:92:46 | [...] | provenance | | -| testGRDB.swift:92:38:92:38 | password | testGRDB.swift:92:37:92:46 | [...] [Collection element] | provenance | | -| testGRDB.swift:95:36:95:45 | [...] [Collection element] | testGRDB.swift:95:36:95:45 | [...] | provenance | | -| testGRDB.swift:95:37:95:37 | password | testGRDB.swift:95:36:95:45 | [...] [Collection element] | provenance | | -| testGRDB.swift:100:72:100:81 | [...] [Collection element] | testGRDB.swift:100:72:100:81 | [...] | provenance | | -| testGRDB.swift:100:73:100:73 | password | testGRDB.swift:100:72:100:81 | [...] [Collection element] | provenance | | -| testGRDB.swift:101:72:101:81 | [...] [Collection element] | testGRDB.swift:101:72:101:81 | [...] | provenance | | -| testGRDB.swift:101:73:101:73 | password | testGRDB.swift:101:72:101:81 | [...] [Collection element] | provenance | | -| testGRDB.swift:107:52:107:61 | [...] [Collection element] | testGRDB.swift:107:52:107:61 | [...] | provenance | | -| testGRDB.swift:107:53:107:53 | password | testGRDB.swift:107:52:107:61 | [...] [Collection element] | provenance | | -| testGRDB.swift:109:52:109:61 | [...] [Collection element] | testGRDB.swift:109:52:109:61 | [...] | provenance | | -| testGRDB.swift:109:53:109:53 | password | testGRDB.swift:109:52:109:61 | [...] [Collection element] | provenance | | -| testGRDB.swift:111:51:111:60 | [...] [Collection element] | testGRDB.swift:111:51:111:60 | [...] | provenance | | -| testGRDB.swift:111:52:111:52 | password | testGRDB.swift:111:51:111:60 | [...] [Collection element] | provenance | | -| testGRDB.swift:116:47:116:56 | [...] [Collection element] | testGRDB.swift:116:47:116:56 | [...] | provenance | | -| testGRDB.swift:116:48:116:48 | password | testGRDB.swift:116:47:116:56 | [...] [Collection element] | provenance | | -| testGRDB.swift:118:47:118:56 | [...] [Collection element] | testGRDB.swift:118:47:118:56 | [...] | provenance | | -| testGRDB.swift:118:48:118:48 | password | testGRDB.swift:118:47:118:56 | [...] [Collection element] | provenance | | -| testGRDB.swift:121:44:121:53 | [...] [Collection element] | testGRDB.swift:121:44:121:53 | [...] | provenance | | -| testGRDB.swift:121:45:121:45 | password | testGRDB.swift:121:44:121:53 | [...] [Collection element] | provenance | | -| testGRDB.swift:123:44:123:53 | [...] [Collection element] | testGRDB.swift:123:44:123:53 | [...] | provenance | | -| testGRDB.swift:123:45:123:45 | password | testGRDB.swift:123:44:123:53 | [...] [Collection element] | provenance | | -| testGRDB.swift:126:44:126:53 | [...] [Collection element] | testGRDB.swift:126:44:126:53 | [...] | provenance | | -| testGRDB.swift:126:45:126:45 | password | testGRDB.swift:126:44:126:53 | [...] [Collection element] | provenance | | -| testGRDB.swift:128:44:128:53 | [...] [Collection element] | testGRDB.swift:128:44:128:53 | [...] | provenance | | -| testGRDB.swift:128:45:128:45 | password | testGRDB.swift:128:44:128:53 | [...] [Collection element] | provenance | | -| testGRDB.swift:131:44:131:53 | [...] [Collection element] | testGRDB.swift:131:44:131:53 | [...] | provenance | | -| testGRDB.swift:131:45:131:45 | password | testGRDB.swift:131:44:131:53 | [...] [Collection element] | provenance | | -| testGRDB.swift:133:44:133:53 | [...] [Collection element] | testGRDB.swift:133:44:133:53 | [...] | provenance | | -| testGRDB.swift:133:45:133:45 | password | testGRDB.swift:133:44:133:53 | [...] [Collection element] | provenance | | -| testGRDB.swift:138:68:138:77 | [...] [Collection element] | testGRDB.swift:138:68:138:77 | [...] | provenance | | -| testGRDB.swift:138:69:138:69 | password | testGRDB.swift:138:68:138:77 | [...] [Collection element] | provenance | | -| testGRDB.swift:140:68:140:77 | [...] [Collection element] | testGRDB.swift:140:68:140:77 | [...] | provenance | | -| testGRDB.swift:140:69:140:69 | password | testGRDB.swift:140:68:140:77 | [...] [Collection element] | provenance | | -| testGRDB.swift:143:65:143:74 | [...] [Collection element] | testGRDB.swift:143:65:143:74 | [...] | provenance | | -| testGRDB.swift:143:66:143:66 | password | testGRDB.swift:143:65:143:74 | [...] [Collection element] | provenance | | -| testGRDB.swift:145:65:145:74 | [...] [Collection element] | testGRDB.swift:145:65:145:74 | [...] | provenance | | -| testGRDB.swift:145:66:145:66 | password | testGRDB.swift:145:65:145:74 | [...] [Collection element] | provenance | | -| testGRDB.swift:148:65:148:74 | [...] [Collection element] | testGRDB.swift:148:65:148:74 | [...] | provenance | | -| testGRDB.swift:148:66:148:66 | password | testGRDB.swift:148:65:148:74 | [...] [Collection element] | provenance | | -| testGRDB.swift:150:65:150:74 | [...] [Collection element] | testGRDB.swift:150:65:150:74 | [...] | provenance | | -| testGRDB.swift:150:66:150:66 | password | testGRDB.swift:150:65:150:74 | [...] [Collection element] | provenance | | -| testGRDB.swift:153:65:153:74 | [...] [Collection element] | testGRDB.swift:153:65:153:74 | [...] | provenance | | -| testGRDB.swift:153:66:153:66 | password | testGRDB.swift:153:65:153:74 | [...] [Collection element] | provenance | | -| testGRDB.swift:155:65:155:74 | [...] [Collection element] | testGRDB.swift:155:65:155:74 | [...] | provenance | | -| testGRDB.swift:155:66:155:66 | password | testGRDB.swift:155:65:155:74 | [...] [Collection element] | provenance | | -| testGRDB.swift:160:59:160:68 | [...] [Collection element] | testGRDB.swift:160:59:160:68 | [...] | provenance | | -| testGRDB.swift:160:60:160:60 | password | testGRDB.swift:160:59:160:68 | [...] [Collection element] | provenance | | -| testGRDB.swift:161:50:161:59 | [...] [Collection element] | testGRDB.swift:161:50:161:59 | [...] | provenance | | -| testGRDB.swift:161:51:161:51 | password | testGRDB.swift:161:50:161:59 | [...] [Collection element] | provenance | | -| testGRDB.swift:164:59:164:68 | [...] [Collection element] | testGRDB.swift:164:59:164:68 | [...] | provenance | | -| testGRDB.swift:164:60:164:60 | password | testGRDB.swift:164:59:164:68 | [...] [Collection element] | provenance | | -| testGRDB.swift:165:50:165:59 | [...] [Collection element] | testGRDB.swift:165:50:165:59 | [...] | provenance | | -| testGRDB.swift:165:51:165:51 | password | testGRDB.swift:165:50:165:59 | [...] [Collection element] | provenance | | -| testGRDB.swift:169:56:169:65 | [...] [Collection element] | testGRDB.swift:169:56:169:65 | [...] | provenance | | -| testGRDB.swift:169:57:169:57 | password | testGRDB.swift:169:56:169:65 | [...] [Collection element] | provenance | | -| testGRDB.swift:170:47:170:56 | [...] [Collection element] | testGRDB.swift:170:47:170:56 | [...] | provenance | | -| testGRDB.swift:170:48:170:48 | password | testGRDB.swift:170:47:170:56 | [...] [Collection element] | provenance | | -| testGRDB.swift:173:56:173:65 | [...] [Collection element] | testGRDB.swift:173:56:173:65 | [...] | provenance | | -| testGRDB.swift:173:57:173:57 | password | testGRDB.swift:173:56:173:65 | [...] [Collection element] | provenance | | -| testGRDB.swift:174:47:174:56 | [...] [Collection element] | testGRDB.swift:174:47:174:56 | [...] | provenance | | -| testGRDB.swift:174:48:174:48 | password | testGRDB.swift:174:47:174:56 | [...] [Collection element] | provenance | | -| testGRDB.swift:178:56:178:65 | [...] [Collection element] | testGRDB.swift:178:56:178:65 | [...] | provenance | | -| testGRDB.swift:178:57:178:57 | password | testGRDB.swift:178:56:178:65 | [...] [Collection element] | provenance | | -| testGRDB.swift:179:47:179:56 | [...] [Collection element] | testGRDB.swift:179:47:179:56 | [...] | provenance | | -| testGRDB.swift:179:48:179:48 | password | testGRDB.swift:179:47:179:56 | [...] [Collection element] | provenance | | -| testGRDB.swift:182:56:182:65 | [...] [Collection element] | testGRDB.swift:182:56:182:65 | [...] | provenance | | -| testGRDB.swift:182:57:182:57 | password | testGRDB.swift:182:56:182:65 | [...] [Collection element] | provenance | | -| testGRDB.swift:183:47:183:56 | [...] [Collection element] | testGRDB.swift:183:47:183:56 | [...] | provenance | | -| testGRDB.swift:183:48:183:48 | password | testGRDB.swift:183:47:183:56 | [...] [Collection element] | provenance | | -| testGRDB.swift:187:56:187:65 | [...] [Collection element] | testGRDB.swift:187:56:187:65 | [...] | provenance | | -| testGRDB.swift:187:57:187:57 | password | testGRDB.swift:187:56:187:65 | [...] [Collection element] | provenance | | -| testGRDB.swift:188:47:188:56 | [...] [Collection element] | testGRDB.swift:188:47:188:56 | [...] | provenance | | -| testGRDB.swift:188:48:188:48 | password | testGRDB.swift:188:47:188:56 | [...] [Collection element] | provenance | | -| testGRDB.swift:191:56:191:65 | [...] [Collection element] | testGRDB.swift:191:56:191:65 | [...] | provenance | | -| testGRDB.swift:191:57:191:57 | password | testGRDB.swift:191:56:191:65 | [...] [Collection element] | provenance | | -| testGRDB.swift:192:47:192:56 | [...] [Collection element] | testGRDB.swift:192:47:192:56 | [...] | provenance | | -| testGRDB.swift:192:48:192:48 | password | testGRDB.swift:192:47:192:56 | [...] [Collection element] | provenance | | -| testGRDB.swift:198:29:198:38 | [...] [Collection element] | testGRDB.swift:198:29:198:38 | [...] | provenance | | -| testGRDB.swift:198:30:198:30 | password | testGRDB.swift:198:29:198:38 | [...] [Collection element] | provenance | | -| testGRDB.swift:201:23:201:32 | [...] [Collection element] | testGRDB.swift:201:23:201:32 | [...] | provenance | | -| testGRDB.swift:201:24:201:24 | password | testGRDB.swift:201:23:201:32 | [...] [Collection element] | provenance | | -| testGRDB.swift:206:66:206:75 | [...] [Collection element] | testGRDB.swift:206:66:206:75 | [...] | provenance | | -| testGRDB.swift:206:67:206:67 | password | testGRDB.swift:206:66:206:75 | [...] [Collection element] | provenance | | -| testGRDB.swift:208:80:208:89 | [...] [Collection element] | testGRDB.swift:208:80:208:89 | [...] | provenance | | -| testGRDB.swift:208:81:208:81 | password | testGRDB.swift:208:80:208:89 | [...] [Collection element] | provenance | | -| testGRDB.swift:210:84:210:93 | [...] [Collection element] | testGRDB.swift:210:84:210:93 | [...] | provenance | | -| testGRDB.swift:210:85:210:85 | password | testGRDB.swift:210:84:210:93 | [...] [Collection element] | provenance | | -| testGRDB.swift:212:98:212:107 | [...] [Collection element] | testGRDB.swift:212:98:212:107 | [...] | provenance | | -| testGRDB.swift:212:99:212:99 | password | testGRDB.swift:212:98:212:107 | [...] [Collection element] | provenance | | +| testGRDB.swift:73:57:73:57 | password | testGRDB.swift:73:56:73:65 | [...] | provenance | | +| testGRDB.swift:76:43:76:43 | password | testGRDB.swift:76:42:76:51 | [...] | provenance | | +| testGRDB.swift:81:45:81:45 | password | testGRDB.swift:81:44:81:53 | [...] | provenance | | +| testGRDB.swift:83:45:83:45 | password | testGRDB.swift:83:44:83:53 | [...] | provenance | | +| testGRDB.swift:85:45:85:45 | password | testGRDB.swift:85:44:85:53 | [...] | provenance | | +| testGRDB.swift:87:45:87:45 | password | testGRDB.swift:87:44:87:53 | [...] | provenance | | +| testGRDB.swift:92:38:92:38 | password | testGRDB.swift:92:37:92:46 | [...] | provenance | | +| testGRDB.swift:95:37:95:37 | password | testGRDB.swift:95:36:95:45 | [...] | provenance | | +| testGRDB.swift:100:73:100:73 | password | testGRDB.swift:100:72:100:81 | [...] | provenance | | +| testGRDB.swift:101:73:101:73 | password | testGRDB.swift:101:72:101:81 | [...] | provenance | | +| testGRDB.swift:107:53:107:53 | password | testGRDB.swift:107:52:107:61 | [...] | provenance | | +| testGRDB.swift:109:53:109:53 | password | testGRDB.swift:109:52:109:61 | [...] | provenance | | +| testGRDB.swift:111:52:111:52 | password | testGRDB.swift:111:51:111:60 | [...] | provenance | | +| testGRDB.swift:116:48:116:48 | password | testGRDB.swift:116:47:116:56 | [...] | provenance | | +| testGRDB.swift:118:48:118:48 | password | testGRDB.swift:118:47:118:56 | [...] | provenance | | +| testGRDB.swift:121:45:121:45 | password | testGRDB.swift:121:44:121:53 | [...] | provenance | | +| testGRDB.swift:123:45:123:45 | password | testGRDB.swift:123:44:123:53 | [...] | provenance | | +| testGRDB.swift:126:45:126:45 | password | testGRDB.swift:126:44:126:53 | [...] | provenance | | +| testGRDB.swift:128:45:128:45 | password | testGRDB.swift:128:44:128:53 | [...] | provenance | | +| testGRDB.swift:131:45:131:45 | password | testGRDB.swift:131:44:131:53 | [...] | provenance | | +| testGRDB.swift:133:45:133:45 | password | testGRDB.swift:133:44:133:53 | [...] | provenance | | +| testGRDB.swift:138:69:138:69 | password | testGRDB.swift:138:68:138:77 | [...] | provenance | | +| testGRDB.swift:140:69:140:69 | password | testGRDB.swift:140:68:140:77 | [...] | provenance | | +| testGRDB.swift:143:66:143:66 | password | testGRDB.swift:143:65:143:74 | [...] | provenance | | +| testGRDB.swift:145:66:145:66 | password | testGRDB.swift:145:65:145:74 | [...] | provenance | | +| testGRDB.swift:148:66:148:66 | password | testGRDB.swift:148:65:148:74 | [...] | provenance | | +| testGRDB.swift:150:66:150:66 | password | testGRDB.swift:150:65:150:74 | [...] | provenance | | +| testGRDB.swift:153:66:153:66 | password | testGRDB.swift:153:65:153:74 | [...] | provenance | | +| testGRDB.swift:155:66:155:66 | password | testGRDB.swift:155:65:155:74 | [...] | provenance | | +| testGRDB.swift:160:60:160:60 | password | testGRDB.swift:160:59:160:68 | [...] | provenance | | +| testGRDB.swift:161:51:161:51 | password | testGRDB.swift:161:50:161:59 | [...] | provenance | | +| testGRDB.swift:164:60:164:60 | password | testGRDB.swift:164:59:164:68 | [...] | provenance | | +| testGRDB.swift:165:51:165:51 | password | testGRDB.swift:165:50:165:59 | [...] | provenance | | +| testGRDB.swift:169:57:169:57 | password | testGRDB.swift:169:56:169:65 | [...] | provenance | | +| testGRDB.swift:170:48:170:48 | password | testGRDB.swift:170:47:170:56 | [...] | provenance | | +| testGRDB.swift:173:57:173:57 | password | testGRDB.swift:173:56:173:65 | [...] | provenance | | +| testGRDB.swift:174:48:174:48 | password | testGRDB.swift:174:47:174:56 | [...] | provenance | | +| testGRDB.swift:178:57:178:57 | password | testGRDB.swift:178:56:178:65 | [...] | provenance | | +| testGRDB.swift:179:48:179:48 | password | testGRDB.swift:179:47:179:56 | [...] | provenance | | +| testGRDB.swift:182:57:182:57 | password | testGRDB.swift:182:56:182:65 | [...] | provenance | | +| testGRDB.swift:183:48:183:48 | password | testGRDB.swift:183:47:183:56 | [...] | provenance | | +| testGRDB.swift:187:57:187:57 | password | testGRDB.swift:187:56:187:65 | [...] | provenance | | +| testGRDB.swift:188:48:188:48 | password | testGRDB.swift:188:47:188:56 | [...] | provenance | | +| testGRDB.swift:191:57:191:57 | password | testGRDB.swift:191:56:191:65 | [...] | provenance | | +| testGRDB.swift:192:48:192:48 | password | testGRDB.swift:192:47:192:56 | [...] | provenance | | +| testGRDB.swift:198:30:198:30 | password | testGRDB.swift:198:29:198:38 | [...] | provenance | | +| testGRDB.swift:201:24:201:24 | password | testGRDB.swift:201:23:201:32 | [...] | provenance | | +| testGRDB.swift:206:67:206:67 | password | testGRDB.swift:206:66:206:75 | [...] | provenance | | +| testGRDB.swift:208:81:208:81 | password | testGRDB.swift:208:80:208:89 | [...] | provenance | | +| testGRDB.swift:210:85:210:85 | password | testGRDB.swift:210:84:210:93 | [...] | provenance | | +| testGRDB.swift:212:99:212:99 | password | testGRDB.swift:212:98:212:107 | [...] | provenance | | | testRealm2.swift:13:6:13:6 | value | file://:0:0:0:0 | value | provenance | | | testRealm2.swift:13:6:13:6 | value [Collection element] | file://:0:0:0:0 | value [Collection element] | provenance | | -| testRealm2.swift:18:2:18:2 | [post] o [data] | testRealm2.swift:18:2:18:2 | [post] o | provenance | | | testRealm2.swift:18:11:18:11 | myPassword | testRealm2.swift:13:6:13:6 | value | provenance | | -| testRealm2.swift:18:11:18:11 | myPassword | testRealm2.swift:18:2:18:2 | [post] o [data] | provenance | | -| testRealm2.swift:24:2:24:2 | [post] o [data] | testRealm2.swift:24:2:24:2 | [post] o | provenance | | +| testRealm2.swift:18:11:18:11 | myPassword | testRealm2.swift:18:2:18:2 | [post] o | provenance | | | testRealm2.swift:24:11:24:11 | socialSecurityNumber | testRealm2.swift:13:6:13:6 | value | provenance | | -| testRealm2.swift:24:11:24:11 | socialSecurityNumber | testRealm2.swift:24:2:24:2 | [post] o [data] | provenance | | -| testRealm2.swift:25:2:25:2 | [post] o [data] | testRealm2.swift:25:2:25:2 | [post] o | provenance | | +| testRealm2.swift:24:11:24:11 | socialSecurityNumber | testRealm2.swift:24:2:24:2 | [post] o | provenance | | | testRealm2.swift:25:11:25:11 | ssn | testRealm2.swift:13:6:13:6 | value | provenance | | -| testRealm2.swift:25:11:25:11 | ssn | testRealm2.swift:25:2:25:2 | [post] o [data] | provenance | | -| testRealm2.swift:26:2:26:2 | [post] o [data, Collection element] | testRealm2.swift:26:2:26:2 | [post] o | provenance | | -| testRealm2.swift:26:2:26:2 | [post] o [data] | testRealm2.swift:26:2:26:2 | [post] o | provenance | | +| testRealm2.swift:25:11:25:11 | ssn | testRealm2.swift:25:2:25:2 | [post] o | provenance | | | testRealm2.swift:26:11:26:25 | call to String.init(_:) | testRealm2.swift:13:6:13:6 | value | provenance | | -| testRealm2.swift:26:11:26:25 | call to String.init(_:) | testRealm2.swift:26:2:26:2 | [post] o [data] | provenance | | +| testRealm2.swift:26:11:26:25 | call to String.init(_:) | testRealm2.swift:26:2:26:2 | [post] o | provenance | | | testRealm2.swift:26:11:26:25 | call to String.init(_:) [Collection element] | testRealm2.swift:13:6:13:6 | value [Collection element] | provenance | | -| testRealm2.swift:26:11:26:25 | call to String.init(_:) [Collection element] | testRealm2.swift:26:2:26:2 | [post] o [data, Collection element] | provenance | | +| testRealm2.swift:26:11:26:25 | call to String.init(_:) [Collection element] | testRealm2.swift:26:2:26:2 | [post] o | provenance | | | testRealm2.swift:26:18:26:18 | ssn_int | testRealm2.swift:26:11:26:25 | call to String.init(_:) | provenance | | | testRealm2.swift:26:18:26:18 | ssn_int | testRealm2.swift:26:11:26:25 | call to String.init(_:) [Collection element] | provenance | | -| testRealm2.swift:32:2:32:2 | [post] o [data] | testRealm2.swift:32:2:32:2 | [post] o | provenance | | | testRealm2.swift:32:11:32:11 | creditCardNumber | testRealm2.swift:13:6:13:6 | value | provenance | | -| testRealm2.swift:32:11:32:11 | creditCardNumber | testRealm2.swift:32:2:32:2 | [post] o [data] | provenance | | -| testRealm2.swift:33:2:33:2 | [post] o [data] | testRealm2.swift:33:2:33:2 | [post] o | provenance | | +| testRealm2.swift:32:11:32:11 | creditCardNumber | testRealm2.swift:32:2:32:2 | [post] o | provenance | | | testRealm2.swift:33:11:33:11 | CCN | testRealm2.swift:13:6:13:6 | value | provenance | | -| testRealm2.swift:33:11:33:11 | CCN | testRealm2.swift:33:2:33:2 | [post] o [data] | provenance | | -| testRealm2.swift:34:2:34:2 | [post] o [data, Collection element] | testRealm2.swift:34:2:34:2 | [post] o | provenance | | -| testRealm2.swift:34:2:34:2 | [post] o [data] | testRealm2.swift:34:2:34:2 | [post] o | provenance | | +| testRealm2.swift:33:11:33:11 | CCN | testRealm2.swift:33:2:33:2 | [post] o | provenance | | | testRealm2.swift:34:11:34:25 | call to String.init(_:) | testRealm2.swift:13:6:13:6 | value | provenance | | -| testRealm2.swift:34:11:34:25 | call to String.init(_:) | testRealm2.swift:34:2:34:2 | [post] o [data] | provenance | | +| testRealm2.swift:34:11:34:25 | call to String.init(_:) | testRealm2.swift:34:2:34:2 | [post] o | provenance | | | testRealm2.swift:34:11:34:25 | call to String.init(_:) [Collection element] | testRealm2.swift:13:6:13:6 | value [Collection element] | provenance | | -| testRealm2.swift:34:11:34:25 | call to String.init(_:) [Collection element] | testRealm2.swift:34:2:34:2 | [post] o [data, Collection element] | provenance | | +| testRealm2.swift:34:11:34:25 | call to String.init(_:) [Collection element] | testRealm2.swift:34:2:34:2 | [post] o | provenance | | | testRealm2.swift:34:18:34:18 | int_ccn | testRealm2.swift:34:11:34:25 | call to String.init(_:) | provenance | | | testRealm2.swift:34:18:34:18 | int_ccn | testRealm2.swift:34:11:34:25 | call to String.init(_:) [Collection element] | provenance | | | testRealm.swift:27:6:27:6 | value | file://:0:0:0:0 | value | provenance | | | testRealm.swift:34:6:34:6 | value | file://:0:0:0:0 | value | provenance | | -| testRealm.swift:41:2:41:2 | [post] a [data] | testRealm.swift:41:2:41:2 | [post] a | provenance | | | testRealm.swift:41:11:41:11 | myPassword | testRealm.swift:27:6:27:6 | value | provenance | | -| testRealm.swift:41:11:41:11 | myPassword | testRealm.swift:41:2:41:2 | [post] a [data] | provenance | | -| testRealm.swift:49:2:49:2 | [post] c [data] | testRealm.swift:49:2:49:2 | [post] c | provenance | | +| testRealm.swift:41:11:41:11 | myPassword | testRealm.swift:41:2:41:2 | [post] a | provenance | | | testRealm.swift:49:11:49:11 | myPassword | testRealm.swift:27:6:27:6 | value | provenance | | -| testRealm.swift:49:11:49:11 | myPassword | testRealm.swift:49:2:49:2 | [post] c [data] | provenance | | -| testRealm.swift:59:2:59:3 | [post] ...! [data] | testRealm.swift:59:2:59:3 | [post] ...! | provenance | | +| testRealm.swift:49:11:49:11 | myPassword | testRealm.swift:49:2:49:2 | [post] c | provenance | | | testRealm.swift:59:12:59:12 | myPassword | testRealm.swift:27:6:27:6 | value | provenance | | -| testRealm.swift:59:12:59:12 | myPassword | testRealm.swift:59:2:59:3 | [post] ...! [data] | provenance | | -| testRealm.swift:66:2:66:2 | [post] g [data] | testRealm.swift:66:2:66:2 | [post] g | provenance | | +| testRealm.swift:59:12:59:12 | myPassword | testRealm.swift:59:2:59:3 | [post] ...! | provenance | | | testRealm.swift:66:11:66:11 | myPassword | testRealm.swift:27:6:27:6 | value | provenance | | -| testRealm.swift:66:11:66:11 | myPassword | testRealm.swift:66:2:66:2 | [post] g [data] | provenance | | -| testRealm.swift:73:2:73:2 | [post] h [password] | testRealm.swift:73:2:73:2 | [post] h | provenance | | +| testRealm.swift:66:11:66:11 | myPassword | testRealm.swift:66:2:66:2 | [post] g | provenance | | | testRealm.swift:73:15:73:15 | myPassword | testRealm.swift:34:6:34:6 | value | provenance | | -| testRealm.swift:73:15:73:15 | myPassword | testRealm.swift:73:2:73:2 | [post] h [password] | provenance | | +| testRealm.swift:73:15:73:15 | myPassword | testRealm.swift:73:2:73:2 | [post] h | provenance | | nodes | SQLite.swift:119:70:119:70 | mobilePhoneNumber | semmle.label | mobilePhoneNumber | | SQLite.swift:120:50:120:50 | mobilePhoneNumber | semmle.label | mobilePhoneNumber | @@ -377,45 +274,33 @@ nodes | SQLite.swift:154:23:154:23 | [...] [Collection element] | semmle.label | [...] [Collection element] | | SQLite.swift:154:23:154:23 | mobilePhoneNumber | semmle.label | mobilePhoneNumber | | SQLite.swift:158:32:158:54 | [...] | semmle.label | [...] | -| SQLite.swift:158:32:158:54 | [...] [Collection element] | semmle.label | [...] [Collection element] | | SQLite.swift:158:33:158:33 | mobilePhoneNumber | semmle.label | mobilePhoneNumber | | SQLite.swift:159:28:159:50 | [...] | semmle.label | [...] | -| SQLite.swift:159:28:159:50 | [...] [Collection element] | semmle.label | [...] [Collection element] | | SQLite.swift:159:29:159:29 | mobilePhoneNumber | semmle.label | mobilePhoneNumber | | SQLite.swift:160:31:160:53 | [...] | semmle.label | [...] | -| SQLite.swift:160:31:160:53 | [...] [Collection element] | semmle.label | [...] [Collection element] | | SQLite.swift:160:32:160:32 | mobilePhoneNumber | semmle.label | mobilePhoneNumber | | SQLite.swift:163:21:163:43 | [...] | semmle.label | [...] | -| SQLite.swift:163:21:163:43 | [...] [Collection element] | semmle.label | [...] [Collection element] | | SQLite.swift:163:22:163:22 | mobilePhoneNumber | semmle.label | mobilePhoneNumber | | SQLite.swift:164:20:164:42 | [...] | semmle.label | [...] | -| SQLite.swift:164:20:164:42 | [...] [Collection element] | semmle.label | [...] [Collection element] | | SQLite.swift:164:21:164:21 | mobilePhoneNumber | semmle.label | mobilePhoneNumber | | SQLite.swift:165:23:165:45 | [...] | semmle.label | [...] | -| SQLite.swift:165:23:165:45 | [...] [Collection element] | semmle.label | [...] [Collection element] | | SQLite.swift:165:24:165:24 | mobilePhoneNumber | semmle.label | mobilePhoneNumber | | SQLite.swift:169:32:169:70 | [...] | semmle.label | [...] | -| SQLite.swift:169:32:169:70 | [...] [Collection element, Tuple element at index 1] | semmle.label | [...] [Collection element, Tuple element at index 1] | | SQLite.swift:169:43:169:53 | (...) [Tuple element at index 1] | semmle.label | (...) [Tuple element at index 1] | | SQLite.swift:169:53:169:53 | mobilePhoneNumber | semmle.label | mobilePhoneNumber | | SQLite.swift:170:28:170:66 | [...] | semmle.label | [...] | -| SQLite.swift:170:28:170:66 | [...] [Collection element, Tuple element at index 1] | semmle.label | [...] [Collection element, Tuple element at index 1] | | SQLite.swift:170:39:170:49 | (...) [Tuple element at index 1] | semmle.label | (...) [Tuple element at index 1] | | SQLite.swift:170:49:170:49 | mobilePhoneNumber | semmle.label | mobilePhoneNumber | | SQLite.swift:171:31:171:69 | [...] | semmle.label | [...] | -| SQLite.swift:171:31:171:69 | [...] [Collection element, Tuple element at index 1] | semmle.label | [...] [Collection element, Tuple element at index 1] | | SQLite.swift:171:42:171:52 | (...) [Tuple element at index 1] | semmle.label | (...) [Tuple element at index 1] | | SQLite.swift:171:52:171:52 | mobilePhoneNumber | semmle.label | mobilePhoneNumber | | SQLite.swift:174:21:174:59 | [...] | semmle.label | [...] | -| SQLite.swift:174:21:174:59 | [...] [Collection element, Tuple element at index 1] | semmle.label | [...] [Collection element, Tuple element at index 1] | | SQLite.swift:174:32:174:42 | (...) [Tuple element at index 1] | semmle.label | (...) [Tuple element at index 1] | | SQLite.swift:174:42:174:42 | mobilePhoneNumber | semmle.label | mobilePhoneNumber | | SQLite.swift:175:20:175:58 | [...] | semmle.label | [...] | -| SQLite.swift:175:20:175:58 | [...] [Collection element, Tuple element at index 1] | semmle.label | [...] [Collection element, Tuple element at index 1] | | SQLite.swift:175:31:175:41 | (...) [Tuple element at index 1] | semmle.label | (...) [Tuple element at index 1] | | SQLite.swift:175:41:175:41 | mobilePhoneNumber | semmle.label | mobilePhoneNumber | | SQLite.swift:176:23:176:61 | [...] | semmle.label | [...] | -| SQLite.swift:176:23:176:61 | [...] [Collection element, Tuple element at index 1] | semmle.label | [...] [Collection element, Tuple element at index 1] | | SQLite.swift:176:34:176:44 | (...) [Tuple element at index 1] | semmle.label | (...) [Tuple element at index 1] | | SQLite.swift:176:44:176:44 | mobilePhoneNumber | semmle.label | mobilePhoneNumber | | SQLite.swift:186:40:186:54 | ... <-(_:_:) ... | semmle.label | ... <-(_:_:) ... | @@ -467,40 +352,28 @@ nodes | testCoreData2.swift:23:13:23:13 | self [Return] [notStoredBankAccountNumber] | semmle.label | self [Return] [notStoredBankAccountNumber] | | testCoreData2.swift:23:13:23:13 | value | semmle.label | value | | testCoreData2.swift:37:2:37:2 | [post] obj | semmle.label | [post] obj | -| testCoreData2.swift:37:2:37:2 | [post] obj [myValue] | semmle.label | [post] obj [myValue] | | testCoreData2.swift:37:16:37:16 | bankAccountNo | semmle.label | bankAccountNo | | testCoreData2.swift:39:2:39:2 | [post] obj | semmle.label | [post] obj | -| testCoreData2.swift:39:2:39:2 | [post] obj [myBankAccountNumber] | semmle.label | [post] obj [myBankAccountNumber] | | testCoreData2.swift:39:28:39:28 | bankAccountNo | semmle.label | bankAccountNo | | testCoreData2.swift:41:2:41:2 | [post] obj | semmle.label | [post] obj | -| testCoreData2.swift:41:2:41:2 | [post] obj [myBankAccountNumber2] | semmle.label | [post] obj [myBankAccountNumber2] | | testCoreData2.swift:41:29:41:29 | bankAccountNo | semmle.label | bankAccountNo | | testCoreData2.swift:43:2:43:2 | [post] obj | semmle.label | [post] obj | -| testCoreData2.swift:43:2:43:2 | [post] obj [notStoredBankAccountNumber] | semmle.label | [post] obj [notStoredBankAccountNumber] | | testCoreData2.swift:43:35:43:35 | bankAccountNo | semmle.label | bankAccountNo | | testCoreData2.swift:46:2:46:10 | [post] ...? | semmle.label | [post] ...? | -| testCoreData2.swift:46:2:46:10 | [post] ...? [myValue] | semmle.label | [post] ...? [myValue] | | testCoreData2.swift:46:22:46:22 | bankAccountNo | semmle.label | bankAccountNo | | testCoreData2.swift:48:2:48:10 | [post] ...? | semmle.label | [post] ...? | -| testCoreData2.swift:48:2:48:10 | [post] ...? [myBankAccountNumber] | semmle.label | [post] ...? [myBankAccountNumber] | | testCoreData2.swift:48:34:48:34 | bankAccountNo | semmle.label | bankAccountNo | | testCoreData2.swift:50:2:50:10 | [post] ...? | semmle.label | [post] ...? | -| testCoreData2.swift:50:2:50:10 | [post] ...? [myBankAccountNumber2] | semmle.label | [post] ...? [myBankAccountNumber2] | | testCoreData2.swift:50:35:50:35 | bankAccountNo | semmle.label | bankAccountNo | | testCoreData2.swift:52:2:52:10 | [post] ...? | semmle.label | [post] ...? | -| testCoreData2.swift:52:2:52:10 | [post] ...? [notStoredBankAccountNumber] | semmle.label | [post] ...? [notStoredBankAccountNumber] | | testCoreData2.swift:52:41:52:41 | bankAccountNo | semmle.label | bankAccountNo | | testCoreData2.swift:57:3:57:3 | [post] obj | semmle.label | [post] obj | -| testCoreData2.swift:57:3:57:3 | [post] obj [myBankAccountNumber] | semmle.label | [post] obj [myBankAccountNumber] | | testCoreData2.swift:57:29:57:29 | bankAccountNo | semmle.label | bankAccountNo | | testCoreData2.swift:60:4:60:4 | [post] obj | semmle.label | [post] obj | -| testCoreData2.swift:60:4:60:4 | [post] obj [myBankAccountNumber] | semmle.label | [post] obj [myBankAccountNumber] | | testCoreData2.swift:60:30:60:30 | bankAccountNo | semmle.label | bankAccountNo | | testCoreData2.swift:62:4:62:4 | [post] obj | semmle.label | [post] obj | -| testCoreData2.swift:62:4:62:4 | [post] obj [myBankAccountNumber] | semmle.label | [post] obj [myBankAccountNumber] | | testCoreData2.swift:62:30:62:30 | bankAccountNo | semmle.label | bankAccountNo | | testCoreData2.swift:65:3:65:3 | [post] obj | semmle.label | [post] obj | -| testCoreData2.swift:65:3:65:3 | [post] obj [myBankAccountNumber] | semmle.label | [post] obj [myBankAccountNumber] | | testCoreData2.swift:65:29:65:29 | bankAccountNo | semmle.label | bankAccountNo | | testCoreData2.swift:70:9:70:9 | self | semmle.label | self | | testCoreData2.swift:70:9:70:9 | self [Return] [value] | semmle.label | self [Return] [value] | @@ -508,41 +381,32 @@ nodes | testCoreData2.swift:70:9:70:9 | value | semmle.label | value | | testCoreData2.swift:71:9:71:9 | self | semmle.label | self | | testCoreData2.swift:79:2:79:2 | [post] dbObj | semmle.label | [post] dbObj | -| testCoreData2.swift:79:2:79:2 | [post] dbObj [myValue] | semmle.label | [post] dbObj [myValue] | | testCoreData2.swift:79:18:79:28 | .bankAccountNo | semmle.label | .bankAccountNo | | testCoreData2.swift:80:2:80:2 | [post] dbObj | semmle.label | [post] dbObj | -| testCoreData2.swift:80:2:80:2 | [post] dbObj [myValue] | semmle.label | [post] dbObj [myValue] | | testCoreData2.swift:80:18:80:28 | ...! | semmle.label | ...! | | testCoreData2.swift:80:18:80:28 | .bankAccountNo2 | semmle.label | .bankAccountNo2 | | testCoreData2.swift:82:2:82:2 | [post] dbObj | semmle.label | [post] dbObj | -| testCoreData2.swift:82:2:82:2 | [post] dbObj [myValue] | semmle.label | [post] dbObj [myValue] | | testCoreData2.swift:82:18:82:18 | bankAccountNo | semmle.label | bankAccountNo | | testCoreData2.swift:82:18:82:32 | .value | semmle.label | .value | | testCoreData2.swift:83:2:83:2 | [post] dbObj | semmle.label | [post] dbObj | -| testCoreData2.swift:83:2:83:2 | [post] dbObj [myValue] | semmle.label | [post] dbObj [myValue] | | testCoreData2.swift:83:18:83:18 | bankAccountNo | semmle.label | bankAccountNo | | testCoreData2.swift:83:18:83:32 | ...! | semmle.label | ...! | | testCoreData2.swift:83:18:83:32 | .value2 | semmle.label | .value2 | | testCoreData2.swift:84:2:84:2 | [post] dbObj | semmle.label | [post] dbObj | -| testCoreData2.swift:84:2:84:2 | [post] dbObj [myValue] | semmle.label | [post] dbObj [myValue] | | testCoreData2.swift:84:18:84:18 | ...! | semmle.label | ...! | | testCoreData2.swift:84:18:84:18 | bankAccountNo2 | semmle.label | bankAccountNo2 | | testCoreData2.swift:84:18:84:33 | .value | semmle.label | .value | | testCoreData2.swift:85:2:85:2 | [post] dbObj | semmle.label | [post] dbObj | -| testCoreData2.swift:85:2:85:2 | [post] dbObj [myValue] | semmle.label | [post] dbObj [myValue] | | testCoreData2.swift:85:18:85:18 | ...! | semmle.label | ...! | | testCoreData2.swift:85:18:85:18 | bankAccountNo2 | semmle.label | bankAccountNo2 | | testCoreData2.swift:85:18:85:33 | ...! | semmle.label | ...! | | testCoreData2.swift:85:18:85:33 | .value2 | semmle.label | .value2 | | testCoreData2.swift:87:2:87:10 | [post] ...? | semmle.label | [post] ...? | -| testCoreData2.swift:87:2:87:10 | [post] ...? [myValue] | semmle.label | [post] ...? [myValue] | | testCoreData2.swift:87:22:87:32 | .bankAccountNo | semmle.label | .bankAccountNo | | testCoreData2.swift:88:2:88:10 | [post] ...? | semmle.label | [post] ...? | -| testCoreData2.swift:88:2:88:10 | [post] ...? [myValue] | semmle.label | [post] ...? [myValue] | | testCoreData2.swift:88:22:88:22 | bankAccountNo | semmle.label | bankAccountNo | | testCoreData2.swift:88:22:88:36 | .value | semmle.label | .value | | testCoreData2.swift:89:2:89:10 | [post] ...? | semmle.label | [post] ...? | -| testCoreData2.swift:89:2:89:10 | [post] ...? [myValue] | semmle.label | [post] ...? [myValue] | | testCoreData2.swift:89:22:89:22 | ...! | semmle.label | ...! | | testCoreData2.swift:89:22:89:22 | bankAccountNo2 | semmle.label | bankAccountNo2 | | testCoreData2.swift:89:22:89:37 | ...! | semmle.label | ...! | @@ -551,24 +415,20 @@ nodes | testCoreData2.swift:92:10:92:10 | a | semmle.label | a | | testCoreData2.swift:92:10:92:12 | .value | semmle.label | .value | | testCoreData2.swift:93:2:93:2 | [post] dbObj | semmle.label | [post] dbObj | -| testCoreData2.swift:93:2:93:2 | [post] dbObj [myValue] | semmle.label | [post] dbObj [myValue] | | testCoreData2.swift:93:18:93:18 | b | semmle.label | b | | testCoreData2.swift:95:10:95:10 | bankAccountNo | semmle.label | bankAccountNo | | testCoreData2.swift:97:2:97:2 | [post] d [value] | semmle.label | [post] d [value] | | testCoreData2.swift:97:12:97:12 | c | semmle.label | c | | testCoreData2.swift:97:12:97:14 | .value | semmle.label | .value | | testCoreData2.swift:98:2:98:2 | [post] dbObj | semmle.label | [post] dbObj | -| testCoreData2.swift:98:2:98:2 | [post] dbObj [myValue] | semmle.label | [post] dbObj [myValue] | | testCoreData2.swift:98:18:98:18 | d [value] | semmle.label | d [value] | | testCoreData2.swift:98:18:98:20 | .value | semmle.label | .value | | testCoreData2.swift:101:10:101:10 | bankAccountNo | semmle.label | bankAccountNo | | testCoreData2.swift:103:13:103:13 | e | semmle.label | e | | testCoreData2.swift:104:2:104:2 | [post] dbObj | semmle.label | [post] dbObj | -| testCoreData2.swift:104:2:104:2 | [post] dbObj [myValue] | semmle.label | [post] dbObj [myValue] | | testCoreData2.swift:104:18:104:18 | e | semmle.label | e | | testCoreData2.swift:104:18:104:20 | .value | semmle.label | .value | | testCoreData2.swift:105:2:105:2 | [post] dbObj | semmle.label | [post] dbObj | -| testCoreData2.swift:105:2:105:2 | [post] dbObj [myValue] | semmle.label | [post] dbObj [myValue] | | testCoreData2.swift:105:18:105:18 | e | semmle.label | e | | testCoreData2.swift:105:18:105:20 | ...! | semmle.label | ...! | | testCoreData2.swift:105:18:105:20 | .value2 | semmle.label | .value2 | @@ -581,7 +441,6 @@ nodes | testCoreData.swift:58:15:58:15 | password | semmle.label | password | | testCoreData.swift:61:25:61:25 | password | semmle.label | password | | testCoreData.swift:64:2:64:2 | [post] obj | semmle.label | [post] obj | -| testCoreData.swift:64:2:64:2 | [post] obj [myValue] | semmle.label | [post] obj [myValue] | | testCoreData.swift:64:16:64:16 | password | semmle.label | password | | testCoreData.swift:77:24:77:24 | x | semmle.label | x | | testCoreData.swift:78:15:78:15 | x | semmle.label | x | @@ -597,186 +456,126 @@ nodes | testCoreData.swift:128:15:128:33 | call to generateSecretKey() | semmle.label | call to generateSecretKey() | | testCoreData.swift:129:15:129:30 | call to getCertificate() | semmle.label | call to getCertificate() | | testGRDB.swift:73:56:73:65 | [...] | semmle.label | [...] | -| testGRDB.swift:73:56:73:65 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:73:57:73:57 | password | semmle.label | password | | testGRDB.swift:76:42:76:51 | [...] | semmle.label | [...] | -| testGRDB.swift:76:42:76:51 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:76:43:76:43 | password | semmle.label | password | | testGRDB.swift:81:44:81:53 | [...] | semmle.label | [...] | -| testGRDB.swift:81:44:81:53 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:81:45:81:45 | password | semmle.label | password | | testGRDB.swift:83:44:83:53 | [...] | semmle.label | [...] | -| testGRDB.swift:83:44:83:53 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:83:45:83:45 | password | semmle.label | password | | testGRDB.swift:85:44:85:53 | [...] | semmle.label | [...] | -| testGRDB.swift:85:44:85:53 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:85:45:85:45 | password | semmle.label | password | | testGRDB.swift:87:44:87:53 | [...] | semmle.label | [...] | -| testGRDB.swift:87:44:87:53 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:87:45:87:45 | password | semmle.label | password | | testGRDB.swift:92:37:92:46 | [...] | semmle.label | [...] | -| testGRDB.swift:92:37:92:46 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:92:38:92:38 | password | semmle.label | password | | testGRDB.swift:95:36:95:45 | [...] | semmle.label | [...] | -| testGRDB.swift:95:36:95:45 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:95:37:95:37 | password | semmle.label | password | | testGRDB.swift:100:72:100:81 | [...] | semmle.label | [...] | -| testGRDB.swift:100:72:100:81 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:100:73:100:73 | password | semmle.label | password | | testGRDB.swift:101:72:101:81 | [...] | semmle.label | [...] | -| testGRDB.swift:101:72:101:81 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:101:73:101:73 | password | semmle.label | password | | testGRDB.swift:107:52:107:61 | [...] | semmle.label | [...] | -| testGRDB.swift:107:52:107:61 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:107:53:107:53 | password | semmle.label | password | | testGRDB.swift:109:52:109:61 | [...] | semmle.label | [...] | -| testGRDB.swift:109:52:109:61 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:109:53:109:53 | password | semmle.label | password | | testGRDB.swift:111:51:111:60 | [...] | semmle.label | [...] | -| testGRDB.swift:111:51:111:60 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:111:52:111:52 | password | semmle.label | password | | testGRDB.swift:116:47:116:56 | [...] | semmle.label | [...] | -| testGRDB.swift:116:47:116:56 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:116:48:116:48 | password | semmle.label | password | | testGRDB.swift:118:47:118:56 | [...] | semmle.label | [...] | -| testGRDB.swift:118:47:118:56 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:118:48:118:48 | password | semmle.label | password | | testGRDB.swift:121:44:121:53 | [...] | semmle.label | [...] | -| testGRDB.swift:121:44:121:53 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:121:45:121:45 | password | semmle.label | password | | testGRDB.swift:123:44:123:53 | [...] | semmle.label | [...] | -| testGRDB.swift:123:44:123:53 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:123:45:123:45 | password | semmle.label | password | | testGRDB.swift:126:44:126:53 | [...] | semmle.label | [...] | -| testGRDB.swift:126:44:126:53 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:126:45:126:45 | password | semmle.label | password | | testGRDB.swift:128:44:128:53 | [...] | semmle.label | [...] | -| testGRDB.swift:128:44:128:53 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:128:45:128:45 | password | semmle.label | password | | testGRDB.swift:131:44:131:53 | [...] | semmle.label | [...] | -| testGRDB.swift:131:44:131:53 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:131:45:131:45 | password | semmle.label | password | | testGRDB.swift:133:44:133:53 | [...] | semmle.label | [...] | -| testGRDB.swift:133:44:133:53 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:133:45:133:45 | password | semmle.label | password | | testGRDB.swift:138:68:138:77 | [...] | semmle.label | [...] | -| testGRDB.swift:138:68:138:77 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:138:69:138:69 | password | semmle.label | password | | testGRDB.swift:140:68:140:77 | [...] | semmle.label | [...] | -| testGRDB.swift:140:68:140:77 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:140:69:140:69 | password | semmle.label | password | | testGRDB.swift:143:65:143:74 | [...] | semmle.label | [...] | -| testGRDB.swift:143:65:143:74 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:143:66:143:66 | password | semmle.label | password | | testGRDB.swift:145:65:145:74 | [...] | semmle.label | [...] | -| testGRDB.swift:145:65:145:74 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:145:66:145:66 | password | semmle.label | password | | testGRDB.swift:148:65:148:74 | [...] | semmle.label | [...] | -| testGRDB.swift:148:65:148:74 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:148:66:148:66 | password | semmle.label | password | | testGRDB.swift:150:65:150:74 | [...] | semmle.label | [...] | -| testGRDB.swift:150:65:150:74 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:150:66:150:66 | password | semmle.label | password | | testGRDB.swift:153:65:153:74 | [...] | semmle.label | [...] | -| testGRDB.swift:153:65:153:74 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:153:66:153:66 | password | semmle.label | password | | testGRDB.swift:155:65:155:74 | [...] | semmle.label | [...] | -| testGRDB.swift:155:65:155:74 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:155:66:155:66 | password | semmle.label | password | | testGRDB.swift:160:59:160:68 | [...] | semmle.label | [...] | -| testGRDB.swift:160:59:160:68 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:160:60:160:60 | password | semmle.label | password | | testGRDB.swift:161:50:161:59 | [...] | semmle.label | [...] | -| testGRDB.swift:161:50:161:59 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:161:51:161:51 | password | semmle.label | password | | testGRDB.swift:164:59:164:68 | [...] | semmle.label | [...] | -| testGRDB.swift:164:59:164:68 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:164:60:164:60 | password | semmle.label | password | | testGRDB.swift:165:50:165:59 | [...] | semmle.label | [...] | -| testGRDB.swift:165:50:165:59 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:165:51:165:51 | password | semmle.label | password | | testGRDB.swift:169:56:169:65 | [...] | semmle.label | [...] | -| testGRDB.swift:169:56:169:65 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:169:57:169:57 | password | semmle.label | password | | testGRDB.swift:170:47:170:56 | [...] | semmle.label | [...] | -| testGRDB.swift:170:47:170:56 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:170:48:170:48 | password | semmle.label | password | | testGRDB.swift:173:56:173:65 | [...] | semmle.label | [...] | -| testGRDB.swift:173:56:173:65 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:173:57:173:57 | password | semmle.label | password | | testGRDB.swift:174:47:174:56 | [...] | semmle.label | [...] | -| testGRDB.swift:174:47:174:56 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:174:48:174:48 | password | semmle.label | password | | testGRDB.swift:178:56:178:65 | [...] | semmle.label | [...] | -| testGRDB.swift:178:56:178:65 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:178:57:178:57 | password | semmle.label | password | | testGRDB.swift:179:47:179:56 | [...] | semmle.label | [...] | -| testGRDB.swift:179:47:179:56 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:179:48:179:48 | password | semmle.label | password | | testGRDB.swift:182:56:182:65 | [...] | semmle.label | [...] | -| testGRDB.swift:182:56:182:65 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:182:57:182:57 | password | semmle.label | password | | testGRDB.swift:183:47:183:56 | [...] | semmle.label | [...] | -| testGRDB.swift:183:47:183:56 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:183:48:183:48 | password | semmle.label | password | | testGRDB.swift:187:56:187:65 | [...] | semmle.label | [...] | -| testGRDB.swift:187:56:187:65 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:187:57:187:57 | password | semmle.label | password | | testGRDB.swift:188:47:188:56 | [...] | semmle.label | [...] | -| testGRDB.swift:188:47:188:56 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:188:48:188:48 | password | semmle.label | password | | testGRDB.swift:191:56:191:65 | [...] | semmle.label | [...] | -| testGRDB.swift:191:56:191:65 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:191:57:191:57 | password | semmle.label | password | | testGRDB.swift:192:47:192:56 | [...] | semmle.label | [...] | -| testGRDB.swift:192:47:192:56 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:192:48:192:48 | password | semmle.label | password | | testGRDB.swift:198:29:198:38 | [...] | semmle.label | [...] | -| testGRDB.swift:198:29:198:38 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:198:30:198:30 | password | semmle.label | password | | testGRDB.swift:201:23:201:32 | [...] | semmle.label | [...] | -| testGRDB.swift:201:23:201:32 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:201:24:201:24 | password | semmle.label | password | | testGRDB.swift:206:66:206:75 | [...] | semmle.label | [...] | -| testGRDB.swift:206:66:206:75 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:206:67:206:67 | password | semmle.label | password | | testGRDB.swift:208:80:208:89 | [...] | semmle.label | [...] | -| testGRDB.swift:208:80:208:89 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:208:81:208:81 | password | semmle.label | password | | testGRDB.swift:210:84:210:93 | [...] | semmle.label | [...] | -| testGRDB.swift:210:84:210:93 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:210:85:210:85 | password | semmle.label | password | | testGRDB.swift:212:98:212:107 | [...] | semmle.label | [...] | -| testGRDB.swift:212:98:212:107 | [...] [Collection element] | semmle.label | [...] [Collection element] | | testGRDB.swift:212:99:212:99 | password | semmle.label | password | | testRealm2.swift:13:6:13:6 | self [Return] [data, Collection element] | semmle.label | self [Return] [data, Collection element] | | testRealm2.swift:13:6:13:6 | self [Return] [data] | semmle.label | self [Return] [data] | | testRealm2.swift:13:6:13:6 | value | semmle.label | value | | testRealm2.swift:13:6:13:6 | value [Collection element] | semmle.label | value [Collection element] | | testRealm2.swift:18:2:18:2 | [post] o | semmle.label | [post] o | -| testRealm2.swift:18:2:18:2 | [post] o [data] | semmle.label | [post] o [data] | | testRealm2.swift:18:11:18:11 | myPassword | semmle.label | myPassword | | testRealm2.swift:24:2:24:2 | [post] o | semmle.label | [post] o | -| testRealm2.swift:24:2:24:2 | [post] o [data] | semmle.label | [post] o [data] | | testRealm2.swift:24:11:24:11 | socialSecurityNumber | semmle.label | socialSecurityNumber | | testRealm2.swift:25:2:25:2 | [post] o | semmle.label | [post] o | -| testRealm2.swift:25:2:25:2 | [post] o [data] | semmle.label | [post] o [data] | | testRealm2.swift:25:11:25:11 | ssn | semmle.label | ssn | | testRealm2.swift:26:2:26:2 | [post] o | semmle.label | [post] o | -| testRealm2.swift:26:2:26:2 | [post] o [data, Collection element] | semmle.label | [post] o [data, Collection element] | -| testRealm2.swift:26:2:26:2 | [post] o [data] | semmle.label | [post] o [data] | | testRealm2.swift:26:11:26:25 | call to String.init(_:) | semmle.label | call to String.init(_:) | | testRealm2.swift:26:11:26:25 | call to String.init(_:) [Collection element] | semmle.label | call to String.init(_:) [Collection element] | | testRealm2.swift:26:18:26:18 | ssn_int | semmle.label | ssn_int | | testRealm2.swift:32:2:32:2 | [post] o | semmle.label | [post] o | -| testRealm2.swift:32:2:32:2 | [post] o [data] | semmle.label | [post] o [data] | | testRealm2.swift:32:11:32:11 | creditCardNumber | semmle.label | creditCardNumber | | testRealm2.swift:33:2:33:2 | [post] o | semmle.label | [post] o | -| testRealm2.swift:33:2:33:2 | [post] o [data] | semmle.label | [post] o [data] | | testRealm2.swift:33:11:33:11 | CCN | semmle.label | CCN | | testRealm2.swift:34:2:34:2 | [post] o | semmle.label | [post] o | -| testRealm2.swift:34:2:34:2 | [post] o [data, Collection element] | semmle.label | [post] o [data, Collection element] | -| testRealm2.swift:34:2:34:2 | [post] o [data] | semmle.label | [post] o [data] | | testRealm2.swift:34:11:34:25 | call to String.init(_:) | semmle.label | call to String.init(_:) | | testRealm2.swift:34:11:34:25 | call to String.init(_:) [Collection element] | semmle.label | call to String.init(_:) [Collection element] | | testRealm2.swift:34:18:34:18 | int_ccn | semmle.label | int_ccn | @@ -785,23 +584,18 @@ nodes | testRealm.swift:34:6:34:6 | self [Return] [password] | semmle.label | self [Return] [password] | | testRealm.swift:34:6:34:6 | value | semmle.label | value | | testRealm.swift:41:2:41:2 | [post] a | semmle.label | [post] a | -| testRealm.swift:41:2:41:2 | [post] a [data] | semmle.label | [post] a [data] | | testRealm.swift:41:11:41:11 | myPassword | semmle.label | myPassword | | testRealm.swift:49:2:49:2 | [post] c | semmle.label | [post] c | -| testRealm.swift:49:2:49:2 | [post] c [data] | semmle.label | [post] c [data] | | testRealm.swift:49:11:49:11 | myPassword | semmle.label | myPassword | | testRealm.swift:59:2:59:3 | [post] ...! | semmle.label | [post] ...! | -| testRealm.swift:59:2:59:3 | [post] ...! [data] | semmle.label | [post] ...! [data] | | testRealm.swift:59:12:59:12 | myPassword | semmle.label | myPassword | | testRealm.swift:66:2:66:2 | [post] g | semmle.label | [post] g | -| testRealm.swift:66:2:66:2 | [post] g [data] | semmle.label | [post] g [data] | | testRealm.swift:66:11:66:11 | myPassword | semmle.label | myPassword | | testRealm.swift:73:2:73:2 | [post] h | semmle.label | [post] h | -| testRealm.swift:73:2:73:2 | [post] h [password] | semmle.label | [post] h [password] | | testRealm.swift:73:15:73:15 | myPassword | semmle.label | myPassword | subpaths -| testCoreData2.swift:43:35:43:35 | bankAccountNo | testCoreData2.swift:23:13:23:13 | value | testCoreData2.swift:23:13:23:13 | self [Return] [notStoredBankAccountNumber] | testCoreData2.swift:43:2:43:2 | [post] obj [notStoredBankAccountNumber] | -| testCoreData2.swift:52:41:52:41 | bankAccountNo | testCoreData2.swift:23:13:23:13 | value | testCoreData2.swift:23:13:23:13 | self [Return] [notStoredBankAccountNumber] | testCoreData2.swift:52:2:52:10 | [post] ...? [notStoredBankAccountNumber] | +| testCoreData2.swift:43:35:43:35 | bankAccountNo | testCoreData2.swift:23:13:23:13 | value | testCoreData2.swift:23:13:23:13 | self [Return] [notStoredBankAccountNumber] | testCoreData2.swift:43:2:43:2 | [post] obj | +| testCoreData2.swift:52:41:52:41 | bankAccountNo | testCoreData2.swift:23:13:23:13 | value | testCoreData2.swift:23:13:23:13 | self [Return] [notStoredBankAccountNumber] | testCoreData2.swift:52:2:52:10 | [post] ...? | | testCoreData2.swift:82:18:82:18 | bankAccountNo | testCoreData2.swift:70:9:70:9 | self | file://:0:0:0:0 | .value | testCoreData2.swift:82:18:82:32 | .value | | testCoreData2.swift:83:18:83:18 | bankAccountNo | testCoreData2.swift:71:9:71:9 | self | file://:0:0:0:0 | .value2 | testCoreData2.swift:83:18:83:32 | .value2 | | testCoreData2.swift:84:18:84:18 | ...! | testCoreData2.swift:70:9:70:9 | self | file://:0:0:0:0 | .value | testCoreData2.swift:84:18:84:33 | .value | @@ -814,20 +608,20 @@ subpaths | testCoreData2.swift:98:18:98:18 | d [value] | testCoreData2.swift:70:9:70:9 | self [value] | file://:0:0:0:0 | .value | testCoreData2.swift:98:18:98:20 | .value | | testCoreData2.swift:104:18:104:18 | e | testCoreData2.swift:70:9:70:9 | self | file://:0:0:0:0 | .value | testCoreData2.swift:104:18:104:20 | .value | | testCoreData2.swift:105:18:105:18 | e | testCoreData2.swift:71:9:71:9 | self | file://:0:0:0:0 | .value2 | testCoreData2.swift:105:18:105:20 | .value2 | -| testRealm2.swift:18:11:18:11 | myPassword | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:18:2:18:2 | [post] o [data] | -| testRealm2.swift:24:11:24:11 | socialSecurityNumber | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:24:2:24:2 | [post] o [data] | -| testRealm2.swift:25:11:25:11 | ssn | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:25:2:25:2 | [post] o [data] | -| testRealm2.swift:26:11:26:25 | call to String.init(_:) | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:26:2:26:2 | [post] o [data] | -| testRealm2.swift:26:11:26:25 | call to String.init(_:) [Collection element] | testRealm2.swift:13:6:13:6 | value [Collection element] | testRealm2.swift:13:6:13:6 | self [Return] [data, Collection element] | testRealm2.swift:26:2:26:2 | [post] o [data, Collection element] | -| testRealm2.swift:32:11:32:11 | creditCardNumber | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:32:2:32:2 | [post] o [data] | -| testRealm2.swift:33:11:33:11 | CCN | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:33:2:33:2 | [post] o [data] | -| testRealm2.swift:34:11:34:25 | call to String.init(_:) | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:34:2:34:2 | [post] o [data] | -| testRealm2.swift:34:11:34:25 | call to String.init(_:) [Collection element] | testRealm2.swift:13:6:13:6 | value [Collection element] | testRealm2.swift:13:6:13:6 | self [Return] [data, Collection element] | testRealm2.swift:34:2:34:2 | [post] o [data, Collection element] | -| testRealm.swift:41:11:41:11 | myPassword | testRealm.swift:27:6:27:6 | value | testRealm.swift:27:6:27:6 | self [Return] [data] | testRealm.swift:41:2:41:2 | [post] a [data] | -| testRealm.swift:49:11:49:11 | myPassword | testRealm.swift:27:6:27:6 | value | testRealm.swift:27:6:27:6 | self [Return] [data] | testRealm.swift:49:2:49:2 | [post] c [data] | -| testRealm.swift:59:12:59:12 | myPassword | testRealm.swift:27:6:27:6 | value | testRealm.swift:27:6:27:6 | self [Return] [data] | testRealm.swift:59:2:59:3 | [post] ...! [data] | -| testRealm.swift:66:11:66:11 | myPassword | testRealm.swift:27:6:27:6 | value | testRealm.swift:27:6:27:6 | self [Return] [data] | testRealm.swift:66:2:66:2 | [post] g [data] | -| testRealm.swift:73:15:73:15 | myPassword | testRealm.swift:34:6:34:6 | value | testRealm.swift:34:6:34:6 | self [Return] [password] | testRealm.swift:73:2:73:2 | [post] h [password] | +| testRealm2.swift:18:11:18:11 | myPassword | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:18:2:18:2 | [post] o | +| testRealm2.swift:24:11:24:11 | socialSecurityNumber | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:24:2:24:2 | [post] o | +| testRealm2.swift:25:11:25:11 | ssn | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:25:2:25:2 | [post] o | +| testRealm2.swift:26:11:26:25 | call to String.init(_:) | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:26:2:26:2 | [post] o | +| testRealm2.swift:26:11:26:25 | call to String.init(_:) [Collection element] | testRealm2.swift:13:6:13:6 | value [Collection element] | testRealm2.swift:13:6:13:6 | self [Return] [data, Collection element] | testRealm2.swift:26:2:26:2 | [post] o | +| testRealm2.swift:32:11:32:11 | creditCardNumber | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:32:2:32:2 | [post] o | +| testRealm2.swift:33:11:33:11 | CCN | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:33:2:33:2 | [post] o | +| testRealm2.swift:34:11:34:25 | call to String.init(_:) | testRealm2.swift:13:6:13:6 | value | testRealm2.swift:13:6:13:6 | self [Return] [data] | testRealm2.swift:34:2:34:2 | [post] o | +| testRealm2.swift:34:11:34:25 | call to String.init(_:) [Collection element] | testRealm2.swift:13:6:13:6 | value [Collection element] | testRealm2.swift:13:6:13:6 | self [Return] [data, Collection element] | testRealm2.swift:34:2:34:2 | [post] o | +| testRealm.swift:41:11:41:11 | myPassword | testRealm.swift:27:6:27:6 | value | testRealm.swift:27:6:27:6 | self [Return] [data] | testRealm.swift:41:2:41:2 | [post] a | +| testRealm.swift:49:11:49:11 | myPassword | testRealm.swift:27:6:27:6 | value | testRealm.swift:27:6:27:6 | self [Return] [data] | testRealm.swift:49:2:49:2 | [post] c | +| testRealm.swift:59:12:59:12 | myPassword | testRealm.swift:27:6:27:6 | value | testRealm.swift:27:6:27:6 | self [Return] [data] | testRealm.swift:59:2:59:3 | [post] ...! | +| testRealm.swift:66:11:66:11 | myPassword | testRealm.swift:27:6:27:6 | value | testRealm.swift:27:6:27:6 | self [Return] [data] | testRealm.swift:66:2:66:2 | [post] g | +| testRealm.swift:73:15:73:15 | myPassword | testRealm.swift:34:6:34:6 | value | testRealm.swift:34:6:34:6 | self [Return] [password] | testRealm.swift:73:2:73:2 | [post] h | #select | SQLite.swift:123:17:123:17 | insertQuery | SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:123:17:123:17 | insertQuery | This operation stores 'insertQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:119:70:119:70 | mobilePhoneNumber | mobilePhoneNumber | | SQLite.swift:124:17:124:17 | updateQuery | SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:124:17:124:17 | updateQuery | This operation stores 'updateQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:120:50:120:50 | mobilePhoneNumber | mobilePhoneNumber | diff --git a/swift/ql/test/query-tests/Security/CWE-321/HardcodedEncryptionKey.expected b/swift/ql/test/query-tests/Security/CWE-321/HardcodedEncryptionKey.expected index 544431cfb4fa..bd2119ac332d 100644 --- a/swift/ql/test/query-tests/Security/CWE-321/HardcodedEncryptionKey.expected +++ b/swift/ql/test/query-tests/Security/CWE-321/HardcodedEncryptionKey.expected @@ -26,8 +26,8 @@ edges | cryptoswift.swift:94:18:94:36 | call to getConstantString() | cryptoswift.swift:155:26:155:26 | keyString | provenance | | | cryptoswift.swift:94:18:94:36 | call to getConstantString() | cryptoswift.swift:164:24:164:24 | keyString | provenance | | | cryptoswift.swift:94:18:94:36 | call to getConstantString() | cryptoswift.swift:166:24:166:24 | keyString | provenance | | -| file://:0:0:0:0 | [post] self [encryptionKey] | file://:0:0:0:0 | [post] self | provenance | | | file://:0:0:0:0 | [post] self [encryptionKey] | misc.swift:30:7:30:7 | self [Return] [encryptionKey] | provenance | | +| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self | provenance | | | file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [encryptionKey] | provenance | | | grdb.swift:21:20:21:20 | abc123 | grdb.swift:27:23:27:23 | constString | provenance | | | grdb.swift:21:20:21:20 | abc123 | grdb.swift:31:26:31:26 | constString | provenance | | @@ -40,18 +40,14 @@ edges | misc.swift:57:19:57:38 | call to Data.init(_:) | misc.swift:66:25:66:25 | myConstKey | provenance | | | misc.swift:57:19:57:38 | call to Data.init(_:) | misc.swift:70:41:70:41 | myConstKey | provenance | | | misc.swift:57:24:57:24 | abcdef123456 | misc.swift:57:19:57:38 | call to Data.init(_:) | provenance | | -| misc.swift:66:2:66:2 | [post] config [encryptionKey] | misc.swift:66:2:66:2 | [post] config | provenance | | | misc.swift:66:25:66:25 | myConstKey | misc.swift:30:7:30:7 | value | provenance | | -| misc.swift:66:25:66:25 | myConstKey | misc.swift:66:2:66:2 | [post] config [encryptionKey] | provenance | | -| misc.swift:70:2:70:18 | [post] getter for .config [encryptionKey] | misc.swift:70:2:70:18 | [post] getter for .config | provenance | | +| misc.swift:66:25:66:25 | myConstKey | misc.swift:66:2:66:2 | [post] config | provenance | | | misc.swift:70:41:70:41 | myConstKey | misc.swift:30:7:30:7 | value | provenance | | -| misc.swift:70:41:70:41 | myConstKey | misc.swift:70:2:70:18 | [post] getter for .config [encryptionKey] | provenance | | +| misc.swift:70:41:70:41 | myConstKey | misc.swift:70:2:70:18 | [post] getter for .config | provenance | | | misc.swift:73:14:73:20 | k1 | misc.swift:76:26:76:29 | .utf8 | provenance | | | misc.swift:73:28:73:34 | k2 | misc.swift:77:26:77:29 | .utf8 | provenance | | -| misc.swift:76:20:76:33 | call to Array.init(_:) [Collection element] | misc.swift:76:20:76:33 | call to Array.init(_:) | provenance | | -| misc.swift:76:26:76:29 | .utf8 | misc.swift:76:20:76:33 | call to Array.init(_:) [Collection element] | provenance | | -| misc.swift:77:20:77:33 | call to Array.init(_:) [Collection element] | misc.swift:77:20:77:33 | call to Array.init(_:) | provenance | | -| misc.swift:77:26:77:29 | .utf8 | misc.swift:77:20:77:33 | call to Array.init(_:) [Collection element] | provenance | | +| misc.swift:76:26:76:29 | .utf8 | misc.swift:76:20:76:33 | call to Array.init(_:) | provenance | | +| misc.swift:77:26:77:29 | .utf8 | misc.swift:77:20:77:33 | call to Array.init(_:) | provenance | | | misc.swift:82:10:82:10 | abc123 | misc.swift:73:14:73:20 | k1 | provenance | | | misc.swift:83:10:83:10 | abc123 | misc.swift:73:14:73:20 | k1 | provenance | | | misc.swift:83:20:83:20 | abc123 | misc.swift:73:28:73:34 | k2 | provenance | | @@ -128,18 +124,14 @@ nodes | misc.swift:57:24:57:24 | abcdef123456 | semmle.label | abcdef123456 | | misc.swift:62:41:62:41 | myConstKey | semmle.label | myConstKey | | misc.swift:66:2:66:2 | [post] config | semmle.label | [post] config | -| misc.swift:66:2:66:2 | [post] config [encryptionKey] | semmle.label | [post] config [encryptionKey] | | misc.swift:66:25:66:25 | myConstKey | semmle.label | myConstKey | | misc.swift:70:2:70:18 | [post] getter for .config | semmle.label | [post] getter for .config | -| misc.swift:70:2:70:18 | [post] getter for .config [encryptionKey] | semmle.label | [post] getter for .config [encryptionKey] | | misc.swift:70:41:70:41 | myConstKey | semmle.label | myConstKey | | misc.swift:73:14:73:20 | k1 | semmle.label | k1 | | misc.swift:73:28:73:34 | k2 | semmle.label | k2 | | misc.swift:76:20:76:33 | call to Array.init(_:) | semmle.label | call to Array.init(_:) | -| misc.swift:76:20:76:33 | call to Array.init(_:) [Collection element] | semmle.label | call to Array.init(_:) [Collection element] | | misc.swift:76:26:76:29 | .utf8 | semmle.label | .utf8 | | misc.swift:77:20:77:33 | call to Array.init(_:) | semmle.label | call to Array.init(_:) | -| misc.swift:77:20:77:33 | call to Array.init(_:) [Collection element] | semmle.label | call to Array.init(_:) [Collection element] | | misc.swift:77:26:77:29 | .utf8 | semmle.label | .utf8 | | misc.swift:82:10:82:10 | abc123 | semmle.label | abc123 | | misc.swift:83:10:83:10 | abc123 | semmle.label | abc123 | @@ -168,8 +160,8 @@ nodes | sqlite3_c_api.swift:49:36:49:36 | buffer | semmle.label | buffer | | sqlite3_c_api.swift:50:38:50:38 | buffer | semmle.label | buffer | subpaths -| misc.swift:66:25:66:25 | myConstKey | misc.swift:30:7:30:7 | value | misc.swift:30:7:30:7 | self [Return] [encryptionKey] | misc.swift:66:2:66:2 | [post] config [encryptionKey] | -| misc.swift:70:41:70:41 | myConstKey | misc.swift:30:7:30:7 | value | misc.swift:30:7:30:7 | self [Return] [encryptionKey] | misc.swift:70:2:70:18 | [post] getter for .config [encryptionKey] | +| misc.swift:66:25:66:25 | myConstKey | misc.swift:30:7:30:7 | value | misc.swift:30:7:30:7 | self [Return] [encryptionKey] | misc.swift:66:2:66:2 | [post] config | +| misc.swift:70:41:70:41 | myConstKey | misc.swift:30:7:30:7 | value | misc.swift:30:7:30:7 | self [Return] [encryptionKey] | misc.swift:70:2:70:18 | [post] getter for .config | #select | SQLite.swift:43:13:43:13 | hardcoded_key | SQLite.swift:43:13:43:13 | hardcoded_key | SQLite.swift:43:13:43:13 | hardcoded_key | The key 'hardcoded_key' has been initialized with hard-coded values from $@. | SQLite.swift:43:13:43:13 | hardcoded_key | hardcoded_key | | SQLite.swift:45:23:45:23 | hardcoded_key | SQLite.swift:45:23:45:23 | hardcoded_key | SQLite.swift:45:23:45:23 | hardcoded_key | The key 'hardcoded_key' has been initialized with hard-coded values from $@. | SQLite.swift:45:23:45:23 | hardcoded_key | hardcoded_key | diff --git a/swift/ql/test/query-tests/Security/CWE-757/InsecureTLS.expected b/swift/ql/test/query-tests/Security/CWE-757/InsecureTLS.expected index f463e8d939b5..e48f6c9a9b6d 100644 --- a/swift/ql/test/query-tests/Security/CWE-757/InsecureTLS.expected +++ b/swift/ql/test/query-tests/Security/CWE-757/InsecureTLS.expected @@ -3,62 +3,51 @@ edges | InsecureTLS.swift:20:7:20:7 | value | file://:0:0:0:0 | value | provenance | | | InsecureTLS.swift:22:7:22:7 | value | file://:0:0:0:0 | value | provenance | | | InsecureTLS.swift:23:7:23:7 | value | file://:0:0:0:0 | value | provenance | | -| InsecureTLS.swift:40:3:40:3 | [post] config [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:40:3:40:3 | [post] config | provenance | | | InsecureTLS.swift:40:47:40:70 | .TLSv10 | InsecureTLS.swift:19:7:19:7 | value | provenance | | -| InsecureTLS.swift:40:47:40:70 | .TLSv10 | InsecureTLS.swift:40:3:40:3 | [post] config [tlsMinimumSupportedProtocolVersion] | provenance | | -| InsecureTLS.swift:45:3:45:3 | [post] config [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:45:3:45:3 | [post] config | provenance | | +| InsecureTLS.swift:40:47:40:70 | .TLSv10 | InsecureTLS.swift:40:3:40:3 | [post] config | provenance | | | InsecureTLS.swift:45:47:45:70 | .TLSv11 | InsecureTLS.swift:19:7:19:7 | value | provenance | | -| InsecureTLS.swift:45:47:45:70 | .TLSv11 | InsecureTLS.swift:45:3:45:3 | [post] config [tlsMinimumSupportedProtocolVersion] | provenance | | -| InsecureTLS.swift:57:3:57:3 | [post] config [tlsMaximumSupportedProtocolVersion] | InsecureTLS.swift:57:3:57:3 | [post] config | provenance | | +| InsecureTLS.swift:45:47:45:70 | .TLSv11 | InsecureTLS.swift:45:3:45:3 | [post] config | provenance | | | InsecureTLS.swift:57:47:57:70 | .TLSv10 | InsecureTLS.swift:20:7:20:7 | value | provenance | | -| InsecureTLS.swift:57:47:57:70 | .TLSv10 | InsecureTLS.swift:57:3:57:3 | [post] config [tlsMaximumSupportedProtocolVersion] | provenance | | -| InsecureTLS.swift:64:3:64:3 | [post] config [tlsMinimumSupportedProtocol] | InsecureTLS.swift:64:3:64:3 | [post] config | provenance | | +| InsecureTLS.swift:57:47:57:70 | .TLSv10 | InsecureTLS.swift:57:3:57:3 | [post] config | provenance | | | InsecureTLS.swift:64:40:64:52 | .tlsProtocol10 | InsecureTLS.swift:22:7:22:7 | value | provenance | | -| InsecureTLS.swift:64:40:64:52 | .tlsProtocol10 | InsecureTLS.swift:64:3:64:3 | [post] config [tlsMinimumSupportedProtocol] | provenance | | -| InsecureTLS.swift:76:3:76:3 | [post] config [tlsMaximumSupportedProtocol] | InsecureTLS.swift:76:3:76:3 | [post] config | provenance | | +| InsecureTLS.swift:64:40:64:52 | .tlsProtocol10 | InsecureTLS.swift:64:3:64:3 | [post] config | provenance | | | InsecureTLS.swift:76:40:76:52 | .tlsProtocol10 | InsecureTLS.swift:23:7:23:7 | value | provenance | | -| InsecureTLS.swift:76:40:76:52 | .tlsProtocol10 | InsecureTLS.swift:76:3:76:3 | [post] config [tlsMaximumSupportedProtocol] | provenance | | +| InsecureTLS.swift:76:40:76:52 | .tlsProtocol10 | InsecureTLS.swift:76:3:76:3 | [post] config | provenance | | | InsecureTLS.swift:102:10:102:33 | .TLSv10 | InsecureTLS.swift:111:47:111:64 | call to getBadTLSVersion() | provenance | | -| InsecureTLS.swift:111:3:111:3 | [post] config [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:111:3:111:3 | [post] config | provenance | | | InsecureTLS.swift:111:47:111:64 | call to getBadTLSVersion() | InsecureTLS.swift:19:7:19:7 | value | provenance | | -| InsecureTLS.swift:111:47:111:64 | call to getBadTLSVersion() | InsecureTLS.swift:111:3:111:3 | [post] config [tlsMinimumSupportedProtocolVersion] | provenance | | +| InsecureTLS.swift:111:47:111:64 | call to getBadTLSVersion() | InsecureTLS.swift:111:3:111:3 | [post] config | provenance | | | InsecureTLS.swift:121:55:121:66 | version | InsecureTLS.swift:122:47:122:47 | version | provenance | | -| InsecureTLS.swift:122:3:122:3 | [post] config [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:122:3:122:3 | [post] config | provenance | | | InsecureTLS.swift:122:47:122:47 | version | InsecureTLS.swift:19:7:19:7 | value | provenance | | -| InsecureTLS.swift:122:47:122:47 | version | InsecureTLS.swift:122:3:122:3 | [post] config [tlsMinimumSupportedProtocolVersion] | provenance | | +| InsecureTLS.swift:122:47:122:47 | version | InsecureTLS.swift:122:3:122:3 | [post] config | provenance | | | InsecureTLS.swift:127:25:127:48 | .TLSv11 | InsecureTLS.swift:121:55:121:66 | version | provenance | | | InsecureTLS.swift:158:7:158:7 | self [TLSVersion] | file://:0:0:0:0 | self [TLSVersion] | provenance | | | InsecureTLS.swift:158:7:158:7 | value | file://:0:0:0:0 | value | provenance | | | InsecureTLS.swift:163:3:163:3 | [post] def [TLSVersion] | InsecureTLS.swift:165:47:165:47 | def [TLSVersion] | provenance | | | InsecureTLS.swift:163:20:163:43 | .TLSv10 | InsecureTLS.swift:158:7:158:7 | value | provenance | | | InsecureTLS.swift:163:20:163:43 | .TLSv10 | InsecureTLS.swift:163:3:163:3 | [post] def [TLSVersion] | provenance | | -| InsecureTLS.swift:165:3:165:3 | [post] config [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:165:3:165:3 | [post] config | provenance | | | InsecureTLS.swift:165:47:165:47 | def [TLSVersion] | InsecureTLS.swift:158:7:158:7 | self [TLSVersion] | provenance | | | InsecureTLS.swift:165:47:165:47 | def [TLSVersion] | InsecureTLS.swift:165:47:165:51 | .TLSVersion | provenance | | | InsecureTLS.swift:165:47:165:51 | .TLSVersion | InsecureTLS.swift:19:7:19:7 | value | provenance | | -| InsecureTLS.swift:165:47:165:51 | .TLSVersion | InsecureTLS.swift:165:3:165:3 | [post] config [tlsMinimumSupportedProtocolVersion] | provenance | | -| InsecureTLS.swift:181:3:181:9 | [post] getter for .config [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:181:3:181:9 | [post] getter for .config | provenance | | +| InsecureTLS.swift:165:47:165:51 | .TLSVersion | InsecureTLS.swift:165:3:165:3 | [post] config | provenance | | | InsecureTLS.swift:181:53:181:76 | .TLSv10 | InsecureTLS.swift:19:7:19:7 | value | provenance | | -| InsecureTLS.swift:181:53:181:76 | .TLSv10 | InsecureTLS.swift:181:3:181:9 | [post] getter for .config [tlsMinimumSupportedProtocolVersion] | provenance | | +| InsecureTLS.swift:181:53:181:76 | .TLSv10 | InsecureTLS.swift:181:3:181:9 | [post] getter for .config | provenance | | | InsecureTLS.swift:185:20:185:36 | withMinVersion | InsecureTLS.swift:187:42:187:42 | withMinVersion | provenance | | -| InsecureTLS.swift:187:5:187:5 | [post] self [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:187:5:187:5 | [post] self | provenance | | -| InsecureTLS.swift:187:42:187:42 | withMinVersion | InsecureTLS.swift:187:5:187:5 | [post] self [tlsMinimumSupportedProtocolVersion] | provenance | | +| InsecureTLS.swift:187:42:187:42 | withMinVersion | InsecureTLS.swift:187:5:187:5 | [post] self | provenance | | | InsecureTLS.swift:193:51:193:74 | .TLSv10 | InsecureTLS.swift:185:20:185:36 | withMinVersion | provenance | | | InsecureTLS.swift:196:56:196:63 | value | InsecureTLS.swift:196:1:198:1 | version[return] | provenance | | -| InsecureTLS.swift:202:24:202:24 | [post] config [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:202:24:202:24 | [post] config | provenance | | -| InsecureTLS.swift:202:24:202:31 | [post] getter for .tlsMinimumSupportedProtocolVersion | InsecureTLS.swift:202:24:202:24 | [post] config [tlsMinimumSupportedProtocolVersion] | provenance | | +| InsecureTLS.swift:202:24:202:31 | [post] getter for .tlsMinimumSupportedProtocolVersion | InsecureTLS.swift:202:24:202:24 | [post] config | provenance | | | InsecureTLS.swift:202:74:202:97 | .TLSv10 | InsecureTLS.swift:196:56:196:63 | value | provenance | | | InsecureTLS.swift:202:74:202:97 | .TLSv10 | InsecureTLS.swift:202:24:202:31 | [post] getter for .tlsMinimumSupportedProtocolVersion | provenance | | | file://:0:0:0:0 | [post] self [TLSVersion] | InsecureTLS.swift:158:7:158:7 | self [Return] [TLSVersion] | provenance | | | file://:0:0:0:0 | [post] self [tlsMaximumSupportedProtocolVersion] | InsecureTLS.swift:20:7:20:7 | self [Return] [tlsMaximumSupportedProtocolVersion] | provenance | | -| file://:0:0:0:0 | [post] self [tlsMaximumSupportedProtocolVersion] | file://:0:0:0:0 | [post] self | provenance | | | file://:0:0:0:0 | [post] self [tlsMaximumSupportedProtocol] | InsecureTLS.swift:23:7:23:7 | self [Return] [tlsMaximumSupportedProtocol] | provenance | | -| file://:0:0:0:0 | [post] self [tlsMaximumSupportedProtocol] | file://:0:0:0:0 | [post] self | provenance | | | file://:0:0:0:0 | [post] self [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:19:7:19:7 | self [Return] [tlsMinimumSupportedProtocolVersion] | provenance | | -| file://:0:0:0:0 | [post] self [tlsMinimumSupportedProtocolVersion] | file://:0:0:0:0 | [post] self | provenance | | | file://:0:0:0:0 | [post] self [tlsMinimumSupportedProtocol] | InsecureTLS.swift:22:7:22:7 | self [Return] [tlsMinimumSupportedProtocol] | provenance | | -| file://:0:0:0:0 | [post] self [tlsMinimumSupportedProtocol] | file://:0:0:0:0 | [post] self | provenance | | | file://:0:0:0:0 | self [TLSVersion] | file://:0:0:0:0 | .TLSVersion | provenance | | +| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self | provenance | | +| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self | provenance | | +| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self | provenance | | +| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self | provenance | | | file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [TLSVersion] | provenance | | | file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [tlsMaximumSupportedProtocolVersion] | provenance | | | file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [tlsMaximumSupportedProtocol] | provenance | | @@ -74,27 +63,20 @@ nodes | InsecureTLS.swift:23:7:23:7 | self [Return] [tlsMaximumSupportedProtocol] | semmle.label | self [Return] [tlsMaximumSupportedProtocol] | | InsecureTLS.swift:23:7:23:7 | value | semmle.label | value | | InsecureTLS.swift:40:3:40:3 | [post] config | semmle.label | [post] config | -| InsecureTLS.swift:40:3:40:3 | [post] config [tlsMinimumSupportedProtocolVersion] | semmle.label | [post] config [tlsMinimumSupportedProtocolVersion] | | InsecureTLS.swift:40:47:40:70 | .TLSv10 | semmle.label | .TLSv10 | | InsecureTLS.swift:45:3:45:3 | [post] config | semmle.label | [post] config | -| InsecureTLS.swift:45:3:45:3 | [post] config [tlsMinimumSupportedProtocolVersion] | semmle.label | [post] config [tlsMinimumSupportedProtocolVersion] | | InsecureTLS.swift:45:47:45:70 | .TLSv11 | semmle.label | .TLSv11 | | InsecureTLS.swift:57:3:57:3 | [post] config | semmle.label | [post] config | -| InsecureTLS.swift:57:3:57:3 | [post] config [tlsMaximumSupportedProtocolVersion] | semmle.label | [post] config [tlsMaximumSupportedProtocolVersion] | | InsecureTLS.swift:57:47:57:70 | .TLSv10 | semmle.label | .TLSv10 | | InsecureTLS.swift:64:3:64:3 | [post] config | semmle.label | [post] config | -| InsecureTLS.swift:64:3:64:3 | [post] config [tlsMinimumSupportedProtocol] | semmle.label | [post] config [tlsMinimumSupportedProtocol] | | InsecureTLS.swift:64:40:64:52 | .tlsProtocol10 | semmle.label | .tlsProtocol10 | | InsecureTLS.swift:76:3:76:3 | [post] config | semmle.label | [post] config | -| InsecureTLS.swift:76:3:76:3 | [post] config [tlsMaximumSupportedProtocol] | semmle.label | [post] config [tlsMaximumSupportedProtocol] | | InsecureTLS.swift:76:40:76:52 | .tlsProtocol10 | semmle.label | .tlsProtocol10 | | InsecureTLS.swift:102:10:102:33 | .TLSv10 | semmle.label | .TLSv10 | | InsecureTLS.swift:111:3:111:3 | [post] config | semmle.label | [post] config | -| InsecureTLS.swift:111:3:111:3 | [post] config [tlsMinimumSupportedProtocolVersion] | semmle.label | [post] config [tlsMinimumSupportedProtocolVersion] | | InsecureTLS.swift:111:47:111:64 | call to getBadTLSVersion() | semmle.label | call to getBadTLSVersion() | | InsecureTLS.swift:121:55:121:66 | version | semmle.label | version | | InsecureTLS.swift:122:3:122:3 | [post] config | semmle.label | [post] config | -| InsecureTLS.swift:122:3:122:3 | [post] config [tlsMinimumSupportedProtocolVersion] | semmle.label | [post] config [tlsMinimumSupportedProtocolVersion] | | InsecureTLS.swift:122:47:122:47 | version | semmle.label | version | | InsecureTLS.swift:127:25:127:48 | .TLSv11 | semmle.label | .TLSv11 | | InsecureTLS.swift:158:7:158:7 | self [Return] [TLSVersion] | semmle.label | self [Return] [TLSVersion] | @@ -103,21 +85,17 @@ nodes | InsecureTLS.swift:163:3:163:3 | [post] def [TLSVersion] | semmle.label | [post] def [TLSVersion] | | InsecureTLS.swift:163:20:163:43 | .TLSv10 | semmle.label | .TLSv10 | | InsecureTLS.swift:165:3:165:3 | [post] config | semmle.label | [post] config | -| InsecureTLS.swift:165:3:165:3 | [post] config [tlsMinimumSupportedProtocolVersion] | semmle.label | [post] config [tlsMinimumSupportedProtocolVersion] | | InsecureTLS.swift:165:47:165:47 | def [TLSVersion] | semmle.label | def [TLSVersion] | | InsecureTLS.swift:165:47:165:51 | .TLSVersion | semmle.label | .TLSVersion | | InsecureTLS.swift:181:3:181:9 | [post] getter for .config | semmle.label | [post] getter for .config | -| InsecureTLS.swift:181:3:181:9 | [post] getter for .config [tlsMinimumSupportedProtocolVersion] | semmle.label | [post] getter for .config [tlsMinimumSupportedProtocolVersion] | | InsecureTLS.swift:181:53:181:76 | .TLSv10 | semmle.label | .TLSv10 | | InsecureTLS.swift:185:20:185:36 | withMinVersion | semmle.label | withMinVersion | | InsecureTLS.swift:187:5:187:5 | [post] self | semmle.label | [post] self | -| InsecureTLS.swift:187:5:187:5 | [post] self [tlsMinimumSupportedProtocolVersion] | semmle.label | [post] self [tlsMinimumSupportedProtocolVersion] | | InsecureTLS.swift:187:42:187:42 | withMinVersion | semmle.label | withMinVersion | | InsecureTLS.swift:193:51:193:74 | .TLSv10 | semmle.label | .TLSv10 | | InsecureTLS.swift:196:1:198:1 | version[return] | semmle.label | version[return] | | InsecureTLS.swift:196:56:196:63 | value | semmle.label | value | | InsecureTLS.swift:202:24:202:24 | [post] config | semmle.label | [post] config | -| InsecureTLS.swift:202:24:202:24 | [post] config [tlsMinimumSupportedProtocolVersion] | semmle.label | [post] config [tlsMinimumSupportedProtocolVersion] | | InsecureTLS.swift:202:24:202:31 | [post] getter for .tlsMinimumSupportedProtocolVersion | semmle.label | [post] getter for .tlsMinimumSupportedProtocolVersion | | InsecureTLS.swift:202:74:202:97 | .TLSv10 | semmle.label | .TLSv10 | | file://:0:0:0:0 | .TLSVersion | semmle.label | .TLSVersion | @@ -137,17 +115,17 @@ nodes | file://:0:0:0:0 | value | semmle.label | value | | file://:0:0:0:0 | value | semmle.label | value | subpaths -| InsecureTLS.swift:40:47:40:70 | .TLSv10 | InsecureTLS.swift:19:7:19:7 | value | InsecureTLS.swift:19:7:19:7 | self [Return] [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:40:3:40:3 | [post] config [tlsMinimumSupportedProtocolVersion] | -| InsecureTLS.swift:45:47:45:70 | .TLSv11 | InsecureTLS.swift:19:7:19:7 | value | InsecureTLS.swift:19:7:19:7 | self [Return] [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:45:3:45:3 | [post] config [tlsMinimumSupportedProtocolVersion] | -| InsecureTLS.swift:57:47:57:70 | .TLSv10 | InsecureTLS.swift:20:7:20:7 | value | InsecureTLS.swift:20:7:20:7 | self [Return] [tlsMaximumSupportedProtocolVersion] | InsecureTLS.swift:57:3:57:3 | [post] config [tlsMaximumSupportedProtocolVersion] | -| InsecureTLS.swift:64:40:64:52 | .tlsProtocol10 | InsecureTLS.swift:22:7:22:7 | value | InsecureTLS.swift:22:7:22:7 | self [Return] [tlsMinimumSupportedProtocol] | InsecureTLS.swift:64:3:64:3 | [post] config [tlsMinimumSupportedProtocol] | -| InsecureTLS.swift:76:40:76:52 | .tlsProtocol10 | InsecureTLS.swift:23:7:23:7 | value | InsecureTLS.swift:23:7:23:7 | self [Return] [tlsMaximumSupportedProtocol] | InsecureTLS.swift:76:3:76:3 | [post] config [tlsMaximumSupportedProtocol] | -| InsecureTLS.swift:111:47:111:64 | call to getBadTLSVersion() | InsecureTLS.swift:19:7:19:7 | value | InsecureTLS.swift:19:7:19:7 | self [Return] [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:111:3:111:3 | [post] config [tlsMinimumSupportedProtocolVersion] | -| InsecureTLS.swift:122:47:122:47 | version | InsecureTLS.swift:19:7:19:7 | value | InsecureTLS.swift:19:7:19:7 | self [Return] [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:122:3:122:3 | [post] config [tlsMinimumSupportedProtocolVersion] | +| InsecureTLS.swift:40:47:40:70 | .TLSv10 | InsecureTLS.swift:19:7:19:7 | value | InsecureTLS.swift:19:7:19:7 | self [Return] [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:40:3:40:3 | [post] config | +| InsecureTLS.swift:45:47:45:70 | .TLSv11 | InsecureTLS.swift:19:7:19:7 | value | InsecureTLS.swift:19:7:19:7 | self [Return] [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:45:3:45:3 | [post] config | +| InsecureTLS.swift:57:47:57:70 | .TLSv10 | InsecureTLS.swift:20:7:20:7 | value | InsecureTLS.swift:20:7:20:7 | self [Return] [tlsMaximumSupportedProtocolVersion] | InsecureTLS.swift:57:3:57:3 | [post] config | +| InsecureTLS.swift:64:40:64:52 | .tlsProtocol10 | InsecureTLS.swift:22:7:22:7 | value | InsecureTLS.swift:22:7:22:7 | self [Return] [tlsMinimumSupportedProtocol] | InsecureTLS.swift:64:3:64:3 | [post] config | +| InsecureTLS.swift:76:40:76:52 | .tlsProtocol10 | InsecureTLS.swift:23:7:23:7 | value | InsecureTLS.swift:23:7:23:7 | self [Return] [tlsMaximumSupportedProtocol] | InsecureTLS.swift:76:3:76:3 | [post] config | +| InsecureTLS.swift:111:47:111:64 | call to getBadTLSVersion() | InsecureTLS.swift:19:7:19:7 | value | InsecureTLS.swift:19:7:19:7 | self [Return] [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:111:3:111:3 | [post] config | +| InsecureTLS.swift:122:47:122:47 | version | InsecureTLS.swift:19:7:19:7 | value | InsecureTLS.swift:19:7:19:7 | self [Return] [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:122:3:122:3 | [post] config | | InsecureTLS.swift:163:20:163:43 | .TLSv10 | InsecureTLS.swift:158:7:158:7 | value | InsecureTLS.swift:158:7:158:7 | self [Return] [TLSVersion] | InsecureTLS.swift:163:3:163:3 | [post] def [TLSVersion] | | InsecureTLS.swift:165:47:165:47 | def [TLSVersion] | InsecureTLS.swift:158:7:158:7 | self [TLSVersion] | file://:0:0:0:0 | .TLSVersion | InsecureTLS.swift:165:47:165:51 | .TLSVersion | -| InsecureTLS.swift:165:47:165:51 | .TLSVersion | InsecureTLS.swift:19:7:19:7 | value | InsecureTLS.swift:19:7:19:7 | self [Return] [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:165:3:165:3 | [post] config [tlsMinimumSupportedProtocolVersion] | -| InsecureTLS.swift:181:53:181:76 | .TLSv10 | InsecureTLS.swift:19:7:19:7 | value | InsecureTLS.swift:19:7:19:7 | self [Return] [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:181:3:181:9 | [post] getter for .config [tlsMinimumSupportedProtocolVersion] | +| InsecureTLS.swift:165:47:165:51 | .TLSVersion | InsecureTLS.swift:19:7:19:7 | value | InsecureTLS.swift:19:7:19:7 | self [Return] [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:165:3:165:3 | [post] config | +| InsecureTLS.swift:181:53:181:76 | .TLSv10 | InsecureTLS.swift:19:7:19:7 | value | InsecureTLS.swift:19:7:19:7 | self [Return] [tlsMinimumSupportedProtocolVersion] | InsecureTLS.swift:181:3:181:9 | [post] getter for .config | | InsecureTLS.swift:202:74:202:97 | .TLSv10 | InsecureTLS.swift:196:56:196:63 | value | InsecureTLS.swift:196:1:198:1 | version[return] | InsecureTLS.swift:202:24:202:31 | [post] getter for .tlsMinimumSupportedProtocolVersion | #select | InsecureTLS.swift:40:3:40:3 | [post] config | InsecureTLS.swift:40:47:40:70 | .TLSv10 | InsecureTLS.swift:40:3:40:3 | [post] config | This TLS configuration is insecure. |