Skip to content

Commit 15dff7d

Browse files
Merge pull request diffblue#2260 from antlechner/antonia/annotation-class-value
Add support for Java annotations with Class value
2 parents e0a5142 + e0ad069 commit 15dff7d

11 files changed

+115
-2
lines changed

jbmc/src/java_bytecode/java_bytecode_parser.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -1514,6 +1514,9 @@ void java_bytecode_parsert::relement_value_pairs(
15141514
}
15151515
}
15161516

1517+
/// Corresponds to the element_value structure
1518+
/// Described in Java 8 specification 4.7.16.1
1519+
/// https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.16.1
15171520
void java_bytecode_parsert::relement_value_pair(
15181521
annotationt::element_value_pairt &element_value_pair)
15191522
{
@@ -1531,8 +1534,8 @@ void java_bytecode_parsert::relement_value_pair(
15311534

15321535
case 'c':
15331536
{
1534-
UNUSED u2 class_info_index=read_u2();
1535-
// todo: class
1537+
u2 class_info_index = read_u2();
1538+
element_value_pair.value = symbol_exprt(pool_entry(class_info_index).s);
15361539
}
15371540
break;
15381541

Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
public @interface AnnotationWithClassType {
2+
Class<?> value();
3+
}
Binary file not shown.
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.
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.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@AnnotationWithClassType(void.class)
2+
public class ClassWithVoidTypeAnnotation {
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
java-testing-utils
2+
testing-utils
3+
java_bytecode
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
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 <java_bytecode/java_bytecode_convert_class.h>
11+
#include <java_bytecode/java_bytecode_parse_tree.h>
12+
#include <java_bytecode/java_types.h>
13+
#include <testing-utils/catch.hpp>
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(
24+
"Parsing an annotation with Class value specified to non-primitive "
25+
"(java.lang.String)")
26+
{
27+
const symbol_tablet &new_symbol_table = load_java_class(
28+
"ClassWithClassTypeAnnotation", "./java_bytecode/java_bytecode_parser");
29+
30+
THEN("The annotation should store the correct type (String)")
31+
{
32+
const symbolt &class_symbol =
33+
*new_symbol_table.lookup("java::ClassWithClassTypeAnnotation");
34+
const std::vector<java_annotationt> &java_annotations =
35+
to_annotated_type(class_symbol.type).get_annotations();
36+
java_bytecode_parse_treet::annotationst annotations;
37+
convert_java_annotations(java_annotations, annotations);
38+
REQUIRE(annotations.size() == 1);
39+
const auto &annotation = annotations.front();
40+
const auto &element_value_pair = annotation.element_value_pairs.front();
41+
const auto &id =
42+
to_symbol_expr(element_value_pair.value).get_identifier();
43+
const auto &java_type = java_type_from_string(id2string(id));
44+
const std::string &class_name =
45+
id2string(to_symbol_type(java_type.subtype()).get_identifier());
46+
REQUIRE(id2string(class_name) == "java::java.lang.String");
47+
}
48+
}
49+
WHEN("Parsing an annotation with Class value specified to primitive (byte)")
50+
{
51+
const symbol_tablet &new_symbol_table = load_java_class(
52+
"ClassWithPrimitiveTypeAnnotation",
53+
"./java_bytecode/java_bytecode_parser");
54+
55+
THEN("The annotation should store the correct type (byte)")
56+
{
57+
const symbolt &class_symbol =
58+
*new_symbol_table.lookup("java::ClassWithPrimitiveTypeAnnotation");
59+
const std::vector<java_annotationt> &java_annotations =
60+
to_annotated_type(class_symbol.type).get_annotations();
61+
java_bytecode_parse_treet::annotationst annotations;
62+
convert_java_annotations(java_annotations, annotations);
63+
REQUIRE(annotations.size() == 1);
64+
const auto &annotation = annotations.front();
65+
const auto &element_value_pair = annotation.element_value_pairs.front();
66+
const auto &id =
67+
to_symbol_expr(element_value_pair.value).get_identifier();
68+
const auto &java_type = java_type_from_string(id2string(id));
69+
REQUIRE(java_type == java_byte_type());
70+
}
71+
}
72+
WHEN("Parsing an annotation with Class value specified to void")
73+
{
74+
const symbol_tablet &new_symbol_table = load_java_class(
75+
"ClassWithVoidTypeAnnotation", "./java_bytecode/java_bytecode_parser");
76+
77+
THEN("The annotation should store the correct type (void)")
78+
{
79+
const symbolt &class_symbol =
80+
*new_symbol_table.lookup("java::ClassWithVoidTypeAnnotation");
81+
const std::vector<java_annotationt> &java_annotations =
82+
to_annotated_type(class_symbol.type).get_annotations();
83+
java_bytecode_parse_treet::annotationst annotations;
84+
convert_java_annotations(java_annotations, annotations);
85+
REQUIRE(annotations.size() == 1);
86+
const auto &annotation = annotations.front();
87+
const auto &element_value_pair = annotation.element_value_pairs.front();
88+
const auto &id =
89+
to_symbol_expr(element_value_pair.value).get_identifier();
90+
const auto &java_type = java_type_from_string(id2string(id));
91+
REQUIRE(java_type == void_type());
92+
}
93+
}
94+
}
95+
}

0 commit comments

Comments
 (0)