/** * Main method: enter one class from a list of toplevel trees and place the rest on uncompleted * for later processing. * * @param trees The list of trees to be processed. * @param c The class symbol to be processed. */ public void complete(List<JCCompilationUnit> trees, ClassSymbol c) { annotate.enterStart(); ListBuffer<ClassSymbol> prevUncompleted = uncompleted; if (memberEnter.completionEnabled) uncompleted = new ListBuffer<ClassSymbol>(); try { // enter all classes, and construct uncompleted list classEnter(trees, null); // complete all uncompleted classes in memberEnter if (memberEnter.completionEnabled) { while (uncompleted.nonEmpty()) { ClassSymbol clazz = uncompleted.next(); if (c == null || c == clazz || prevUncompleted == null) clazz.complete(); else // defer prevUncompleted.append(clazz); } // if there remain any unimported toplevels (these must have // no classes at all), process their import statements as well. for (JCCompilationUnit tree : trees) { if (tree.starImportScope.elems == null) { JavaFileObject prev = log.useSource(tree.sourcefile); Env<AttrContext> topEnv = topLevelEnv(tree); memberEnter.memberEnter(tree, topEnv); log.useSource(prev); } } } } finally { uncompleted = prevUncompleted; annotate.enterDone(); } }
/** * Format the arguments of a given diagnostic. * * @param d diagnostic whose arguments are to be formatted * @param l locale object to be used for i18n * @return a Collection whose elements are the formatted arguments of the diagnostic */ protected Collection<String> formatArguments(JCDiagnostic d, Locale l) { ListBuffer<String> buf = new ListBuffer<String>(); for (Object o : d.getArgs()) { buf.append(formatArgument(d, o, l)); } return buf.toList(); }
/** Visitor method: enter classes of a list of trees, returning a list of types. */ <T extends JCTree> List<Type> classEnter(List<T> trees, Env<AttrContext> env) { ListBuffer<Type> ts = new ListBuffer<Type>(); for (List<T> l = trees; l.nonEmpty(); l = l.tail) { Type t = classEnter(l.head, env); if (t != null) ts.append(t); } return ts.toList(); }
public List<A> intersect(List<A> that) { ListBuffer<A> buf = ListBuffer.lb(); for (A el : this) { if (that.contains(el)) { buf.append(el); } } return buf.toList(); }
public void flush() { if (enterCount != 0) return; enterCount++; try { while (q.nonEmpty()) q.next().enterAnnotation(); } finally { enterCount--; } }
private <T extends Attribute.Compound> List<T> getAttributesForCompletion( final Annotate.AnnotateRepeatedContext<T> ctx) { Map<Symbol.TypeSymbol, ListBuffer<T>> annotated = ctx.annotated; boolean atLeastOneRepeated = false; List<T> buf = List.<T>nil(); for (ListBuffer<T> lb : annotated.values()) { if (lb.size() == 1) { buf = buf.prepend(lb.first()); } else { // repeated // This will break when other subtypes of Attributs.Compound // are introduced, because PlaceHolder is a subtype of TypeCompound. T res; @SuppressWarnings("unchecked") T ph = (T) new Placeholder<T>(ctx, lb.toList(), sym); res = ph; buf = buf.prepend(res); atLeastOneRepeated = true; } } if (atLeastOneRepeated) { // The Symbol s is now annotated with a combination of // finished non-repeating annotations and placeholders for // repeating annotations. // // We need to do this in two passes because when creating // a container for a repeating annotation we must // guarantee that the @Repeatable on the // contained annotation is fully annotated // // The way we force this order is to do all repeating // annotations in a pass after all non-repeating are // finished. This will work because @Repeatable // is non-repeating and therefore will be annotated in the // fist pass. // Queue a pass that will replace Attribute.Placeholders // with Attribute.Compound (made from synthesized containers). ctx.annotateRepeated( new Annotate.Annotator() { @Override public String toString() { return "repeated annotation pass of: " + sym + " in: " + sym.owner; } @Override public void enterAnnotation() { complete(ctx); } }); } // Add non-repeating attributes return buf.reverse(); }
// where private DeclaredType getDeclaredType0(Type outer, ClassSymbol sym, TypeMirror... typeArgs) { if (typeArgs.length != sym.type.getTypeArguments().length()) throw new IllegalArgumentException("Incorrect number of type arguments"); ListBuffer<Type> targs = new ListBuffer<Type>(); for (TypeMirror t : typeArgs) { if (!(t instanceof ReferenceType || t instanceof WildcardType)) throw new IllegalArgumentException(t.toString()); targs.append((Type) t); } // TODO: Would like a way to check that type args match formals. return (DeclaredType) new Type.ClassType(outer, targs.toList(), sym); }
// where private void handleFlowResults(Queue<Env<AttrContext>> queue, ListBuffer<Element> elems) { for (Env<AttrContext> env : queue) { switch (env.tree.getTag()) { case JCTree.CLASSDEF: JCClassDecl cdef = (JCClassDecl) env.tree; if (cdef.sym != null) elems.append(cdef.sym); break; case JCTree.TOPLEVEL: JCCompilationUnit unit = (JCCompilationUnit) env.tree; if (unit.packge != null) elems.append(unit.packge); break; } } genList.addAll(queue); }
/** * Translate the given abstract syntax trees to elements. * * @param trees a list of abstract syntax trees. * @throws java.io.IOException TODO * @return a list of elements corresponding to the top level classes in the abstract syntax trees */ public Iterable<? extends TypeElement> enter(Iterable<? extends CompilationUnitTree> trees) throws IOException { prepareCompiler(); ListBuffer<JCCompilationUnit> roots = null; if (trees == null) { // If there are still files which were specified to be compiled // (i.e. in fileObjects) but which have not yet been entered, // then we make sure they have been parsed and add them to the // list to be entered. if (notYetEntered.size() > 0) { if (!parsed) parse(); // TODO would be nice to specify files needed to be parsed for (JavaFileObject file : fileObjects) { JCCompilationUnit unit = notYetEntered.remove(file); if (unit != null) { if (roots == null) roots = new ListBuffer<JCCompilationUnit>(); roots.append(unit); } } notYetEntered.clear(); } } else { for (CompilationUnitTree cu : trees) { if (cu instanceof JCCompilationUnit) { if (roots == null) roots = new ListBuffer<JCCompilationUnit>(); roots.append((JCCompilationUnit) cu); notYetEntered.remove(cu.getSourceFile()); } else throw new IllegalArgumentException(cu.toString()); } } if (roots == null) return List.nil(); try { List<JCCompilationUnit> units = compiler.enterTrees(roots.toList()); if (notYetEntered.isEmpty()) compiler = compiler.processAnnotations(units); ListBuffer<TypeElement> elements = new ListBuffer<TypeElement>(); for (JCCompilationUnit unit : units) { for (JCTree node : unit.defs) { if (node.getTag() == JCTree.CLASSDEF) { JCClassDecl cdef = (JCClassDecl) node; if (cdef.sym != null) // maybe null if errors in anno processing elements.append(cdef.sym); } } } return elements.toList(); } finally { compiler.log.flush(); } }
void run(Queue<Env<AttrContext>> list, Iterable<? extends TypeElement> classes) { Set<TypeElement> set = new HashSet<TypeElement>(); for (TypeElement item : classes) set.add(item); ListBuffer<Env<AttrContext>> defer = ListBuffer.<Env<AttrContext>>lb(); while (list.peek() != null) { Env<AttrContext> env = list.remove(); ClassSymbol csym = env.enclClass.sym; if (csym != null && set.contains(csym.outermostClass())) process(env); else defer = defer.append(env); } list.addAll(defer); }
private <T extends Attribute.Compound> T replaceOne( Placeholder<T> placeholder, Annotate.AnnotateRepeatedContext<T> ctx) { Log log = ctx.log; // Process repeated annotations T validRepeated = ctx.processRepeatedAnnotations(placeholder.getPlaceholderFor(), sym); if (validRepeated != null) { // Check that the container isn't manually // present along with repeated instances of // its contained annotation. ListBuffer<T> manualContainer = ctx.annotated.get(validRepeated.type.tsym); if (manualContainer != null) { log.error( ctx.pos.get(manualContainer.first()), "invalid.repeatable.annotation.repeated.and.container.present", manualContainer.first().type.tsym); } } // A null return will delete the Placeholder return validRepeated; }
/** * A DiagnosticHandler that can defer some or all diagnostics, by buffering them for later * examination and/or reporting. If a diagnostic is not deferred, or is subsequently reported with * reportAllDiagnostics(), it will be reported to the previously active diagnostic handler. */ public static class DeferredDiagnosticHandler extends DiagnosticHandler { private Queue<JCDiagnostic> deferred = ListBuffer.lb(); private final Filter<JCDiagnostic> filter; public DeferredDiagnosticHandler(Log log) { this(log, null); } public DeferredDiagnosticHandler(Log log, Filter<JCDiagnostic> filter) { this.filter = filter; install(log); } public void report(JCDiagnostic diag) { if (filter == null || filter.accepts(diag)) deferred.add(diag); else prev.report(diag); } public Queue<JCDiagnostic> getDiagnostics() { return deferred; } /** Report all deferred diagnostics. */ public void reportDeferredDiagnostics() { reportDeferredDiagnostics(EnumSet.allOf(JCDiagnostic.Kind.class)); } /** Report selected deferred diagnostics. */ public void reportDeferredDiagnostics(Set<JCDiagnostic.Kind> kinds) { JCDiagnostic d; while ((d = deferred.poll()) != null) { if (kinds.contains(d.getKind())) prev.report(d); } deferred = null; // prevent accidental ongoing use } }
/** * Programmatic interface for main function. * * @param args The command line parameters. */ public int compile( String[] args, Context context, List<JavaFileObject> fileObjects, Iterable<? extends Processor> processors) { if (options == null) options = Options.instance(context); // creates a new one filenames = new ListBuffer<File>(); classnames = new ListBuffer<String>(); JavaCompiler comp = null; /* * TODO: Logic below about what is an acceptable command line * should be updated to take annotation processing semantics * into account. */ try { if (args.length == 0 && fileObjects.isEmpty()) { help(); return EXIT_CMDERR; } List<File> files; try { files = processArgs(CommandLine.parse(args)); if (files == null) { // null signals an error in options, abort return EXIT_CMDERR; } else if (files.isEmpty() && fileObjects.isEmpty() && classnames.isEmpty()) { // it is allowed to compile nothing if just asking for help or version info if (options.get("-help") != null || options.get("-X") != null || options.get("-version") != null || options.get("-fullversion") != null) return EXIT_OK; error("err.no.source.files"); return EXIT_CMDERR; } } catch (java.io.FileNotFoundException e) { Log.printLines( out, ownName + ": " + getLocalizedString("err.file.not.found", e.getMessage())); return EXIT_SYSERR; } boolean forceStdOut = options.get("stdout") != null; if (forceStdOut) { out.flush(); out = new PrintWriter(System.out, true); } context.put(Log.outKey, out); // allow System property in following line as a Mustang legacy boolean batchMode = (options.get("nonBatchMode") == null && System.getProperty("nonBatchMode") == null); if (batchMode) CacheFSInfo.preRegister(context); fileManager = context.get(JavaFileManager.class); comp = JavaCompiler.instance(context); if (comp == null) return EXIT_SYSERR; if (!files.isEmpty()) { // add filenames to fileObjects comp = JavaCompiler.instance(context); List<JavaFileObject> otherFiles = List.nil(); JavacFileManager dfm = (JavacFileManager) fileManager; for (JavaFileObject fo : dfm.getJavaFileObjectsFromFiles(files)) otherFiles = otherFiles.prepend(fo); for (JavaFileObject fo : otherFiles) fileObjects = fileObjects.prepend(fo); } comp.compile(fileObjects, classnames.toList(), processors); if (comp.errorCount() != 0) return EXIT_ERROR; } catch (IOException ex) { ioMessage(ex); return EXIT_SYSERR; } catch (OutOfMemoryError ex) { resourceMessage(ex); return EXIT_SYSERR; } catch (StackOverflowError ex) { resourceMessage(ex); return EXIT_SYSERR; } catch (FatalError ex) { feMessage(ex); return EXIT_SYSERR; } catch (AnnotationProcessingError ex) { apMessage(ex); return EXIT_SYSERR; } catch (ClientCodeException ex) { // as specified by javax.tools.JavaCompiler#getTask // and javax.tools.JavaCompiler.CompilationTask#call throw new RuntimeException(ex.getCause()); } catch (PropagatedException ex) { throw ex.getCause(); } catch (Throwable ex) { // Nasty. If we've already reported an error, compensate // for buggy compiler error recovery by swallowing thrown // exceptions. if (comp == null || comp.errorCount() == 0 || options == null || options.get("dev") != null) bugMessage(ex); return EXIT_ABNORMAL; } finally { if (comp != null) comp.close(); filenames = null; options = null; } return EXIT_OK; }
/** * Process command line arguments: store all command line options in `options' table and return * all source filenames. * * @param flags The array of command line arguments. */ public List<File> processArgs(String[] flags) { // XXX sb protected int ac = 0; while (ac < flags.length) { String flag = flags[ac]; ac++; int j; // quick hack to speed up file processing: // if the option does not begin with '-', there is no need to check // most of the compiler options. int firstOptionToCheck = flag.charAt(0) == '-' ? 0 : recognizedOptions.length - 1; for (j = firstOptionToCheck; j < recognizedOptions.length; j++) if (recognizedOptions[j].matches(flag)) break; if (j == recognizedOptions.length) { error("err.invalid.flag", flag); return null; } Option option = recognizedOptions[j]; if (option.hasArg()) { if (ac == flags.length) { error("err.req.arg", flag); return null; } String operand = flags[ac]; ac++; if (option.process(options, flag, operand)) return null; } else { if (option.process(options, flag)) return null; } } if (!checkDirectory("-d")) return null; if (!checkDirectory("-s")) return null; String sourceString = options.get("-source"); Source source = (sourceString != null) ? Source.lookup(sourceString) : Source.DEFAULT; String targetString = options.get("-target"); Target target = (targetString != null) ? Target.lookup(targetString) : Target.DEFAULT; // We don't check source/target consistency for CLDC, as J2ME // profiles are not aligned with J2SE targets; moreover, a // single CLDC target may have many profiles. In addition, // this is needed for the continued functioning of the JSR14 // prototype. if (Character.isDigit(target.name.charAt(0))) { if (target.compareTo(source.requiredTarget()) < 0) { if (targetString != null) { if (sourceString == null) { warning( "warn.target.default.source.conflict", targetString, source.requiredTarget().name); } else { warning("warn.source.target.conflict", sourceString, source.requiredTarget().name); } return null; } else { options.put("-target", source.requiredTarget().name); } } else { if (targetString == null && !source.allowGenerics()) { options.put("-target", Target.JDK1_4.name); } } } return filenames.toList(); }
Attribute enterAttributeValue(Type expected, JCExpression tree, Env<AttrContext> env) { // first, try completing the attribution value sym - if a completion // error is thrown, we should recover gracefully, and display an // ordinary resolution diagnostic. try { expected.tsym.complete(); } catch (CompletionFailure e) { log.error(tree.pos(), "cant.resolve", Kinds.kindName(e.sym), e.sym); return new Attribute.Error(expected); } if (expected.isPrimitive() || types.isSameType(expected, syms.stringType)) { Type result = attr.attribExpr(tree, env, expected); if (result.isErroneous()) return new Attribute.Error(expected); if (result.constValue() == null) { log.error(tree.pos(), "attribute.value.must.be.constant"); return new Attribute.Error(expected); } result = cfolder.coerce(result, expected); return new Attribute.Constant(expected, result.constValue()); } if (expected.tsym == syms.classType.tsym) { Type result = attr.attribExpr(tree, env, expected); if (result.isErroneous()) return new Attribute.Error(expected); if (TreeInfo.name(tree) != names._class) { log.error(tree.pos(), "annotation.value.must.be.class.literal"); return new Attribute.Error(expected); } return new Attribute.Class(types, (((JCFieldAccess) tree).selected).type); } if ((expected.tsym.flags() & Flags.ANNOTATION) != 0 || types.isSameType(expected, syms.annotationType)) { if (tree.getTag() != JCTree.ANNOTATION) { log.error(tree.pos(), "annotation.value.must.be.annotation"); expected = syms.errorType; } return enterAnnotation((JCAnnotation) tree, expected, env); } if (expected.tag == TypeTags.ARRAY) { // should really be isArray() if (tree.getTag() != JCTree.NEWARRAY) { tree = make.at(tree.pos).NewArray(null, List.<JCExpression>nil(), List.of(tree)); } JCNewArray na = (JCNewArray) tree; if (na.elemtype != null) { log.error(na.elemtype.pos(), "new.not.allowed.in.annotation"); return new Attribute.Error(expected); } ListBuffer<Attribute> buf = new ListBuffer<Attribute>(); for (List<JCExpression> l = na.elems; l.nonEmpty(); l = l.tail) { buf.append(enterAttributeValue(types.elemtype(expected), l.head, env)); } na.type = expected; return new Attribute.Array(expected, buf.toArray(new Attribute[buf.length()])); } if (expected.tag == TypeTags.CLASS && (expected.tsym.flags() & Flags.ENUM) != 0) { attr.attribExpr(tree, env, expected); Symbol sym = TreeInfo.symbol(tree); if (sym == null || TreeInfo.nonstaticSelect(tree) || sym.kind != Kinds.VAR || (sym.flags() & Flags.ENUM) == 0) { log.error(tree.pos(), "enum.annotation.must.be.enum.constant"); return new Attribute.Error(expected); } VarSymbol enumerator = (VarSymbol) sym; return new Attribute.Enum(expected, enumerator); } if (!expected.isErroneous()) log.error(tree.pos(), "annotation.value.not.allowable.type"); return new Attribute.Error(attr.attribExpr(tree, env, expected)); }
/** * Main method: compile a list of files, return all compiled classes * * @param filenames The names of all files to be compiled. */ public List<ClassSymbol> compile( List<String> filenames, Map<String, String> origOptions, ClassLoader aptCL, AnnotationProcessorFactory providedFactory, java.util.Set<Class<? extends AnnotationProcessorFactory>> productiveFactories, java.util.Set<java.io.File> aggregateGenFiles) throws Throwable { // as a JavaCompiler can only be used once, throw an exception if // it has been used before. assert !hasBeenUsed : "attempt to reuse JavaCompiler"; hasBeenUsed = true; this.aggregateGenFiles = aggregateGenFiles; long msec = System.currentTimeMillis(); ListBuffer<ClassSymbol> classes = new ListBuffer<ClassSymbol>(); try { JavacFileManager fm = (JavacFileManager) fileManager; // parse all files ListBuffer<JCCompilationUnit> trees = new ListBuffer<JCCompilationUnit>(); for (List<String> l = filenames; l.nonEmpty(); l = l.tail) { if (classesAsDecls) { if (!l.head.endsWith(".java")) { // process as class file ClassSymbol cs = reader.enterClass(names.fromString(l.head)); try { cs.complete(); } catch (Symbol.CompletionFailure cf) { bark.aptError("CantFindClass", l); continue; } classes.append(cs); // add to list of classes continue; } } JavaFileObject fo = fm.getJavaFileObjectsFromStrings(List.of(l.head)).iterator().next(); trees.append(parse(fo)); } // enter symbols for all files List<JCCompilationUnit> roots = trees.toList(); if (errorCount() == 0) { boolean prev = bark.setDiagnosticsIgnored(true); try { enter.main(roots); } finally { bark.setDiagnosticsIgnored(prev); } } if (errorCount() == 0) { apt.main(roots, classes, origOptions, aptCL, providedFactory, productiveFactories); genSourceFileNames.addAll(apt.getSourceFileNames()); genClassFileNames.addAll(apt.getClassFileNames()); } } catch (Abort ex) { } if (verbose) log.printVerbose("total", Long.toString(System.currentTimeMillis() - msec)); chk.reportDeferredDiagnostics(); printCount("error", errorCount()); printCount("warn", warningCount()); return classes.toList(); }
public void visitClassDef(JCClassDecl tree) { Symbol owner = env.info.scope.owner; Scope enclScope = enterScope(env); ClassSymbol c; if (owner.kind == PCK) { // We are seeing a toplevel class. PackageSymbol packge = (PackageSymbol) owner; for (Symbol q = packge; q != null && q.kind == PCK; q = q.owner) q.flags_field |= EXISTS; c = reader.enterClass(tree.name, packge); packge.members().enterIfAbsent(c); if ((tree.mods.flags & PUBLIC) != 0 && !classNameMatchesFileName(c, env)) { log.error(tree.pos(), "class.public.should.be.in.file", tree.name); } } else { if (!tree.name.isEmpty() && !chk.checkUniqueClassName(tree.pos(), tree.name, enclScope)) { result = null; return; } if (owner.kind == TYP) { // We are seeing a member class. c = reader.enterClass(tree.name, (TypeSymbol) owner); if ((owner.flags_field & INTERFACE) != 0) { tree.mods.flags |= PUBLIC | STATIC; } } else { // We are seeing a local class. c = reader.defineClass(tree.name, owner); c.flatname = chk.localClassName(c); if (!c.name.isEmpty()) chk.checkTransparentClass(tree.pos(), c, env.info.scope); } } tree.sym = c; // Enter class into `compiled' table and enclosing scope. if (chk.compiled.get(c.flatname) != null) { duplicateClass(tree.pos(), c); result = types.createErrorType(tree.name, (TypeSymbol) owner, Type.noType); tree.sym = (ClassSymbol) result.tsym; return; } chk.compiled.put(c.flatname, c); enclScope.enter(c); // Set up an environment for class block and store in `typeEnvs' // table, to be retrieved later in memberEnter and attribution. Env<AttrContext> localEnv = classEnv(tree, env); typeEnvs.put(c, localEnv); // Fill out class fields. c.completer = memberEnter; c.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, c, tree); c.sourcefile = env.toplevel.sourcefile; c.members_field = new Scope(c); ClassType ct = (ClassType) c.type; if (owner.kind != PCK && (c.flags_field & STATIC) == 0) { // We are seeing a local or inner class. // Set outer_field of this class to closest enclosing class // which contains this class in a non-static context // (its "enclosing instance class"), provided such a class exists. Symbol owner1 = owner; while ((owner1.kind & (VAR | MTH)) != 0 && (owner1.flags_field & STATIC) == 0) { owner1 = owner1.owner; } if (owner1.kind == TYP) { ct.setEnclosingType(owner1.type); } } // Enter type parameters. ct.typarams_field = classEnter(tree.typarams, localEnv); // Add non-local class to uncompleted, to make sure it will be // completed later. if (!c.isLocal() && uncompleted != null) uncompleted.append(c); // System.err.println("entering " + c.fullname + " in " + c.owner);//DEBUG // Recursively enter all member classes. classEnter(tree.defs, localEnv); result = c.type; }
public void later(Annotator a) { q.append(a); }
public void earlier(Annotator a) { q.prepend(a); }
/** Append given list buffer at length, forming and returning a new list. */ public List<A> appendList(ListBuffer<A> x) { return appendList(x.toList()); }
private static List<JavaFileObject> toList(Iterable<? extends JavaFileObject> fileObjects) { if (fileObjects == null) return List.nil(); ListBuffer<JavaFileObject> result = new ListBuffer<JavaFileObject>(); for (JavaFileObject fo : fileObjects) result.append(fo); return result.toList(); }
private static String[] toArray(Iterable<String> iter) { ListBuffer<String> result = new ListBuffer<String>(); if (iter != null) for (String s : iter) result.append(s); return result.toArray(new String[result.length()]); }