Processor.java revision 3155:30e288cb2d22
1/* 2 * Copyright (c) 2013, 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 24import java.io.File; 25import java.io.IOException; 26import java.io.Writer; 27import java.net.URI; 28import java.net.URISyntaxException; 29import java.util.Arrays; 30import java.util.Comparator; 31import java.util.Map; 32import java.util.Map.Entry; 33import java.util.Set; 34import java.util.TreeMap; 35import javax.annotation.processing.AbstractProcessor; 36import javax.annotation.processing.RoundEnvironment; 37import javax.annotation.processing.SupportedAnnotationTypes; 38import javax.annotation.processing.SupportedOptions; 39import javax.lang.model.element.TypeElement; 40import javax.tools.Diagnostic; 41import javax.tools.DiagnosticCollector; 42import javax.tools.DiagnosticListener; 43import javax.tools.FileObject; 44import javax.tools.ForwardingJavaFileManager; 45import javax.tools.JavaFileManager; 46import javax.tools.JavaFileObject; 47import javax.tools.JavaFileObject.Kind; 48import javax.tools.SimpleJavaFileObject; 49import com.sun.source.tree.AnnotationTree; 50import com.sun.source.tree.CompilationUnitTree; 51import com.sun.source.tree.LiteralTree; 52import com.sun.source.util.JavacTask; 53import com.sun.source.util.TreeScanner; 54import com.sun.source.util.Trees; 55import com.sun.tools.javac.api.JavacTool; 56import com.sun.tools.javac.file.JavacFileManager; 57import com.sun.tools.javac.util.Assert; 58 59@SupportedAnnotationTypes("*") 60@SupportedOptions("target") 61public class Processor extends AbstractProcessor { 62 63 private int round = 0; 64 @Override 65 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 66 if (round++ == 0) { 67 try (Writer out = processingEnv.getFiler() 68 .createSourceFile("Anno.java") 69 .openWriter()) { 70 String target = processingEnv.getOptions().get("target"); 71 String code = "import java.lang.annotation.ElementType;\n" + 72 "import java.lang.annotation.Target;\n" + 73 "@Target(ElementType." + target + ")\n" + 74 "@interface Anno { public String value(); }\n"; 75 out.write(code); 76 } catch (IOException exc) { 77 throw new IllegalStateException(exc); 78 } 79 } 80 return true; 81 } 82 83 public static void main(String... args) throws IOException, URISyntaxException { 84 if (args.length != 1) throw new IllegalStateException("Must provide class name!"); 85 String testContent = null; 86 File testSrc = new File(System.getProperty("test.src")); 87 File testFile = new File(testSrc, args[0]); 88 if (!testFile.canRead()) throw new IllegalStateException("Cannot read the test source"); 89 JavacTool compiler = JavacTool.create(); 90 JavacFileManager fm = compiler.getStandardFileManager(null, null, null); 91 testContent = fm.getJavaFileObject(testFile.toPath()).getCharContent(true).toString(); 92 JavaFileObject testFileObject = new TestFO(new URI("mem://" + args[0]), testContent); 93 TestFM testFileManager = new TestFM(fm); 94 JavacTask task = compiler.getTask(null, 95 testFileManager, 96 new DiagnosticCollector<JavaFileObject>(), 97 null, 98 null, 99 Arrays.asList(testFileObject)); 100 final Trees trees = Trees.instance(task); 101 final CompilationUnitTree cut = task.parse().iterator().next(); 102 103 final Map<int[], String> annotation2Target = new TreeMap<>(new Comparator<int[]>() { 104 @Override public int compare(int[] o1, int[] o2) { 105 return o2[0] - o1[0]; 106 } 107 }); 108 109 new TreeScanner<Void, Void>() { 110 @Override 111 public Void visitAnnotation(AnnotationTree node, Void p) { 112 int endPos = (int) trees.getSourcePositions().getEndPosition(cut, node); 113 114 Assert.check(endPos >= 0); 115 116 int startPos = (int) trees.getSourcePositions().getStartPosition(cut, node); 117 String target = ((LiteralTree) node.getArguments().get(0)).getValue().toString(); 118 119 annotation2Target.put(new int[] {startPos, endPos}, target); 120 121 return super.visitAnnotation(node, p); 122 } 123 }.scan(cut.getTypeDecls().get(0), null); 124 125 DiagnosticListener<JavaFileObject> noErrors = new DiagnosticListener<JavaFileObject>() { 126 @Override public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 127 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { 128 throw new IllegalStateException(diagnostic.toString()); 129 } 130 } 131 }; 132 133 for (Entry<int[], String> e : annotation2Target.entrySet()) { 134 StringBuilder updatedContent = new StringBuilder(); 135 int last = testContent.length(); 136 137 for (int[] toRemove : annotation2Target.keySet()) { 138 if (toRemove == e.getKey()) continue; 139 updatedContent.insert(0, testContent.substring(toRemove[1], last)); 140 last = toRemove[0]; 141 } 142 143 updatedContent.insert(0, testContent.substring(0, last)); 144 145 JavaFileObject updatedFile = new TestFO(new URI("mem://" + args[0]), 146 updatedContent.toString()); 147 JavacTask testTask = compiler.getTask(null, 148 testFileManager, 149 noErrors, 150 Arrays.asList("-processor", "Processor", 151 "-Atarget=" + e.getValue()), 152 null, 153 Arrays.asList(updatedFile)); 154 155 try { 156 testTask.analyze(); 157 } catch (Throwable exc) { 158 System.out.println("error while processing:"); 159 System.out.println(updatedContent); 160 throw exc; 161 } 162 163 JavacTask testTask2 = compiler.getTask(null, 164 testFileManager, 165 new DiagnosticCollector<JavaFileObject>(), 166 null, 167 null, 168 Arrays.asList(updatedFile)); 169 170 try { 171 testTask2.analyze(); 172 } catch (Throwable exc) { 173 System.out.println("error while processing:"); 174 System.out.println(updatedContent); 175 throw exc; 176 } 177 } 178 } 179 180 private static final class TestFO extends SimpleJavaFileObject { 181 private final String content; 182 public TestFO(URI uri, String content) { 183 super(uri, Kind.SOURCE); 184 this.content = content; 185 } 186 187 @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { 188 return content; 189 } 190 191 @Override public boolean isNameCompatible(String simpleName, Kind kind) { 192 return true; 193 } 194 } 195 196 private static final class TestFM extends ForwardingJavaFileManager<JavaFileManager> { 197 198 public TestFM(JavaFileManager fileManager) { 199 super(fileManager); 200 } 201 202 @Override 203 public boolean isSameFile(FileObject a, FileObject b) { 204 return a.equals(b); 205 } 206 207 } 208} 209