Skip to content

Commit a47a63c

Browse files
Enable parsing of annotations on parameters
1 parent bcb7c76 commit a47a63c

File tree

5 files changed

+145
-0
lines changed

5 files changed

+145
-0
lines changed

jbmc/src/java_bytecode/java_bytecode_parse_tree.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ struct java_bytecode_parse_treet
9898
return instructions.back();
9999
}
100100

101+
std::vector<annotationst> parameter_annotations;
102+
101103
struct exceptiont
102104
{
103105
exceptiont()

jbmc/src/java_bytecode/java_bytecode_parser.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,6 +1243,16 @@ void java_bytecode_parsert::rmethod_attribute(methodt &method)
12431243
{
12441244
rRuntimeAnnotation_attribute(method.annotations);
12451245
}
1246+
else if(
1247+
attribute_name == "RuntimeInvisibleParameterAnnotations" ||
1248+
attribute_name == "RuntimeVisibleParameterAnnotations")
1249+
{
1250+
u1 parameter_count = read_u1();
1251+
if(method.parameter_annotations.size() < parameter_count)
1252+
method.parameter_annotations.resize(parameter_count);
1253+
for(u2 param_no = 0; param_no < parameter_count; ++param_no)
1254+
rRuntimeAnnotation_attribute(method.parameter_annotations[param_no]);
1255+
}
12461256
else if(attribute_name == "Exceptions")
12471257
{
12481258
method.throws_exception_table = rexceptions_attribute();
Binary file not shown.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
@interface ClassAnnotation {
2+
}
3+
4+
@interface FieldAnnotation {
5+
}
6+
7+
@interface MethodAnnotation {
8+
}
9+
10+
@interface ParameterAnnotation {
11+
}
12+
13+
@ClassAnnotation
14+
public class AnnotationsEverywhere {
15+
@FieldAnnotation
16+
public int x;
17+
18+
@MethodAnnotation
19+
public void foo(@ParameterAnnotation int p)
20+
{
21+
}
22+
}

jbmc/unit/java_bytecode/java_bytecode_parser/parse_java_annotations.cpp

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,30 @@
1111
#include <java_bytecode/java_bytecode_parse_tree.h>
1212
#include <java_bytecode/java_types.h>
1313
#include <testing-utils/catch.hpp>
14+
#include <testing-utils/free_form_cmdline.h>
15+
#include <testing-utils/message.h>
16+
17+
class test_java_bytecode_languaget : public java_bytecode_languaget
18+
{
19+
public:
20+
std::vector<irep_idt> get_parsed_class_names()
21+
{
22+
std::vector<irep_idt> parsed_class_names;
23+
for(const auto &named_class
24+
: java_class_loader.get_class_with_overlays_map())
25+
{
26+
parsed_class_names.push_back(named_class.first);
27+
}
28+
return parsed_class_names;
29+
}
30+
31+
java_class_loadert::parse_tree_with_overlayst &get_parse_trees_for_class(
32+
const irep_idt &class_name)
33+
{
34+
//return java_class_loader(class_name);
35+
return java_class_loader.get_class_with_overlays_map().at(class_name);
36+
}
37+
};
1438

1539
// See
1640
// https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.16.1
@@ -91,5 +115,92 @@ SCENARIO(
91115
REQUIRE(java_type == void_type());
92116
}
93117
}
118+
WHEN("Parsing a class with annotations everywhere")
119+
{
120+
free_form_cmdlinet command_line;
121+
command_line.add_flag("no-lazy-methods");
122+
command_line.add_flag("no-refine-strings");
123+
test_java_bytecode_languaget language;
124+
language.set_message_handler(null_message_handler);
125+
language.get_language_options(command_line);
126+
127+
std::istringstream java_code_stream("ignored");
128+
language.parse(java_code_stream, "AnnotationsEverywhere.class");
129+
const java_class_loadert::parse_tree_with_overlayst &parse_trees =
130+
language.get_parse_trees_for_class("AnnotationsEverywhere");
131+
REQUIRE(parse_trees.size() == 1);
132+
const java_bytecode_parse_treet::classt &parsed_class =
133+
parse_trees.front().parsed_class;
134+
auto method_it = std::find_if(
135+
parsed_class.methods.begin(),
136+
parsed_class.methods.end(),
137+
[](const java_bytecode_parse_treet::methodt &method)
138+
{
139+
return method.name == "foo";
140+
});
141+
REQUIRE(method_it != parsed_class.methods.end());
142+
const java_bytecode_parse_treet::methodt &method = *method_it;
143+
144+
THEN("Only the correct annotation should be on the class")
145+
{
146+
const java_bytecode_parse_treet::annotationst &annotations =
147+
parsed_class.annotations;
148+
REQUIRE(annotations.size() == 1);
149+
const java_bytecode_parse_treet::annotationt &annotation =
150+
annotations.front();
151+
INVARIANT(
152+
annotation.type.id() == ID_pointer,
153+
"Annotation type should be pointer.");
154+
REQUIRE(
155+
annotation.type.subtype().get(ID_C_base_name) == "ClassAnnotation");
156+
}
157+
158+
THEN("Only the correct annotation should be on the field")
159+
{
160+
REQUIRE(parsed_class.fields.size() == 1);
161+
const java_bytecode_parse_treet::fieldt &field =
162+
parsed_class.fields.front();
163+
const java_bytecode_parse_treet::annotationst &annotations =
164+
field.annotations;
165+
REQUIRE(annotations.size() == 1);
166+
const java_bytecode_parse_treet::annotationt &annotation =
167+
annotations.front();
168+
INVARIANT(
169+
annotation.type.id() == ID_pointer,
170+
"Annotation type should be pointer.");
171+
REQUIRE(
172+
annotation.type.subtype().get(ID_C_base_name) == "FieldAnnotation");
173+
}
174+
175+
THEN("Only the correct annotation should be on the method")
176+
{
177+
const java_bytecode_parse_treet::annotationst &annotations =
178+
method.annotations;
179+
REQUIRE(annotations.size() == 1);
180+
const java_bytecode_parse_treet::annotationt &annotation =
181+
annotations.front();
182+
INVARIANT(
183+
annotation.type.id() == ID_pointer,
184+
"Annotation type should be pointer.");
185+
REQUIRE(
186+
annotation.type.subtype().get(ID_C_base_name) == "MethodAnnotation");
187+
}
188+
189+
THEN("Only the correct annotation should be on the parameter")
190+
{
191+
REQUIRE(method.parameter_annotations.size() == 1);
192+
const java_bytecode_parse_treet::annotationst &annotations =
193+
method.parameter_annotations.front();
194+
REQUIRE(annotations.size() == 1);
195+
const java_bytecode_parse_treet::annotationt &annotation =
196+
annotations.front();
197+
INVARIANT(
198+
annotation.type.id() == ID_pointer,
199+
"Annotation type should be pointer.");
200+
REQUIRE(
201+
annotation.type.subtype().get(ID_C_base_name) ==
202+
"ParameterAnnotation");
203+
}
204+
}
94205
}
95206
}

0 commit comments

Comments
 (0)