Skip to content

Commit cbf0027

Browse files
committed
Java: Add BoundedType.getTypeBound(int)
1 parent a760ed8 commit cbf0027

File tree

8 files changed

+184
-69
lines changed

8 files changed

+184
-69
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,16 @@ abstract class BoundedType extends RefType, @boundedtype {
9191
/** Holds if this type is bounded. */
9292
predicate hasTypeBound() { exists(TypeBound tb | tb = this.getATypeBound()) }
9393

94+
/** Gets the type bound for this type at the 0-based position, if any. */
95+
TypeBound getTypeBound(int position) {
96+
result = getATypeBound() and result.getPosition() = position
97+
}
98+
9499
/** Gets a type bound for this type, if any. */
95100
TypeBound getATypeBound() { result.getBoundedType() = this }
96101

97102
/** Gets the first type bound for this type, if any. */
98-
TypeBound getFirstTypeBound() { result = getATypeBound() and result.getPosition() = 0 }
103+
TypeBound getFirstTypeBound() { result = getTypeBound(0) }
99104

100105
/**
101106
* Gets an upper type bound of this type, or `Object`
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +0,0 @@
1-
| generics/A.java:13:26:13:54 | new HashMap<String,Object>(...) | 0 | generics/A.java:13:38:13:43 | String |
2-
| generics/A.java:13:26:13:54 | new HashMap<String,Object>(...) | 1 | generics/A.java:13:46:13:51 | Object |
Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
import default
2+
import TestUtilities.InlineExpectationsTest
23

3-
from ClassInstanceExpr cie, Expr typearg, int idx
4-
where typearg = cie.getTypeArgument(idx)
5-
select cie, idx, typearg
4+
class ParameterizedClassInstanceTest extends InlineExpectationsTest {
5+
ParameterizedClassInstanceTest() { this = "ParameterizedClassInstanceTest" }
6+
7+
override string getARelevantTag() { result = ["parameterizedNew"] }
8+
9+
override predicate hasActualResult(Location location, string element, string tag, string value) {
10+
exists(ClassInstanceExpr cie |
11+
location = cie.getLocation() and
12+
element = cie.toString() and
13+
tag = "parameterizedNew" and
14+
value =
15+
concat(int idx, Expr typearg |
16+
typearg = cie.getTypeArgument(idx)
17+
|
18+
idx.toString() + typearg.toString(), "," order by idx
19+
)
20+
)
21+
}
22+
}

java/ql/test/library-tests/generics/PrintAst.expected

Lines changed: 92 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,42 +7,96 @@ generics/A.java:
77
#-----| -2: (Generic Parameters)
88
# 6| 0: [TypeVariable] T
99
# 7| 2: [Class] B
10-
# 10| 2: [Class] C
11-
# 11| 3: [FieldDeclaration] A<String> f, ...;
12-
# 11| -1: [TypeAccess] A<String>
13-
# 11| 0: [TypeAccess] String
14-
# 12| 4: [FieldDeclaration] A<String>.B<> b, ...;
15-
# 12| -1: [TypeAccess] A<String>.B<>
16-
# 12| -1: [TypeAccess] A<String>
17-
# 12| 0: [TypeAccess] String
18-
# 13| 5: [FieldDeclaration] Map<String,Object> m, ...;
19-
# 13| -1: [TypeAccess] Map<String,Object>
20-
# 13| 0: [TypeAccess] String
21-
# 13| 1: [TypeAccess] Object
22-
# 13| 0: [ClassInstanceExpr] new HashMap<String,Object>(...)
23-
# 13| -3: [TypeAccess] HashMap<String,Object>
24-
# 13| 0: [TypeAccess] String
25-
# 13| 1: [TypeAccess] Object
26-
# 16| 3: [Class] D
10+
# 9| 3: [Method] noBound
11+
#-----| 2: (Generic Parameters)
12+
# 9| 0: [TypeVariable] R
13+
# 9| 3: [TypeAccess] void
14+
# 9| 5: [BlockStmt] stmt
15+
# 10| 4: [Method] upperBound
16+
#-----| 2: (Generic Parameters)
17+
# 10| 0: [TypeVariable] R
18+
# 10| 0: [TypeAccess] String
19+
# 10| 3: [TypeAccess] void
20+
# 10| 5: [BlockStmt] stmt
21+
# 13| 2: [Class] C
22+
# 14| 3: [FieldDeclaration] A<String> f, ...;
23+
# 14| -1: [TypeAccess] A<String>
24+
# 14| 0: [TypeAccess] String
25+
# 15| 4: [FieldDeclaration] A<String>.B<> b, ...;
26+
# 15| -1: [TypeAccess] A<String>.B<>
27+
# 15| -1: [TypeAccess] A<String>
28+
# 15| 0: [TypeAccess] String
29+
# 16| 5: [FieldDeclaration] Map<String,Object> m, ...;
30+
# 16| -1: [TypeAccess] Map<String,Object>
31+
# 16| 0: [TypeAccess] String
32+
# 16| 1: [TypeAccess] Object
33+
# 16| 0: [ClassInstanceExpr] new HashMap<String,Object>(...)
34+
# 16| -3: [TypeAccess] HashMap<String,Object>
35+
# 16| 0: [TypeAccess] String
36+
# 16| 1: [TypeAccess] Object
37+
# 19| 3: [Class] D
2738
#-----| -2: (Generic Parameters)
28-
# 16| 0: [TypeVariable] V
29-
# 16| 0: [TypeAccess] Number
30-
# 17| 3: [FieldDeclaration] D<?> d1, ...;
31-
# 17| -1: [TypeAccess] D<?>
32-
# 17| 0: [WildcardTypeAccess] ? ...
33-
# 18| 4: [FieldDeclaration] D<? extends Object> d2, ...;
34-
# 18| -1: [TypeAccess] D<? extends Object>
35-
# 18| 0: [WildcardTypeAccess] ? ...
36-
# 18| 0: [TypeAccess] Object
37-
# 19| 5: [FieldDeclaration] D<? extends Float> d3, ...;
38-
# 19| -1: [TypeAccess] D<? extends Float>
39-
# 19| 0: [WildcardTypeAccess] ? ...
40-
# 19| 0: [TypeAccess] Float
41-
# 20| 6: [FieldDeclaration] D<? super Double> d4, ...;
42-
# 20| -1: [TypeAccess] D<? super Double>
43-
# 20| 0: [WildcardTypeAccess] ? ...
44-
# 20| 1: [TypeAccess] Double
45-
# 21| 7: [BlockStmt] stmt
46-
# 21| 0: [ExprStmt] stmt
47-
# 21| 0: [MethodAccess] asList(...)
48-
# 21| -1: [TypeAccess] Arrays
39+
# 19| 0: [TypeVariable] V
40+
# 19| 0: [TypeAccess] Number
41+
# 21| 3: [FieldDeclaration] D<?> d1, ...;
42+
# 21| -1: [TypeAccess] D<?>
43+
# 21| 0: [WildcardTypeAccess] ? ...
44+
# 22| 4: [FieldDeclaration] D<? extends Object> d2, ...;
45+
# 22| -1: [TypeAccess] D<? extends Object>
46+
# 22| 0: [WildcardTypeAccess] ? ...
47+
# 22| 0: [TypeAccess] Object
48+
# 23| 5: [FieldDeclaration] D<? extends Float> d3, ...;
49+
# 23| -1: [TypeAccess] D<? extends Float>
50+
# 23| 0: [WildcardTypeAccess] ? ...
51+
# 23| 0: [TypeAccess] Float
52+
# 24| 6: [FieldDeclaration] D<? super Double> d4, ...;
53+
# 24| -1: [TypeAccess] D<? super Double>
54+
# 24| 0: [WildcardTypeAccess] ? ...
55+
# 24| 1: [TypeAccess] Double
56+
# 25| 7: [BlockStmt] stmt
57+
# 25| 0: [ExprStmt] stmt
58+
# 25| 0: [MethodAccess] asList(...)
59+
# 25| -1: [TypeAccess] Arrays
60+
# 28| 4: [Interface] I1
61+
# 29| 5: [Interface] I2
62+
# 31| 6: [Class] E1
63+
#-----| -2: (Generic Parameters)
64+
# 31| 0: [TypeVariable] T
65+
# 31| 0: [TypeAccess] C
66+
# 31| 1: [TypeAccess] I1
67+
# 31| 2: [TypeAccess] I2
68+
# 32| 7: [Class] E2
69+
#-----| -2: (Generic Parameters)
70+
# 32| 0: [TypeVariable] T
71+
# 32| 0: [TypeAccess] I2
72+
# 32| 1: [TypeAccess] I1
73+
# 33| 8: [Class] E3
74+
#-----| -2: (Generic Parameters)
75+
# 33| 0: [TypeVariable] T
76+
# 33| 0: [TypeAccess] Object
77+
# 33| 1: [TypeAccess] I2
78+
# 33| 2: [TypeAccess] I1
79+
# 35| 9: [Class] F
80+
# 36| 2: [Method] test1
81+
#-----| 2: (Generic Parameters)
82+
# 36| 0: [TypeVariable] T
83+
# 36| 0: [TypeAccess] C
84+
# 36| 1: [TypeAccess] I1
85+
# 36| 2: [TypeAccess] I2
86+
# 36| 3: [TypeAccess] void
87+
# 36| 5: [BlockStmt] stmt
88+
# 37| 3: [Method] test2
89+
#-----| 2: (Generic Parameters)
90+
# 37| 0: [TypeVariable] T
91+
# 37| 0: [TypeAccess] I2
92+
# 37| 1: [TypeAccess] I1
93+
# 37| 3: [TypeAccess] void
94+
# 37| 5: [BlockStmt] stmt
95+
# 38| 4: [Method] test3
96+
#-----| 2: (Generic Parameters)
97+
# 38| 0: [TypeVariable] T
98+
# 38| 0: [TypeAccess] Object
99+
# 38| 1: [TypeAccess] I2
100+
# 38| 2: [TypeAccess] I1
101+
# 38| 3: [TypeAccess] void
102+
# 38| 5: [BlockStmt] stmt
Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
| 0 | generics/A$B.class:0:0:0:0 | B<> | 7 | generics/A.java:7:8:7:8 | B |
22
| 0 | generics/A.class:0:0:0:0 | A<String> | 6 | generics/A.java:6:14:6:14 | A |
3-
| 0 | generics/D.class:0:0:0:0 | D<? extends Float> | 16 | generics/A.java:16:7:16:7 | D |
4-
| 0 | generics/D.class:0:0:0:0 | D<? extends Object> | 16 | generics/A.java:16:7:16:7 | D |
5-
| 0 | generics/D.class:0:0:0:0 | D<? super Double> | 16 | generics/A.java:16:7:16:7 | D |
6-
| 0 | generics/D.class:0:0:0:0 | D<?> | 16 | generics/A.java:16:7:16:7 | D |
3+
| 0 | generics/D.class:0:0:0:0 | D<? extends Float> | 19 | generics/A.java:19:7:19:7 | D |
4+
| 0 | generics/D.class:0:0:0:0 | D<? extends Object> | 19 | generics/A.java:19:7:19:7 | D |
5+
| 0 | generics/D.class:0:0:0:0 | D<? super Double> | 19 | generics/A.java:19:7:19:7 | D |
6+
| 0 | generics/D.class:0:0:0:0 | D<?> | 19 | generics/A.java:19:7:19:7 | D |
77
| 6 | generics/A.java:6:14:6:14 | A | 6 | generics/A.java:6:14:6:14 | A |
88
| 7 | generics/A.java:7:8:7:8 | B | 7 | generics/A.java:7:8:7:8 | B |
9-
| 10 | generics/A.java:10:7:10:7 | C | 10 | generics/A.java:10:7:10:7 | C |
10-
| 16 | generics/A.java:16:7:16:7 | D | 16 | generics/A.java:16:7:16:7 | D |
9+
| 13 | generics/A.java:13:7:13:7 | C | 13 | generics/A.java:13:7:13:7 | C |
10+
| 19 | generics/A.java:19:7:19:7 | D | 19 | generics/A.java:19:7:19:7 | D |
11+
| 31 | generics/A.java:31:7:31:8 | E1 | 31 | generics/A.java:31:7:31:8 | E1 |
12+
| 32 | generics/A.java:32:7:32:8 | E2 | 32 | generics/A.java:32:7:32:8 | E2 |
13+
| 33 | generics/A.java:33:7:33:8 | E3 | 33 | generics/A.java:33:7:33:8 | E3 |
14+
| 35 | generics/A.java:35:7:35:7 | F | 35 | generics/A.java:35:7:35:7 | F |
Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +0,0 @@
1-
| file://:0:0:0:0 | ? | Object |
2-
| file://:0:0:0:0 | ? extends Float | Float |
3-
| file://:0:0:0:0 | ? extends Object | Object |
4-
| file://:0:0:0:0 | ? super Double | Object |
5-
| generics/A.java:6:16:6:16 | T | Object |
6-
| generics/A.java:16:9:16:24 | V | Number |
Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,33 @@
11
import default
2+
import TestUtilities.InlineExpectationsTest
23

3-
from BoundedType bt
4-
where
5-
bt.fromSource() or
6-
exists(TypeAccess ta | ta.getType().(ParameterizedType).getATypeArgument() = bt)
7-
select bt, bt.getUpperBoundType().toString()
4+
private string getOrderedBounds(BoundedType bt) {
5+
result =
6+
concat(TypeBound bound, int position |
7+
bound = bt.getTypeBound(position)
8+
|
9+
bound.getType().toString(), "," order by position
10+
)
11+
}
12+
13+
class TypeVariableBoundTest extends InlineExpectationsTest {
14+
TypeVariableBoundTest() { this = "TypeVariableBoundTest" }
15+
16+
override string getARelevantTag() { result = ["bounded", "boundedAccess"] }
17+
18+
override predicate hasActualResult(Location location, string element, string tag, string value) {
19+
exists(BoundedType bt | value = getOrderedBounds(bt) |
20+
bt.fromSource() and
21+
location = bt.getLocation() and
22+
element = bt.toString() and
23+
tag = "bounded"
24+
or
25+
exists(TypeAccess ta |
26+
ta.getType().(ParameterizedType).getATypeArgument() = bt and
27+
location = ta.getLocation() and
28+
element = ta.toString() and
29+
tag = "boundedAccess"
30+
)
31+
)
32+
}
33+
}

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

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,37 @@
33
import java.util.HashMap;
44
import java.util.Map;
55

6-
public class A<T> {
6+
public class A<T> { // $bounded=
77
class B { }
8+
9+
public <R> void noBound() { } // $bounded=
10+
public <R extends String> void upperBound() { } // $bounded=String
811
}
912

1013
class C {
1114
A<String> f;
1215
A<String>.B b;
13-
Map<String, Object> m = new HashMap<String, Object>();
16+
Map<String, Object> m = new HashMap<String, Object>(); // $parameterizedNew=0String,1Object
1417
}
1518

16-
class D<V extends Number> {
17-
D<?> d1;
18-
D<? extends Object> d2;
19-
D<? extends Float> d3;
20-
D<? super Double> d4;
19+
class D<V extends Number> { // $bounded=Number
20+
// Currently erroneously reports implicit Object as bound, see https://github.com/github/codeql/issues/5405
21+
D<?> d1; // $SPURIOUS: boundedAccess=Object MISSING: boundedAccess=
22+
D<? extends Object> d2; // $boundedAccess=Object
23+
D<? extends Float> d3; // $boundedAccess=Float
24+
D<? super Double> d4; // $boundedAccess=Double
2125
{ java.util.Arrays.asList(); }
22-
}
26+
}
27+
28+
interface I1 { }
29+
interface I2 { }
30+
31+
class E1<T extends C & I1 & I2> { } // $bounded=C,I1,I2
32+
class E2<T extends I2 & I1> { } // $bounded=I2,I1
33+
class E3<T extends Object & I2 & I1> { } // $bounded=Object,I2,I1
34+
35+
class F {
36+
public <T extends C & I1 & I2> void test1() { } // $bounded=C,I1,I2
37+
public <T extends I2 & I1> void test2() { } // $bounded=I2,I1
38+
public <T extends Object & I2 & I1> void test3() { } // $bounded=Object,I2,I1
39+
}

0 commit comments

Comments
 (0)