mirror of
https://github.com/github/codeql.git
synced 2026-04-27 09:45:15 +02:00
Migrate to shared FlowSummary library
This commit is contained in:
@@ -2,81 +2,25 @@
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.internal.sharedlib.FlowSummaryImpl as Impl
|
||||
private import semmle.javascript.dataflow.internal.sharedlib.FlowSummaryImplSpecific
|
||||
private import semmle.javascript.dataflow.internal.FlowSummaryPrivate
|
||||
private import semmle.javascript.dataflow.internal.sharedlib.DataFlowImplCommon as DataFlowImplCommon
|
||||
private import semmle.javascript.dataflow.internal.DataFlowPrivate
|
||||
|
||||
class SummaryComponent = Impl::Public::SummaryComponent;
|
||||
|
||||
/** Provides predicates for constructing summary components. */
|
||||
module SummaryComponent {
|
||||
private import Impl::Public::SummaryComponent as SC
|
||||
|
||||
predicate parameter = SC::parameter/1;
|
||||
|
||||
predicate argument = SC::argument/1;
|
||||
|
||||
predicate content = SC::content/1;
|
||||
|
||||
predicate withoutContent = SC::withoutContent/1;
|
||||
|
||||
predicate withContent = SC::withContent/1;
|
||||
|
||||
class SyntheticGlobal = SC::SyntheticGlobal;
|
||||
|
||||
/** Gets a summary component that represents a receiver. */
|
||||
SummaryComponent receiver() { result = argument(MkThisParameter()) }
|
||||
|
||||
/** Gets a summary component that represents the return value of a call. */
|
||||
SummaryComponent return() { result = SC::return(MkNormalReturnKind()) }
|
||||
|
||||
/** Gets a summary component that represents the exception thrown from a call. */
|
||||
SummaryComponent exceptionalReturn() { result = SC::return(MkExceptionalReturnKind()) }
|
||||
}
|
||||
|
||||
class SummaryComponentStack = Impl::Public::SummaryComponentStack;
|
||||
|
||||
/** Provides predicates for constructing stacks of summary components. */
|
||||
module SummaryComponentStack {
|
||||
private import Impl::Public::SummaryComponentStack as SCS
|
||||
|
||||
predicate singleton = SCS::singleton/1;
|
||||
|
||||
predicate push = SCS::push/2;
|
||||
|
||||
predicate argument = SCS::argument/1;
|
||||
|
||||
/** Gets a singleton stack representing a receiver. */
|
||||
SummaryComponentStack receiver() { result = singleton(SummaryComponent::receiver()) }
|
||||
|
||||
/** Gets a singleton stack representing the return value of a call. */
|
||||
SummaryComponentStack return() { result = singleton(SummaryComponent::return()) }
|
||||
|
||||
/** Gets a singleton stack representing the exception thrown from a call. */
|
||||
SummaryComponentStack exceptionalReturn() {
|
||||
result = singleton(SummaryComponent::exceptionalReturn())
|
||||
}
|
||||
}
|
||||
|
||||
/** A callable with a flow summary, identified by a unique string. */
|
||||
abstract class SummarizedCallable extends LibraryCallable, Impl::Public::SummarizedCallable {
|
||||
bindingset[this]
|
||||
SummarizedCallable() { any() }
|
||||
|
||||
/**
|
||||
* Same as
|
||||
*
|
||||
* ```ql
|
||||
* propagatesFlow(
|
||||
* SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
* )
|
||||
* ```
|
||||
*
|
||||
* but uses an external (string) representation of the input and output stacks.
|
||||
*/
|
||||
// TODO: rename 'propagatesFlowExt' and/or override 'propagatesFlow' directly
|
||||
pragma[nomagic]
|
||||
predicate propagatesFlowExt(string input, string output, boolean preservesValue) { none() }
|
||||
|
||||
override predicate propagatesFlow(
|
||||
string input, string output, boolean preservesValue, string model
|
||||
) {
|
||||
this.propagatesFlowExt(input, output, preservesValue) and model = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the synthesized parameter that results from an input specification
|
||||
* that starts with `Argument[s]` for this library callable.
|
||||
@@ -88,5 +32,3 @@ abstract class SummarizedCallable extends LibraryCallable, Impl::Public::Summari
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class RequiredSummaryComponentStack = Impl::Public::RequiredSummaryComponentStack;
|
||||
|
||||
@@ -10,6 +10,7 @@ private import semmle.javascript.dataflow.internal.Contents::Private
|
||||
private import semmle.javascript.dataflow.internal.sharedlib.DataFlowImplCommon as DataFlowImplCommon
|
||||
private import semmle.javascript.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
||||
private import semmle.javascript.dataflow.internal.sharedlib.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate
|
||||
private import semmle.javascript.dataflow.internal.VariableCapture as VariableCapture
|
||||
|
||||
cached
|
||||
@@ -58,7 +59,10 @@ private module Cached {
|
||||
TConstructorThisPostUpdate(Constructor ctor) or
|
||||
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or
|
||||
TFlowSummaryIntermediateAwaitStoreNode(FlowSummaryImpl::Private::SummaryNode sn) {
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(sn, MkAwaited(), _)
|
||||
// NOTE: This dependency goes through the 'Steps' module whose instantiation depends on the call graph,
|
||||
// but the specific predicate we're referering to does not use that information.
|
||||
// So it doesn't cause negative recursion but it might look a bit surprising.
|
||||
FlowSummaryPrivate::Steps::summaryStoreStep(sn, MkAwaited(), _)
|
||||
} or
|
||||
TSynthCaptureNode(VariableCapture::VariableCaptureOutput::SynthesizedCaptureNode node) or
|
||||
TGenericSynthesizedNode(AstNode node, string tag, DataFlowPrivate::DataFlowCallable container) {
|
||||
|
||||
@@ -8,6 +8,8 @@ private import semmle.javascript.dataflow.internal.VariableCapture
|
||||
private import semmle.javascript.dataflow.internal.sharedlib.DataFlowImplCommon as DataFlowImplCommon
|
||||
private import semmle.javascript.internal.flow_summaries.AllFlowSummaries
|
||||
private import sharedlib.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate
|
||||
private import semmle.javascript.dataflow.FlowSummary as FlowSummary
|
||||
private import semmle.javascript.dataflow.internal.BarrierGuards
|
||||
|
||||
class DataFlowSecondLevelScope = Unit;
|
||||
@@ -117,7 +119,8 @@ private DataFlow::Node getAnOutNodeImpl(DataFlowCall call, ReturnKind kind) {
|
||||
or
|
||||
kind = MkNormalReturnKind() and result = call.asAccessorCall().(DataFlow::PropRead)
|
||||
or
|
||||
FlowSummaryImpl::Private::summaryOutNode(call, result.(FlowSummaryNode).getSummaryNode(), kind)
|
||||
FlowSummaryImpl::Private::summaryOutNode(call.(SummaryCall).getReceiver(),
|
||||
result.(FlowSummaryNode).getSummaryNode(), kind)
|
||||
}
|
||||
|
||||
class ReturnNode extends DataFlow::Node {
|
||||
@@ -275,7 +278,8 @@ private predicate isArgumentNodeImpl(Node n, DataFlowCall call, ArgumentPosition
|
||||
// argument to setter (TODO: this has no post-update node)
|
||||
pos.asPositional() = 0 and n = call.asAccessorCall().(DataFlow::PropWrite).getRhs()
|
||||
or
|
||||
FlowSummaryImpl::Private::summaryArgumentNode(call, n.(FlowSummaryNode).getSummaryNode(), pos)
|
||||
FlowSummaryImpl::Private::summaryArgumentNode(call.(SummaryCall).getReceiver(),
|
||||
n.(FlowSummaryNode).getSummaryNode(), pos)
|
||||
}
|
||||
|
||||
predicate isArgumentNode(ArgumentNode n, DataFlowCall call, ArgumentPosition pos) {
|
||||
@@ -802,8 +806,8 @@ private predicate valuePreservingStep(Node node1, Node node2) {
|
||||
or
|
||||
node2 = FlowSteps::getThrowTarget(node1)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(node1.(FlowSummaryNode).getSummaryNode(),
|
||||
node2.(FlowSummaryNode).getSummaryNode(), true)
|
||||
FlowSummaryPrivate::Steps::summaryLocalStep(node1.(FlowSummaryNode).getSummaryNode(),
|
||||
node2.(FlowSummaryNode).getSummaryNode(), true, _) // TODO: preserve 'model'
|
||||
or
|
||||
// Step from post-update nodes to local sources of the pre-update node. This emulates how JS usually tracks side effects.
|
||||
exists(PostUpdateNode postUpdate |
|
||||
@@ -828,7 +832,7 @@ predicate simpleLocalFlowStep(Node node1, Node node2) {
|
||||
nodeGetEnclosingCallable(pragma[only_bind_out](node2))
|
||||
or
|
||||
exists(FlowSummaryImpl::Private::SummaryNode input, FlowSummaryImpl::Private::SummaryNode output |
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(input, MkAwaited(), output) and
|
||||
FlowSummaryPrivate::Steps::summaryStoreStep(input, MkAwaited(), output) and
|
||||
node1 = TFlowSummaryNode(input) and
|
||||
(
|
||||
node2 = TFlowSummaryNode(output) and
|
||||
@@ -837,7 +841,7 @@ predicate simpleLocalFlowStep(Node node1, Node node2) {
|
||||
node2 = TFlowSummaryIntermediateAwaitStoreNode(input)
|
||||
)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryReadStep(input, MkAwaited(), output) and
|
||||
FlowSummaryPrivate::Steps::summaryReadStep(input, MkAwaited(), output) and
|
||||
node1 = TFlowSummaryNode(input) and
|
||||
node2 = TFlowSummaryNode(output)
|
||||
)
|
||||
@@ -859,7 +863,7 @@ predicate jumpStep(Node node1, Node node2) {
|
||||
valuePreservingStep(node1, node2) and
|
||||
node1.getContainer() != node2.getContainer()
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryJumpStep(node1.(FlowSummaryNode).getSummaryNode(),
|
||||
FlowSummaryPrivate::Steps::summaryJumpStep(node1.(FlowSummaryNode).getSummaryNode(),
|
||||
node2.(FlowSummaryNode).getSummaryNode())
|
||||
or
|
||||
DataFlow::AdditionalFlowStep::jumpStep(node1, node2)
|
||||
@@ -882,8 +886,8 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
|
||||
)
|
||||
or
|
||||
exists(ContentSet contentSet |
|
||||
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(),
|
||||
contentSet, node2.(FlowSummaryNode).getSummaryNode())
|
||||
FlowSummaryPrivate::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), contentSet,
|
||||
node2.(FlowSummaryNode).getSummaryNode())
|
||||
|
|
||||
not isSpecialContentSet(contentSet) and
|
||||
c = contentSet
|
||||
@@ -894,7 +898,7 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
|
||||
or
|
||||
// For deep reads, generate read edges with a self-loop
|
||||
exists(Node origin, ContentSet contentSet |
|
||||
FlowSummaryImpl::Private::Steps::summaryReadStep(origin.(FlowSummaryNode).getSummaryNode(),
|
||||
FlowSummaryPrivate::Steps::summaryReadStep(origin.(FlowSummaryNode).getSummaryNode(),
|
||||
contentSet, node2.(FlowSummaryNode).getSummaryNode()) and
|
||||
node1 = [origin, node2]
|
||||
|
|
||||
@@ -938,13 +942,13 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
|
||||
node2 = tryGetPostUpdate(write.getBase())
|
||||
)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
FlowSummaryPrivate::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
node2.(FlowSummaryNode).getSummaryNode()) and
|
||||
not isSpecialContentSet(c)
|
||||
or
|
||||
// Store into Awaited
|
||||
exists(FlowSummaryImpl::Private::SummaryNode input, FlowSummaryImpl::Private::SummaryNode output |
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(input, MkAwaited(), output) and
|
||||
FlowSummaryPrivate::Steps::summaryStoreStep(input, MkAwaited(), output) and
|
||||
node1 = TFlowSummaryIntermediateAwaitStoreNode(input) and
|
||||
node2 = TFlowSummaryNode(output) and
|
||||
c = ContentSet::promiseValue()
|
||||
@@ -964,15 +968,14 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
|
||||
* in `x.f = newValue`.
|
||||
*/
|
||||
predicate clearsContent(Node n, ContentSet c) {
|
||||
FlowSummaryImpl::Private::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), c)
|
||||
FlowSummaryPrivate::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), c)
|
||||
or
|
||||
// Clear promise content before storing into promise value, to avoid creating nested promises
|
||||
n = TFlowSummaryIntermediateAwaitStoreNode(_) and
|
||||
c = MkPromiseFilter()
|
||||
or
|
||||
// After reading from Awaited, the output must not be stored in a promise content
|
||||
FlowSummaryImpl::Private::Steps::summaryReadStep(_, MkAwaited(),
|
||||
n.(FlowSummaryNode).getSummaryNode()) and
|
||||
FlowSummaryPrivate::Steps::summaryReadStep(_, MkAwaited(), n.(FlowSummaryNode).getSummaryNode()) and
|
||||
c = MkPromiseFilter()
|
||||
or
|
||||
any(AdditionalFlowInternal flow).clearsContent(n, c)
|
||||
@@ -998,12 +1001,11 @@ predicate clearsContent(Node n, ContentSet c) {
|
||||
* at node `n`.
|
||||
*/
|
||||
predicate expectsContent(Node n, ContentSet c) {
|
||||
FlowSummaryImpl::Private::Steps::summaryExpectsContent(n.(FlowSummaryNode).getSummaryNode(), c)
|
||||
FlowSummaryPrivate::Steps::summaryExpectsContent(n.(FlowSummaryNode).getSummaryNode(), c)
|
||||
or
|
||||
// After storing into Awaited, the result must be stored in a promise-content.
|
||||
// There is a value step from the input directly to this node, hence the need for expectsContent.
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(_, MkAwaited(),
|
||||
n.(FlowSummaryNode).getSummaryNode()) and
|
||||
FlowSummaryPrivate::Steps::summaryStoreStep(_, MkAwaited(), n.(FlowSummaryNode).getSummaryNode()) and
|
||||
c = MkPromiseFilter()
|
||||
or
|
||||
any(AdditionalFlowInternal flow).expectsContent(n, c)
|
||||
@@ -1035,7 +1037,10 @@ int accessPathLimit() { result = 2 }
|
||||
* by default as a heuristic.
|
||||
*/
|
||||
predicate allowParameterReturnInSelf(ParameterNode p) {
|
||||
FlowSummaryImpl::Private::summaryAllowParameterReturnInSelf(p)
|
||||
exists(DataFlowCallable callable, ParameterPosition pos |
|
||||
isParameterNodeImpl(p, callable, pos) and
|
||||
FlowSummaryImpl::Private::summaryAllowParameterReturnInSelf(callable.asLibraryCallable(), pos)
|
||||
)
|
||||
or
|
||||
exists(Function f |
|
||||
VariableCaptureOutput::heuristicAllowInstanceParameterReturnInSelf(f) and
|
||||
|
||||
@@ -70,11 +70,6 @@ DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) {
|
||||
result = TAnyType() and exists(t) and exists(rk)
|
||||
}
|
||||
|
||||
/** Gets the type of synthetic global `sg`. */
|
||||
DataFlowType getSyntheticGlobalType(SummaryComponent::SyntheticGlobal sg) {
|
||||
result = TAnyType() and exists(sg)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an external flow summary exists for `c` with input specification
|
||||
* `input`, output specification `output`, kind `kind`, and provenance `provenance`.
|
||||
@@ -97,21 +92,21 @@ predicate summaryElement(
|
||||
predicate neutralSummaryElement(FlowSummary::SummarizedCallable c, string provenance) { none() }
|
||||
|
||||
pragma[inline]
|
||||
private SummaryComponent makeContentComponents(
|
||||
private Private::SummaryComponent makeContentComponents(
|
||||
Private::AccessPathToken token, string name, ContentSet contents
|
||||
) {
|
||||
token.getName() = name and
|
||||
result = FlowSummary::SummaryComponent::content(contents)
|
||||
result = Private::SummaryComponent::content(contents)
|
||||
or
|
||||
token.getName() = "With" + name and
|
||||
result = FlowSummary::SummaryComponent::withContent(contents)
|
||||
result = Private::SummaryComponent::withContent(contents)
|
||||
or
|
||||
token.getName() = "Without" + name and
|
||||
result = FlowSummary::SummaryComponent::withoutContent(contents)
|
||||
result = Private::SummaryComponent::withoutContent(contents)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private SummaryComponent makePropertyContentComponents(
|
||||
private Private::SummaryComponent makePropertyContentComponents(
|
||||
Private::AccessPathToken token, string name, PropertyName content
|
||||
) {
|
||||
result = makeContentComponents(token, name, ContentSet::property(content))
|
||||
@@ -160,12 +155,12 @@ private ParameterPosition parsePosition(string operand) {
|
||||
*
|
||||
* This covers all the JS-specific components of a flow summary.
|
||||
*/
|
||||
SummaryComponent interpretComponentSpecific(Private::AccessPathToken c) {
|
||||
Private::SummaryComponent interpretComponentSpecific(Private::AccessPathToken c) {
|
||||
c.getName() = "Argument" and
|
||||
result = FlowSummary::SummaryComponent::argument(parsePosition(c.getAnArgument()))
|
||||
result = Private::SummaryComponent::argument(parsePosition(c.getAnArgument()))
|
||||
or
|
||||
c.getName() = "Parameter" and
|
||||
result = FlowSummary::SummaryComponent::parameter(parsePosition(c.getAnArgument()))
|
||||
result = Private::SummaryComponent::parameter(parsePosition(c.getAnArgument()))
|
||||
or
|
||||
result = makePropertyContentComponents(c, "Member", c.getAnArgument())
|
||||
or
|
||||
@@ -210,20 +205,20 @@ SummaryComponent interpretComponentSpecific(Private::AccessPathToken c) {
|
||||
or
|
||||
c.getName() = "ReturnValue" and
|
||||
c.getAnArgument() = "exception" and
|
||||
result = SummaryComponent::return(MkExceptionalReturnKind())
|
||||
result = Private::SummaryComponent::return(MkExceptionalReturnKind())
|
||||
or
|
||||
// Awaited is mapped down to a combination steps that handle coercion and promise-flattening.
|
||||
c.getName() = "Awaited" and
|
||||
c.getNumArgument() = 0 and
|
||||
result = SummaryComponent::content(MkAwaited())
|
||||
result = Private::SummaryComponent::content(MkAwaited())
|
||||
or
|
||||
c.getName() = "AnyMemberDeep" and
|
||||
c.getNumArgument() = 0 and
|
||||
result = SummaryComponent::content(MkAnyPropertyDeep())
|
||||
result = Private::SummaryComponent::content(MkAnyPropertyDeep())
|
||||
or
|
||||
c.getName() = "ArrayElementDeep" and
|
||||
c.getNumArgument() = 0 and
|
||||
result = SummaryComponent::content(MkArrayElementDeep())
|
||||
result = Private::SummaryComponent::content(MkArrayElementDeep())
|
||||
}
|
||||
|
||||
private string getMadStringFromContentSetAux(ContentSet cs) {
|
||||
@@ -272,13 +267,14 @@ private string getMadStringFromContentSet(ContentSet cs) {
|
||||
}
|
||||
|
||||
/** Gets the textual representation of a summary component in the format used for MaD models. */
|
||||
string getMadRepresentationSpecific(SummaryComponent sc) {
|
||||
string getMadRepresentationSpecific(Private::SummaryComponent sc) {
|
||||
exists(ContentSet cs |
|
||||
sc = Private::TContentSummaryComponent(cs) and result = getMadStringFromContentSet(cs)
|
||||
sc = Private::SummaryComponent::content(cs) and
|
||||
result = getMadStringFromContentSet(cs)
|
||||
)
|
||||
or
|
||||
exists(ReturnKind rk |
|
||||
sc = Private::TReturnSummaryComponent(rk) and
|
||||
sc = Private::SummaryComponent::return(rk) and
|
||||
not rk = getReturnValueKind() and
|
||||
result = "ReturnValue[" + rk + "]"
|
||||
)
|
||||
@@ -368,3 +364,13 @@ bindingset[s]
|
||||
ParameterPosition parseArgBody(string s) {
|
||||
result = parseParamBody(s) // Currently these are identical
|
||||
}
|
||||
|
||||
private module FlowSummaryStepInput implements Private::StepsInputSig {
|
||||
DataFlowCall getACall(SummarizedCallable sc) {
|
||||
exists(LibraryCallable callable | callable = sc |
|
||||
result.asOrdinaryCall() = [callable.getACall(), callable.getACallSimple()]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module Steps = Private::Steps<FlowSummaryStepInput>;
|
||||
|
||||
@@ -2,20 +2,21 @@ private import javascript
|
||||
private import semmle.javascript.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.javascript.dataflow.internal.Contents::Public
|
||||
private import semmle.javascript.dataflow.internal.sharedlib.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate
|
||||
private import semmle.javascript.dataflow.internal.BarrierGuards
|
||||
|
||||
cached
|
||||
predicate defaultAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
TaintTracking::AdditionalTaintStep::step(node1, node2)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(node1.(FlowSummaryNode).getSummaryNode(),
|
||||
node2.(FlowSummaryNode).getSummaryNode(), false)
|
||||
FlowSummaryPrivate::Steps::summaryLocalStep(node1.(FlowSummaryNode).getSummaryNode(),
|
||||
node2.(FlowSummaryNode).getSummaryNode(), false, _) // TODO: preserve 'model' parameter
|
||||
or
|
||||
// Convert steps into and out of array elements to plain taint steps
|
||||
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(),
|
||||
FlowSummaryPrivate::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(),
|
||||
ContentSet::arrayElement(), node2.(FlowSummaryNode).getSummaryNode())
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(),
|
||||
FlowSummaryPrivate::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(),
|
||||
ContentSet::arrayElement(), node2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
import semmle.javascript.dataflow.internal.FlowSummaryPrivate
|
||||
Reference in New Issue
Block a user