Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added support for data flow through property patterns in `is` expressions and `switch` cases.
Original file line number Diff line number Diff line change
Expand Up @@ -1990,16 +1990,22 @@ class FieldOrProperty extends Assignable, Modifiable {
}
}

/** A string that is a reference to a late-bound target of a dynamic member access. */
/** A member name used by a dynamic access or a property pattern without type information. */
class DynamicProperty extends string {
private DynamicMemberAccess dma;

DynamicProperty() { this = dma.getLateBoundTargetName() }
DynamicProperty() {
this = any(DynamicMemberAccess dma).getLateBoundTargetName()
or
exists(PatternExpr qualifier, LabeledPatternExpr label |
propertyPatternQualifier(qualifier, label) and
qualifier.getType() instanceof NullType and
this = label.getLabel()
)
}

ContentSet getContentSet() { result.isDynamicProperty(this) }

/** Gets an access of this dynamic property. */
DynamicMemberAccess getAnAccess() { result = dma }
DynamicMemberAccess getAnAccess() { result.getLateBoundTargetName() = this }
}

private class InstanceFieldOrProperty extends FieldOrProperty {
Expand Down Expand Up @@ -2308,6 +2314,40 @@ private predicate readStepDelegateCall(Node node1, ContentSet c, OutNode node2)
)
}

private predicate propertyPatternQualifier(PatternExpr qualifier, LabeledPatternExpr label) {
qualifier.(RecursivePatternExpr).getPropertyPatterns().getPattern(_) = label
or
qualifier instanceof LabeledPatternExpr and
qualifier.(PropertyPatternExpr).getPattern(_) = label
}

/**
* Holds if data can flow from `node1` to `node2` via a property pattern.
*/
private predicate fieldOrPropertyPatternRead(Node node1, ContentSet c, Node node2) {
exists(PatternExpr pattern, LabeledPatternExpr label |
node1.asExpr() = pattern and
propertyPatternQualifier(pattern, label) and
if pattern.getType() instanceof NullType
then c.isDynamicProperty(label.getLabel())
else
exists(FieldOrProperty f |
c = f.getContentSet() and
f.getName() = label.getLabel() and
pattern.getType().(ValueOrRefType).hasMember(f)
)
|
node2.asExpr() = label.(RecursivePatternExpr)
or
node2.asExpr() = label.(PropertyPatternExpr)
or
exists(AssignableDefinitions::PatternDefinition lvd |
node2.(AssignableDefinitionNode).getDefinition() = lvd and
label.(BindingPatternExpr).getVariableDeclExpr() = lvd.getDeclaration()
)
)
}

/**
* Holds if data can flow from `node1` to `node2` via a read of content `c`.
*/
Expand All @@ -2319,6 +2359,8 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
or
fieldOrPropertyRead(node1.asExpr(), c, node2.asExpr())
or
fieldOrPropertyPatternRead(node1, c, node2)
or
dynamicPropertyRead(node1.asExpr(), c, node2.asExpr())
or
node2.asExpr().(AwaitExpr).getExpr() = node1.asExpr() and
Expand Down
Loading
Loading