Skip to content

Commit 9942dff

Browse files
authored
Merge pull request #8695 from atorralba/atorralba/stub-generator-annotation-types
Java: Add support for Annotation types stub generation
2 parents a0fcd4a + f860ae8 commit 9942dff

File tree

12 files changed

+121
-19
lines changed

12 files changed

+121
-19
lines changed

java/ql/src/utils/stub-generator/MinimalStubsFromSource.ql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ class UsedInSource extends GeneratedDeclaration {
2020
this = any(RefType t | t.fromSource())
2121
or
2222
this = any(TypeAccess ta | ta.fromSource())
23+
or
24+
this = any(Annotation a | a.getAnnotatedElement().fromSource()).getType()
2325
)
2426
}
2527
}

java/ql/src/utils/stub-generator/Stubs.qll

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ abstract private class GeneratedType extends ClassOrInterface {
1616
}
1717

1818
private string stubKeyword() {
19-
this instanceof Interface and result = "interface"
19+
this instanceof Interface and
20+
(if this instanceof AnnotationType then result = "@interface" else result = "interface")
2021
or
2122
this instanceof Class and
2223
(if this instanceof EnumType then result = "enum" else result = "class")
@@ -27,19 +28,29 @@ abstract private class GeneratedType extends ClassOrInterface {
2728
}
2829

2930
private string stubStaticModifier() {
30-
if this.isStatic() then result = "static " else result = ""
31+
if this.(NestedType).isStatic() then result = "static " else result = ""
3132
}
3233

3334
private string stubAccessibilityModifier() {
3435
if this.isPublic() then result = "public " else result = ""
3536
}
3637

38+
private string stubAnnotations() {
39+
result =
40+
concat(Annotation an |
41+
this.(AnnotationType).getAnAnnotation() = an
42+
|
43+
stubAnnotation(an), "\n" order by an.getType().getQualifiedName()
44+
)
45+
}
46+
3747
/** Gets the entire Java stub code for this type. */
3848
final string getStub() {
3949
result =
40-
this.stubAbstractModifier() + this.stubStaticModifier() + this.stubAccessibilityModifier() +
41-
this.stubKeyword() + " " + this.getName() + stubGenericArguments(this, true) +
42-
this.stubBaseTypesString() + "\n{\n" + this.stubMembers() + "}"
50+
this.stubAnnotations() + this.stubAbstractModifier() + this.stubStaticModifier() +
51+
this.stubAccessibilityModifier() + this.stubKeyword() + " " + this.getName() +
52+
stubGenericArguments(this, true) + this.stubBaseTypesString() + "\n{\n" + this.stubMembers()
53+
+ "}"
4354
}
4455

4556
private RefType getAnInterestingBaseType() {
@@ -60,7 +71,9 @@ abstract private class GeneratedType extends ClassOrInterface {
6071
else cls = ""
6172
) and
6273
(
63-
if exists(this.getAnInterestingBaseType().(Interface))
74+
if
75+
exists(this.getAnInterestingBaseType().(Interface)) and
76+
not this instanceof AnnotationType
6477
then (
6578
(if this instanceof Class then int_kw = " implements " else int_kw = " extends ") and
6679
interface = concat(stubTypeName(this.getAnInterestingBaseType().(Interface)), ", ")
@@ -96,15 +109,14 @@ abstract private class GeneratedType extends ClassOrInterface {
96109
}
97110

98111
final Type getAGeneratedType() {
99-
result = this.getAnInterestingBaseType()
100-
or
101-
result = this.getAGeneratedMember().(Callable).getReturnType()
102-
or
103-
result = this.getAGeneratedMember().(Callable).getAParameter().getType()
104-
or
105-
result = this.getAGeneratedMember().(Field).getType()
106-
or
107-
result = this.getAGeneratedMember().(NestedType)
112+
result = this.getAnInterestingBaseType() or
113+
result = this.getAGeneratedMember().(Callable).getReturnType() or
114+
result = this.getAGeneratedMember().(Callable).getAParameter().getType() or
115+
result = this.getAGeneratedMember().(Field).getType() or
116+
result = this.getAGeneratedMember().(NestedType) or
117+
result = this.(AnnotationType).getAnAnnotation().getType() or
118+
result = this.(AnnotationType).getAnAnnotation().getValue(_).getType() or
119+
result = this.(AnnotationType).getAnAnnotation().getAnArrayValue(_).getType()
108120
}
109121
}
110122

@@ -391,6 +403,47 @@ private string stubMember(Member m) {
391403
)
392404
}
393405

406+
language[monotonicAggregates]
407+
private string stubAnnotation(Annotation a) {
408+
if exists(a.getValue(_))
409+
then
410+
result =
411+
"@" + a.getType().getName() + "(" +
412+
concat(string name, Expr value |
413+
value = a.getValue(name)
414+
|
415+
name + "=" + stubAnnotationValue(value), ","
416+
) + ")"
417+
else result = "@" + a.getType().getName()
418+
}
419+
420+
language[monotonicAggregates]
421+
private string stubAnnotationValue(Expr value) {
422+
result = value.(FieldAccess).getField().getQualifiedName()
423+
or
424+
(
425+
value instanceof Literal or
426+
value instanceof CompileTimeConstantExpr
427+
) and
428+
if value instanceof StringLiteral
429+
then result = "\"\""
430+
else result = stubDefaultValue(value.getType())
431+
or
432+
result = stubAnnotation(value)
433+
or
434+
result = value.(TypeLiteral).getReferencedType().getName() + ".class"
435+
or
436+
value instanceof ArrayInit and
437+
result =
438+
"{" +
439+
concat(int i, Expr arrayElement |
440+
i >= 0 and
441+
arrayElement = value.(ArrayInit).getInit(i)
442+
|
443+
stubAnnotationValue(arrayElement), "," order by i
444+
) + "}"
445+
}
446+
394447
bindingset[s]
395448
private string indent(string s) { result = " " + s.replaceAll("\n", "\n ") + "\n" }
396449

java/ql/src/utils/stub-generator/makeStubs.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ def check_file_exists(path):
9999
dbDir = os.path.join(workDir, "db")
100100

101101

102-
def print_javac_output():
103-
logFiles = glob.glob(os.path.join(dbDir, "log", "javac-output*"))
102+
def print_javac_output(db_dir):
103+
logFiles = glob.glob(os.path.join(db_dir, "log", "javac-output*"))
104104

105105
if not(logFiles):
106106
print("\nNo javac output found.")
@@ -124,7 +124,7 @@ def run(cmd):
124124
print("Stubbing qltest in", testDir)
125125

126126
if run(['codeql', 'database', 'create', '--language=java', '--source-root='+projectDir, dbDir]):
127-
print_javac_output()
127+
print_javac_output(dbDir)
128128
print("codeql database create failed. Please fix up the test before proceeding.")
129129
exit(1)
130130

@@ -167,7 +167,9 @@ def run(cmd):
167167
print("Verifying stub correctness")
168168

169169
if run(['codeql', 'test', 'run', testDir]):
170-
print_javac_output()
170+
test_db_dir = glob.glob(os.path.join(testDir, "*.testproj"))
171+
if test_db_dir:
172+
print_javac_output(test_db_dir[0])
171173
print('\nTest failed. You may need to fix up the generated stubs.')
172174
exit(1)
173175

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
noGeneratedStubs
2+
multipleGeneratedStubs
3+
#select
4+
| org.test.SampleAnnotationType | // Generated automatically from org.test.SampleAnnotationType for testing purposes\n\npackage org.test;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Target;\n\n@Target(value={java.lang.annotation.ElementType.METHOD})public @interface SampleAnnotationType\n{\n}\n |
5+
| org.test.SampleType | // Generated automatically from org.test.SampleType for testing purposes\n\npackage org.test;\n\n\npublic class SampleType\n{\n public Object sampleField = null;\n public SampleType(){}\n public void sampleMethod(){}\n}\n |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
utils/stub-generator/MinimalStubsFromSource.ql
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import org.test.SampleAnnotationType;
2+
import org.test.SampleType;
3+
4+
public class Test {
5+
6+
@SampleAnnotationType
7+
public void test() {
8+
new SampleType().sampleField = null;
9+
new SampleType().sampleMethod();
10+
}
11+
12+
}
13+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
//semmle-extractor-options: --javac-args -cp ${testdir}/testlib.jar
Binary file not shown.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# testlib
2+
3+
Library for testing stub generation (we need a binary dependency because normal stubs are source files, and thus are excluded by the stub generator).
4+
5+
Run `generate.sh` to update `testlib.jar` in the test directory.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#/bin/bash
2+
javac org/test/*.java
3+
jar cf ../Minimal/testlib.jar org/test/*.class

0 commit comments

Comments
 (0)