@Override public final void init(ProcessingEnvironment env) { super.init(env); JavacTask.instance(env).addTaskListener(listener); Context ctx = ((JavacProcessingEnvironment) processingEnv).getContext(); JavaCompiler compiler = JavaCompiler.instance(ctx); compiler.shouldStopPolicyIfNoError = CompileState.max(compiler.shouldStopPolicyIfNoError, CompileState.FLOW); }
/** Create the compiler to be used for the final compilation. */ JavaCompiler finalCompiler(boolean errorStatus) { try { JavaCompiler c = JavaCompiler.instance(nextContext()); c.log.nwarnings += compiler.log.nwarnings; if (errorStatus) { c.log.nerrors += compiler.log.nerrors; } return c; } finally { compiler.close(false); } }
protected void flow(Env<AttrContext> env, Queue<Env<AttrContext>> results) { if (env.toplevel.sourcefile instanceof CeylonFileObject) { try { Context.SourceLanguage.push(Language.CEYLON); super.flow(env, results); return; } finally { Context.SourceLanguage.pop(); } } super.flow(env, results); }
protected void desugar( final Env<AttrContext> env, Queue<Pair<Env<AttrContext>, JCClassDecl>> results) { if (env.toplevel.sourcefile instanceof CeylonFileObject) { try { Context.SourceLanguage.push(Language.CEYLON); super.desugar(env, results); return; } finally { Context.SourceLanguage.pop(); } } super.desugar(env, results); }
/** Create the next round to be used. */ Round next(Set<JavaFileObject> newSourceFiles, Map<String, JavaFileObject> newClassFiles) { try { return new Round(this, newSourceFiles, newClassFiles); } finally { compiler.close(false); } }
@Override public void generate( Queue<Pair<Env<AttrContext>, JCClassDecl>> queue, Queue<JavaFileObject> results) { timer.startTask("Generate"); super.generate(queue, results); timer.endTask(); }
/** Create a new round. */ private Round( Round prev, Set<JavaFileObject> newSourceFiles, Map<String, JavaFileObject> newClassFiles) { this(prev.nextContext(), prev.number + 1, prev.nMessagerErrors, prev.compiler.log.nwarnings); this.genClassFiles = prev.genClassFiles; List<JCCompilationUnit> parsedFiles = compiler.parseFiles(newSourceFiles); roots = cleanTrees(prev.roots).appendList(parsedFiles); // Check for errors after parsing if (unrecoverableError()) return; enterClassFiles(genClassFiles); List<ClassSymbol> newClasses = enterClassFiles(newClassFiles); genClassFiles.putAll(newClassFiles); enterTrees(roots); if (unrecoverableError()) return; topLevelClasses = join(getTopLevelClasses(parsedFiles), getTopLevelClassesFromClasses(newClasses)); packageInfoFiles = join(getPackageInfoFiles(parsedFiles), getPackageInfoFilesFromClasses(newClasses)); findAnnotationsPresent(); }
@Override public void close(boolean disposeNames) { if (resourceFileObjects != null) { addResources(); resourceFileObjects = null; } super.close(disposeNames); }
@Override public void complete(ClassSymbol c) throws CompletionFailure { try { Context.SourceLanguage.push(Language.JAVA); super.complete(c); } finally { Context.SourceLanguage.pop(); } }
/** Create a round (common code). */ private Round(Context context, int number, int priorErrors, int priorWarnings) { this.context = context; this.number = number; compiler = JavaCompiler.instance(context); log = Log.instance(context); log.nerrors = priorErrors; log.nwarnings += priorWarnings; log.deferDiagnostics = true; // the following is for the benefit of JavacProcessingEnvironment.getContext() JavacProcessingEnvironment.this.context = context; // the following will be populated as needed topLevelClasses = List.nil(); packageInfoFiles = List.nil(); }
@Override public void compile( List<JavaFileObject> fileObjects, List<String> classnames, Iterable<? extends Processor> processors) { // Now we first split the files into sources/modules and resources List<JavaFileObject> sourceFiles = List.nil(); List<JavaFileObject> resourceFiles = List.nil(); for (JavaFileObject fo : fileObjects) { if (isResource(fo)) { resourceFiles = resourceFiles.append(fo); } else { sourceFiles = sourceFiles.append(fo); } } this.resourceFileObjects = resourceFiles; // Add any module files for the resources (if needed) sourceFiles = addModuleDescriptors(sourceFiles, resourceFiles); // And then continue to the compilation of the source files super.compile(sourceFiles, classnames, processors); }
public boolean delombok() throws IOException { Options options = Options.instance(context); options.put(OptionName.ENCODING, charset.name()); if (classpath != null) options.put(OptionName.CLASSPATH, classpath); if (sourcepath != null) options.put(OptionName.SOURCEPATH, sourcepath); options.put("compilePolicy", "attr"); CommentCollectingScanner.Factory.preRegister(context); JavaCompiler compiler = new JavaCompiler(context); compiler.keepComments = true; compiler.genEndPos = true; List<JCCompilationUnit> roots = new ArrayList<JCCompilationUnit>(); Map<JCCompilationUnit, Comments> commentsMap = new IdentityHashMap<JCCompilationUnit, Comments>(); Map<JCCompilationUnit, File> baseMap = new IdentityHashMap<JCCompilationUnit, File>(); compiler.initProcessAnnotations(Collections.singleton(new lombok.javac.apt.Processor())); for (File fileToParse : filesToParse) { Comments comments = new Comments(); context.put(Comments.class, comments); @SuppressWarnings("deprecation") JCCompilationUnit unit = compiler.parse(fileToParse.getAbsolutePath()); commentsMap.put(unit, comments); baseMap.put(unit, fileToBase.get(fileToParse)); roots.add(unit); } if (compiler.errorCount() > 0) { // At least one parse error. No point continuing (a real javac run doesn't either). return false; } TrackChangedAsts tca = new TrackChangedAsts(); context.put(TrackChangedAsts.class, tca); JavaCompiler delegate = compiler.processAnnotations(compiler.enterTrees(toJavacList(roots))); for (JCCompilationUnit unit : roots) { DelombokResult result = new DelombokResult( commentsMap.get(unit).comments.toList(), unit, force || tca.changed.contains(unit)); if (verbose) feedback.printf( "File: %s [%s]\n", unit.sourcefile.getName(), result.isChanged() ? "delomboked" : "unchanged"); Writer rawWriter; if (presetWriter != null) rawWriter = presetWriter; else if (output == null) rawWriter = createStandardOutWriter(); else rawWriter = createFileWriter(output, baseMap.get(unit), unit.sourcefile.toUri()); BufferedWriter writer = new BufferedWriter(rawWriter); try { result.print(writer); } finally { writer.close(); } } delegate.close(); return true; }
private static void openAnnotatedJava() { // Create list with source code names @SuppressWarnings("unchecked") Vector<String> myfilelist = new Vector<String>(cmd.getArgList()); // Table that stores parsed compilation units Hashtable<String, CompilationUnit> myjpunitlist = new Hashtable<String, CompilationUnit>(); // Declare outside, so filename can be used in case of exception. // Generate AST with JavaParser for (Enumeration<String> e = myfilelist.elements(); e.hasMoreElements(); ) { String mysource = ""; CompilationUnit mycunit = null; try { // read filename mysource = e.nextElement(); // Compile it with java parser. mycunit = JavaParser.parse(new FileInputStream(mysource)); // Then fix the AST following the JC requirements ComplyToJCVisitor myfixervisitor = new ComplyToJCVisitor(); mycunit = (CompilationUnit) myfixervisitor.visit(mycunit, new Integer(0)); // creates an input stream and parse it using Java Parser myjpunitlist.put(mysource, mycunit); if (cmd.hasOption("d")) { // ASTDumpVisitor myjpvisitor = new ASTDumpVisitor(); DumpVisitor myjpvisitor = new DumpVisitor(); myjpvisitor.visit(myjpunitlist.get(mysource), null); System.out.print(myjpvisitor.getSource()); } } catch (com.github.javaparser.ParseException ex) { System.out.println("Error: Parsing of Java file failed: " + mysource + ". Exiting..."); System.exit(1); } catch (FileNotFoundException ex) { System.out.println("Error: File not found: " + mysource + ". Exiting..."); System.exit(1); } } // Building internals from Java Compiler Context mycontext = new Context(); JavaCompiler myjcompiler = new JavaCompiler(mycontext); JavaFileManager myfilemanager = mycontext.get(JavaFileManager.class); // Phase that Javac may go to: Setting code generation myjcompiler.shouldStopPolicyIfNoError = CompileState.GENERATE; // Table that stores the Java Compiler's ASTs List<JCCompilationUnit> ljctreelist = List.<JCCompilationUnit>nil(); // Convert to Java Parser AST to JCTree AST's for (Enumeration<String> e = myjpunitlist.keys(); e.hasMoreElements(); ) { // read filename String mysource = e.nextElement(); CompilationUnit myjpunit = myjpunitlist.get(mysource); JavaParser2JCTree translator = new JavaParser2JCTree(mycontext); AJCCompilationUnit myjctreeunit = (AJCCompilationUnit) translator.visit(myjpunit, myjpunit); // Setting additional information for Javac: // - Source file. Otherwise it throws a NullPointerException myjctreeunit.sourcefile = ((JavacFileManager) myfilemanager).getFileForInput(mysource); // Storing in the list ljctreelist = ljctreelist.append(myjctreeunit); // Debug: Shows how the JCTree AST was generated. Output node types. if (cmd.hasOption("d")) { try { Writer mystdout = new OutputStreamWriter(System.out); (new PrintAstVisitor(mystdout, true)).visitTopLevel(myjctreeunit); mystdout.flush(); } catch (Exception z) { } } } // Enter (phase I): starting to build symtable Enter myenter = Enter.instance(mycontext); myenter.main(ljctreelist); // Enter (phase II): Finishing to build symtable /* MemberEnter mymemberenter = MemberEnter.instance(mycontext); mymemberenter.visitTopLevel(myjctreeunit); */ // Get the todo list generated by Enter phase // From now on, the output of a phase is the input of the other. Todo mytodo = Todo.instance(mycontext); // atrribute: type-checking, name resolution, constant folding // flow: deadcode elimination // desugar: removes synctactic sugar: inner classes, class literals, assertions, foreachs myjcompiler.desugar(myjcompiler.flow(myjcompiler.attribute(mytodo))); // generate: produce bytecode or source code. Erases the whole AST // myjcompiler.generate(myjcompiler.desugar(myjcompiler.flow(myjcompiler.attribute( mytodo)))); // Prints the Java program to output files and leave for (ListIterator<JCCompilationUnit> i = ljctreelist.listIterator(); i.hasNext(); ) { JCCompilationUnit myjctreeunit = i.next(); try { Writer myoutputfile; if (cmd.getOptionValue("o") == null) { myoutputfile = new FileWriter(FileDescriptor.out); } else { myoutputfile = new FileWriter(myjctreeunit.sourcefile + ".new"); } (new APretty(myoutputfile, true)).visitTopLevel(myjctreeunit); myoutputfile.flush(); } catch (Exception e) { // TODO - Check what to report in case of error. } } }
/** * Get the context for the next round of processing. Important values are propogated from round * to round; other values are implicitly reset. */ private Context nextContext() { Context next = new Context(context); Options options = Options.instance(context); Assert.checkNonNull(options); next.put(Options.optionsKey, options); PrintWriter out = context.get(Log.outKey); Assert.checkNonNull(out); next.put(Log.outKey, out); Locale locale = context.get(Locale.class); if (locale != null) next.put(Locale.class, locale); Assert.checkNonNull(messages); next.put(JavacMessages.messagesKey, messages); final boolean shareNames = true; if (shareNames) { Names names = Names.instance(context); Assert.checkNonNull(names); next.put(Names.namesKey, names); } DiagnosticListener<?> dl = context.get(DiagnosticListener.class); if (dl != null) next.put(DiagnosticListener.class, dl); TaskListener tl = context.get(TaskListener.class); if (tl != null) next.put(TaskListener.class, tl); FSInfo fsInfo = context.get(FSInfo.class); if (fsInfo != null) next.put(FSInfo.class, fsInfo); JavaFileManager jfm = context.get(JavaFileManager.class); Assert.checkNonNull(jfm); next.put(JavaFileManager.class, jfm); if (jfm instanceof JavacFileManager) { ((JavacFileManager) jfm).setContext(next); } Names names = Names.instance(context); Assert.checkNonNull(names); next.put(Names.namesKey, names); Keywords keywords = Keywords.instance(context); Assert.checkNonNull(keywords); next.put(Keywords.keywordsKey, keywords); JavaCompiler oldCompiler = JavaCompiler.instance(context); JavaCompiler nextCompiler = JavaCompiler.instance(next); nextCompiler.initRound(oldCompiler); filer.newRound(next); messager.newRound(next); elementUtils.setContext(next); typeUtils.setContext(next); JavacTaskImpl task = context.get(JavacTaskImpl.class); if (task != null) { next.put(JavacTaskImpl.class, task); task.updateContext(next); } JavacTrees trees = context.get(JavacTrees.class); if (trees != null) { next.put(JavacTrees.class, trees); trees.updateContext(next); } context.clear(); return next; }
/** Enter a set of syntax trees. */ private void enterTrees(List<JCCompilationUnit> roots) { compiler.enterTrees(roots); }
/** Return the number of warnings found so far in this round. */ int warningCount() { return compiler.warningCount(); }
/** * Return the number of errors found so far in this round. This may include uncoverable errors, * such as parse errors, and transient errors, such as missing symbols. */ int errorCount() { return compiler.errorCount(); }
void createSymbols() throws IOException { Set<String> legacy = getLegacyPackages(); Set<String> legacyProprietary = getLegacyPackages(); Set<String> documented = new HashSet<String>(); Set<PackageSymbol> packages = ((JavacProcessingEnvironment) processingEnv).getSpecifiedPackages(); String jarName = processingEnv.getOptions().get("com.sun.tools.javac.sym.Jar"); if (jarName == null) throw new RuntimeException("Must use -Acom.sun.tools.javac.sym.Jar=LOCATION_OF_JAR"); String destName = processingEnv.getOptions().get("com.sun.tools.javac.sym.Dest"); if (destName == null) throw new RuntimeException("Must use -Acom.sun.tools.javac.sym.Dest=LOCATION_OF_JAR"); for (PackageSymbol psym : packages) { String name = psym.getQualifiedName().toString(); legacyProprietary.remove(name); documented.add(name); } JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null); Location jarLocation = StandardLocation.locationFor(jarName); File jarFile = new File(jarName); fm.setLocation(jarLocation, List.of(jarFile)); fm.setLocation(StandardLocation.CLASS_PATH, List.<File>nil()); fm.setLocation(StandardLocation.SOURCE_PATH, List.<File>nil()); { ArrayList<File> bootClassPath = new ArrayList<File>(); bootClassPath.add(jarFile); for (File path : fm.getLocation(StandardLocation.PLATFORM_CLASS_PATH)) { if (!new File(path.getName()).equals(new File("rt.jar"))) bootClassPath.add(path); } System.err.println("Using boot class path = " + bootClassPath); fm.setLocation(StandardLocation.PLATFORM_CLASS_PATH, bootClassPath); } // System.out.println(fm.getLocation(StandardLocation.PLATFORM_CLASS_PATH)); File destDir = new File(destName); if (!destDir.exists()) if (!destDir.mkdirs()) throw new RuntimeException("Could not create " + destDir); fm.setLocation(StandardLocation.CLASS_OUTPUT, List.of(destDir)); Set<String> hiddenPackages = new HashSet<String>(); Set<String> crisp = new HashSet<String>(); List<String> options = List.of("-XDdev"); // options = options.prepend("-doe"); // options = options.prepend("-verbose"); JavacTaskImpl task = (JavacTaskImpl) tool.getTask(null, fm, null, options, null, null); com.sun.tools.javac.main.JavaCompiler compiler = com.sun.tools.javac.main.JavaCompiler.instance(task.getContext()); ClassReader reader = ClassReader.instance(task.getContext()); ClassWriter writer = ClassWriter.instance(task.getContext()); Symtab syms = Symtab.instance(task.getContext()); Attribute.Compound proprietary = new Attribute.Compound( syms.proprietaryType, List.<Pair<Symbol.MethodSymbol, Attribute>>nil()); Type.moreInfo = true; Pool pool = new Pool(); for (JavaFileObject file : fm.list(jarLocation, "", EnumSet.of(CLASS), true)) { String className = fm.inferBinaryName(jarLocation, file); int index = className.lastIndexOf('.'); String pckName = index == -1 ? "" : className.substring(0, index); boolean addLegacyAnnotation = false; if (documented.contains(pckName)) { if (!legacy.contains(pckName)) crisp.add(pckName); // System.out.println("Documented: " + className); } else if (legacyProprietary.contains(pckName)) { addLegacyAnnotation = true; // System.out.println("Legacy proprietary: " + className); } else { // System.out.println("Hidden " + className); hiddenPackages.add(pckName); continue; } TypeSymbol sym = (TypeSymbol) compiler.resolveIdent(className); if (sym.kind != Kinds.TYP) { if (className.indexOf('$') < 0) { System.err.println("Ignoring (other) " + className + " : " + sym); System.err.println(" " + sym.getClass().getSimpleName() + " " + sym.type); } continue; } sym.complete(); if (sym.getEnclosingElement().getKind() != ElementKind.PACKAGE) { System.err.println("Ignoring (bad) " + sym.getQualifiedName()); continue; } ClassSymbol cs = (ClassSymbol) sym; if (addLegacyAnnotation) { cs.attributes_field = (cs.attributes_field == null) ? List.of(proprietary) : cs.attributes_field.prepend(proprietary); } writeClass(pool, cs, writer); } if (false) { for (String pckName : crisp) System.out.println("Crisp: " + pckName); for (String pckName : hiddenPackages) System.out.println("Hidden: " + pckName); for (String pckName : legacyProprietary) System.out.println("Legacy proprietary: " + pckName); for (String pckName : documented) System.out.println("Documented: " + pckName); } }
// 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) { TaskListener taskListener = context.get(TaskListener.class); log = Log.instance(context); Set<PackageSymbol> specifiedPackages = new LinkedHashSet<PackageSymbol>(); for (PackageSymbol psym : pckSymbols) specifiedPackages.add(psym); this.specifiedPackages = Collections.unmodifiableSet(specifiedPackages); Round round = new Round(context, roots, classSymbols); boolean errorStatus; boolean moreToDo; do { // Run processors for round n round.run(false, false); // Processors for round n have run to completion. // Check for errors and whether there is more work to do. errorStatus = round.unrecoverableError(); moreToDo = moreToDo(); round.showDiagnostics(errorStatus || showResolveErrors); // Set up next round. // Copy mutable collections returned from filer. round = round.next( new LinkedHashSet<JavaFileObject>(filer.getGeneratedSourceFileObjects()), new LinkedHashMap<String, JavaFileObject>(filer.getGeneratedClasses())); // Check for errors during setup. if (round.unrecoverableError()) errorStatus = true; } while (moreToDo && !errorStatus); // run last round round.run(true, errorStatus); round.showDiagnostics(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. */ if (messager.errorRaised() || werror && round.warningCount() > 0 && round.errorCount() > 0) errorStatus = true; Set<JavaFileObject> newSourceFiles = new LinkedHashSet<JavaFileObject>(filer.getGeneratedSourceFileObjects()); roots = cleanTrees(round.roots); JavaCompiler compiler = round.finalCompiler(errorStatus); if (newSourceFiles.size() > 0) roots = roots.appendList(compiler.parseFiles(newSourceFiles)); errorStatus = errorStatus || (compiler.errorCount() > 0); // Free resources this.close(); if (taskListener != null) taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING)); if (errorStatus) { if (compiler.errorCount() == 0) compiler.log.nerrors++; return compiler; } if (procOnly && !foundTypeProcessors) { compiler.todo.clear(); } else { if (procOnly && foundTypeProcessors) compiler.shouldStopPolicy = CompileState.FLOW; compiler.enterTrees(roots); } return compiler; }