|
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 | + const std::set<irep_idt> &expectedAnnotations) |
| 47 | +{ |
| 48 | + REQUIRE(annotations.size() == expectedAnnotations.size()); |
| 49 | + std::set<irep_idt> annotation_names; |
| 50 | + std::transform( |
| 51 | + annotations.begin(), |
| 52 | + annotations.end(), |
| 53 | + std::inserter(annotation_names, annotation_names.end()), |
| 54 | + [&annotations](const java_bytecode_parse_treet::annotationt &annotation) |
| 55 | + { |
| 56 | + return get_base_name( |
| 57 | + require_type::require_pointer(annotations[0].type, {}).subtype()); |
| 58 | + }); |
| 59 | + auto result = std::mismatch( |
| 60 | + annotation_names.begin(), |
| 61 | + annotation_names.end(), |
| 62 | + expectedAnnotations.begin()); |
| 63 | + REQUIRE(result.first == annotation_names.end()); |
| 64 | +} |
14 | 65 |
|
15 | 66 | // See
|
16 | 67 | // https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.16.1
|
@@ -116,5 +167,63 @@ SCENARIO(
|
116 | 167 | REQUIRE(id2string(another_dave) == "Another Dave");
|
117 | 168 | }
|
118 | 169 | }
|
| 170 | + WHEN("Parsing a class with annotations everywhere") |
| 171 | + { |
| 172 | + free_form_cmdlinet command_line; |
| 173 | + command_line.add_flag("no-lazy-methods"); |
| 174 | + command_line.add_flag("no-refine-strings"); |
| 175 | + test_java_bytecode_languaget language; |
| 176 | + language.set_message_handler(null_message_handler); |
| 177 | + language.get_language_options(command_line); |
| 178 | + |
| 179 | + std::istringstream java_code_stream("ignored"); |
| 180 | + language.parse(java_code_stream, "AnnotationsEverywhere.class"); |
| 181 | + const java_class_loadert::parse_tree_with_overlayst &parse_trees = |
| 182 | + language.get_parse_trees_for_class("AnnotationsEverywhere"); |
| 183 | + REQUIRE(parse_trees.size() == 1); |
| 184 | + const java_bytecode_parse_treet::classt &parsed_class = |
| 185 | + parse_trees.front().parsed_class; |
| 186 | + |
| 187 | + THEN("Only the correct annotations should be on the class") |
| 188 | + { |
| 189 | + require_matching_annotations( |
| 190 | + parsed_class.annotations, |
| 191 | + { "ClassAnnotation", "RuntimeClassAnnotation" }); |
| 192 | + } |
| 193 | + |
| 194 | + THEN("Only the correct annotations should be on the field") |
| 195 | + { |
| 196 | + REQUIRE(parsed_class.fields.size() == 1); |
| 197 | + const java_bytecode_parse_treet::fieldt &field = |
| 198 | + parsed_class.fields.front(); |
| 199 | + require_matching_annotations( |
| 200 | + field.annotations, { "FieldAnnotation", "RuntimeFieldAnnotation" }); |
| 201 | + } |
| 202 | + |
| 203 | + auto method_it = std::find_if( |
| 204 | + parsed_class.methods.begin(), |
| 205 | + parsed_class.methods.end(), |
| 206 | + [](const java_bytecode_parse_treet::methodt &method) |
| 207 | + { |
| 208 | + return method.name == "foo"; |
| 209 | + }); |
| 210 | + REQUIRE(method_it != parsed_class.methods.end()); |
| 211 | + const java_bytecode_parse_treet::methodt &method = *method_it; |
| 212 | + |
| 213 | + THEN("Only the correct annotations should be on the method") |
| 214 | + { |
| 215 | + require_matching_annotations( |
| 216 | + method.annotations, |
| 217 | + { "MethodAnnotation", "RuntimeMethodAnnotation" }); |
| 218 | + } |
| 219 | + |
| 220 | + THEN("Only the correct annotations should be on the parameter") |
| 221 | + { |
| 222 | + REQUIRE(method.parameter_annotations.size() == 1); |
| 223 | + require_matching_annotations( |
| 224 | + method.parameter_annotations.front(), |
| 225 | + { "ParameterAnnotation", "RuntimeParameterAnnotation" }); |
| 226 | + } |
| 227 | + } |
119 | 228 | }
|
120 | 229 | }
|
0 commit comments