Skip to content

Commit 43b7bc5

Browse files
committed
Java: Add MemberRefExpr.getReceiverType()
1 parent b2e4276 commit 43b7bc5

File tree

4 files changed

+108
-0
lines changed

4 files changed

+108
-0
lines changed

java/ql/lib/semmle/code/java/Expr.qll

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,27 @@ class MemberRefExpr extends FunctionalExpr, @memberref {
12251225
*/
12261226
override Method asMethod() { result = getAnonymousClass().getAMethod() }
12271227

1228+
/**
1229+
* Gets the receiver type whose member this expression refers to. The result might not be
1230+
* the type which actually declares the member (makes a difference for inherited non-overridden
1231+
* methods).
1232+
*/
1233+
RefType getReceiverType() {
1234+
exists(Stmt stmt, Expr resultExpr |
1235+
stmt = asMethod().getBody().(SingletonBlock).getStmt() and
1236+
(
1237+
resultExpr = stmt.(ReturnStmt).getResult()
1238+
or
1239+
// Note: Currently never an ExprStmt, but might change once https://github.com/github/codeql/issues/3605 is fixed
1240+
resultExpr = stmt.(ExprStmt).getExpr()
1241+
)
1242+
|
1243+
result = resultExpr.(MethodAccess).getReceiverType() or
1244+
result = resultExpr.(ClassInstanceExpr).getConstructedType() or
1245+
result = resultExpr.(ArrayCreationExpr).getType()
1246+
)
1247+
}
1248+
12281249
/**
12291250
* Gets the method or constructor referenced by this member reference expression.
12301251
*/
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
| Test.java:24:26:24:51 | ...::... | Inner<>.Inner<> | Test$Generic$Inner.class:0:0:0:0 | Inner<> |
2+
| Test.java:38:29:38:42 | ...::... | Object.toString | Test.java:1:7:1:10 | Test |
3+
| Test.java:39:29:39:42 | ...::... | Object.hashCode | Test.java:1:7:1:10 | Test |
4+
| Test.java:40:29:40:39 | ...::... | Object.clone | Test.java:1:7:1:10 | Test |
5+
| Test.java:41:40:41:64 | ...::... | Object.toString | Test$Generic.class:0:0:0:0 | Generic<String> |
6+
| Test.java:43:23:43:36 | ...::... | Object.toString | Test.java:1:7:1:10 | Test |
7+
| Test.java:44:23:44:36 | ...::... | Object.hashCode | Test.java:1:7:1:10 | Test |
8+
| Test.java:45:23:45:33 | ...::... | Object.clone | Test.java:1:7:1:10 | Test |
9+
| Test.java:48:22:48:35 | ...::... | Object.toString | Test.java:1:7:1:10 | Test |
10+
| Test.java:51:13:51:21 | ...::... | Test.Test | Test.java:1:7:1:10 | Test |
11+
| Test.java:52:13:52:32 | ...::... | Generic<String>.Generic<String> | Test$Generic.class:0:0:0:0 | Generic<String> |
12+
| Test.java:56:13:56:22 | ...::... | | file://:0:0:0:0 | int[] |
13+
| Test.java:57:13:57:26 | ...::... | | file://:0:0:0:0 | Generic<>[] |
14+
| Test.java:61:31:61:47 | ...::... | Test.doSomething | Test.java:1:7:1:10 | Test |
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import java
2+
3+
string getReferencedCallable(MemberRefExpr e) {
4+
if exists(e.getReferencedCallable())
5+
then result = e.getReferencedCallable().getQualifiedName()
6+
else result = ""
7+
}
8+
9+
from MemberRefExpr e
10+
select e, getReferencedCallable(e), e.getReceiverType()
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
class Test {
2+
interface Function<T> {
3+
Object apply(T o) throws Exception;
4+
}
5+
6+
interface IntFunction {
7+
Object apply(int i);
8+
}
9+
10+
interface Supplier {
11+
Object get() throws Exception;
12+
}
13+
14+
public Test() { }
15+
16+
static class Generic<T> {
17+
public Generic() { }
18+
19+
class Inner {
20+
public Inner() { }
21+
}
22+
23+
void test() {
24+
Supplier s = Generic<Number>.Inner::new;
25+
}
26+
}
27+
28+
void doSomething() { }
29+
30+
static class Sub extends Test {
31+
}
32+
33+
interface SubtypeConsumer {
34+
void consume(Sub s);
35+
}
36+
37+
void test() {
38+
Function<Test> f0 = Test::toString;
39+
Function<Test> f1 = Test::hashCode;
40+
Function<Test> f2 = Test::clone;
41+
Function<Generic<String>> f3 = Generic<String>::toString;
42+
43+
Supplier s0 = this::toString;
44+
Supplier s1 = this::hashCode;
45+
Supplier s2 = this::clone;
46+
47+
// Discards result of method call
48+
Runnable r = this::toString;
49+
50+
Supplier[] classInstances = {
51+
Test::new,
52+
Generic<String>::new,
53+
};
54+
55+
IntFunction[] arrays = {
56+
int[]::new,
57+
Generic[]::new,
58+
};
59+
60+
// SubtypeConsumer has `Sub` as parameter type, but receiver here is `Test` (supertype)
61+
SubtypeConsumer sub = Test::doSomething;
62+
}
63+
}

0 commit comments

Comments
 (0)