Skip to content

Commit 29222e6

Browse files
committed
Java: Adopt shared SSA data-flow integration (WIP)
1 parent dfda6e8 commit 29222e6

File tree

13 files changed

+191
-49
lines changed

13 files changed

+191
-49
lines changed

java/ql/lib/semmle/code/java/dataflow/internal/DataFlowNodes.qll

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,121 @@ private predicate deadcode(Expr e) {
2121
)
2222
}
2323

24+
module SsaFlow {
25+
import codeql.ssa.Ssa
26+
27+
private module SsaInput implements InputSig<Location> {
28+
private import semmle.code.java.controlflow.BasicBlocks as BB
29+
private import semmle.code.java.controlflow.Dominance as Dom
30+
private import semmle.code.java.ControlFlowGraph as Cfg
31+
32+
class BasicBlock = BB::BasicBlock;
33+
34+
class ControlFlowNode = Cfg::ControlFlowNode;
35+
36+
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { Dom::bbIDominates(result, bb) }
37+
38+
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getABBSuccessor() }
39+
40+
class ExitBasicBlock extends BasicBlock {
41+
ExitBasicBlock() { not exists(this.getABBSuccessor()) }
42+
}
43+
44+
class SourceVariable = LocalScopeVariable;
45+
46+
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
47+
bb.getNode(i) =
48+
any(VariableUpdate upd |
49+
v.getAnAccess() = upd.(Assignment).getDest()
50+
or
51+
v = upd.(LocalVariableDeclExpr).getVariable()
52+
or
53+
v.getAnAccess() = upd.(UnaryAssignExpr).getExpr()
54+
) and
55+
certain = true
56+
or
57+
exists(Callable c |
58+
bb = c.getBody() and
59+
i = -1 and
60+
v = c.getAParameter() and
61+
certain = true
62+
)
63+
}
64+
65+
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
66+
bb.getNode(i).(VarRead).getVariable() = v and certain = true
67+
}
68+
}
69+
70+
module SsaImpl = Make<Location, SsaInput>;
71+
72+
module IntegrationInput implements SsaImpl::DataFlowIntegrationInputSig {
73+
private import java as J
74+
75+
class Expr instanceof J::Expr {
76+
string toString() { result = super.toString() }
77+
78+
Location getLocation() { result = super.getLocation() }
79+
80+
predicate hasCfgNode(BasicBlock bb, int i) { this = bb.(J::BasicBlock).getNode(i) }
81+
}
82+
83+
class Parameter = J::Parameter;
84+
85+
predicate ssaDefAssigns(SsaImpl::WriteDefinition def, Expr value) {
86+
exists(BasicBlock bb, int i, VariableUpdate upd |
87+
def.definesAt(_, bb, i) and
88+
bb.getNode(i) = upd
89+
|
90+
value = upd.(VariableAssign).getSource() or
91+
value = upd.(AssignOp) or
92+
value = upd.(RecordBindingVariableExpr)
93+
)
94+
}
95+
96+
predicate ssaDefInitializesParam(SsaImpl::WriteDefinition def, Parameter p) {
97+
def.definesAt(p, _, -1)
98+
}
99+
100+
private import semmle.code.java.controlflow.Guards as Guards
101+
102+
class Guard extends Guards::Guard {
103+
predicate hasCfgNode(SsaInput::BasicBlock bb, int i) { this = bb.getNode(i) }
104+
}
105+
106+
/** Holds if the guard `guard` controls block `bb` upon evaluating to `branch`. */
107+
predicate guardControlsBlock(Guard guard, SsaInput::BasicBlock bb, boolean branch) {
108+
guard.controls(bb, branch)
109+
}
110+
111+
/** Gets an immediate conditional successor of basic block `bb`, if any. */
112+
SsaInput::BasicBlock getAConditionalBasicBlockSuccessor(SsaInput::BasicBlock bb, boolean branch) {
113+
result = bb.(Guards::ConditionBlock).getTestSuccessor(branch)
114+
}
115+
}
116+
117+
module Integration = SsaImpl::DataFlowIntegration<IntegrationInput>;
118+
119+
Integration::Node asNode(Node n) {
120+
n = TSsaNode(result)
121+
or
122+
result.(Integration::ExprNode).getExpr() = n.asExpr()
123+
or
124+
result.(Integration::ExprPostUpdateNode).getExpr() =
125+
n.(PostUpdateNode).getPreUpdateNode().asExpr()
126+
or
127+
TExplicitParameterNode(result.(Integration::ParameterNode).getParameter()) = n
128+
}
129+
130+
predicate localFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
131+
Integration::localFlowStep(def, asNode(nodeFrom), asNode(nodeTo))
132+
}
133+
134+
predicate localMustFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
135+
Integration::localMustFlowStep(def, asNode(nodeFrom), asNode(nodeTo))
136+
}
137+
}
138+
24139
cached
25140
private module Cached {
26141
cached
@@ -31,6 +146,7 @@ private module Cached {
31146
not e.getType() instanceof VoidType and
32147
not e.getParent*() instanceof Annotation
33148
} or
149+
TSsaNode(SsaFlow::Integration::SsaNode node) or
34150
TExplicitParameterNode(Parameter p) { exists(p.getCallable().getBody()) } or
35151
TImplicitVarargsArray(Call c) {
36152
c.getCallee().isVarargs() and
@@ -137,6 +253,8 @@ module Public {
137253
result = this.(FieldValueNode).getField().getType()
138254
or
139255
result instanceof TypeObject and this instanceof AdditionalNode
256+
or
257+
result = this.(SsaNode).getDefinitionExt().getSourceVariable().getType()
140258
}
141259

142260
/** Gets the callable in which this node occurs. */
@@ -198,6 +316,18 @@ module Public {
198316
abstract predicate isParameterOf(DataFlowCallable c, int pos);
199317
}
200318

319+
class SsaNode extends Node, TSsaNode {
320+
private SsaFlow::Integration::SsaNode node;
321+
322+
SsaNode() { this = TSsaNode(node) }
323+
324+
SsaFlow::SsaImpl::DefinitionExt getDefinitionExt() { result = node.getDefinitionExt() }
325+
326+
override Location getLocation() { result = node.getLocation() }
327+
328+
override string toString() { result = node.toString() }
329+
}
330+
201331
/**
202332
* A parameter, viewed as a node in a data flow graph.
203333
*/
@@ -398,7 +528,8 @@ module Private {
398528
result.asSummarizedCallable() = n.(FlowSummaryNode).getSummarizedCallable() or
399529
result.asCallable() = n.(CaptureNode).getSynthesizedCaptureNode().getEnclosingCallable() or
400530
result.asFieldScope() = n.(FieldValueNode).getField() or
401-
result.asCallable() = any(Expr e | n.(AdditionalNode).nodeAt(e, _)).getEnclosingCallable()
531+
result.asCallable() = any(Expr e | n.(AdditionalNode).nodeAt(e, _)).getEnclosingCallable() or
532+
result.asCallable() = n.(SsaNode).getDefinitionExt().getBasicBlock().getEnclosingCallable()
402533
}
403534

404535
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */

java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,11 @@ predicate forceHighPrecision(Content c) {
610610
}
611611

612612
/** Holds if `n` should be hidden from path explanations. */
613-
predicate nodeIsHidden(Node n) { n instanceof FlowSummaryNode }
613+
predicate nodeIsHidden(Node n) {
614+
n instanceof FlowSummaryNode
615+
or
616+
n instanceof SsaNode
617+
}
614618

615619
class LambdaCallKind = Method; // the "apply" method in the functional interface
616620

java/ql/lib/semmle/code/java/dataflow/internal/DataFlowUtil.qll

Lines changed: 16 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ private module Cached {
108108
predicate localFlowStep(Node node1, Node node2) {
109109
simpleLocalFlowStep0(node1, node2, _)
110110
or
111-
adjacentUseUse(node1.asExpr(), node2.asExpr())
111+
SsaFlow::localFlowStep(_, node1, node2)
112112
or
113113
// Simple flow through library code is included in the exposed local
114114
// step relation, even though flow is technically inter-procedural
@@ -125,6 +125,10 @@ private module Cached {
125125
predicate simpleLocalFlowStep(Node node1, Node node2, string model) {
126126
simpleLocalFlowStep0(node1, node2, model)
127127
or
128+
SsaFlow::localFlowStep(_, node1, node2) and
129+
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(node1, _) and
130+
model = ""
131+
or
128132
any(AdditionalValueStep a).step(node1, node2) and
129133
pragma[only_bind_out](node1.getEnclosingCallable()) =
130134
pragma[only_bind_out](node2.getEnclosingCallable()) and
@@ -147,14 +151,7 @@ predicate localMustFlowStep(Node node1, Node node2) {
147151
node2.(ImplicitInstanceAccess).getInstanceAccess().(OwnInstanceAccess).getEnclosingCallable()
148152
)
149153
or
150-
exists(SsaImplicitInit init |
151-
init.isParameterDefinition(node1.asParameter()) and init.getAUse() = node2.asExpr()
152-
)
153-
or
154-
exists(SsaExplicitUpdate upd |
155-
upd.getDefiningExpr().(VariableAssign).getSource() = node1.asExpr() and
156-
upd.getAUse() = node2.asExpr()
157-
)
154+
SsaFlow::localMustFlowStep(_, node1, node2)
158155
or
159156
node2.asExpr().(CastingExpr).getExpr() = node1.asExpr()
160157
or
@@ -169,10 +166,6 @@ predicate localMustFlowStep(Node node1, Node node2) {
169166

170167
import Cached
171168

172-
private predicate capturedVariableRead(Node n) {
173-
n.asExpr().(VarRead).getVariable() instanceof CapturedVariable
174-
}
175-
176169
/**
177170
* Holds if there is a data flow step from `e1` to `e2` that only steps from
178171
* child to parent in the AST.
@@ -214,34 +207,8 @@ predicate simpleAstFlowStep(Expr e1, Expr e2) {
214207
private predicate simpleLocalFlowStep0(Node node1, Node node2, string model) {
215208
(
216209
TaintTrackingUtil::forceCachingInSameStage() and
217-
// Variable flow steps through adjacent def-use and use-use pairs.
218-
exists(SsaExplicitUpdate upd |
219-
upd.getDefiningExpr().(VariableAssign).getSource() = node1.asExpr() or
220-
upd.getDefiningExpr().(AssignOp) = node1.asExpr() or
221-
upd.getDefiningExpr().(RecordBindingVariableExpr) = node1.asExpr()
222-
|
223-
node2.asExpr() = upd.getAFirstUse() and
224-
not capturedVariableRead(node2)
225-
)
226-
or
227-
exists(SsaImplicitInit init |
228-
init.isParameterDefinition(node1.asParameter()) and
229-
node2.asExpr() = init.getAFirstUse() and
230-
not capturedVariableRead(node2)
231-
)
232-
or
233-
adjacentUseUse(node1.asExpr(), node2.asExpr()) and
234-
not exists(FieldRead fr |
235-
hasNonlocalValue(fr) and fr.getField().isStatic() and fr = node1.asExpr()
236-
) and
237-
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(node1, _) and
238-
not capturedVariableRead(node2)
239-
or
240210
ThisFlow::adjacentThisRefs(node1, node2)
241211
or
242-
adjacentUseUse(node1.(PostUpdateNode).getPreUpdateNode().asExpr(), node2.asExpr()) and
243-
not capturedVariableRead(node2)
244-
or
245212
ThisFlow::adjacentThisRefs(node1.(PostUpdateNode).getPreUpdateNode(), node2)
246213
or
247214
simpleAstFlowStep(node1.asExpr(), node2.asExpr())
@@ -401,13 +368,23 @@ signature predicate guardChecksSig(Guard g, Expr e, boolean branch);
401368
* in data flow and taint tracking.
402369
*/
403370
module BarrierGuard<guardChecksSig/3 guardChecks> {
371+
// pragma[nomagic]
372+
// private predicate guardChecksSsaDef(Guard g, SsaFlow::SsaImpl::Definition def, boolean branch) {
373+
// guardChecks(g, def.get, branch)
374+
// }
404375
/** Gets a node that is safely guarded by the given guard check. */
405376
Node getABarrierNode() {
377+
// still needed for fields
406378
exists(Guard g, SsaVariable v, boolean branch, VarRead use |
407379
guardChecks(g, v.getAUse(), branch) and
408380
use = v.getAUse() and
409381
g.controls(use.getBasicBlock(), branch) and
410382
result.asExpr() = use
411383
)
384+
// or
385+
// exists(Guard g, SsaFlow::SsaImpl::Definition def, boolean branch |
386+
// guardChecksSsaDef(g, def, branch) and
387+
// SsaFlow::asNode(result) = SsaFlow::Integration::getABarrierNode(g, def, branch)
388+
// )
412389
}
413390
}

java/ql/test/experimental/query-tests/security/CWE-400/ThreadResourceAbuse.expected

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,7 @@ edges
2828
| UploadListener.java:16:17:16:33 | sleepMilliseconds : Number | UploadListener.java:16:3:16:13 | this <.field> [post update] : UploadListener [slowUploads] : Number | provenance | |
2929
| UploadListener.java:28:14:28:19 | parameter this : UploadListener [slowUploads] : Number | UploadListener.java:29:3:29:11 | this <.field> : UploadListener [slowUploads] : Number | provenance | |
3030
| UploadListener.java:29:3:29:11 | this <.field> : UploadListener [slowUploads] : Number | UploadListener.java:30:3:30:15 | this <.field> : UploadListener [slowUploads] : Number | provenance | |
31-
| UploadListener.java:30:3:30:15 | this <.field> : UploadListener [slowUploads] : Number | UploadListener.java:33:7:33:17 | this <.field> : UploadListener [slowUploads] : Number | provenance | |
3231
| UploadListener.java:30:3:30:15 | this <.field> : UploadListener [slowUploads] : Number | UploadListener.java:35:18:35:28 | this <.field> : UploadListener [slowUploads] : Number | provenance | |
33-
| UploadListener.java:33:7:33:17 | slowUploads : Number | UploadListener.java:35:18:35:28 | slowUploads | provenance | Sink:MaD:1982 |
34-
| UploadListener.java:33:7:33:17 | this <.field> : UploadListener [slowUploads] : Number | UploadListener.java:33:7:33:17 | slowUploads : Number | provenance | |
3532
| UploadListener.java:35:18:35:28 | this <.field> : UploadListener [slowUploads] : Number | UploadListener.java:35:18:35:28 | slowUploads | provenance | Sink:MaD:1982 |
3633
nodes
3734
| ThreadResourceAbuse.java:18:25:18:57 | getParameter(...) : String | semmle.label | getParameter(...) : String |
@@ -68,8 +65,6 @@ nodes
6865
| UploadListener.java:28:14:28:19 | parameter this : UploadListener [slowUploads] : Number | semmle.label | parameter this : UploadListener [slowUploads] : Number |
6966
| UploadListener.java:29:3:29:11 | this <.field> : UploadListener [slowUploads] : Number | semmle.label | this <.field> : UploadListener [slowUploads] : Number |
7067
| UploadListener.java:30:3:30:15 | this <.field> : UploadListener [slowUploads] : Number | semmle.label | this <.field> : UploadListener [slowUploads] : Number |
71-
| UploadListener.java:33:7:33:17 | slowUploads : Number | semmle.label | slowUploads : Number |
72-
| UploadListener.java:33:7:33:17 | this <.field> : UploadListener [slowUploads] : Number | semmle.label | this <.field> : UploadListener [slowUploads] : Number |
7368
| UploadListener.java:35:18:35:28 | slowUploads | semmle.label | slowUploads |
7469
| UploadListener.java:35:18:35:28 | this <.field> : UploadListener [slowUploads] : Number | semmle.label | this <.field> : UploadListener [slowUploads] : Number |
7570
subpaths
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
failures
21
testFailures
2+
failures

java/ql/test/library-tests/dataflow/capture/test.expected

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
| A.java:14:14:14:16 | "A" : String | A.java:14:7:14:20 | SSA def(A a) : new A(...) { ... } [p] |
12
| A.java:14:14:14:16 | "A" : String | A.java:14:11:14:20 | f2(...) : new A(...) { ... } [p] |
23
| A.java:14:14:14:16 | "A" : String | A.java:15:16:15:16 | a : new A(...) { ... } [p] |
34
| A.java:14:14:14:16 | "A" : String | A.java:15:16:15:22 | get(...) : String |
45
| A.java:14:14:14:16 | "A" : String | A.java:18:8:18:15 | p : String |
6+
| A.java:14:14:14:16 | "A" : String | A.java:28:7:38:5 | SSA def(A a) : new A(...) { ... } [p] |
57
| A.java:14:14:14:16 | "A" : String | A.java:28:11:38:5 | new (...) : new A(...) { ... } [p] |
68
| A.java:14:14:14:16 | "A" : String | A.java:28:11:38:5 | p : String |
79
| A.java:14:14:14:16 | "A" : String | A.java:30:14:30:16 | parameter this : new A(...) { ... } [p] |
@@ -13,11 +15,13 @@
1315
| A.java:14:14:14:16 | "A" : String | A.java:35:26:35:27 | this : new A(...) { ... } [p] |
1416
| A.java:14:14:14:16 | "A" : String | A.java:39:12:39:12 | a : new A(...) { ... } [p] |
1517
| A.java:14:14:14:16 | "A" : String | A.java:39:12:39:12 | p : String |
18+
| A.java:21:11:21:13 | "B" : String | A.java:14:7:14:20 | SSA def(A a) : new A(...) { ... } [String s] |
1619
| A.java:21:11:21:13 | "B" : String | A.java:14:11:14:20 | f2(...) : new A(...) { ... } [String s] |
1720
| A.java:21:11:21:13 | "B" : String | A.java:15:16:15:16 | a : new A(...) { ... } [String s] |
1821
| A.java:21:11:21:13 | "B" : String | A.java:15:16:15:22 | get(...) : String |
1922
| A.java:21:11:21:13 | "B" : String | A.java:21:7:21:13 | ...=... : String |
2023
| A.java:21:11:21:13 | "B" : String | A.java:25:5:25:26 | phi(String s) : String |
24+
| A.java:21:11:21:13 | "B" : String | A.java:28:7:38:5 | SSA def(A a) : new A(...) { ... } [String s] |
2125
| A.java:21:11:21:13 | "B" : String | A.java:28:11:38:5 | String s : String |
2226
| A.java:21:11:21:13 | "B" : String | A.java:28:11:38:5 | new (...) : new A(...) { ... } [String s] |
2327
| A.java:21:11:21:13 | "B" : String | A.java:30:14:30:16 | parameter this : new A(...) { ... } [String s] |
@@ -29,11 +33,13 @@
2933
| A.java:21:11:21:13 | "B" : String | A.java:35:26:35:27 | this : new A(...) { ... } [String s] |
3034
| A.java:21:11:21:13 | "B" : String | A.java:39:12:39:12 | String s : String |
3135
| A.java:21:11:21:13 | "B" : String | A.java:39:12:39:12 | a : new A(...) { ... } [String s] |
36+
| A.java:23:11:23:13 | "C" : String | A.java:14:7:14:20 | SSA def(A a) : new A(...) { ... } [String s] |
3237
| A.java:23:11:23:13 | "C" : String | A.java:14:11:14:20 | f2(...) : new A(...) { ... } [String s] |
3338
| A.java:23:11:23:13 | "C" : String | A.java:15:16:15:16 | a : new A(...) { ... } [String s] |
3439
| A.java:23:11:23:13 | "C" : String | A.java:15:16:15:22 | get(...) : String |
3540
| A.java:23:11:23:13 | "C" : String | A.java:23:7:23:13 | ...=... : String |
3641
| A.java:23:11:23:13 | "C" : String | A.java:25:5:25:26 | phi(String s) : String |
42+
| A.java:23:11:23:13 | "C" : String | A.java:28:7:38:5 | SSA def(A a) : new A(...) { ... } [String s] |
3743
| A.java:23:11:23:13 | "C" : String | A.java:28:11:38:5 | String s : String |
3844
| A.java:23:11:23:13 | "C" : String | A.java:28:11:38:5 | new (...) : new A(...) { ... } [String s] |
3945
| A.java:23:11:23:13 | "C" : String | A.java:30:14:30:16 | parameter this : new A(...) { ... } [String s] |
@@ -47,16 +53,19 @@
4753
| A.java:23:11:23:13 | "C" : String | A.java:39:12:39:12 | a : new A(...) { ... } [String s] |
4854
| A.java:25:22:25:24 | "D" : String | A.java:4:5:4:7 | parameter this [Return] : Box [elem] |
4955
| A.java:25:22:25:24 | "D" : String | A.java:4:9:4:16 | e : String |
56+
| A.java:25:22:25:24 | "D" : String | A.java:4:19:4:31 | SSA def(e) : String |
5057
| A.java:25:22:25:24 | "D" : String | A.java:4:21:4:24 | this <.field> [post update] : Box [elem] |
5158
| A.java:25:22:25:24 | "D" : String | A.java:4:21:4:28 | ...=... : String |
5259
| A.java:25:22:25:24 | "D" : String | A.java:4:28:4:28 | e : String |
5360
| A.java:25:22:25:24 | "D" : String | A.java:6:12:6:18 | parameter this : Box [elem] |
5461
| A.java:25:22:25:24 | "D" : String | A.java:6:31:6:34 | elem : String |
5562
| A.java:25:22:25:24 | "D" : String | A.java:6:31:6:34 | this <.field> : Box [elem] |
63+
| A.java:25:22:25:24 | "D" : String | A.java:14:7:14:20 | SSA def(A a) : new A(...) { ... } [Box b1, ... (2)] |
5664
| A.java:25:22:25:24 | "D" : String | A.java:14:11:14:20 | f2(...) : new A(...) { ... } [Box b1, ... (2)] |
5765
| A.java:25:22:25:24 | "D" : String | A.java:15:16:15:16 | a : new A(...) { ... } [Box b1, ... (2)] |
5866
| A.java:25:22:25:24 | "D" : String | A.java:15:16:15:22 | get(...) : String |
5967
| A.java:25:22:25:24 | "D" : String | A.java:25:14:25:25 | new Box(...) : Box [elem] |
68+
| A.java:25:22:25:24 | "D" : String | A.java:28:7:38:5 | SSA def(A a) : new A(...) { ... } [Box b1, ... (2)] |
6069
| A.java:25:22:25:24 | "D" : String | A.java:28:11:38:5 | Box b1 : Box [elem] |
6170
| A.java:25:22:25:24 | "D" : String | A.java:28:11:38:5 | new (...) : new A(...) { ... } [Box b1, ... (2)] |
6271
| A.java:25:22:25:24 | "D" : String | A.java:30:14:30:16 | parameter this : new A(...) { ... } [Box b1, ... (2)] |
@@ -71,16 +80,19 @@
7180
| A.java:25:22:25:24 | "D" : String | A.java:39:12:39:12 | a : new A(...) { ... } [Box b1, ... (2)] |
7281
| A.java:27:16:27:18 | "E" : String | A.java:5:10:5:16 | parameter this [Return] : Box [elem] |
7382
| A.java:27:16:27:18 | "E" : String | A.java:5:18:5:25 | e : String |
83+
| A.java:27:16:27:18 | "E" : String | A.java:5:28:5:40 | SSA def(e) : String |
7484
| A.java:27:16:27:18 | "E" : String | A.java:5:30:5:33 | this <.field> [post update] : Box [elem] |
7585
| A.java:27:16:27:18 | "E" : String | A.java:5:30:5:37 | ...=... : String |
7686
| A.java:27:16:27:18 | "E" : String | A.java:5:37:5:37 | e : String |
7787
| A.java:27:16:27:18 | "E" : String | A.java:6:12:6:18 | parameter this : Box [elem] |
7888
| A.java:27:16:27:18 | "E" : String | A.java:6:31:6:34 | elem : String |
7989
| A.java:27:16:27:18 | "E" : String | A.java:6:31:6:34 | this <.field> : Box [elem] |
90+
| A.java:27:16:27:18 | "E" : String | A.java:14:7:14:20 | SSA def(A a) : new A(...) { ... } [Box b2, ... (2)] |
8091
| A.java:27:16:27:18 | "E" : String | A.java:14:11:14:20 | f2(...) : new A(...) { ... } [Box b2, ... (2)] |
8192
| A.java:27:16:27:18 | "E" : String | A.java:15:16:15:16 | a : new A(...) { ... } [Box b2, ... (2)] |
8293
| A.java:27:16:27:18 | "E" : String | A.java:15:16:15:22 | get(...) : String |
8394
| A.java:27:16:27:18 | "E" : String | A.java:27:5:27:6 | b2 [post update] : Box [elem] |
95+
| A.java:27:16:27:18 | "E" : String | A.java:28:7:38:5 | SSA def(A a) : new A(...) { ... } [Box b2, ... (2)] |
8496
| A.java:27:16:27:18 | "E" : String | A.java:28:11:38:5 | Box b2 : Box [elem] |
8597
| A.java:27:16:27:18 | "E" : String | A.java:28:11:38:5 | new (...) : new A(...) { ... } [Box b2, ... (2)] |
8698
| A.java:27:16:27:18 | "E" : String | A.java:30:14:30:16 | parameter this : new A(...) { ... } [Box b2, ... (2)] |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
| A.java:5:18:5:21 | null | A.java:2:13:2:20 | o |
2+
| A.java:5:18:5:21 | null | A.java:5:12:5:21 | SSA def(Object src) |
23
| A.java:5:18:5:21 | null | A.java:5:18:5:21 | null |
4+
| A.java:5:18:5:21 | null | A.java:6:12:6:18 | SSA def(Object x) |
35
| A.java:5:18:5:21 | null | A.java:6:16:6:18 | src |
46
| A.java:5:18:5:21 | null | A.java:7:10:7:10 | x |

0 commit comments

Comments
 (0)