Skip to content

Commit 274147c

Browse files
Merge pull request #4339 from joefarebrother/printAST-java-var-decls
Java: Add synthetic nodes for `LocalVariableDeclExpr`s in the AST view
2 parents 20c4d94 + 5256c0b commit 274147c

File tree

5 files changed

+304
-66
lines changed

5 files changed

+304
-66
lines changed

java/ql/src/semmle/code/java/PrintAst.qll

Lines changed: 175 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ private predicate locationSortKeys(Element ast, string file, int line, int colum
113113
*/
114114
private newtype TPrintAstNode =
115115
TElementNode(Element el) { shouldPrint(el, _) } or
116+
TForInitNode(ForStmt fs) { shouldPrint(fs, _) and exists(fs.getAnInit()) } or
117+
TLocalVarDeclNode(LocalVariableDeclExpr lvde) {
118+
shouldPrint(lvde, _) and lvde.getParent() instanceof SingleLocalVarDeclParent
119+
} or
116120
TAnnotationsNode(Annotatable ann) {
117121
shouldPrint(ann, _) and ann.hasAnnotation() and not partOfAnnotation(ann)
118122
} or
@@ -221,56 +225,148 @@ abstract class ElementNode extends PrintAstNode, TElementNode {
221225
final Element getElement() { result = element }
222226
}
223227

228+
/**
229+
* A node representing an `Expr` or a `Stmt`.
230+
*/
231+
class ExprStmtNode extends ElementNode {
232+
ExprStmtNode() { element instanceof ExprOrStmt }
233+
234+
override PrintAstNode getChild(int childIndex) {
235+
exists(Element el | result.(ElementNode).getElement() = el |
236+
el.(Expr).isNthChildOf(element, childIndex)
237+
or
238+
el.(Stmt).isNthChildOf(element, childIndex)
239+
)
240+
}
241+
}
242+
243+
/**
244+
* Holds if the given expression is part of an annotation.
245+
*/
224246
private predicate partOfAnnotation(Expr e) {
225247
e instanceof Annotation
226248
or
227249
e instanceof ArrayInit and
228250
partOfAnnotation(e.getParent())
229251
}
230252

231-
private Expr getAnAnnotationChild(Expr e) {
232-
partOfAnnotation(e) and
233-
(
234-
result = e.(Annotation).getValue(_)
253+
/**
254+
* A node representing an `Expr` that is part of an annotation.
255+
*/
256+
final class AnnotationPartNode extends ExprStmtNode {
257+
AnnotationPartNode() { partOfAnnotation(element) }
258+
259+
override ElementNode getChild(int childIndex) {
260+
result.getElement() =
261+
rank[childIndex](Element ch, string file, int line, int column |
262+
ch = getAnAnnotationChild() and locationSortKeys(ch, file, line, column)
263+
|
264+
ch order by file, line, column
265+
)
266+
}
267+
268+
private Expr getAnAnnotationChild() {
269+
result = element.(Annotation).getValue(_)
235270
or
236-
result = e.(ArrayInit).getAnInit()
271+
result = element.(ArrayInit).getAnInit()
237272
or
238-
result = e.(ArrayInit).(Annotatable).getAnAnnotation()
239-
)
273+
result = element.(ArrayInit).(Annotatable).getAnAnnotation()
274+
}
240275
}
241276

242277
/**
243-
* An node representing an `Expr` or a `Stmt`.
278+
* A node representing a `LocalVariableDeclExpr`.
244279
*/
245-
final class ExprStmtNode extends ElementNode {
246-
ExprStmtNode() { element instanceof ExprOrStmt }
280+
final class LocalVarDeclExprNode extends ExprStmtNode {
281+
LocalVarDeclExprNode() { element instanceof LocalVariableDeclExpr }
247282

248283
override PrintAstNode getChild(int childIndex) {
249-
exists(Element el | result.(ElementNode).getElement() = el |
250-
el.(Expr).isNthChildOf(element, childIndex) and
251-
not partOfAnnotation(element)
252-
or
253-
el.(Stmt).isNthChildOf(element, childIndex)
254-
or
255-
childIndex = -4 and
256-
el = element.(ClassInstanceExpr).getAnonymousClass()
257-
or
258-
childIndex = 0 and
259-
el = element.(LocalClassDeclStmt).getLocalClass()
260-
or
261-
partOfAnnotation(element) and
262-
el =
263-
rank[childIndex](Element ch, string file, int line, int column |
264-
ch = getAnAnnotationChild(element) and locationSortKeys(ch, file, line, column)
265-
|
266-
ch order by file, line, column
267-
)
268-
)
284+
result = super.getChild(childIndex)
269285
or
270-
exists(Element el | result.(AnnotationsNode).getAnnotated() = el |
271-
childIndex = -2 and
272-
el = element.(LocalVariableDeclExpr).getVariable()
273-
)
286+
childIndex = -2 and
287+
result.(AnnotationsNode).getAnnotated() = element.(LocalVariableDeclExpr).getVariable()
288+
}
289+
}
290+
291+
/**
292+
* A node representing a `ClassInstanceExpr`.
293+
*/
294+
final class ClassInstanceExprNode extends ExprStmtNode {
295+
ClassInstanceExprNode() { element instanceof ClassInstanceExpr }
296+
297+
override ElementNode getChild(int childIndex) {
298+
result = super.getChild(childIndex)
299+
or
300+
childIndex = -4 and
301+
result.getElement() = element.(ClassInstanceExpr).getAnonymousClass()
302+
}
303+
}
304+
305+
/**
306+
* A node representing a `LocalClassDeclStmt`.
307+
*/
308+
final class LocalClassDeclStmtNode extends ExprStmtNode {
309+
LocalClassDeclStmtNode() { element instanceof LocalClassDeclStmt }
310+
311+
override ElementNode getChild(int childIndex) {
312+
result = super.getChild(childIndex)
313+
or
314+
childIndex = 0 and
315+
result.getElement() = element.(LocalClassDeclStmt).getLocalClass()
316+
}
317+
}
318+
319+
/**
320+
* A node representing a `ForStmt`.
321+
*/
322+
final class ForStmtNode extends ExprStmtNode {
323+
ForStmtNode() { element instanceof ForStmt }
324+
325+
override PrintAstNode getChild(int childIndex) {
326+
childIndex >= 1 and
327+
result = super.getChild(childIndex)
328+
or
329+
childIndex = 0 and
330+
result.(ForInitNode).getForStmt() = element
331+
}
332+
}
333+
334+
/**
335+
* An element that can be the parent of up to one `LocalVariableDeclExpr` for which we want
336+
* to use a synthetic node to hold the variable declaration and its `TypeAccess`.
337+
*/
338+
private class SingleLocalVarDeclParent extends ExprOrStmt {
339+
SingleLocalVarDeclParent() {
340+
this instanceof EnhancedForStmt or
341+
this instanceof CatchClause or
342+
this.(InstanceOfExpr).isPattern()
343+
}
344+
345+
/** Gets the variable declaration that this element contains */
346+
LocalVariableDeclExpr getVariable() { result.getParent() = this }
347+
348+
/** Gets the type access of the variable */
349+
Expr getTypeAccess() { result = getVariable().getTypeAccess() }
350+
}
351+
352+
/**
353+
* A node representing an element that can be the parent of up to one `LocalVariableDeclExpr` for which we
354+
* want to use a synthetic node to variable declaration and its type access.
355+
*
356+
* Excludes `LocalVariableDeclStmt` and `ForStmt`, as they can hold multiple declarations.
357+
* For these cases, either a synthetic node is not necassary or a different synthetic node is used.
358+
*/
359+
final class SingleLocalVarDeclParentNode extends ExprStmtNode {
360+
SingleLocalVarDeclParent lvdp;
361+
362+
SingleLocalVarDeclParentNode() { lvdp = element }
363+
364+
override PrintAstNode getChild(int childIndex) {
365+
result = super.getChild(childIndex) and
366+
not result.(ElementNode).getElement() = [lvdp.getVariable(), lvdp.getTypeAccess()]
367+
or
368+
childIndex = lvdp.getVariable().getIndex() and
369+
result.(LocalVarDeclSynthNode).getVariable() = lvdp.getVariable()
274370
}
275371
}
276372

@@ -432,6 +528,51 @@ final class TypeVariableNode extends ElementNode {
432528
}
433529
}
434530

531+
/**
532+
* A node representing the initializers of a `ForStmt`.
533+
*/
534+
final class ForInitNode extends PrintAstNode, TForInitNode {
535+
ForStmt fs;
536+
537+
ForInitNode() { this = TForInitNode(fs) }
538+
539+
override string toString() { result = "(For Initializers) " }
540+
541+
override ElementNode getChild(int childIndex) {
542+
childIndex >= 0 and
543+
result.getElement().(Expr).isNthChildOf(fs, -childIndex)
544+
}
545+
546+
/**
547+
* Gets the underlying `ForStmt`.
548+
*/
549+
ForStmt getForStmt() { result = fs }
550+
}
551+
552+
/**
553+
* A synthetic node holding a `LocalVariableDeclExpr` and its type access.
554+
*/
555+
final class LocalVarDeclSynthNode extends PrintAstNode, TLocalVarDeclNode {
556+
LocalVariableDeclExpr lvde;
557+
558+
LocalVarDeclSynthNode() { this = TLocalVarDeclNode(lvde) }
559+
560+
override string toString() { result = "(Single Local Variable Declaration)" }
561+
562+
override ElementNode getChild(int childIndex) {
563+
childIndex = 0 and
564+
result.getElement() = lvde.getTypeAccess()
565+
or
566+
childIndex = 1 and
567+
result.getElement() = lvde
568+
}
569+
570+
/**
571+
* Gets the underlying `LocalVariableDeclExpr`
572+
*/
573+
LocalVariableDeclExpr getVariable() { result = lvde }
574+
}
575+
435576
/**
436577
* A node representing the annotations of an `Annotatable`.
437578
* Only rendered if there is at least one annotation.

java/ql/test/library-tests/java7/MultiCatch/PrintAst.expected

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ MultiCatch.java:
2121
# 14| 0: [ClassInstanceExpr] new SQLException(...)
2222
# 14| -3: [TypeAccess] SQLException
2323
# 15| 0: [CatchClause] stmt
24-
# 15| -1: [UnionTypeAccess] ...|...
25-
# 15| 0: [TypeAccess] IOException
26-
# 15| 1: [TypeAccess] SQLException
27-
# 15| 0: [LocalVariableDeclExpr] e
24+
#-----| 0: (Single Local Variable Declaration)
25+
# 15| 0: [UnionTypeAccess] ...|...
26+
# 15| 0: [TypeAccess] IOException
27+
# 15| 1: [TypeAccess] SQLException
28+
# 15| 1: [LocalVariableDeclExpr] e
2829
# 16| 1: [BlockStmt] stmt
2930
# 17| 0: [ExprStmt] stmt
3031
# 17| 0: [MethodAccess] printStackTrace(...)
@@ -55,10 +56,11 @@ MultiCatch.java:
5556
# 30| 0: [ClassInstanceExpr] new Exception(...)
5657
# 30| -3: [TypeAccess] Exception
5758
# 31| 0: [CatchClause] stmt
58-
# 31| -1: [UnionTypeAccess] ...|...
59-
# 31| 0: [TypeAccess] IOException
60-
# 31| 1: [TypeAccess] SQLException
61-
# 31| 0: [LocalVariableDeclExpr] e
59+
#-----| 0: (Single Local Variable Declaration)
60+
# 31| 0: [UnionTypeAccess] ...|...
61+
# 31| 0: [TypeAccess] IOException
62+
# 31| 1: [TypeAccess] SQLException
63+
# 31| 1: [LocalVariableDeclExpr] e
6264
# 32| 1: [BlockStmt] stmt
6365
# 35| 4: [Method] ordinaryCatch
6466
# 35| 3: [TypeAccess] void
@@ -69,6 +71,7 @@ MultiCatch.java:
6971
# 39| 0: [ClassInstanceExpr] new IOException(...)
7072
# 39| -3: [TypeAccess] IOException
7173
# 40| 0: [CatchClause] stmt
72-
# 40| -1: [TypeAccess] Exception
73-
# 40| 0: [LocalVariableDeclExpr] e
74+
#-----| 0: (Single Local Variable Declaration)
75+
# 40| 0: [TypeAccess] Exception
76+
# 40| 1: [LocalVariableDeclExpr] e
7477
# 41| 1: [BlockStmt] stmt

java/ql/test/library-tests/printAst/A.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ class A {
1818
/** Does something */
1919
@Deprecated
2020
static int doSomething(@SuppressWarnings("all") String text) {
21+
int i=0, j=1;
22+
23+
for(i=0, j=1; i<3; i++) {}
24+
25+
for(int m=0, n=1; m<3; m++) {}
26+
2127
return 0;
2228
}
2329

@@ -34,4 +40,20 @@ static int doSomething(@SuppressWarnings("all") String text) {
3440
@Ann2(7)
3541
})
3642
String doSomethingElse() { return "c"; }
43+
44+
void varDecls(Object[] things) {
45+
try {
46+
for(Object thing : things) {
47+
if (thing instanceof Integer) {
48+
return;
49+
}
50+
if (thing instanceof String s) {
51+
throw new RuntimeException(s);
52+
}
53+
}
54+
}
55+
catch (RuntimeException rte) {
56+
return;
57+
}
58+
}
3759
}

0 commit comments

Comments
 (0)