1/* 2 * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/* 25 * @test 26 * @bug 8171355 27 * @summary Test behavior of javax.lang.model.util.Elements.getOrigin. 28 * @library /tools/lib 29 * @modules jdk.compiler/com.sun.tools.javac.api 30 * jdk.compiler/com.sun.tools.javac.main 31 * jdk.jdeps/com.sun.tools.classfile 32 * @build toolbox.ToolBox toolbox.JavacTask toolbox.TestRunner 33 * @build TestOrigin 34 * @run main TestOrigin 35 */ 36 37import java.io.OutputStream; 38import java.nio.file.Files; 39import java.nio.file.Path; 40import java.nio.file.Paths; 41import java.util.ArrayList; 42import java.util.Arrays; 43import java.util.Collections; 44import java.util.HashMap; 45import java.util.List; 46import java.util.Map; 47import java.util.Set; 48 49import javax.annotation.processing.*; 50import javax.lang.model.SourceVersion; 51import javax.lang.model.element.*; 52import javax.lang.model.element.ModuleElement.Directive; 53import javax.lang.model.element.ModuleElement.ExportsDirective; 54import javax.lang.model.element.ModuleElement.OpensDirective; 55import javax.lang.model.element.ModuleElement.RequiresDirective; 56import javax.lang.model.util.Elements; 57 58import com.sun.tools.classfile.Attribute; 59import com.sun.tools.classfile.Attributes; 60import com.sun.tools.classfile.ClassFile; 61import com.sun.tools.classfile.ClassWriter; 62import com.sun.tools.classfile.Module_attribute; 63import com.sun.tools.classfile.Module_attribute.ExportsEntry; 64import com.sun.tools.classfile.Module_attribute.OpensEntry; 65import com.sun.tools.classfile.Module_attribute.RequiresEntry; 66import toolbox.JavacTask; 67import toolbox.Task; 68import toolbox.TestRunner; 69import toolbox.ToolBox; 70 71public class TestOrigin extends TestRunner { 72 73 private final ToolBox tb; 74 75 TestOrigin() { 76 super(System.err); 77 tb = new ToolBox(); 78 } 79 80 public static void main(String... args) throws Exception { 81 new TestOrigin().runTests(m -> new Object[] { Paths.get(m.getName()) }); 82 } 83 84 @Test 85 public void testGeneratedConstr(Path base) throws Exception { 86 Path src = base.resolve("src"); 87 tb.writeJavaFiles(src, 88 "package test; public class Test { private void test() { } }", 89 "class Dummy {}"); 90 Path classes = base.resolve("classes"); 91 tb.createDirectories(classes); 92 93 List<String> log; 94 List<String> expected; 95 96 //from source: 97 log = new JavacTask(tb) 98 .options("-processor", ListMembersAP.class.getName()) 99 .outdir(classes) 100 .files(tb.findJavaFiles(src)) 101 .run() 102 .writeAll() 103 .getOutputLines(Task.OutputKind.STDOUT); 104 105 expected = Arrays.asList( 106 "<init>:MANDATED", 107 "test:EXPLICIT"); 108 109 if (!expected.equals(log)) 110 throw new AssertionError("expected output not found: " + log); 111 112 //from class: 113 log = new JavacTask(tb) 114 .options("-classpath", classes.toString(), 115 "-processorpath", System.getProperty("test.classes"), 116 "-processor", ListMembersAP.class.getName()) 117 .outdir(classes) 118 .files(src.resolve("Dummy.java")) 119 .run() 120 .writeAll() 121 .getOutputLines(Task.OutputKind.STDOUT); 122 123 expected = Arrays.asList( 124 "<init>:EXPLICIT", 125 "test:EXPLICIT"); 126 127 if (!expected.equals(log)) 128 throw new AssertionError("expected output not found: " + log); 129 } 130 131 @SupportedAnnotationTypes("*") 132 public static final class ListMembersAP extends AbstractProcessor { 133 134 @Override 135 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 136 if (!roundEnv.processingOver()) 137 return false; 138 139 Elements elements = processingEnv.getElementUtils(); 140 TypeElement test = elements.getTypeElement("test.Test"); 141 List<? extends Element> members = new ArrayList<>(test.getEnclosedElements()); 142 143 Collections.sort(members, 144 (e1, e2) -> e1.getSimpleName().toString().compareTo(e2.getSimpleName().toString())); 145 146 for (Element el : members) { 147 System.out.println(el.getSimpleName() + ":" + elements.getOrigin(el)); 148 } 149 150 return false; 151 } 152 153 @Override 154 public SourceVersion getSupportedSourceVersion() { 155 return SourceVersion.latestSupported(); 156 } 157 158 } 159 160 @Test 161 public void testRepeatableAnnotations(Path base) throws Exception { 162 Path src = base.resolve("src"); 163 tb.writeJavaFiles(src, 164 "package test; @A @A public class Test { }", 165 "package test;" + 166 "import java.lang.annotation.*;" + 167 "@Repeatable(Container.class)" + 168 "@Retention(RetentionPolicy.CLASS)" + 169 "@interface A {}", 170 "package test; @interface Container { A[] value(); }", 171 "class Dummy {}"); 172 Path classes = base.resolve("classes"); 173 tb.createDirectories(classes); 174 175 List<String> log; 176 List<String> expected; 177 178 //from source: 179 log = new JavacTask(tb) 180 .options("-processor", ListAnnotationsAP.class.getName()) 181 .outdir(classes) 182 .files(tb.findJavaFiles(src)) 183 .run() 184 .writeAll() 185 .getOutputLines(Task.OutputKind.STDOUT); 186 187 expected = Arrays.asList("test.Container:MANDATED"); 188 189 if (!expected.equals(log)) 190 throw new AssertionError("expected output not found: " + log); 191 192 //from class: 193 log = new JavacTask(tb) 194 .options("-classpath", classes.toString(), 195 "-processorpath", System.getProperty("test.classes"), 196 "-processor", ListAnnotationsAP.class.getName()) 197 .outdir(classes) 198 .files(src.resolve("Dummy.java")) 199 .run() 200 .writeAll() 201 .getOutputLines(Task.OutputKind.STDOUT); 202 203 expected = Arrays.asList("test.Container:EXPLICIT"); 204 205 if (!expected.equals(log)) 206 throw new AssertionError("expected output not found: " + log); 207 } 208 209 @SupportedAnnotationTypes("*") 210 public static final class ListAnnotationsAP extends AbstractProcessor { 211 212 @Override 213 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 214 if (!roundEnv.processingOver()) 215 return false; 216 217 Elements elements = processingEnv.getElementUtils(); 218 TypeElement test = elements.getTypeElement("test.Test"); 219 220 for (AnnotationMirror am : test.getAnnotationMirrors()) { 221 System.out.println(am.getAnnotationType() + ":" + elements.getOrigin(test, am)); 222 } 223 224 return false; 225 } 226 227 @Override 228 public SourceVersion getSupportedSourceVersion() { 229 return SourceVersion.latestSupported(); 230 } 231 232 } 233 234 @Test 235 public void testModuleDirectives(Path base) throws Exception { 236 Path src = base.resolve("src"); 237 tb.writeJavaFiles(src, 238 "module m {}", 239 "package p1; class Test {}", 240 "package p2; class Test {}", 241 "package p3; class Test {}", 242 "package test; class Dummy {}"); 243 Path classes = base.resolve("classes"); 244 tb.createDirectories(classes); 245 246 List<String> log; 247 List<String> expected; 248 249 //from source: 250 log = new JavacTask(tb) 251 .options("-processor", ListModuleAP.class.getName()) 252 .outdir(classes) 253 .files(tb.findJavaFiles(src)) 254 .run() 255 .writeAll() 256 .getOutputLines(Task.OutputKind.STDOUT); 257 258 expected = Arrays.asList("REQUIRES:java.base:MANDATED"); 259 260 if (!expected.equals(log)) 261 throw new AssertionError("expected output not found: " + log); 262 263 tb.writeJavaFiles(src, 264 "module m {" + 265 " requires java.base;" + 266 " requires java.compiler;" + 267 " requires jdk.compiler;" + 268 " exports p1;" + 269 " exports p2;" + 270 " exports p3;" + 271 " opens p1;" + 272 " opens p2;" + 273 " opens p3;" + 274 "}"); 275 276 new JavacTask(tb) 277 .outdir(classes) 278 .files(src.resolve("module-info.java")) 279 .run() 280 .writeAll(); 281 282 Path moduleInfo = classes.resolve("module-info.class"); 283 ClassFile cf = ClassFile.read(moduleInfo); 284 Module_attribute module = (Module_attribute) cf.getAttribute(Attribute.Module); 285 286 RequiresEntry[] newRequires = new RequiresEntry[3]; 287 newRequires[0] = new RequiresEntry(module.requires[0].requires_index, 288 Module_attribute.ACC_MANDATED, 289 module.requires[0].requires_version_index); 290 newRequires[1] = new RequiresEntry(module.requires[1].requires_index, 291 Module_attribute.ACC_SYNTHETIC, 292 module.requires[1].requires_version_index); 293 newRequires[2] = module.requires[2]; 294 295 ExportsEntry[] newExports = new ExportsEntry[3]; 296 newExports[0] = new ExportsEntry(module.exports[0].exports_index, 297 Module_attribute.ACC_MANDATED, 298 module.exports[0].exports_to_index); 299 newExports[1] = new ExportsEntry(module.exports[1].exports_index, 300 Module_attribute.ACC_SYNTHETIC, 301 module.exports[1].exports_to_index); 302 newExports[2] = module.exports[2]; 303 304 OpensEntry[] newOpens = new OpensEntry[3]; 305 newOpens[0] = new OpensEntry(module.opens[0].opens_index, 306 Module_attribute.ACC_MANDATED, 307 module.opens[0].opens_to_index); 308 newOpens[1] = new OpensEntry(module.opens[1].opens_index, 309 Module_attribute.ACC_SYNTHETIC, 310 module.opens[1].opens_to_index); 311 newOpens[2] = module.opens[2]; 312 313 Module_attribute newModule = new Module_attribute(module.attribute_name_index, 314 module.module_name, 315 module.module_flags, 316 module.module_version_index, 317 newRequires, 318 newExports, 319 newOpens, 320 module.uses_index, 321 module.provides); 322 Map<String, Attribute> newAttributesMap = new HashMap<>(cf.attributes.map); 323 324 newAttributesMap.put(Attribute.Module, newModule); 325 326 Attributes newAttributes = new Attributes(newAttributesMap); 327 ClassFile newClassFile = new ClassFile(cf.magic, 328 cf.minor_version, 329 cf.major_version, 330 cf.constant_pool, 331 cf.access_flags, 332 cf.this_class, 333 cf.super_class, 334 cf.interfaces, 335 cf.fields, 336 cf.methods, 337 newAttributes); 338 339 try (OutputStream out = Files.newOutputStream(moduleInfo)) { 340 new ClassWriter().write(newClassFile, out); 341 } 342 343 //from class: 344 log = new JavacTask(tb) 345 .options("-processor", ListModuleAP.class.getName()) 346 .outdir(classes) 347 .files(src.resolve("test").resolve("Dummy.java")) 348 .run() 349 .writeAll() 350 .getOutputLines(Task.OutputKind.STDOUT); 351 352 expected = Arrays.asList( 353 "REQUIRES:java.base:MANDATED", 354 "REQUIRES:java.compiler:SYNTHETIC", 355 "REQUIRES:jdk.compiler:EXPLICIT", 356 "EXPORTS:p1:MANDATED", 357 "EXPORTS:p2:SYNTHETIC", 358 "EXPORTS:p3:EXPLICIT", 359 "OPENS:p1:MANDATED", 360 "OPENS:p2:SYNTHETIC", 361 "OPENS:p3:EXPLICIT"); 362 363 if (!expected.equals(log)) 364 throw new AssertionError("expected output not found: " + log); 365 } 366 367 @SupportedAnnotationTypes("*") 368 public static final class ListModuleAP extends AbstractProcessor { 369 370 @Override 371 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 372 if (!roundEnv.processingOver()) 373 return false; 374 375 Elements elements = processingEnv.getElementUtils(); 376 ModuleElement m = elements.getModuleElement("m"); 377 378 for (Directive d : m.getDirectives()) { 379 switch (d.getKind()) { 380 case REQUIRES: 381 RequiresDirective rd = (RequiresDirective) d; 382 System.out.println(rd.getKind() + ":" + 383 rd.getDependency().getQualifiedName() + ":" + 384 elements.getOrigin(m, rd)); 385 break; 386 case EXPORTS: 387 ExportsDirective ed = (ExportsDirective) d; 388 System.out.println(ed.getKind() + ":" + 389 ed.getPackage() + ":" + 390 elements.getOrigin(m, ed)); 391 break; 392 case OPENS: 393 OpensDirective od = (OpensDirective) d; 394 System.out.println(od.getKind() + ":" + 395 od.getPackage() + ":" + 396 elements.getOrigin(m, od)); 397 break; 398 } 399 } 400 401 return false; 402 } 403 404 @Override 405 public SourceVersion getSupportedSourceVersion() { 406 return SourceVersion.latestSupported(); 407 } 408 409 } 410 411} 412