📄 javacprocessingenvironment.java
字号:
} /** * Computes the set of annotations on the symbol in question. * Leave class public for external testing purposes. */ public static class ComputeAnnotationSet extends ElementScanner6<Set<TypeElement>, Set<TypeElement>> { final Elements elements; public ComputeAnnotationSet(Elements elements) { super(); this.elements = elements; } @Override public Set<TypeElement> visitPackage(PackageElement e, Set<TypeElement> p) { // Don't scan enclosed elements of a package return p; } @Override public Set<TypeElement> scan(Element e, Set<TypeElement> p) { for (AnnotationMirror annotationMirror : elements.getAllAnnotationMirrors(e) ) { Element e2 = annotationMirror.getAnnotationType().asElement(); p.add((TypeElement) e2); } return super.scan(e, p); } } private boolean callProcessor(Processor proc, Set<? extends TypeElement> tes, RoundEnvironment renv) { try { return proc.process(tes, renv); } catch (CompletionFailure ex) { StringWriter out = new StringWriter(); ex.printStackTrace(new PrintWriter(out)); log.error("proc.cant.access", ex.sym, ex.errmsg, out.toString()); return false; } catch (Throwable t) { throw new AnnotationProcessingError(t); } } // TODO: internal catch clauses?; catch and rethrow an annotation // processing error public JavaCompiler doProcessing(Context context, List<JCCompilationUnit> roots, List<ClassSymbol> classSymbols, Iterable<? extends PackageSymbol> pckSymbols) throws IOException { log = Log.instance(context); // Writer for -XprintRounds and -XprintProcessorInfo data PrintWriter xout = context.get(Log.outKey); TaskListener taskListener = context.get(TaskListener.class); AnnotationCollector collector = new AnnotationCollector(); JavaCompiler compiler = JavaCompiler.instance(context); compiler.todo.clear(); // free the compiler's resources int round = 0; // List<JCAnnotation> annotationsPresentInSource = collector.findAnnotations(roots); List<ClassSymbol> topLevelClasses = getTopLevelClasses(roots); for (ClassSymbol classSym : classSymbols) topLevelClasses = topLevelClasses.prepend(classSym); List<PackageSymbol> packageInfoFiles = getPackageInfoFiles(roots); Set<PackageSymbol> specifiedPackages = new LinkedHashSet<PackageSymbol>(); for (PackageSymbol psym : pckSymbols) specifiedPackages.add(psym); this.specifiedPackages = Collections.unmodifiableSet(specifiedPackages); // Use annotation processing to compute the set of annotations present Set<TypeElement> annotationsPresent = new LinkedHashSet<TypeElement>(); ComputeAnnotationSet annotationComputer = new ComputeAnnotationSet(elementUtils); for (ClassSymbol classSym : topLevelClasses) annotationComputer.scan(classSym, annotationsPresent); for (PackageSymbol pkgSym : packageInfoFiles) annotationComputer.scan(pkgSym, annotationsPresent); Context currentContext = context; int roundNumber = 0; boolean errorStatus = false; runAround: while(true) { if (fatalErrors && compiler.errorCount() != 0) { errorStatus = true; break runAround; } this.context = currentContext; roundNumber++; printRoundInfo(xout, roundNumber, topLevelClasses, annotationsPresent, false); if (taskListener != null) taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND)); try { discoverAndRunProcs(currentContext, annotationsPresent, topLevelClasses, packageInfoFiles); } finally { if (taskListener != null) taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND)); } /* * Processors for round n have run to completion. Prepare * for round (n+1) by checked for errors raised by * annotation processors and then checking for syntax * errors on any generated source files. */ if (messager.errorRaised()) { errorStatus = true; break runAround; } else { if (moreToDo()) { // annotationsPresentInSource = List.nil(); annotationsPresent = new LinkedHashSet<TypeElement>(); topLevelClasses = List.nil(); packageInfoFiles = List.nil(); compiler.close(); currentContext = contextForNextRound(currentContext, true); JavaFileManager fileManager = currentContext.get(JavaFileManager.class); List<JavaFileObject> fileObjects = List.nil(); for (JavaFileObject jfo : filer.getGeneratedSourceFileObjects() ) { fileObjects = fileObjects.prepend(jfo); } compiler = JavaCompiler.instance(currentContext); List<JCCompilationUnit> parsedFiles = compiler.parseFiles(fileObjects); roots = cleanTrees(roots).reverse(); for (JCCompilationUnit unit : parsedFiles) roots = roots.prepend(unit); roots = roots.reverse(); // Check for errors after parsing if (compiler.parseErrors()) { errorStatus = true; break runAround; } else { ListBuffer<ClassSymbol> classes = enterNewClassFiles(currentContext); compiler.enterTrees(roots); // annotationsPresentInSource = // collector.findAnnotations(parsedFiles); classes.appendList(getTopLevelClasses(parsedFiles)); topLevelClasses = classes.toList(); packageInfoFiles = getPackageInfoFiles(parsedFiles); annotationsPresent = new LinkedHashSet<TypeElement>(); for (ClassSymbol classSym : topLevelClasses) annotationComputer.scan(classSym, annotationsPresent); for (PackageSymbol pkgSym : packageInfoFiles) annotationComputer.scan(pkgSym, annotationsPresent); updateProcessingState(currentContext, false); } } else break runAround; // No new files } } runLastRound(xout, roundNumber, errorStatus, taskListener); compiler.close(); currentContext = contextForNextRound(currentContext, true); compiler = JavaCompiler.instance(currentContext); filer.newRound(currentContext, true); filer.warnIfUnclosedFiles(); warnIfUnmatchedOptions(); /* * If an annotation processor raises an error in a round, * that round runs to completion and one last round occurs. * The last round may also occur because no more source or * class files have been generated. Therefore, if an error * was raised on either of the last *two* rounds, the compile * should exit with a nonzero exit code. The current value of * errorStatus holds whether or not an error was raised on the * second to last round; errorRaised() gives the error status * of the last round. */ errorStatus = errorStatus || messager.errorRaised(); // Free resources this.close(); if (taskListener != null) taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING)); if (errorStatus) { compiler.log.nerrors += messager.errorCount(); if (compiler.errorCount() == 0) compiler.log.nerrors++; } else if (procOnly) { compiler.todo.clear(); } else { // Final compilation compiler.close(); currentContext = contextForNextRound(currentContext, true); compiler = JavaCompiler.instance(currentContext); if (true) { compiler.enterTrees(cleanTrees(roots)); } else { List<JavaFileObject> fileObjects = List.nil(); for (JCCompilationUnit unit : roots) fileObjects = fileObjects.prepend(unit.getSourceFile()); roots = null; compiler.enterTrees(compiler.parseFiles(fileObjects.reverse())); } } return compiler; } // Call the last round of annotation processing private void runLastRound(PrintWriter xout, int roundNumber, boolean errorStatus, TaskListener taskListener) throws IOException { roundNumber++; List<ClassSymbol> noTopLevelClasses = List.nil(); Set<TypeElement> noAnnotations = Collections.emptySet(); printRoundInfo(xout, roundNumber, noTopLevelClasses, noAnnotations, true); Set<Element> emptyRootElements = Collections.emptySet(); // immutable RoundEnvironment renv = new JavacRoundEnvironment(true, errorStatus, emptyRootElements, JavacProcessingEnvironment.this); if (taskListener != null) taskListener.started(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND)); try { discoveredProcs.iterator().runContributingProcs(renv); } finally { if (taskListener != null) taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND)); } } private void updateProcessingState(Context currentContext, boolean lastRound) { filer.newRound(currentContext, lastRound); messager.newRound(currentContext); elementUtils.setContext(currentContext); typeUtils.setContext(currentContext); } private void warnIfUnmatchedOptions() { if (!unmatchedProcessorOptions.isEmpty()) { log.warning("proc.unmatched.processor.options", unmatchedProcessorOptions.toString()); } } private void printRoundInfo(PrintWriter xout, int roundNumber, List<ClassSymbol> topLevelClasses, Set<TypeElement> annotationsPresent, boolean lastRound) { if (printRounds || verbose) { xout.println(Log.getLocalizedString("x.print.rounds", roundNumber, "{" + topLevelClasses.toString(", ") + "}", annotationsPresent, lastRound)); } } private ListBuffer<ClassSymbol> enterNewClassFiles(Context currentContext) { ClassReader reader = ClassReader.instance(currentContext); Name.Table names = Name.Table.instance(currentContext); ListBuffer<ClassSymbol> list = new ListBuffer<ClassSymbol>(); for (Map.Entry<String,JavaFileObject> entry : filer.getGeneratedClasses().entrySet()) { Name name = names.fromString(entry.getKey()); JavaFileObject file = entry.getValue(); if (file.getKind() != JavaFileObject.Kind.CLASS) throw new AssertionError(file); ClassSymbol cs = reader.enterClass(name, file); list.append(cs); } return list; } /** * Free resources related to annotation processing. */ public void close() { filer.close(); discoveredProcs = null; } private List<ClassSymbol> getTopLevelClasses(List<? extends JCCompilationUnit> units) { List<ClassSymbol> classes = List.nil(); for (JCCompilationUnit unit : units) { for (JCTree node : unit.defs) { if (node.getTag() == JCTree.CLASSDEF) { classes = classes.prepend(((JCClassDecl) node).sym); } } } return classes.reverse(); } private List<PackageSymbol> getPackageInfoFiles(List<? extends JCCompilationUnit> units) { List<PackageSymbol> packages = List.nil(); for (JCCompilationUnit unit : units) { boolean isPkgInfo = unit.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE); if (isPkgInfo) { packages = packages.prepend(unit.packge); } } return packages.reverse(); } private Context contextForNextRound(Context context, boolean shareNames) throws IOException { Context next = new Context(); Options options = Options.instance(context); assert options != null; next.put(Options.optionsKey, options); PrintWriter out = context.get(Log.outKey); assert out != null; next.put(Log.outKey, out); if (shareNames) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -