Skip to content

Commit a1b8be2

Browse files
committed
Add support for Java annotations with Class value
Java annotations can store element-value pairs, where each value is of type String, Enum, Class, annotation, array or a primitive type. The Class case was among the cases that did not have support in the java bytecode parser before. For minimal support (without storing any reference to java.lang.Class), we can just store the name of the type as retrieved from the constant pool in a symbol_exprt.
1 parent 9905440 commit a1b8be2

11 files changed

+109
-2
lines changed

jbmc/src/java_bytecode/java_bytecode_parser.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,6 +1509,8 @@ void java_bytecode_parsert::relement_value_pairs(
15091509
}
15101510
}
15111511

1512+
/// Corresponds to the element_value structure
1513+
/// Described in Java 8 specification 4.7.16.1
15121514
void java_bytecode_parsert::relement_value_pair(
15131515
annotationt::element_value_pairt &element_value_pair)
15141516
{
@@ -1526,8 +1528,8 @@ void java_bytecode_parsert::relement_value_pair(
15261528

15271529
case 'c':
15281530
{
1529-
UNUSED u2 class_info_index=read_u2();
1530-
// todo: class
1531+
u2 class_info_index=read_u2();
1532+
element_value_pair.value = symbol_exprt(pool_entry(class_info_index).s);
15311533
}
15321534
break;
15331535

Binary file not shown.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
public @interface AnnotationWithClassType {
2+
Class<?> value();
3+
}
Binary file not shown.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@AnnotationWithClassType(java.lang.String.class)
2+
public class ClassWithClassTypeAnnotation {
3+
}
Binary file not shown.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@AnnotationWithClassType(byte.class)
2+
public class ClassWithPrimitiveTypeAnnotation {
3+
}
Binary file not shown.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@AnnotationWithClassType(void.class)
2+
public class ClassWithVoidTypeAnnotation {
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
java-testing-utils
2+
testing-utils
3+
java_bytecode
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*******************************************************************\
2+
3+
Module: Unit tests for converting annotations
4+
5+
Author: Diffblue Ltd.
6+
7+
\*******************************************************************/
8+
9+
#include <java-testing-utils/load_java_class.h>
10+
#include <testing-utils/catch.hpp>
11+
#include <java_bytecode/java_types.h>
12+
#include <java_bytecode/java_bytecode_parse_tree.h>
13+
#include <java_bytecode/java_bytecode_convert_class.h>
14+
15+
// See
16+
// https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.16.1
17+
SCENARIO(
18+
"java_bytecode_parse_annotations",
19+
"[core][java_bytecode][java_bytecode_parser]")
20+
{
21+
GIVEN("Some class files in the class path")
22+
{
23+
WHEN("Parsing an annotation with Class value specified to non-primitive")
24+
{
25+
const symbol_tablet &new_symbol_table = load_java_class(
26+
"ClassWithClassTypeAnnotation",
27+
"./java_bytecode/java_bytecode_parser");
28+
29+
THEN("The annotation should store the correct type")
30+
{
31+
const symbolt &class_symbol =
32+
*new_symbol_table.lookup("java::ClassWithClassTypeAnnotation");
33+
const std::vector<java_annotationt> &java_annotations =
34+
to_annotated_type(class_symbol.type).get_annotations();
35+
java_bytecode_parse_treet::annotationst annotations;
36+
convert_java_annotations(java_annotations, annotations);
37+
REQUIRE(annotations.size() == 1);
38+
const auto &annotation = annotations.front();
39+
const auto &element_value_pair = annotation.element_value_pairs.front();
40+
const auto &id = to_symbol_expr(element_value_pair.value)
41+
.get_identifier();
42+
REQUIRE(id2string(id) == "Ljava/lang/String;");
43+
}
44+
}
45+
WHEN("Parsing an annotation with Class value specified to primitive")
46+
{
47+
const symbol_tablet &new_symbol_table = load_java_class(
48+
"ClassWithPrimitiveTypeAnnotation",
49+
"./java_bytecode/java_bytecode_parser");
50+
51+
THEN("The annotation should store the correct type")
52+
{
53+
const symbolt &class_symbol =
54+
*new_symbol_table.lookup("java::ClassWithPrimitiveTypeAnnotation");
55+
const std::vector<java_annotationt> &java_annotations =
56+
to_annotated_type(class_symbol.type).get_annotations();
57+
java_bytecode_parse_treet::annotationst annotations;
58+
convert_java_annotations(java_annotations, annotations);
59+
REQUIRE(annotations.size() == 1);
60+
const auto &annotation = annotations.front();
61+
const auto &element_value_pair = annotation.element_value_pairs.front();
62+
const auto &id = to_symbol_expr(element_value_pair.value)
63+
.get_identifier();
64+
REQUIRE(id2string(id) == "B");
65+
}
66+
}
67+
WHEN("Parsing an annotation with Class value specified to void")
68+
{
69+
const symbol_tablet &new_symbol_table = load_java_class(
70+
"ClassWithVoidTypeAnnotation",
71+
"./java_bytecode/java_bytecode_parser");
72+
73+
THEN("The annotation should store the correct type")
74+
{
75+
const symbolt &class_symbol =
76+
*new_symbol_table.lookup("java::ClassWithVoidTypeAnnotation");
77+
const std::vector<java_annotationt> &java_annotations =
78+
to_annotated_type(class_symbol.type).get_annotations();
79+
java_bytecode_parse_treet::annotationst annotations;
80+
convert_java_annotations(java_annotations, annotations);
81+
REQUIRE(annotations.size() == 1);
82+
const auto &annotation = annotations.front();
83+
const auto &element_value_pair = annotation.element_value_pairs.front();
84+
const auto &id = to_symbol_expr(element_value_pair.value)
85+
.get_identifier();
86+
REQUIRE(id2string(id) == "V");
87+
}
88+
}
89+
}
90+
}

0 commit comments

Comments
 (0)