|
7 | 7 | \*******************************************************************/
|
8 | 8 |
|
9 | 9 | #include <java-testing-utils/load_java_class.h>
|
| 10 | +#include <java-testing-utils/require_type.h> |
10 | 11 | #include <java_bytecode/java_bytecode_convert_class.h>
|
11 | 12 | #include <java_bytecode/java_bytecode_parse_tree.h>
|
12 | 13 | #include <java_bytecode/java_types.h>
|
13 | 14 | #include <testing-utils/catch.hpp>
|
| 15 | +#include <testing-utils/free_form_cmdline.h> |
| 16 | +#include <testing-utils/message.h> |
| 17 | + |
| 18 | +class test_java_bytecode_languaget : public java_bytecode_languaget |
| 19 | +{ |
| 20 | +public: |
| 21 | + std::vector<irep_idt> get_parsed_class_names() |
| 22 | + { |
| 23 | + std::vector<irep_idt> parsed_class_names; |
| 24 | + for(const auto &named_class |
| 25 | + : java_class_loader.get_class_with_overlays_map()) |
| 26 | + { |
| 27 | + parsed_class_names.push_back(named_class.first); |
| 28 | + } |
| 29 | + return parsed_class_names; |
| 30 | + } |
| 31 | + |
| 32 | + java_class_loadert::parse_tree_with_overlayst &get_parse_trees_for_class( |
| 33 | + const irep_idt &class_name) |
| 34 | + { |
| 35 | + return java_class_loader.get_class_with_overlays_map().at(class_name); |
| 36 | + } |
| 37 | +}; |
| 38 | + |
| 39 | +static irep_idt get_base_name(const typet &type) |
| 40 | +{ |
| 41 | + return type.get(ID_C_base_name); |
| 42 | +} |
| 43 | + |
| 44 | +static void require_matching_annotations( |
| 45 | + const java_bytecode_parse_treet::annotationst &annotations, |
| 46 | + std::vector<irep_idt> expected_annotations) |
| 47 | +{ |
| 48 | + std::vector<irep_idt> annotation_names; |
| 49 | + std::transform( |
| 50 | + annotations.begin(), |
| 51 | + annotations.end(), |
| 52 | + std::back_inserter(annotation_names), |
| 53 | + [](const java_bytecode_parse_treet::annotationt &annotation) |
| 54 | + { |
| 55 | + return get_base_name( |
| 56 | + require_type::require_pointer(annotation.type, {}).subtype()); |
| 57 | + }); |
| 58 | + std::sort(annotation_names.begin(), annotation_names.end()); |
| 59 | + std::sort(expected_annotations.begin(), expected_annotations.end()); |
| 60 | + REQUIRE_THAT( |
| 61 | + annotation_names, |
| 62 | + Catch::Matchers::Equals(expected_annotations)); |
| 63 | +} |
14 | 64 |
|
15 | 65 | // See
|
16 | 66 | // https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.16.1
|
@@ -116,5 +166,66 @@ SCENARIO(
|
116 | 166 | REQUIRE(id2string(another_dave) == "Another Dave");
|
117 | 167 | }
|
118 | 168 | }
|
| 169 | + WHEN("Parsing a class with annotations everywhere") |
| 170 | + { |
| 171 | + free_form_cmdlinet command_line; |
| 172 | + command_line.add_flag("no-lazy-methods"); |
| 173 | + command_line.add_flag("no-refine-strings"); |
| 174 | + test_java_bytecode_languaget language; |
| 175 | + language.set_message_handler(null_message_handler); |
| 176 | + language.get_language_options(command_line); |
| 177 | + |
| 178 | + std::istringstream java_code_stream("ignored"); |
| 179 | + language.parse(java_code_stream, "AnnotationsEverywhere.class"); |
| 180 | + const java_class_loadert::parse_tree_with_overlayst &parse_trees = |
| 181 | + language.get_parse_trees_for_class("AnnotationsEverywhere"); |
| 182 | + REQUIRE(parse_trees.size() == 1); |
| 183 | + const java_bytecode_parse_treet::classt &parsed_class = |
| 184 | + parse_trees.front().parsed_class; |
| 185 | + |
| 186 | + THEN("Only the correct annotations should be on the class") |
| 187 | + { |
| 188 | + require_matching_annotations( |
| 189 | + parsed_class.annotations, |
| 190 | + { "ClassAnnotation", "RuntimeClassAnnotation" }); |
| 191 | + } |
| 192 | + |
| 193 | + THEN("Only the correct annotations should be on the field") |
| 194 | + { |
| 195 | + REQUIRE(parsed_class.fields.size() == 1); |
| 196 | + const java_bytecode_parse_treet::fieldt &field = |
| 197 | + parsed_class.fields.front(); |
| 198 | + require_matching_annotations( |
| 199 | + field.annotations, { "FieldAnnotation", "RuntimeFieldAnnotation" }); |
| 200 | + } |
| 201 | + |
| 202 | + auto method_it = std::find_if( |
| 203 | + parsed_class.methods.begin(), |
| 204 | + parsed_class.methods.end(), |
| 205 | + [](const java_bytecode_parse_treet::methodt &method) |
| 206 | + { |
| 207 | + return method.name == "foo"; |
| 208 | + }); |
| 209 | + REQUIRE(method_it != parsed_class.methods.end()); |
| 210 | + const java_bytecode_parse_treet::methodt &method = *method_it; |
| 211 | + |
| 212 | + THEN("Only the correct annotations should be on the method") |
| 213 | + { |
| 214 | + require_matching_annotations( |
| 215 | + method.annotations, |
| 216 | + { "MethodAnnotation", "RuntimeMethodAnnotation" }); |
| 217 | + } |
| 218 | + |
| 219 | + THEN("Only the correct annotations should be on the parameter") |
| 220 | + { |
| 221 | + REQUIRE(method.parameter_annotations.size() == 2); |
| 222 | + require_matching_annotations( |
| 223 | + method.parameter_annotations[0], |
| 224 | + { "RuntimeParameterAnnotation" }); |
| 225 | + require_matching_annotations( |
| 226 | + method.parameter_annotations[1], |
| 227 | + { "ParameterAnnotation" }); |
| 228 | + } |
| 229 | + } |
119 | 230 | }
|
120 | 231 | }
|
0 commit comments