Skip to content

Commit 1aa0e4d

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

File tree

4 files changed

+61
-19
lines changed

4 files changed

+61
-19
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 & 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: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
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 {
@@ -13,10 +16,24 @@ class C {
1316
Map<String, Object> m = new HashMap<String, Object>();
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)