# HG changeset patch # User lana # Date 1417735373 28800 # Node ID a48998a1fc72a9c1b5f2ec08bc041e435ecd1794 # Parent 66e93fa62eb32bb06407d3b373786d8ded2240bc# Parent f5bd37460a09ce29937dda9206b0655a87da67db Merge diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java Thu Dec 04 15:22:53 2014 -0800 @@ -58,6 +58,7 @@ import static com.sun.tools.javac.code.Kinds.Kind.*; import static com.sun.tools.javac.main.Option.*; +import com.sun.tools.javac.util.Dependencies.CompletionCause; /** * This class provides operations to locate class definitions @@ -270,7 +271,7 @@ if (sym.kind == TYP) { try { ClassSymbol c = (ClassSymbol) sym; - dependencies.push(c); + dependencies.push(c, CompletionCause.CLASS_READER); c.members_field = new Scope.ErrorScope(c); // make sure it's always defined annotate.enterStart(); try { diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Kinds.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Kinds.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Kinds.java Thu Dec 04 15:22:53 2014 -0800 @@ -168,6 +168,7 @@ public static final KindSelector MTH = new KindSelector(0x10); public static final KindSelector ERR = new KindSelector(0x3f); public static final KindSelector POLY = new KindSelector(0x20); + public static final KindSelector ASG = new KindSelector(0x44); //common derived selectors public static final KindSelector TYP_PCK = of(TYP, PCK); diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java Thu Dec 04 15:22:53 2014 -0800 @@ -80,6 +80,16 @@ return l; } + /** + * Returns a new Lint that has the given LintCategory suppressed. + */ + public Lint suppress(LintCategory lc) { + Lint l = new Lint(this); + l.values.remove(lc); + l.suppressedValues.add(lc); + return l; + } + private final AugmentVisitor augmentor; private final EnumSet values; diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Scope.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Scope.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Scope.java Thu Dec 04 15:22:53 2014 -0800 @@ -25,13 +25,18 @@ package com.sun.tools.javac.code; +import com.sun.tools.javac.code.Kinds.Kind; import java.util.*; +import com.sun.tools.javac.code.Symbol.TypeSymbol; +import com.sun.tools.javac.tree.JCTree.JCImport; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.List; import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE; import static com.sun.tools.javac.code.Scope.LookupKind.RECURSIVE; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; /** A scope represents an area of visibility in a Java program. The * Scope class is a container for symbols which provides @@ -672,28 +677,67 @@ } - public static class NamedImportScope extends CompoundScope { + public static class ImportScope extends CompoundScope { + + public ImportScope(Symbol owner) { + super(owner); + } + + /**Finalize the content of the ImportScope to speed-up future lookups. + * No further changes to class hierarchy or class content will be reflected. + */ + public void finalizeScope() { + for (List scopes = this.subScopes; scopes.nonEmpty(); scopes = scopes.tail) { + Scope impScope = scopes.head; + + if (impScope instanceof FilterImportScope && impScope.owner.kind == Kind.TYP) { + WriteableScope finalized = WriteableScope.create(impScope.owner); + + for (Symbol sym : impScope.getSymbols()) { + finalized.enter(sym); + } + + finalized.addScopeListener(new ScopeListener() { + @Override + public void symbolAdded(Symbol sym, Scope s) { + Assert.error("The scope is sealed."); + } + @Override + public void symbolRemoved(Symbol sym, Scope s) { + Assert.error("The scope is sealed."); + } + }); + + scopes.head = finalized; + } + } + } + + } + + public static class NamedImportScope extends ImportScope { public NamedImportScope(Symbol owner, Scope currentFileScope) { super(owner); prependSubScope(currentFileScope); } - public void importByName(Scope delegate, Scope origin, Name name, ImportFilter filter) { - appendScope(new FilterImportScope(delegate, origin, name, filter, true)); + public Scope importByName(Types types, Scope origin, Name name, ImportFilter filter) { + return appendScope(new FilterImportScope(types, origin, name, filter, true)); } - public void importType(Scope delegate, Scope origin, Symbol sym) { - appendScope(new SingleEntryScope(delegate.owner, sym, origin)); + public Scope importType(Scope delegate, Scope origin, Symbol sym) { + return appendScope(new SingleEntryScope(delegate.owner, sym, origin)); } - private void appendScope(Scope newScope) { + private Scope appendScope(Scope newScope) { List existingScopes = this.subScopes.reverse(); subScopes = List.of(existingScopes.head); subScopes = subScopes.prepend(newScope); for (Scope s : existingScopes.tail) { subScopes = subScopes.prepend(s); } + return newScope; } private static class SingleEntryScope extends Scope { @@ -735,24 +779,23 @@ } } - public static class StarImportScope extends CompoundScope { + public static class StarImportScope extends ImportScope { public StarImportScope(Symbol owner) { super(owner); } - public void importAll(Scope delegate, - Scope origin, + public void importAll(Types types, Scope origin, ImportFilter filter, boolean staticImport) { for (Scope existing : subScopes) { Assert.check(existing instanceof FilterImportScope); FilterImportScope fis = (FilterImportScope) existing; - if (fis.delegate == delegate && fis.origin == origin && - fis.filter == filter && fis.staticImport == staticImport) + if (fis.origin == origin && fis.filter == filter && + fis.staticImport == staticImport) return ; //avoid entering the same scope twice } - prependSubScope(new FilterImportScope(delegate, origin, null, filter, staticImport)); + prependSubScope(new FilterImportScope(types, origin, null, filter, staticImport)); } } @@ -763,19 +806,19 @@ private static class FilterImportScope extends Scope { - private final Scope delegate; + private final Types types; private final Scope origin; private final Name filterName; private final ImportFilter filter; private final boolean staticImport; - public FilterImportScope(Scope delegate, + public FilterImportScope(Types types, Scope origin, Name filterName, ImportFilter filter, boolean staticImport) { - super(delegate.owner); - this.delegate = delegate; + super(origin.owner); + this.types = types; this.origin = origin; this.filterName = filterName; this.filter = filter; @@ -783,19 +826,31 @@ } @Override - public Iterable getSymbols(Filter sf, LookupKind lookupKind) { + public Iterable getSymbols(final Filter sf, final LookupKind lookupKind) { if (filterName != null) return getSymbolsByName(filterName, sf, lookupKind); - return new FilteredIterable(delegate.getSymbols(sf, lookupKind)); + SymbolImporter si = new SymbolImporter(staticImport) { + @Override + Iterable doLookup(TypeSymbol tsym) { + return tsym.members().getSymbols(sf, lookupKind); + } + }; + return si.importFrom((TypeSymbol) origin.owner) :: iterator; } @Override - public Iterable getSymbolsByName(Name name, - Filter sf, - LookupKind lookupKind) { + public Iterable getSymbolsByName(final Name name, + final Filter sf, + final LookupKind lookupKind) { if (filterName != null && filterName != name) return Collections.emptyList(); - return new FilteredIterable(delegate.getSymbolsByName(name, sf, lookupKind)); + SymbolImporter si = new SymbolImporter(staticImport) { + @Override + Iterable doLookup(TypeSymbol tsym) { + return tsym.members().getSymbolsByName(name, sf, lookupKind); + } + }; + return si.importFrom((TypeSymbol) origin.owner) :: iterator; } @Override @@ -808,57 +863,31 @@ return staticImport; } - private class FilteredIterator implements Iterator { - private final Iterator delegate; - private Symbol next; + abstract class SymbolImporter { + Set processed = new HashSet<>(); + List> delegates = List.nil(); + final boolean inspectSuperTypes; + public SymbolImporter(boolean inspectSuperTypes) { + this.inspectSuperTypes = inspectSuperTypes; + } + Stream importFrom(TypeSymbol tsym) { + if (tsym == null || !processed.add(tsym)) + return Stream.empty(); - public FilteredIterator(Iterator delegate) { - this.delegate = delegate; - update(); - } + Stream result = Stream.empty(); - void update() { - while (delegate.hasNext()) { - if (filter.accepts(origin, next = delegate.next())) - return; + if (inspectSuperTypes) { + // also import inherited names + result = importFrom(types.supertype(tsym.type).tsym); + for (Type t : types.interfaces(tsym.type)) + result = Stream.concat(importFrom(t.tsym), result); } - next = null; - } - - @Override - public boolean hasNext() { - return next != null; - } - - @Override - public Symbol next() { - Symbol result = next; - - update(); - - return result; + return Stream.concat(StreamSupport.stream(doLookup(tsym).spliterator(), false) + .filter(s -> filter.accepts(origin, s)), + result); } - - @Override - public void remove() { - throw new UnsupportedOperationException("Not supported."); - } - - } - - private class FilteredIterable implements Iterable { - - private final Iterable unfiltered; - - public FilteredIterable(Iterable unfiltered) { - this.unfiltered = unfiltered; - } - - @Override - public Iterator iterator() { - return new FilteredIterator(unfiltered.iterator()); - } + abstract Iterable doLookup(TypeSymbol tsym); } } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java Thu Dec 04 15:22:53 2014 -0800 @@ -140,6 +140,9 @@ public boolean allowTryWithResources() { return compareTo(JDK1_7) >= 0; } + public boolean allowEffectivelyFinalVariablesInTryWithResources() { + return compareTo(JDK1_9) >= 0; + } public boolean allowBinaryLiterals() { return compareTo(JDK1_7) >= 0; } @@ -149,6 +152,9 @@ public boolean allowStringsInSwitch() { return compareTo(JDK1_7) >= 0; } + public boolean allowDeprecationOnImport() { + return compareTo(JDK1_9) < 0; + } public boolean allowSimplifiedVarargs() { return compareTo(JDK1_7) >= 0; } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Thu Dec 04 15:22:53 2014 -0800 @@ -87,6 +87,7 @@ final Check chk; final Flow flow; final MemberEnter memberEnter; + final TypeEnter typeEnter; final TreeMaker make; final ConstFold cfolder; final Enter enter; @@ -116,6 +117,7 @@ chk = Check.instance(context); flow = Flow.instance(context); memberEnter = MemberEnter.instance(context); + typeEnter = TypeEnter.instance(context); make = TreeMaker.instance(context); enter = Enter.instance(context); infer = Infer.instance(context); @@ -148,7 +150,7 @@ identifyLambdaCandidate = options.getBoolean("identifyLambdaCandidate", false); statInfo = new ResultInfo(KindSelector.NIL, Type.noType); - varInfo = new ResultInfo(KindSelector.VAR, Type.noType); + varAssignmentInfo = new ResultInfo(KindSelector.ASG, Type.noType); unknownExprInfo = new ResultInfo(KindSelector.VAL, Type.noType); unknownAnyPolyInfo = new ResultInfo(KindSelector.VAL, Infer.anyPoly); unknownTypeInfo = new ResultInfo(KindSelector.TYP, Type.noType); @@ -498,7 +500,7 @@ } final ResultInfo statInfo; - final ResultInfo varInfo; + final ResultInfo varAssignmentInfo; final ResultInfo unknownAnyPolyInfo; final ResultInfo unknownExprInfo; final ResultInfo unknownTypeInfo; @@ -629,19 +631,19 @@ /** Attribute the arguments in a method call, returning the method kind. */ - KindSelector attribArgs(List trees, Env env, ListBuffer argtypes) { - boolean polykind = false; + KindSelector attribArgs(KindSelector initialKind, List trees, Env env, ListBuffer argtypes) { + KindSelector kind = initialKind; for (JCExpression arg : trees) { Type argtype; if (allowPoly && deferredAttr.isDeferred(env, arg)) { argtype = deferredAttr.new DeferredType(arg, env); - polykind = true; + kind = KindSelector.of(KindSelector.POLY, kind); } else { argtype = chk.checkNonVoid(arg, attribTree(arg, env, unknownAnyPolyInfo)); } argtypes.append(argtype); } - return polykind ? KindSelector.VAL_POLY : KindSelector.VAL; + return kind; } /** Attribute a type argument list, returning a list of types. @@ -949,7 +951,7 @@ if (body.stats.isEmpty() || !TreeInfo.isSelfCall(body.stats.head)) { body.stats = body.stats. - prepend(memberEnter.SuperCall(make.at(body.pos), + prepend(typeEnter.SuperCall(make.at(body.pos), List.nil(), List.nil(), false)); @@ -1293,7 +1295,7 @@ } }; ResultInfo twrResult = - new ResultInfo(KindSelector.VAL, + new ResultInfo(KindSelector.VAR, syms.autoCloseableType, twrContext); if (resource.hasTag(VARDEF)) { @@ -1704,7 +1706,7 @@ localEnv.info.isSelfCall = true; // Attribute arguments, yielding list of argument types. - attribArgs(tree.args, localEnv, argtypesBuf); + KindSelector kind = attribArgs(KindSelector.MTH, tree.args, localEnv, argtypesBuf); argtypes = argtypesBuf.toList(); typeargtypes = attribTypes(tree.typeargs, localEnv); @@ -1770,7 +1772,7 @@ // (this will also set the tree's type) Type mpt = newMethodTemplate(resultInfo.pt, argtypes, typeargtypes); checkId(tree.meth, site, sym, localEnv, - new ResultInfo(KindSelector.MTH, mpt)); + new ResultInfo(kind, mpt)); } // Otherwise, `site' is an error type and we do nothing } @@ -1778,7 +1780,7 @@ } else { // Otherwise, we are seeing a regular method call. // Attribute the arguments, yielding list of argument types, ... - KindSelector kind = attribArgs(tree.args, localEnv, argtypesBuf); + KindSelector kind = attribArgs(KindSelector.VAL, tree.args, localEnv, argtypesBuf); argtypes = argtypesBuf.toList(); typeargtypes = attribAnyTypes(tree.typeargs, localEnv); @@ -1958,7 +1960,7 @@ // Attribute constructor arguments. ListBuffer argtypesBuf = new ListBuffer<>(); final KindSelector pkind = - attribArgs(tree.args, localEnv, argtypesBuf); + attribArgs(KindSelector.VAL, tree.args, localEnv, argtypesBuf); List argtypes = argtypesBuf.toList(); List typeargtypes = attribTypes(tree.typeargs, localEnv); @@ -2942,7 +2944,7 @@ } public void visitAssign(JCAssign tree) { - Type owntype = attribTree(tree.lhs, env.dup(tree), varInfo); + Type owntype = attribTree(tree.lhs, env.dup(tree), varAssignmentInfo); Type capturedType = capture(owntype); attribExpr(tree.rhs, env, owntype); result = check(tree, capturedType, KindSelector.VAL, resultInfo); @@ -2950,7 +2952,7 @@ public void visitAssignop(JCAssignOp tree) { // Attribute arguments. - Type owntype = attribTree(tree.lhs, env, varInfo); + Type owntype = attribTree(tree.lhs, env, varAssignmentInfo); Type operand = attribExpr(tree.rhs, env); // Find operator. Symbol operator = tree.operator = rs.resolveBinaryOperator( @@ -2976,7 +2978,7 @@ public void visitUnary(JCUnary tree) { // Attribute arguments. Type argtype = (tree.getTag().isIncOrDecUnaryOp()) - ? attribTree(tree.arg, env, varInfo) + ? attribTree(tree.arg, env, varAssignmentInfo) : chk.checkNonVoid(tree.arg.pos(), attribExpr(tree.arg, env)); // Find operator. @@ -3156,7 +3158,7 @@ // If we are expecting a variable (as opposed to a value), check // that the variable is assignable in the current environment. - if (pkind() == KindSelector.VAR) + if (KindSelector.ASG.subset(pkind())) checkAssignable(tree.pos(), v, null, env); } @@ -3233,6 +3235,10 @@ // Determine the symbol represented by the selection. env.info.pendingResolutionPhase = null; Symbol sym = selectSym(tree, sitesym, site, env, resultInfo); + if (sym.kind == VAR && sym.name != names._super && env.info.defaultSuperCallSite != null) { + log.error(tree.selected.pos(), "not.encl.class", site.tsym); + sym = syms.errSymbol; + } if (sym.exists() && !isType(sym) && pkind().contains(KindSelector.TYP_PCK)) { site = capture(site); sym = selectSym(tree, sitesym, site, env, resultInfo); @@ -3255,7 +3261,7 @@ // If we are expecting a variable (as opposed to a value), check // that the variable is assignable in the current environment. - if (pkind() == KindSelector.VAR) + if (KindSelector.ASG.subset(pkind())) checkAssignable(tree.pos(), v, tree.selected, env); } @@ -3538,7 +3544,7 @@ // Test (4): if symbol is an instance field of a raw type, // which is being assigned to, issue an unchecked warning if // its type changes under erasure. - if (resultInfo.pkind == KindSelector.VAR && + if (KindSelector.ASG.subset(pkind()) && v.owner.kind == TYP && (v.flags() & STATIC) == 0 && (site.hasTag(CLASS) || site.hasTag(TYPEVAR))) { @@ -4486,14 +4492,15 @@ super.visitTypeTest(tree); } public void visitNewClass(JCNewClass tree) { - if (tree.clazz.hasTag(ANNOTATED_TYPE)) { - checkForDeclarationAnnotations(((JCAnnotatedType) tree.clazz).annotations, - tree.clazz.type.tsym); - } - if (tree.def != null) { - checkForDeclarationAnnotations(tree.def.mods.annotations, tree.clazz.type.tsym); - } - if (tree.clazz.type != null) { + if (tree.clazz != null && tree.clazz.type != null) { + if (tree.clazz.hasTag(ANNOTATED_TYPE)) { + checkForDeclarationAnnotations(((JCAnnotatedType) tree.clazz).annotations, + tree.clazz.type.tsym); + } + if (tree.def != null) { + checkForDeclarationAnnotations(tree.def.mods.annotations, tree.clazz.type.tsym); + } + validateAnnotatedType(tree.clazz, tree.clazz.type); } super.visitNewClass(tree); diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Thu Dec 04 15:22:53 2014 -0800 @@ -28,7 +28,6 @@ import java.util.*; import javax.tools.JavaFileManager; -import javax.tools.JavaFileObject; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Attribute.Compound; @@ -40,6 +39,7 @@ import com.sun.tools.javac.code.Lint; import com.sun.tools.javac.code.Lint.LintCategory; +import com.sun.tools.javac.code.Scope.CompoundScope; import com.sun.tools.javac.code.Scope.NamedImportScope; import com.sun.tools.javac.code.Scope.WriteableScope; import com.sun.tools.javac.code.Type.*; @@ -3415,56 +3415,69 @@ } } - /** Check that single-type import is not already imported or top-level defined, - * but make an exception for two single-type imports which denote the same type. - * @param pos Position for error reporting. - * @param toplevel The file in which in the check is performed. - * @param sym The symbol. + /**Check that types imported through the ordinary imports don't clash with types imported + * by other (static or ordinary) imports. Note that two static imports may import two clashing + * types without an error on the imports. + * @param toplevel The toplevel tree for which the test should be performed. */ - boolean checkUniqueImport(DiagnosticPosition pos, JCCompilationUnit toplevel, Symbol sym) { - return checkUniqueImport(pos, toplevel, sym, false); - } - - /** Check that static single-type import is not already imported or top-level defined, - * but make an exception for two single-type imports which denote the same type. - * @param pos Position for error reporting. - * @param toplevel The file in which in the check is performed. - * @param sym The symbol. - */ - boolean checkUniqueStaticImport(DiagnosticPosition pos, JCCompilationUnit toplevel, Symbol sym) { - return checkUniqueImport(pos, toplevel, sym, true); + void checkImportsUnique(JCCompilationUnit toplevel) { + WriteableScope ordinallyImportedSoFar = WriteableScope.create(toplevel.packge); + WriteableScope staticallyImportedSoFar = WriteableScope.create(toplevel.packge); + WriteableScope topLevelScope = toplevel.toplevelScope; + + for (JCTree def : toplevel.defs) { + if (!def.hasTag(IMPORT)) + continue; + + JCImport imp = (JCImport) def; + + if (imp.importScope == null) + continue; + + for (Symbol sym : imp.importScope.getSymbols(sym -> sym.kind == TYP)) { + if (imp.isStatic()) { + checkUniqueImport(imp.pos(), ordinallyImportedSoFar, staticallyImportedSoFar, topLevelScope, sym, true); + staticallyImportedSoFar.enter(sym); + } else { + checkUniqueImport(imp.pos(), ordinallyImportedSoFar, staticallyImportedSoFar, topLevelScope, sym, false); + ordinallyImportedSoFar.enter(sym); + } + } + + imp.importScope = null; + } } /** Check that single-type import is not already imported or top-level defined, * but make an exception for two single-type imports which denote the same type. - * @param pos Position for error reporting. - * @param toplevel The file in which in the check is performed. - * @param sym The symbol. - * @param staticImport Whether or not this was a static import + * @param pos Position for error reporting. + * @param ordinallyImportedSoFar A Scope containing types imported so far through + * ordinary imports. + * @param staticallyImportedSoFar A Scope containing types imported so far through + * static imports. + * @param topLevelScope The current file's top-level Scope + * @param sym The symbol. + * @param staticImport Whether or not this was a static import */ - private boolean checkUniqueImport(DiagnosticPosition pos, JCCompilationUnit toplevel, Symbol sym, boolean staticImport) { - NamedImportScope namedImportScope = toplevel.namedImportScope; - WriteableScope topLevelScope = toplevel.toplevelScope; - - for (Symbol byName : namedImportScope.getSymbolsByName(sym.name)) { - // is encountered class entered via a class declaration? - boolean isClassDecl = namedImportScope.getOrigin(byName) == topLevelScope; - if ((isClassDecl || sym != byName) && - sym.kind == byName.kind && - sym.name != names.error && - (!staticImport || !namedImportScope.isStaticallyImported(byName))) { - if (!byName.type.isErroneous()) { - if (!isClassDecl) { - if (staticImport) - log.error(pos, "already.defined.static.single.import", byName); - else - log.error(pos, "already.defined.single.import", byName); - } - else if (sym != byName) - log.error(pos, "already.defined.this.unit", byName); - } - return false; - } + private boolean checkUniqueImport(DiagnosticPosition pos, Scope ordinallyImportedSoFar, + Scope staticallyImportedSoFar, Scope topLevelScope, + Symbol sym, boolean staticImport) { + Filter duplicates = candidate -> candidate != sym && !candidate.type.isErroneous(); + Symbol clashing = ordinallyImportedSoFar.findFirst(sym.name, duplicates); + if (clashing == null && !staticImport) { + clashing = staticallyImportedSoFar.findFirst(sym.name, duplicates); + } + if (clashing != null) { + if (staticImport) + log.error(pos, "already.defined.static.single.import", clashing); + else + log.error(pos, "already.defined.single.import", clashing); + return false; + } + clashing = topLevelScope.findFirst(sym.name, duplicates); + if (clashing != null) { + log.error(pos, "already.defined.this.unit", clashing); + return false; } return true; } @@ -3570,18 +3583,13 @@ if (select.name == names.asterisk || (origin = TreeInfo.symbol(select.selected)) == null || origin.kind != TYP) continue; - JavaFileObject prev = log.useSource(toplevel.sourcefile); - try { - TypeSymbol site = (TypeSymbol) TreeInfo.symbol(select.selected); - if (!checkTypeContainsImportableElement(site, site, toplevel.packge, select.name, new HashSet())) { - log.error(imp.pos(), "cant.resolve.location", - KindName.STATIC, - select.name, List.nil(), List.nil(), - Kinds.typeKindName(TreeInfo.symbol(select.selected).type), - TreeInfo.symbol(select.selected).type); - } - } finally { - log.useSource(prev); + TypeSymbol site = (TypeSymbol) TreeInfo.symbol(select.selected); + if (!checkTypeContainsImportableElement(site, site, toplevel.packge, select.name, new HashSet())) { + log.error(imp.pos(), "cant.resolve.location", + KindName.STATIC, + select.name, List.nil(), List.nil(), + Kinds.typeKindName(TreeInfo.symbol(select.selected).type), + TreeInfo.symbol(select.selected).type); } } } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java Thu Dec 04 15:22:53 2014 -0800 @@ -47,40 +47,34 @@ import static com.sun.tools.javac.code.Kinds.Kind.*; /** This class enters symbols for all encountered definitions into - * the symbol table. The pass consists of two phases, organized as - * follows: + * the symbol table. The pass consists of high-level two phases, + * organized as follows: * *

In the first phase, all class symbols are entered into their * enclosing scope, descending recursively down the tree for classes * which are members of other classes. The class symbols are given a - * MemberEnter object as completer. + * TypeEnter object as completer. * *

In the second phase classes are completed using - * MemberEnter.complete(). Completion might occur on demand, but + * TypeEnter.complete(). Completion might occur on demand, but * any classes that are not completed that way will be eventually - * completed by processing the `uncompleted' queue. Completion - * entails (1) determination of a class's parameters, supertype and - * interfaces, as well as (2) entering all symbols defined in the + * completed by processing the `uncompleted' queue. Completion + * entails determination of a class's parameters, supertype and + * interfaces, as well as entering all symbols defined in the * class into its scope, with the exception of class symbols which - * have been entered in phase 1. (2) depends on (1) having been - * completed for a class and all its superclasses and enclosing - * classes. That's why, after doing (1), we put classes in a - * `halfcompleted' queue. Only when we have performed (1) for a class - * and all it's superclasses and enclosing classes, we proceed to - * (2). + * have been entered in phase 1. * *

Whereas the first phase is organized as a sweep through all - * compiled syntax trees, the second phase is demand. Members of a + * compiled syntax trees, the second phase is on-demand. Members of a * class are entered when the contents of a class are first * accessed. This is accomplished by installing completer objects in - * class symbols for compiled classes which invoke the member-enter + * class symbols for compiled classes which invoke the type-enter * phase for the corresponding class tree. * *

Classes migrate from one phase to the next via queues: * *

{@literal
- *  class enter -> (Enter.uncompleted)         --> member enter (1)
- *              -> (MemberEnter.halfcompleted) --> member enter (2)
+ *  class enter -> (Enter.uncompleted)         --> type enter
  *              -> (Todo)                      --> attribute
  *                                              (only for toplevel classes)
  *  }
@@ -98,7 +92,7 @@ Check chk; TreeMaker make; Annotate annotate; - MemberEnter memberEnter; + TypeEnter typeEnter; Types types; Lint lint; Names names; @@ -122,7 +116,7 @@ make = TreeMaker.instance(context); syms = Symtab.instance(context); chk = Check.instance(context); - memberEnter = MemberEnter.instance(context); + typeEnter = TypeEnter.instance(context); types = Types.instance(context); annotate = Annotate.instance(context); lint = Lint.instance(context); @@ -391,7 +385,7 @@ typeEnvs.put(c, localEnv); // Fill out class fields. - c.completer = memberEnter; + c.completer = typeEnter; c.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, c, tree); c.sourcefile = env.toplevel.sourcefile; c.members_field = WriteableScope.create(c); @@ -469,22 +463,23 @@ complete(trees, null); } - /** Main method: enter one class from a list of toplevel trees and - * place the rest on uncompleted for later processing. + /** Main method: enter classes from the list of toplevel trees, possibly + * skipping TypeEnter for all but 'c' by placing them on the uncompleted + * list. * @param trees The list of trees to be processed. - * @param c The class symbol to be processed. + * @param c The class symbol to be processed or null to process all. */ public void complete(List trees, ClassSymbol c) { annotate.enterStart(); ListBuffer prevUncompleted = uncompleted; - if (memberEnter.completionEnabled) uncompleted = new ListBuffer<>(); + if (typeEnter.completionEnabled) uncompleted = new ListBuffer<>(); try { // enter all classes, and construct uncompleted list classEnter(trees, null); // complete all uncompleted classes in memberEnter - if (memberEnter.completionEnabled) { + if (typeEnter.completionEnabled) { while (uncompleted.nonEmpty()) { ClassSymbol clazz = uncompleted.next(); if (c == null || c == clazz || prevUncompleted == null) @@ -494,16 +489,7 @@ 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.isEmpty()) { - JavaFileObject prev = log.useSource(tree.sourcefile); - Env topEnv = topLevelEnv(tree); - memberEnter.memberEnter(tree, topEnv); - log.useSource(prev); - } - } + typeEnter.ensureImportsChecked(trees); } } finally { uncompleted = prevUncompleted; diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java Thu Dec 04 15:22:53 2014 -0800 @@ -242,9 +242,15 @@ Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log); try { new AssignAnalyzer() { + WriteableScope enclosedSymbols = WriteableScope.create(env.enclClass.sym); + @Override + public void visitVarDef(JCVariableDecl tree) { + enclosedSymbols.enter(tree.sym); + super.visitVarDef(tree); + } @Override protected boolean trackable(VarSymbol sym) { - return !env.info.scope.includes(sym) && + return enclosedSymbols.includes(sym) && sym.owner.kind == MTH; } }.analyzeTree(env, that); @@ -2556,6 +2562,8 @@ * This pass implements the last step of the dataflow analysis, namely * the effectively-final analysis check. This checks that every local variable * reference from a lambda body/local inner class is either final or effectively final. + * Additional this also checks that every variable that is used as an operand to + * try-with-resources is final or effectively final. * As effectively final variables are marked as such during DA/DU, this pass must run after * AssignAnalyzer. */ @@ -2684,6 +2692,18 @@ } } + public void visitTry(JCTry tree) { + for (JCTree resource : tree.resources) { + if (!resource.hasTag(VARDEF)) { + Symbol var = TreeInfo.symbol(resource); + if (var != null && (var.flags() & (FINAL | EFFECTIVELY_FINAL)) == 0) { + log.error(resource.pos(), "try.with.resources.expr.effectively.final.var", var); + } + } + } + super.visitTry(tree); + } + /************************************************************************** * main method *************************************************************************/ diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Thu Dec 04 15:22:53 2014 -0800 @@ -40,6 +40,7 @@ import com.sun.tools.javac.code.Symtab; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Type.MethodType; +import com.sun.tools.javac.code.Type.TypeVar; import com.sun.tools.javac.code.Types; import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*; import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector; @@ -60,6 +61,7 @@ import static com.sun.tools.javac.code.Kinds.Kind.*; import static com.sun.tools.javac.code.TypeTag.*; import static com.sun.tools.javac.tree.JCTree.Tag.*; +import javax.lang.model.type.TypeKind; /** * This pass desugars lambda expressions into static methods @@ -759,49 +761,10 @@ int prevPos = make.pos; try { make.at(tree); - Type samDesc = localContext.bridgedRefSig(); - List samPTypes = samDesc.getParameterTypes(); - - // an extra argument is prepended in the case where the member - // reference is an unbound instance method reference (in which - // case the receiver expression in passed. - VarSymbol rcvr; - switch (tree.kind) { - case BOUND: - rcvr = addParameter("rec$", tree.getQualifierExpression().type, false); - receiverExpression = attr.makeNullCheck(tree.getQualifierExpression()); - break; - case UNBOUND: - rcvr = addParameter("rec$", samPTypes.head, false); - samPTypes = samPTypes.tail; - break; - default: - rcvr = null; - break; - } - - // generate the parameter list for the coverted member reference. - // the signature will match the signature of the target sam descriptor - - List refPTypes = tree.sym.type.getParameterTypes(); - int refSize = refPTypes.size(); - int samSize = samPTypes.size(); - // Last parameter to copy from referenced method - int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize; - - List l = refPTypes; - // Use parameter types of the referenced method, excluding final var args - for (int i = 0; l.nonEmpty() && i < last; ++i) { - addParameter("x$" + i, l.head, true); - l = l.tail; - } - // Flatten out the var args - for (int i = last; i < samSize; ++i) { - addParameter("xva$" + i, tree.varargsElement, true); - } //body generation - this can be either a method call or a //new instance creation expression, depending on the member reference kind + VarSymbol rcvr = addParametersReturnReceiver(); JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE) ? expressionInvoke(rcvr) : expressionNew(); @@ -816,6 +779,78 @@ } } + /** + * Generate the parameter list for the converted member reference. + * + * @return The receiver variable symbol, if any + */ + VarSymbol addParametersReturnReceiver() { + Type samDesc = localContext.bridgedRefSig(); + List samPTypes = samDesc.getParameterTypes(); + List descPTypes = tree.getDescriptorType(types).getParameterTypes(); + + // Determine the receiver, if any + VarSymbol rcvr; + switch (tree.kind) { + case BOUND: + // The receiver is explicit in the method reference + rcvr = addParameter("rec$", tree.getQualifierExpression().type, false); + receiverExpression = attr.makeNullCheck(tree.getQualifierExpression()); + break; + case UNBOUND: + // The receiver is the first parameter, extract it and + // adjust the SAM and unerased type lists accordingly + rcvr = addParameter("rec$", samDesc.getParameterTypes().head, false); + samPTypes = samPTypes.tail; + descPTypes = descPTypes.tail; + break; + default: + rcvr = null; + break; + } + List implPTypes = tree.sym.type.getParameterTypes(); + int implSize = implPTypes.size(); + int samSize = samPTypes.size(); + // Last parameter to copy from referenced method, exclude final var args + int last = localContext.needsVarArgsConversion() ? implSize - 1 : implSize; + + // Failsafe -- assure match-up + boolean checkForIntersection = tree.varargsElement != null || implSize == descPTypes.size(); + + // Use parameter types of the implementation method unless the unerased + // SAM parameter type is an intersection type, in that case use the + // erased SAM parameter type so that the supertype relationship + // the implementation method parameters is not obscured. + // Note: in this loop, the lists implPTypes, samPTypes, and descPTypes + // are used as pointers to the current parameter type information + // and are thus not usable afterwards. + for (int i = 0; implPTypes.nonEmpty() && i < last; ++i) { + // By default use the implementation method parmeter type + Type parmType = implPTypes.head; + // If the unerased parameter type is a type variable whose + // bound is an intersection (eg. ) then + // use the SAM parameter type + if (checkForIntersection && descPTypes.head.getKind() == TypeKind.TYPEVAR) { + TypeVar tv = (TypeVar) descPTypes.head; + if (tv.bound.getKind() == TypeKind.INTERSECTION) { + parmType = samPTypes.head; + } + } + addParameter("x$" + i, parmType, true); + + // Advance to the next parameter + implPTypes = implPTypes.tail; + samPTypes = samPTypes.tail; + descPTypes = descPTypes.tail; + } + // Flatten out the var args + for (int i = last; i < samSize; ++i) { + addParameter("xva$" + i, tree.varargsElement, true); + } + + return rcvr; + } + JCExpression getReceiverExpression() { return receiverExpression; } @@ -2064,11 +2099,35 @@ } /** + * Erasure destroys the implementation parameter subtype + * relationship for intersection types + */ + boolean interfaceParameterIsIntersectionType() { + List tl = tree.getDescriptorType(types).getParameterTypes(); + if (tree.kind == ReferenceKind.UNBOUND) { + tl = tl.tail; + } + for (; tl.nonEmpty(); tl = tl.tail) { + Type pt = tl.head; + if (pt.getKind() == TypeKind.TYPEVAR) { + TypeVar tv = (TypeVar) pt; + if (tv.bound.getKind() == TypeKind.INTERSECTION) { + return true; + } + } + } + return false; + } + + /** * Does this reference need to be converted to a lambda * (i.e. var args need to be expanded or "super" is used) */ final boolean needsConversionToLambda() { - return isSuper || needsVarArgsConversion() || isArrayOp() || + return interfaceParameterIsIntersectionType() || + isSuper || + needsVarArgsConversion() || + isArrayOp() || isPrivateInOtherClass() || !receiverAccessible() || (tree.getMode() == ReferenceMode.NEW && diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java Thu Dec 04 15:22:53 2014 -0800 @@ -25,75 +25,45 @@ package com.sun.tools.javac.comp; -import java.util.Collections; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.Set; - import javax.tools.JavaFileObject; import com.sun.tools.javac.code.*; -import com.sun.tools.javac.code.Scope.ImportFilter; -import com.sun.tools.javac.code.Scope.NamedImportScope; -import com.sun.tools.javac.code.Scope.StarImportScope; import com.sun.tools.javac.code.Scope.WriteableScope; -import com.sun.tools.javac.jvm.*; import com.sun.tools.javac.tree.*; import com.sun.tools.javac.util.*; -import com.sun.tools.javac.util.DefinedBy.Api; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.tree.JCTree.*; import static com.sun.tools.javac.code.Flags.*; -import static com.sun.tools.javac.code.Flags.ANNOTATION; -import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE; import static com.sun.tools.javac.code.Kinds.*; import static com.sun.tools.javac.code.Kinds.Kind.*; -import static com.sun.tools.javac.code.TypeTag.CLASS; -import static com.sun.tools.javac.code.TypeTag.ERROR; import static com.sun.tools.javac.code.TypeTag.TYPEVAR; -import static com.sun.tools.javac.tree.JCTree.Tag.*; -import com.sun.tools.javac.util.Dependencies.AttributionKind; -import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; -import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; - -/** This is the second phase of Enter, in which classes are completed - * by entering their members into the class scope using - * MemberEnter.complete(). See Enter for an overview. +/** Resolves field, method and constructor header, and constructs corresponding Symbols. * *

This is NOT part of any supported API. * If you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice. */ -public class MemberEnter extends JCTree.Visitor implements Completer { +public class MemberEnter extends JCTree.Visitor { protected static final Context.Key memberEnterKey = new Context.Key<>(); /** A switch to determine whether we check for package/class conflicts */ final static boolean checkClash = true; - private final Names names; private final Enter enter; private final Log log; private final Check chk; private final Attr attr; private final Symtab syms; - private final TreeMaker make; - private final Todo todo; private final Annotate annotate; - private final TypeAnnotations typeAnnotations; private final Types types; - private final JCDiagnostic.Factory diags; - private final Source source; - private final Target target; private final DeferredLintHandler deferredLintHandler; - private final Lint lint; - private final TypeEnvs typeEnvs; - private final Dependencies dependencies; public static MemberEnter instance(Context context) { MemberEnter instance = context.get(memberEnterKey); @@ -104,172 +74,14 @@ protected MemberEnter(Context context) { context.put(memberEnterKey, this); - names = Names.instance(context); enter = Enter.instance(context); log = Log.instance(context); chk = Check.instance(context); attr = Attr.instance(context); syms = Symtab.instance(context); - make = TreeMaker.instance(context); - todo = Todo.instance(context); annotate = Annotate.instance(context); - typeAnnotations = TypeAnnotations.instance(context); types = Types.instance(context); - diags = JCDiagnostic.Factory.instance(context); - source = Source.instance(context); - target = Target.instance(context); deferredLintHandler = DeferredLintHandler.instance(context); - lint = Lint.instance(context); - typeEnvs = TypeEnvs.instance(context); - dependencies = Dependencies.instance(context); - allowTypeAnnos = source.allowTypeAnnotations(); - } - - /** Switch: support type annotations. - */ - boolean allowTypeAnnos; - - /** A queue for classes whose members still need to be entered into the - * symbol table. - */ - ListBuffer> halfcompleted = new ListBuffer<>(); - - /** Set to true only when the first of a set of classes is - * processed from the half completed queue. - */ - boolean isFirst = true; - - /** A flag to disable completion from time to time during member - * enter, as we only need to look up types. This avoids - * unnecessarily deep recursion. - */ - boolean completionEnabled = true; - - /* ---------- Processing import clauses ---------------- - */ - - /** Import all classes of a class or package on demand. - * @param pos Position to be used for error reporting. - * @param tsym The class or package the members of which are imported. - * @param env The env in which the imported classes will be entered. - */ - private void importAll(int pos, - final TypeSymbol tsym, - Env env) { - // Check that packages imported from exist (JLS ???). - if (tsym.kind == PCK && tsym.members().isEmpty() && !tsym.exists()) { - // If we can't find java.lang, exit immediately. - if (((PackageSymbol)tsym).fullname.equals(names.java_lang)) { - JCDiagnostic msg = diags.fragment("fatal.err.no.java.lang"); - throw new FatalError(msg); - } else { - log.error(DiagnosticFlag.RESOLVE_ERROR, pos, "doesnt.exist", tsym); - } - } - env.toplevel.starImportScope.importAll(tsym.members(), tsym.members(), typeImportFilter, false); - } - - /** Import all static members of a class or package on demand. - * @param pos Position to be used for error reporting. - * @param tsym The class or package the members of which are imported. - * @param env The env in which the imported classes will be entered. - */ - private void importStaticAll(int pos, - final TypeSymbol tsym, - Env env) { - final StarImportScope toScope = env.toplevel.starImportScope; - final PackageSymbol packge = env.toplevel.packge; - final TypeSymbol origin = tsym; - - // enter imported types immediately - new SymbolImporter() { - void doImport(TypeSymbol tsym) { - toScope.importAll(tsym.members(), origin.members(), staticImportFilter, true); - } - }.importFrom(tsym); - } - - /** Import statics types of a given name. Non-types are handled in Attr. - * @param pos Position to be used for error reporting. - * @param tsym The class from which the name is imported. - * @param name The (simple) name being imported. - * @param env The environment containing the named import - * scope to add to. - */ - private void importNamedStatic(final DiagnosticPosition pos, - final TypeSymbol tsym, - final Name name, - final Env env) { - if (tsym.kind != TYP) { - log.error(DiagnosticFlag.RECOVERABLE, pos, "static.imp.only.classes.and.interfaces"); - return; - } - - final NamedImportScope toScope = env.toplevel.namedImportScope; - final Scope originMembers = tsym.members(); - - // enter imported types immediately - new SymbolImporter() { - void doImport(TypeSymbol tsym) { - Set maskedOut = null; - for (Symbol sym : tsym.members().getSymbolsByName(name)) { - if (sym.kind == TYP && - staticImportFilter.accepts(originMembers, sym) && - !chk.checkUniqueStaticImport(pos, env.toplevel, sym)) { - if (maskedOut == null) - maskedOut = Collections.newSetFromMap(new IdentityHashMap()); - maskedOut.add(sym); - } - } - ImportFilter importFilter = maskedOut != null ? - new MaskedImportFilter(staticImportFilter, maskedOut) : - staticImportFilter; - toScope.importByName(tsym.members(), originMembers, name, importFilter); - } - }.importFrom(tsym); - } - //where: - class MaskedImportFilter implements ImportFilter { - - private final ImportFilter delegate; - private final Set maskedOut; - - public MaskedImportFilter(ImportFilter delegate, Set maskedOut) { - this.delegate = delegate; - this.maskedOut = maskedOut; - } - - @Override - public boolean accepts(Scope origin, Symbol sym) { - return !maskedOut.contains(sym) && delegate.accepts(origin, sym); - } - } - abstract class SymbolImporter { - Set processed = new HashSet<>(); - void importFrom(TypeSymbol tsym) { - if (tsym == null || !processed.add(tsym)) - return; - - // also import inherited names - importFrom(types.supertype(tsym.type).tsym); - for (Type t : types.interfaces(tsym.type)) - importFrom(t.tsym); - - doImport(tsym); - } - abstract void doImport(TypeSymbol tsym); - } - - /** Import given class. - * @param pos Position to be used for error reporting. - * @param tsym The class to be imported. - * @param env The environment containing the named import - * scope to add to. - */ - private void importNamed(DiagnosticPosition pos, final Symbol tsym, Env env) { - if (tsym.kind == TYP && - chk.checkUniqueImport(pos, env.toplevel, tsym)) - env.toplevel.namedImportScope.importType(tsym.owner.members(), tsym.owner.members(), tsym); } /** Construct method type from method signature. @@ -338,32 +150,6 @@ * Visitor methods for member enter *********************************************************************/ - ImportFilter staticImportFilter; - ImportFilter typeImportFilter = new ImportFilter() { - @Override - public boolean accepts(Scope origin, Symbol t) { - return t.kind == TYP; - } - }; - - protected void memberEnter(JCCompilationUnit tree, Env env) { - ImportFilter prevStaticImportFilter = staticImportFilter; - try { - final PackageSymbol packge = env.toplevel.packge; - this.staticImportFilter = new ImportFilter() { - @Override - public boolean accepts(Scope origin, Symbol sym) { - return sym.isStatic() && - chk.staticImportAccessible(sym, packge) && - sym.isMemberOf((TypeSymbol) origin.owner, types); - } - }; - memberEnter((JCTree) tree, env); - } finally { - this.staticImportFilter = prevStaticImportFilter; - } - } - /** Visitor argument: the current environment */ protected Env env; @@ -390,122 +176,6 @@ memberEnter(l.head, env); } - /** Enter members for a class. - */ - void finishClass(JCClassDecl tree, Env env) { - if ((tree.mods.flags & Flags.ENUM) != 0 && - (types.supertype(tree.sym.type).tsym.flags() & Flags.ENUM) == 0) { - addEnumMembers(tree, env); - } - memberEnter(tree.defs, env); - } - - /** Add the implicit members for an enum type - * to the symbol table. - */ - private void addEnumMembers(JCClassDecl tree, Env env) { - JCExpression valuesType = make.Type(new ArrayType(tree.sym.type, syms.arrayClass)); - - // public static T[] values() { return ???; } - JCMethodDecl values = make. - MethodDef(make.Modifiers(Flags.PUBLIC|Flags.STATIC), - names.values, - valuesType, - List.nil(), - List.nil(), - List.nil(), // thrown - null, //make.Block(0, Tree.emptyList.prepend(make.Return(make.Ident(names._null)))), - null); - memberEnter(values, env); - - // public static T valueOf(String name) { return ???; } - JCMethodDecl valueOf = make. - MethodDef(make.Modifiers(Flags.PUBLIC|Flags.STATIC), - names.valueOf, - make.Type(tree.sym.type), - List.nil(), - List.of(make.VarDef(make.Modifiers(Flags.PARAMETER | - Flags.MANDATED), - names.fromString("name"), - make.Type(syms.stringType), null)), - List.nil(), // thrown - null, //make.Block(0, Tree.emptyList.prepend(make.Return(make.Ident(names._null)))), - null); - memberEnter(valueOf, env); - } - - public void visitTopLevel(JCCompilationUnit tree) { - if (!tree.starImportScope.isEmpty()) { - // we must have already processed this toplevel - return; - } - - DiagnosticPosition prevLintPos = deferredLintHandler.immediate(); - Lint prevLint = chk.setLint(lint); - - try { - // Import-on-demand java.lang. - importAll(tree.pos, syms.enterPackage(names.java_lang), env); - - // Process the package def and all import clauses. - memberEnter(tree.defs, env); - } finally { - chk.setLint(prevLint); - deferredLintHandler.setPos(prevLintPos); - } - } - - public void visitPackageDef(JCPackageDecl tree) { - // check that no class exists with same fully qualified name as - // toplevel package - if (checkClash && tree.pid != null) { - Symbol p = env.toplevel.packge; - while (p.owner != syms.rootPackage) { - p.owner.complete(); // enter all class members of p - if (syms.classes.get(p.getQualifiedName()) != null) { - log.error(tree.pos, - "pkg.clashes.with.class.of.same.name", - p); - } - p = p.owner; - } - } - // process package annotations - annotate.annotateLater(tree.annotations, env, env.toplevel.packge, null); - } - - // process the non-static imports and the static imports of types. - public void visitImport(JCImport tree) { - dependencies.push(AttributionKind.IMPORT, tree); - JCFieldAccess imp = (JCFieldAccess)tree.qualid; - Name name = TreeInfo.name(imp); - - // Create a local environment pointing to this tree to disable - // effects of other imports in Resolve.findGlobalType - Env localEnv = env.dup(tree); - - TypeSymbol p = attr.attribImportQualifier(tree, localEnv).tsym; - if (name == names.asterisk) { - // Import on demand. - chk.checkCanonical(imp.selected); - if (tree.staticImport) - importStaticAll(tree.pos, p, env); - else - importAll(tree.pos, p, env); - } else { - // Named type import. - if (tree.staticImport) { - importNamedStatic(tree.pos(), p, name, localEnv); - chk.checkCanonical(imp.selected); - } else { - TypeSymbol c = attribImportType(imp, localEnv).tsym; - chk.checkCanonical(imp); - importNamed(tree.pos(), c, env); - } - } - dependencies.pop(); - } - public void visitMethodDef(JCMethodDecl tree) { WriteableScope enclScope = enter.enterScope(env); MethodSymbol m = new MethodSymbol(0, tree.name, null, enclScope.owner); @@ -765,35 +435,6 @@ return iEnv; } -/* ******************************************************************** - * Type completion - *********************************************************************/ - - Type attribImportType(JCTree tree, Env env) { - Assert.check(completionEnabled); - try { - // To prevent deep recursion, suppress completion of some - // types. - completionEnabled = false; - return attr.attribType(tree, env); - } finally { - completionEnabled = true; - } - } - - /** - * Check if a list of annotations contains a reference to - * java.lang.Deprecated. - **/ - private boolean hasDeprecatedAnnotation(List annotations) { - for (List al = annotations; !al.isEmpty(); al = al.tail) { - JCAnnotation a = al.head; - if (a.annotationType.type == syms.deprecatedType && a.args.isEmpty()) - return true; - } - return false; - } - /** Queue processing of an attribute default value. */ void annotateDefaultValueLater(final JCExpression defaultValue, final Env localEnv, @@ -839,534 +480,4 @@ localEnv); } -/* ******************************************************************** - * Source completer - *********************************************************************/ - - /** Complete entering a class. - * @param sym The symbol of the class to be completed. - */ - public void complete(Symbol sym) throws CompletionFailure { - // Suppress some (recursive) MemberEnter invocations - if (!completionEnabled) { - // Re-install same completer for next time around and return. - Assert.check((sym.flags() & Flags.COMPOUND) == 0); - sym.completer = this; - return; - } - - try { - annotate.enterStart(); - - ClassSymbol c = (ClassSymbol)sym; - ClassType ct = (ClassType)c.type; - Env env = typeEnvs.get(c); - JCClassDecl tree = (JCClassDecl)env.tree; - boolean wasFirst = isFirst; - isFirst = false; - - JavaFileObject prev = log.useSource(env.toplevel.sourcefile); - DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos()); - try { - dependencies.push(c); - - // Save class environment for later member enter (2) processing. - halfcompleted.append(env); - - // Mark class as not yet attributed. - c.flags_field |= UNATTRIBUTED; - - // If this is a toplevel-class, make sure any preceding import - // clauses have been seen. - if (c.owner.kind == PCK) { - memberEnter(env.toplevel, env.enclosing(TOPLEVEL)); - todo.append(env); - } - - if (c.owner.kind == TYP) - c.owner.complete(); - - // create an environment for evaluating the base clauses - Env baseEnv = baseEnv(tree, env); - - if (tree.extending != null) - annotate.annotateTypeLater(tree.extending, baseEnv, sym, tree.pos()); - for (JCExpression impl : tree.implementing) - annotate.annotateTypeLater(impl, baseEnv, sym, tree.pos()); - annotate.flush(); - - // Determine supertype. - Type supertype; - if (tree.extending != null) { - dependencies.push(AttributionKind.EXTENDS, tree.extending); - try { - supertype = attr.attribBase(tree.extending, baseEnv, - true, false, true); - } finally { - dependencies.pop(); - } - } else { - supertype = ((tree.mods.flags & Flags.ENUM) != 0) - ? attr.attribBase(enumBase(tree.pos, c), baseEnv, - true, false, false) - : (c.fullname == names.java_lang_Object) - ? Type.noType - : syms.objectType; - } - ct.supertype_field = modelMissingTypes(supertype, tree.extending, false); - - // Determine interfaces. - ListBuffer interfaces = new ListBuffer<>(); - ListBuffer all_interfaces = null; // lazy init - Set interfaceSet = new HashSet<>(); - List interfaceTrees = tree.implementing; - for (JCExpression iface : interfaceTrees) { - dependencies.push(AttributionKind.IMPLEMENTS, iface); - try { - Type it = attr.attribBase(iface, baseEnv, false, true, true); - if (it.hasTag(CLASS)) { - interfaces.append(it); - if (all_interfaces != null) all_interfaces.append(it); - chk.checkNotRepeated(iface.pos(), types.erasure(it), interfaceSet); - } else { - if (all_interfaces == null) - all_interfaces = new ListBuffer().appendList(interfaces); - all_interfaces.append(modelMissingTypes(it, iface, true)); - } - } finally { - dependencies.pop(); - } - } - - if ((c.flags_field & ANNOTATION) != 0) { - ct.interfaces_field = List.of(syms.annotationType); - ct.all_interfaces_field = ct.interfaces_field; - } else { - ct.interfaces_field = interfaces.toList(); - ct.all_interfaces_field = (all_interfaces == null) - ? ct.interfaces_field : all_interfaces.toList(); - } - - if (c.fullname == names.java_lang_Object) { - if (tree.extending != null) { - chk.checkNonCyclic(tree.extending.pos(), - supertype); - ct.supertype_field = Type.noType; - } - else if (tree.implementing.nonEmpty()) { - chk.checkNonCyclic(tree.implementing.head.pos(), - ct.interfaces_field.head); - ct.interfaces_field = List.nil(); - } - } - - // Annotations. - // In general, we cannot fully process annotations yet, but we - // can attribute the annotation types and then check to see if the - // @Deprecated annotation is present. - attr.attribAnnotationTypes(tree.mods.annotations, baseEnv); - if (hasDeprecatedAnnotation(tree.mods.annotations)) - c.flags_field |= DEPRECATED; - annotate.annotateLater(tree.mods.annotations, baseEnv, - c, tree.pos()); - - chk.checkNonCyclicDecl(tree); - - // class type parameters use baseEnv but everything uses env - attr.attribTypeVariables(tree.typarams, baseEnv); - for (JCTypeParameter tp : tree.typarams) - annotate.annotateTypeLater(tp, baseEnv, sym, tree.pos()); - - // Add default constructor if needed. - if ((c.flags() & INTERFACE) == 0 && - !TreeInfo.hasConstructors(tree.defs)) { - List argtypes = List.nil(); - List typarams = List.nil(); - List thrown = List.nil(); - long ctorFlags = 0; - boolean based = false; - boolean addConstructor = true; - JCNewClass nc = null; - if (c.name.isEmpty()) { - nc = (JCNewClass)env.next.tree; - if (nc.constructor != null) { - addConstructor = nc.constructor.kind != ERR; - Type superConstrType = types.memberType(c.type, - nc.constructor); - argtypes = superConstrType.getParameterTypes(); - typarams = superConstrType.getTypeArguments(); - ctorFlags = nc.constructor.flags() & VARARGS; - if (nc.encl != null) { - argtypes = argtypes.prepend(nc.encl.type); - based = true; - } - thrown = superConstrType.getThrownTypes(); - } - } - if (addConstructor) { - MethodSymbol basedConstructor = nc != null ? - (MethodSymbol)nc.constructor : null; - JCTree constrDef = DefaultConstructor(make.at(tree.pos), c, - basedConstructor, - typarams, argtypes, thrown, - ctorFlags, based); - tree.defs = tree.defs.prepend(constrDef); - } - } - - // enter symbols for 'this' into current scope. - VarSymbol thisSym = - new VarSymbol(FINAL | HASINIT, names._this, c.type, c); - thisSym.pos = Position.FIRSTPOS; - env.info.scope.enter(thisSym); - // if this is a class, enter symbol for 'super' into current scope. - if ((c.flags_field & INTERFACE) == 0 && - ct.supertype_field.hasTag(CLASS)) { - VarSymbol superSym = - new VarSymbol(FINAL | HASINIT, names._super, - ct.supertype_field, c); - superSym.pos = Position.FIRSTPOS; - env.info.scope.enter(superSym); - } - - // check that no package exists with same fully qualified name, - // but admit classes in the unnamed package which have the same - // name as a top-level package. - if (checkClash && - c.owner.kind == PCK && c.owner != syms.unnamedPackage && - syms.packageExists(c.fullname)) { - log.error(tree.pos, "clash.with.pkg.of.same.name", Kinds.kindName(sym), c); - } - if (c.owner.kind == PCK && (c.flags_field & PUBLIC) == 0 && - !env.toplevel.sourcefile.isNameCompatible(c.name.toString(),JavaFileObject.Kind.SOURCE)) { - c.flags_field |= AUXILIARY; - } - } catch (CompletionFailure ex) { - chk.completionError(tree.pos(), ex); - } finally { - deferredLintHandler.setPos(prevLintPos); - log.useSource(prev); - dependencies.pop(); - } - - // Enter all member fields and methods of a set of half completed - // classes in a second phase. - if (wasFirst) { - Set topLevels = new HashSet<>(); - try { - while (halfcompleted.nonEmpty()) { - Env toFinish = halfcompleted.next(); - topLevels.add(toFinish.toplevel); - finish(toFinish); - if (allowTypeAnnos) { - typeAnnotations.organizeTypeAnnotationsSignatures(toFinish, (JCClassDecl)toFinish.tree); - typeAnnotations.validateTypeAnnotationsSignatures(toFinish, (JCClassDecl)toFinish.tree); - } - } - } finally { - isFirst = true; - } - - for (JCCompilationUnit toplevel : topLevels) { - chk.checkImportsResolvable(toplevel); - } - - } - } finally { - annotate.enterDone(); - } - } - - private Env baseEnv(JCClassDecl tree, Env env) { - WriteableScope baseScope = WriteableScope.create(tree.sym); - //import already entered local classes into base scope - for (Symbol sym : env.outer.info.scope.getSymbols(NON_RECURSIVE)) { - if (sym.isLocal()) { - baseScope.enter(sym); - } - } - //import current type-parameters into base scope - if (tree.typarams != null) - for (List typarams = tree.typarams; - typarams.nonEmpty(); - typarams = typarams.tail) - baseScope.enter(typarams.head.type.tsym); - Env outer = env.outer; // the base clause can't see members of this class - Env localEnv = outer.dup(tree, outer.info.dup(baseScope)); - localEnv.baseClause = true; - localEnv.outer = outer; - localEnv.info.isSelfCall = false; - return localEnv; - } - - /** Enter member fields and methods of a class - * @param env the environment current for the class block. - */ - private void finish(Env env) { - JavaFileObject prev = log.useSource(env.toplevel.sourcefile); - try { - JCClassDecl tree = (JCClassDecl)env.tree; - finishClass(tree, env); - } finally { - log.useSource(prev); - } - } - - /** Generate a base clause for an enum type. - * @param pos The position for trees and diagnostics, if any - * @param c The class symbol of the enum - */ - private JCExpression enumBase(int pos, ClassSymbol c) { - JCExpression result = make.at(pos). - TypeApply(make.QualIdent(syms.enumSym), - List.of(make.Type(c.type))); - return result; - } - - Type modelMissingTypes(Type t, final JCExpression tree, final boolean interfaceExpected) { - if (!t.hasTag(ERROR)) - return t; - - return new ErrorType(t.getOriginalType(), t.tsym) { - private Type modelType; - - @Override - public Type getModelType() { - if (modelType == null) - modelType = new Synthesizer(getOriginalType(), interfaceExpected).visit(tree); - return modelType; - } - }; - } - // where - private class Synthesizer extends JCTree.Visitor { - Type originalType; - boolean interfaceExpected; - List synthesizedSymbols = List.nil(); - Type result; - - Synthesizer(Type originalType, boolean interfaceExpected) { - this.originalType = originalType; - this.interfaceExpected = interfaceExpected; - } - - Type visit(JCTree tree) { - tree.accept(this); - return result; - } - - List visit(List trees) { - ListBuffer lb = new ListBuffer<>(); - for (JCTree t: trees) - lb.append(visit(t)); - return lb.toList(); - } - - @Override - public void visitTree(JCTree tree) { - result = syms.errType; - } - - @Override - public void visitIdent(JCIdent tree) { - if (!tree.type.hasTag(ERROR)) { - result = tree.type; - } else { - result = synthesizeClass(tree.name, syms.unnamedPackage).type; - } - } - - @Override - public void visitSelect(JCFieldAccess tree) { - if (!tree.type.hasTag(ERROR)) { - result = tree.type; - } else { - Type selectedType; - boolean prev = interfaceExpected; - try { - interfaceExpected = false; - selectedType = visit(tree.selected); - } finally { - interfaceExpected = prev; - } - ClassSymbol c = synthesizeClass(tree.name, selectedType.tsym); - result = c.type; - } - } - - @Override - public void visitTypeApply(JCTypeApply tree) { - if (!tree.type.hasTag(ERROR)) { - result = tree.type; - } else { - ClassType clazzType = (ClassType) visit(tree.clazz); - if (synthesizedSymbols.contains(clazzType.tsym)) - synthesizeTyparams((ClassSymbol) clazzType.tsym, tree.arguments.size()); - final List actuals = visit(tree.arguments); - result = new ErrorType(tree.type, clazzType.tsym) { - @Override @DefinedBy(Api.LANGUAGE_MODEL) - public List getTypeArguments() { - return actuals; - } - }; - } - } - - ClassSymbol synthesizeClass(Name name, Symbol owner) { - int flags = interfaceExpected ? INTERFACE : 0; - ClassSymbol c = new ClassSymbol(flags, name, owner); - c.members_field = new Scope.ErrorScope(c); - c.type = new ErrorType(originalType, c) { - @Override @DefinedBy(Api.LANGUAGE_MODEL) - public List getTypeArguments() { - return typarams_field; - } - }; - synthesizedSymbols = synthesizedSymbols.prepend(c); - return c; - } - - void synthesizeTyparams(ClassSymbol sym, int n) { - ClassType ct = (ClassType) sym.type; - Assert.check(ct.typarams_field.isEmpty()); - if (n == 1) { - TypeVar v = new TypeVar(names.fromString("T"), sym, syms.botType); - ct.typarams_field = ct.typarams_field.prepend(v); - } else { - for (int i = n; i > 0; i--) { - TypeVar v = new TypeVar(names.fromString("T" + i), sym, - syms.botType); - ct.typarams_field = ct.typarams_field.prepend(v); - } - } - } - } - - -/* *************************************************************************** - * tree building - ****************************************************************************/ - - /** Generate default constructor for given class. For classes different - * from java.lang.Object, this is: - * - * c(argtype_0 x_0, ..., argtype_n x_n) throws thrown { - * super(x_0, ..., x_n) - * } - * - * or, if based == true: - * - * c(argtype_0 x_0, ..., argtype_n x_n) throws thrown { - * x_0.super(x_1, ..., x_n) - * } - * - * @param make The tree factory. - * @param c The class owning the default constructor. - * @param argtypes The parameter types of the constructor. - * @param thrown The thrown exceptions of the constructor. - * @param based Is first parameter a this$n? - */ - JCTree DefaultConstructor(TreeMaker make, - ClassSymbol c, - MethodSymbol baseInit, - List typarams, - List argtypes, - List thrown, - long flags, - boolean based) { - JCTree result; - if ((c.flags() & ENUM) != 0 && - (types.supertype(c.type).tsym == syms.enumSym)) { - // constructors of true enums are private - flags = (flags & ~AccessFlags) | PRIVATE | GENERATEDCONSTR; - } else - flags |= (c.flags() & AccessFlags) | GENERATEDCONSTR; - if (c.name.isEmpty()) { - flags |= ANONCONSTR; - } - Type mType = new MethodType(argtypes, null, thrown, c); - Type initType = typarams.nonEmpty() ? - new ForAll(typarams, mType) : - mType; - MethodSymbol init = new MethodSymbol(flags, names.init, - initType, c); - init.params = createDefaultConstructorParams(make, baseInit, init, - argtypes, based); - List params = make.Params(argtypes, init); - List stats = List.nil(); - if (c.type != syms.objectType) { - stats = stats.prepend(SuperCall(make, typarams, params, based)); - } - result = make.MethodDef(init, make.Block(0, stats)); - return result; - } - - private List createDefaultConstructorParams( - TreeMaker make, - MethodSymbol baseInit, - MethodSymbol init, - List argtypes, - boolean based) { - List initParams = null; - List argTypesList = argtypes; - if (based) { - /* In this case argtypes will have an extra type, compared to baseInit, - * corresponding to the type of the enclosing instance i.e.: - * - * Inner i = outer.new Inner(1){} - * - * in the above example argtypes will be (Outer, int) and baseInit - * will have parameter's types (int). So in this case we have to add - * first the extra type in argtypes and then get the names of the - * parameters from baseInit. - */ - initParams = List.nil(); - VarSymbol param = new VarSymbol(PARAMETER, make.paramName(0), argtypes.head, init); - initParams = initParams.append(param); - argTypesList = argTypesList.tail; - } - if (baseInit != null && baseInit.params != null && - baseInit.params.nonEmpty() && argTypesList.nonEmpty()) { - initParams = (initParams == null) ? List.nil() : initParams; - List baseInitParams = baseInit.params; - while (baseInitParams.nonEmpty() && argTypesList.nonEmpty()) { - VarSymbol param = new VarSymbol(baseInitParams.head.flags() | PARAMETER, - baseInitParams.head.name, argTypesList.head, init); - initParams = initParams.append(param); - baseInitParams = baseInitParams.tail; - argTypesList = argTypesList.tail; - } - } - return initParams; - } - - /** Generate call to superclass constructor. This is: - * - * super(id_0, ..., id_n) - * - * or, if based == true - * - * id_0.super(id_1,...,id_n) - * - * where id_0, ..., id_n are the names of the given parameters. - * - * @param make The tree factory - * @param params The parameters that need to be passed to super - * @param typarams The type parameters that need to be passed to super - * @param based Is first parameter a this$n? - */ - JCExpressionStatement SuperCall(TreeMaker make, - List typarams, - List params, - boolean based) { - JCExpression meth; - if (based) { - meth = make.Select(make.Ident(params.head), names._super); - params = params.tail; - } else { - meth = make.Ident(names._super); - } - List typeargs = typarams.nonEmpty() ? make.Types(typarams) : null; - return make.Exec(make.Apply(typeargs, meth, make.Idents(params))); - } } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java Thu Dec 04 15:22:53 2014 -0800 @@ -3172,7 +3172,7 @@ super(referenceTree, name, site, argtypes.tail, typeargtypes, maxPhase); if (site.isRaw() && !argtypes.head.hasTag(NONE)) { Type asSuperSite = types.asSuper(argtypes.head, site.tsym); - this.site = asSuperSite; + this.site = types.capture(asSuperSite); } } @@ -4039,7 +4039,7 @@ s : new MethodSymbol( s.flags(), s.name, - types.createMethodTypeWithThrown(mt, allThrown), + types.createMethodTypeWithThrown(s.type, allThrown), s.owner); } } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,1070 @@ +/* + * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.javac.comp; + +import java.util.HashSet; +import java.util.Set; + +import javax.tools.JavaFileObject; + +import com.sun.tools.javac.code.*; +import com.sun.tools.javac.code.Lint.LintCategory; +import com.sun.tools.javac.code.Scope.ImportFilter; +import com.sun.tools.javac.code.Scope.NamedImportScope; +import com.sun.tools.javac.code.Scope.StarImportScope; +import com.sun.tools.javac.code.Scope.WriteableScope; +import com.sun.tools.javac.tree.*; +import com.sun.tools.javac.util.*; +import com.sun.tools.javac.util.DefinedBy.Api; + +import com.sun.tools.javac.code.Symbol.*; +import com.sun.tools.javac.code.Type.*; +import com.sun.tools.javac.tree.JCTree.*; + +import static com.sun.tools.javac.code.Flags.*; +import static com.sun.tools.javac.code.Flags.ANNOTATION; +import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE; +import static com.sun.tools.javac.code.Kinds.Kind.*; +import static com.sun.tools.javac.code.TypeTag.CLASS; +import static com.sun.tools.javac.code.TypeTag.ERROR; +import static com.sun.tools.javac.tree.JCTree.Tag.*; + +import com.sun.tools.javac.util.Dependencies.AttributionKind; +import com.sun.tools.javac.util.Dependencies.CompletionCause; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; + +/** This is the second phase of Enter, in which classes are completed + * by resolving their headers and entering their members in the into + * the class scope. See Enter for an overall overview. + * + * This class uses internal phases to process the classes. When a phase + * processes classes, the lower phases are not invoked until all classes + * pass through the current phase. Note that it is possible that upper phases + * are run due to recursive completion. The internal phases are: + * - ImportPhase: shallow pass through imports, adds information about imports + * the NamedImportScope and StarImportScope, but avoids queries + * about class hierarchy. + * - HierarchyPhase: resolves the supertypes of the given class. Does not handle + * type parameters of the class or type argument of the supertypes. + * - HeaderPhase: finishes analysis of the header of the given class by resolving + * type parameters, attributing supertypes including type arguments + * and scheduling full annotation attribution. This phase also adds + * a synthetic default constructor if needed and synthetic "this" field. + * - MembersPhase: resolves headers for fields, methods and constructors in the given class. + * Also generates synthetic enum members. + * + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class TypeEnter implements Completer { + protected static final Context.Key typeEnterKey = new Context.Key<>(); + + /** A switch to determine whether we check for package/class conflicts + */ + final static boolean checkClash = true; + + private final Names names; + private final Enter enter; + private final MemberEnter memberEnter; + private final Log log; + private final Check chk; + private final Attr attr; + private final Symtab syms; + private final TreeMaker make; + private final Todo todo; + private final Annotate annotate; + private final TypeAnnotations typeAnnotations; + private final Types types; + private final JCDiagnostic.Factory diags; + private final Source source; + private final DeferredLintHandler deferredLintHandler; + private final Lint lint; + private final TypeEnvs typeEnvs; + private final Dependencies dependencies; + + public static TypeEnter instance(Context context) { + TypeEnter instance = context.get(typeEnterKey); + if (instance == null) + instance = new TypeEnter(context); + return instance; + } + + protected TypeEnter(Context context) { + context.put(typeEnterKey, this); + names = Names.instance(context); + enter = Enter.instance(context); + memberEnter = MemberEnter.instance(context); + log = Log.instance(context); + chk = Check.instance(context); + attr = Attr.instance(context); + syms = Symtab.instance(context); + make = TreeMaker.instance(context); + todo = Todo.instance(context); + annotate = Annotate.instance(context); + typeAnnotations = TypeAnnotations.instance(context); + types = Types.instance(context); + diags = JCDiagnostic.Factory.instance(context); + source = Source.instance(context); + deferredLintHandler = DeferredLintHandler.instance(context); + lint = Lint.instance(context); + typeEnvs = TypeEnvs.instance(context); + dependencies = Dependencies.instance(context); + allowTypeAnnos = source.allowTypeAnnotations(); + allowDeprecationOnImport = source.allowDeprecationOnImport(); + } + + /** Switch: support type annotations. + */ + boolean allowTypeAnnos; + + /** + * Switch: should deprecation warnings be issued on import + */ + boolean allowDeprecationOnImport; + + /** A flag to disable completion from time to time during member + * enter, as we only need to look up types. This avoids + * unnecessarily deep recursion. + */ + boolean completionEnabled = true; + + /* Verify Imports: + */ + protected void ensureImportsChecked(List trees) { + // 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.isEmpty()) { + Env topEnv = enter.topLevelEnv(tree); + finishImports(tree, () -> { completeClass.resolveImports(tree, topEnv); }); + } + } + } + +/* ******************************************************************** + * Source completer + *********************************************************************/ + + /** Complete entering a class. + * @param sym The symbol of the class to be completed. + */ + public void complete(Symbol sym) throws CompletionFailure { + // Suppress some (recursive) MemberEnter invocations + if (!completionEnabled) { + // Re-install same completer for next time around and return. + Assert.check((sym.flags() & Flags.COMPOUND) == 0); + sym.completer = this; + return; + } + + try { + annotate.enterStart(); + sym.flags_field |= UNATTRIBUTED; + + List> queue; + + dependencies.push((ClassSymbol) sym, CompletionCause.MEMBER_ENTER); + try { + queue = completeClass.runPhase(List.of(typeEnvs.get((ClassSymbol) sym))); + } finally { + dependencies.pop(); + } + + if (!queue.isEmpty()) { + Set seen = new HashSet<>(); + + for (Env env : queue) { + if (env.toplevel.defs.contains(env.enclClass) && seen.add(env.toplevel)) { + finishImports(env.toplevel, () -> {}); + } + } + } + } finally { + annotate.enterDone(); + } + } + + void finishImports(JCCompilationUnit toplevel, Runnable resolve) { + JavaFileObject prev = log.useSource(toplevel.sourcefile); + try { + resolve.run(); + chk.checkImportsUnique(toplevel); + chk.checkImportsResolvable(toplevel); + toplevel.namedImportScope.finalizeScope(); + toplevel.starImportScope.finalizeScope(); + } finally { + log.useSource(prev); + } + } + + abstract class Phase { + private final ListBuffer> queue = new ListBuffer<>(); + private final Phase next; + private final CompletionCause phaseName; + + Phase(CompletionCause phaseName, Phase next) { + this.phaseName = phaseName; + this.next = next; + } + + public List> runPhase(List> envs) { + boolean firstToComplete = queue.isEmpty(); + + for (Env env : envs) { + JCClassDecl tree = (JCClassDecl)env.tree; + + queue.add(env); + + JavaFileObject prev = log.useSource(env.toplevel.sourcefile); + DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos()); + try { + dependencies.push(env.enclClass.sym, phaseName); + doRunPhase(env); + } catch (CompletionFailure ex) { + chk.completionError(tree.pos(), ex); + } finally { + dependencies.pop(); + deferredLintHandler.setPos(prevLintPos); + log.useSource(prev); + } + } + + if (firstToComplete) { + List> out = queue.toList(); + + queue.clear(); + return next != null ? next.runPhase(out) : out; + } else { + return List.nil(); + } + } + + protected abstract void doRunPhase(Env env); + } + + private final ImportsPhase completeClass = new ImportsPhase(); + + /**Analyze import clauses. + */ + private final class ImportsPhase extends Phase { + + public ImportsPhase() { + super(CompletionCause.IMPORTS_PHASE, new HierarchyPhase()); + } + + Env env; + ImportFilter staticImportFilter; + ImportFilter typeImportFilter = new ImportFilter() { + @Override + public boolean accepts(Scope origin, Symbol t) { + return t.kind == TYP; + } + }; + + @Override + protected void doRunPhase(Env env) { + JCClassDecl tree = env.enclClass; + ClassSymbol sym = tree.sym; + + // If sym is a toplevel-class, make sure any import + // clauses in its source file have been seen. + if (sym.owner.kind == PCK) { + resolveImports(env.toplevel, env.enclosing(TOPLEVEL)); + todo.append(env); + } + + if (sym.owner.kind == TYP) + sym.owner.complete(); + } + + private void resolveImports(JCCompilationUnit tree, Env env) { + if (!tree.starImportScope.isEmpty()) { + // we must have already processed this toplevel + return; + } + + ImportFilter prevStaticImportFilter = staticImportFilter; + DiagnosticPosition prevLintPos = deferredLintHandler.immediate(); + Lint prevLint = chk.setLint(lint); + Env prevEnv = this.env; + try { + this.env = env; + final PackageSymbol packge = env.toplevel.packge; + this.staticImportFilter = new ImportFilter() { + @Override + public boolean accepts(Scope origin, Symbol sym) { + return sym.isStatic() && + chk.staticImportAccessible(sym, packge) && + sym.isMemberOf((TypeSymbol) origin.owner, types); + } + }; + + // Import-on-demand java.lang. + importAll(tree.pos, syms.enterPackage(names.java_lang), env); + + // Process the package def and all import clauses. + if (tree.getPackage() != null) + checkClassPackageClash(tree.getPackage()); + + for (JCImport imp : tree.getImports()) { + doImport(imp); + } + } finally { + this.env = prevEnv; + chk.setLint(prevLint); + deferredLintHandler.setPos(prevLintPos); + this.staticImportFilter = prevStaticImportFilter; + } + } + + private void checkClassPackageClash(JCPackageDecl tree) { + // check that no class exists with same fully qualified name as + // toplevel package + if (checkClash && tree.pid != null) { + Symbol p = env.toplevel.packge; + while (p.owner != syms.rootPackage) { + p.owner.complete(); // enter all class members of p + if (syms.classes.get(p.getQualifiedName()) != null) { + log.error(tree.pos, + "pkg.clashes.with.class.of.same.name", + p); + } + p = p.owner; + } + } + // process package annotations + annotate.annotateLater(tree.annotations, env, env.toplevel.packge, null); + } + + private void doImport(JCImport tree) { + dependencies.push(AttributionKind.IMPORT, tree); + JCFieldAccess imp = (JCFieldAccess)tree.qualid; + Name name = TreeInfo.name(imp); + + // Create a local environment pointing to this tree to disable + // effects of other imports in Resolve.findGlobalType + Env localEnv = env.dup(tree); + + TypeSymbol p = attr.attribImportQualifier(tree, localEnv).tsym; + if (name == names.asterisk) { + // Import on demand. + chk.checkCanonical(imp.selected); + if (tree.staticImport) + importStaticAll(tree.pos, p, env); + else + importAll(tree.pos, p, env); + } else { + // Named type import. + if (tree.staticImport) { + importNamedStatic(tree.pos(), p, name, localEnv, tree); + chk.checkCanonical(imp.selected); + } else { + TypeSymbol c = attribImportType(imp, localEnv).tsym; + chk.checkCanonical(imp); + importNamed(tree.pos(), c, env, tree); + } + } + dependencies.pop(); + } + + Type attribImportType(JCTree tree, Env env) { + Assert.check(completionEnabled); + Lint prevLint = chk.setLint(allowDeprecationOnImport ? + lint : lint.suppress(LintCategory.DEPRECATION)); + try { + // To prevent deep recursion, suppress completion of some + // types. + completionEnabled = false; + return attr.attribType(tree, env); + } finally { + completionEnabled = true; + chk.setLint(prevLint); + } + } + + /** Import all classes of a class or package on demand. + * @param pos Position to be used for error reporting. + * @param tsym The class or package the members of which are imported. + * @param env The env in which the imported classes will be entered. + */ + private void importAll(int pos, + final TypeSymbol tsym, + Env env) { + // Check that packages imported from exist (JLS ???). + if (tsym.kind == PCK && tsym.members().isEmpty() && !tsym.exists()) { + // If we can't find java.lang, exit immediately. + if (((PackageSymbol)tsym).fullname.equals(names.java_lang)) { + JCDiagnostic msg = diags.fragment("fatal.err.no.java.lang"); + throw new FatalError(msg); + } else { + log.error(DiagnosticFlag.RESOLVE_ERROR, pos, "doesnt.exist", tsym); + } + } + env.toplevel.starImportScope.importAll(types, tsym.members(), typeImportFilter, false); + } + + /** Import all static members of a class or package on demand. + * @param pos Position to be used for error reporting. + * @param tsym The class or package the members of which are imported. + * @param env The env in which the imported classes will be entered. + */ + private void importStaticAll(int pos, + final TypeSymbol tsym, + Env env) { + final StarImportScope toScope = env.toplevel.starImportScope; + final TypeSymbol origin = tsym; + + toScope.importAll(types, origin.members(), staticImportFilter, true); + } + + /** Import statics types of a given name. Non-types are handled in Attr. + * @param pos Position to be used for error reporting. + * @param tsym The class from which the name is imported. + * @param name The (simple) name being imported. + * @param env The environment containing the named import + * scope to add to. + */ + private void importNamedStatic(final DiagnosticPosition pos, + final TypeSymbol tsym, + final Name name, + final Env env, + final JCImport imp) { + if (tsym.kind != TYP) { + log.error(DiagnosticFlag.RECOVERABLE, pos, "static.imp.only.classes.and.interfaces"); + return; + } + + final NamedImportScope toScope = env.toplevel.namedImportScope; + final Scope originMembers = tsym.members(); + + imp.importScope = toScope.importByName(types, originMembers, name, staticImportFilter); + } + + /** Import given class. + * @param pos Position to be used for error reporting. + * @param tsym The class to be imported. + * @param env The environment containing the named import + * scope to add to. + */ + private void importNamed(DiagnosticPosition pos, final Symbol tsym, Env env, JCImport imp) { + if (tsym.kind == TYP) + imp.importScope = env.toplevel.namedImportScope.importType(tsym.owner.members(), tsym.owner.members(), tsym); + } + + } + + /**Defines common utility methods used by the HierarchyPhase and HeaderPhase. + */ + private abstract class AbstractHeaderPhase extends Phase { + + public AbstractHeaderPhase(CompletionCause phaseName, Phase next) { + super(phaseName, next); + } + + protected Env baseEnv(JCClassDecl tree, Env env) { + WriteableScope baseScope = WriteableScope.create(tree.sym); + //import already entered local classes into base scope + for (Symbol sym : env.outer.info.scope.getSymbols(NON_RECURSIVE)) { + if (sym.isLocal()) { + baseScope.enter(sym); + } + } + //import current type-parameters into base scope + if (tree.typarams != null) + for (List typarams = tree.typarams; + typarams.nonEmpty(); + typarams = typarams.tail) + baseScope.enter(typarams.head.type.tsym); + Env outer = env.outer; // the base clause can't see members of this class + Env localEnv = outer.dup(tree, outer.info.dup(baseScope)); + localEnv.baseClause = true; + localEnv.outer = outer; + localEnv.info.isSelfCall = false; + return localEnv; + } + + /** Generate a base clause for an enum type. + * @param pos The position for trees and diagnostics, if any + * @param c The class symbol of the enum + */ + protected JCExpression enumBase(int pos, ClassSymbol c) { + JCExpression result = make.at(pos). + TypeApply(make.QualIdent(syms.enumSym), + List.of(make.Type(c.type))); + return result; + } + + protected Type modelMissingTypes(Type t, final JCExpression tree, final boolean interfaceExpected) { + if (!t.hasTag(ERROR)) + return t; + + return new ErrorType(t.getOriginalType(), t.tsym) { + private Type modelType; + + @Override + public Type getModelType() { + if (modelType == null) + modelType = new Synthesizer(getOriginalType(), interfaceExpected).visit(tree); + return modelType; + } + }; + } + // where: + private class Synthesizer extends JCTree.Visitor { + Type originalType; + boolean interfaceExpected; + List synthesizedSymbols = List.nil(); + Type result; + + Synthesizer(Type originalType, boolean interfaceExpected) { + this.originalType = originalType; + this.interfaceExpected = interfaceExpected; + } + + Type visit(JCTree tree) { + tree.accept(this); + return result; + } + + List visit(List trees) { + ListBuffer lb = new ListBuffer<>(); + for (JCTree t: trees) + lb.append(visit(t)); + return lb.toList(); + } + + @Override + public void visitTree(JCTree tree) { + result = syms.errType; + } + + @Override + public void visitIdent(JCIdent tree) { + if (!tree.type.hasTag(ERROR)) { + result = tree.type; + } else { + result = synthesizeClass(tree.name, syms.unnamedPackage).type; + } + } + + @Override + public void visitSelect(JCFieldAccess tree) { + if (!tree.type.hasTag(ERROR)) { + result = tree.type; + } else { + Type selectedType; + boolean prev = interfaceExpected; + try { + interfaceExpected = false; + selectedType = visit(tree.selected); + } finally { + interfaceExpected = prev; + } + ClassSymbol c = synthesizeClass(tree.name, selectedType.tsym); + result = c.type; + } + } + + @Override + public void visitTypeApply(JCTypeApply tree) { + if (!tree.type.hasTag(ERROR)) { + result = tree.type; + } else { + ClassType clazzType = (ClassType) visit(tree.clazz); + if (synthesizedSymbols.contains(clazzType.tsym)) + synthesizeTyparams((ClassSymbol) clazzType.tsym, tree.arguments.size()); + final List actuals = visit(tree.arguments); + result = new ErrorType(tree.type, clazzType.tsym) { + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public List getTypeArguments() { + return actuals; + } + }; + } + } + + ClassSymbol synthesizeClass(Name name, Symbol owner) { + int flags = interfaceExpected ? INTERFACE : 0; + ClassSymbol c = new ClassSymbol(flags, name, owner); + c.members_field = new Scope.ErrorScope(c); + c.type = new ErrorType(originalType, c) { + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public List getTypeArguments() { + return typarams_field; + } + }; + synthesizedSymbols = synthesizedSymbols.prepend(c); + return c; + } + + void synthesizeTyparams(ClassSymbol sym, int n) { + ClassType ct = (ClassType) sym.type; + Assert.check(ct.typarams_field.isEmpty()); + if (n == 1) { + TypeVar v = new TypeVar(names.fromString("T"), sym, syms.botType); + ct.typarams_field = ct.typarams_field.prepend(v); + } else { + for (int i = n; i > 0; i--) { + TypeVar v = new TypeVar(names.fromString("T" + i), sym, + syms.botType); + ct.typarams_field = ct.typarams_field.prepend(v); + } + } + } + } + + protected void attribSuperTypes(Env env, Env baseEnv) { + JCClassDecl tree = env.enclClass; + ClassSymbol sym = tree.sym; + ClassType ct = (ClassType)sym.type; + // Determine supertype. + Type supertype; + JCExpression extending; + + if (tree.extending != null) { + extending = clearTypeParams(tree.extending); + dependencies.push(AttributionKind.EXTENDS, tree.extending); + try { + supertype = attr.attribBase(extending, baseEnv, + true, false, true); + } finally { + dependencies.pop(); + } + } else { + extending = null; + supertype = ((tree.mods.flags & Flags.ENUM) != 0) + ? attr.attribBase(enumBase(tree.pos, sym), baseEnv, + true, false, false) + : (sym.fullname == names.java_lang_Object) + ? Type.noType + : syms.objectType; + } + ct.supertype_field = modelMissingTypes(supertype, extending, false); + + // Determine interfaces. + ListBuffer interfaces = new ListBuffer<>(); + ListBuffer all_interfaces = null; // lazy init + List interfaceTrees = tree.implementing; + for (JCExpression iface : interfaceTrees) { + iface = clearTypeParams(iface); + dependencies.push(AttributionKind.IMPLEMENTS, iface); + try { + Type it = attr.attribBase(iface, baseEnv, false, true, true); + if (it.hasTag(CLASS)) { + interfaces.append(it); + if (all_interfaces != null) all_interfaces.append(it); + } else { + if (all_interfaces == null) + all_interfaces = new ListBuffer().appendList(interfaces); + all_interfaces.append(modelMissingTypes(it, iface, true)); + + } + } finally { + dependencies.pop(); + } + } + + if ((sym.flags_field & ANNOTATION) != 0) { + ct.interfaces_field = List.of(syms.annotationType); + ct.all_interfaces_field = ct.interfaces_field; + } else { + ct.interfaces_field = interfaces.toList(); + ct.all_interfaces_field = (all_interfaces == null) + ? ct.interfaces_field : all_interfaces.toList(); + } + } + //where: + protected JCExpression clearTypeParams(JCExpression superType) { + return superType; + } + } + + private final class HierarchyPhase extends AbstractHeaderPhase { + + public HierarchyPhase() { + super(CompletionCause.HIERARCHY_PHASE, new HeaderPhase()); + } + + @Override + protected void doRunPhase(Env env) { + JCClassDecl tree = env.enclClass; + ClassSymbol sym = tree.sym; + ClassType ct = (ClassType)sym.type; + + Env baseEnv = baseEnv(tree, env); + + attribSuperTypes(env, baseEnv); + + if (sym.fullname == names.java_lang_Object) { + if (tree.extending != null) { + chk.checkNonCyclic(tree.extending.pos(), + ct.supertype_field); + ct.supertype_field = Type.noType; + } + else if (tree.implementing.nonEmpty()) { + chk.checkNonCyclic(tree.implementing.head.pos(), + ct.interfaces_field.head); + ct.interfaces_field = List.nil(); + } + } + + // Annotations. + // In general, we cannot fully process annotations yet, but we + // can attribute the annotation types and then check to see if the + // @Deprecated annotation is present. + attr.attribAnnotationTypes(tree.mods.annotations, baseEnv); + if (hasDeprecatedAnnotation(tree.mods.annotations)) + sym.flags_field |= DEPRECATED; + + chk.checkNonCyclicDecl(tree); + } + //where: + protected JCExpression clearTypeParams(JCExpression superType) { + switch (superType.getTag()) { + case TYPEAPPLY: + return ((JCTypeApply) superType).clazz; + } + + return superType; + } + + /** + * Check if a list of annotations contains a reference to + * java.lang.Deprecated. + **/ + private boolean hasDeprecatedAnnotation(List annotations) { + for (List al = annotations; !al.isEmpty(); al = al.tail) { + JCAnnotation a = al.head; + if (a.annotationType.type == syms.deprecatedType && a.args.isEmpty()) + return true; + } + return false; + } + } + + private final class HeaderPhase extends AbstractHeaderPhase { + + public HeaderPhase() { + super(CompletionCause.HEADER_PHASE, new MembersPhase()); + } + + @Override + protected void doRunPhase(Env env) { + JCClassDecl tree = env.enclClass; + ClassSymbol sym = tree.sym; + ClassType ct = (ClassType)sym.type; + + // create an environment for evaluating the base clauses + Env baseEnv = baseEnv(tree, env); + + if (tree.extending != null) + annotate.annotateTypeLater(tree.extending, baseEnv, sym, tree.pos()); + for (JCExpression impl : tree.implementing) + annotate.annotateTypeLater(impl, baseEnv, sym, tree.pos()); + annotate.flush(); + + attribSuperTypes(env, baseEnv); + + Set interfaceSet = new HashSet<>(); + + for (JCExpression iface : tree.implementing) { + Type it = iface.type; + if (it.hasTag(CLASS)) + chk.checkNotRepeated(iface.pos(), types.erasure(it), interfaceSet); + } + + annotate.annotateLater(tree.mods.annotations, baseEnv, + sym, tree.pos()); + + attr.attribTypeVariables(tree.typarams, baseEnv); + for (JCTypeParameter tp : tree.typarams) + annotate.annotateTypeLater(tp, baseEnv, sym, tree.pos()); + + // check that no package exists with same fully qualified name, + // but admit classes in the unnamed package which have the same + // name as a top-level package. + if (checkClash && + sym.owner.kind == PCK && sym.owner != syms.unnamedPackage && + syms.packageExists(sym.fullname)) { + log.error(tree.pos, "clash.with.pkg.of.same.name", Kinds.kindName(sym), sym); + } + if (sym.owner.kind == PCK && (sym.flags_field & PUBLIC) == 0 && + !env.toplevel.sourcefile.isNameCompatible(sym.name.toString(),JavaFileObject.Kind.SOURCE)) { + sym.flags_field |= AUXILIARY; + } + } + } + + /** Enter member fields and methods of a class + */ + private final class MembersPhase extends Phase { + + public MembersPhase() { + super(CompletionCause.MEMBERS_PHASE, null); + } + + @Override + protected void doRunPhase(Env env) { + JCClassDecl tree = env.enclClass; + ClassSymbol sym = tree.sym; + ClassType ct = (ClassType)sym.type; + + // Add default constructor if needed. + if ((sym.flags() & INTERFACE) == 0 && + !TreeInfo.hasConstructors(tree.defs)) { + List argtypes = List.nil(); + List typarams = List.nil(); + List thrown = List.nil(); + long ctorFlags = 0; + boolean based = false; + boolean addConstructor = true; + JCNewClass nc = null; + if (sym.name.isEmpty()) { + nc = (JCNewClass)env.next.tree; + if (nc.constructor != null) { + addConstructor = nc.constructor.kind != ERR; + Type superConstrType = types.memberType(sym.type, + nc.constructor); + argtypes = superConstrType.getParameterTypes(); + typarams = superConstrType.getTypeArguments(); + ctorFlags = nc.constructor.flags() & VARARGS; + if (nc.encl != null) { + argtypes = argtypes.prepend(nc.encl.type); + based = true; + } + thrown = superConstrType.getThrownTypes(); + } + } + if (addConstructor) { + MethodSymbol basedConstructor = nc != null ? + (MethodSymbol)nc.constructor : null; + JCTree constrDef = DefaultConstructor(make.at(tree.pos), sym, + basedConstructor, + typarams, argtypes, thrown, + ctorFlags, based); + tree.defs = tree.defs.prepend(constrDef); + } + } + + // enter symbols for 'this' into current scope. + VarSymbol thisSym = + new VarSymbol(FINAL | HASINIT, names._this, sym.type, sym); + thisSym.pos = Position.FIRSTPOS; + env.info.scope.enter(thisSym); + // if this is a class, enter symbol for 'super' into current scope. + if ((sym.flags_field & INTERFACE) == 0 && + ct.supertype_field.hasTag(CLASS)) { + VarSymbol superSym = + new VarSymbol(FINAL | HASINIT, names._super, + ct.supertype_field, sym); + superSym.pos = Position.FIRSTPOS; + env.info.scope.enter(superSym); + } + + finishClass(tree, env); + + if (allowTypeAnnos) { + typeAnnotations.organizeTypeAnnotationsSignatures(env, (JCClassDecl)env.tree); + typeAnnotations.validateTypeAnnotationsSignatures(env, (JCClassDecl)env.tree); + } + } + + /** Enter members for a class. + */ + void finishClass(JCClassDecl tree, Env env) { + if ((tree.mods.flags & Flags.ENUM) != 0 && + (types.supertype(tree.sym.type).tsym.flags() & Flags.ENUM) == 0) { + addEnumMembers(tree, env); + } + memberEnter.memberEnter(tree.defs, env); + } + + /** Add the implicit members for an enum type + * to the symbol table. + */ + private void addEnumMembers(JCClassDecl tree, Env env) { + JCExpression valuesType = make.Type(new ArrayType(tree.sym.type, syms.arrayClass)); + + // public static T[] values() { return ???; } + JCMethodDecl values = make. + MethodDef(make.Modifiers(Flags.PUBLIC|Flags.STATIC), + names.values, + valuesType, + List.nil(), + List.nil(), + List.nil(), // thrown + null, //make.Block(0, Tree.emptyList.prepend(make.Return(make.Ident(names._null)))), + null); + memberEnter.memberEnter(values, env); + + // public static T valueOf(String name) { return ???; } + JCMethodDecl valueOf = make. + MethodDef(make.Modifiers(Flags.PUBLIC|Flags.STATIC), + names.valueOf, + make.Type(tree.sym.type), + List.nil(), + List.of(make.VarDef(make.Modifiers(Flags.PARAMETER | + Flags.MANDATED), + names.fromString("name"), + make.Type(syms.stringType), null)), + List.nil(), // thrown + null, //make.Block(0, Tree.emptyList.prepend(make.Return(make.Ident(names._null)))), + null); + memberEnter.memberEnter(valueOf, env); + } + + } + +/* *************************************************************************** + * tree building + ****************************************************************************/ + + /** Generate default constructor for given class. For classes different + * from java.lang.Object, this is: + * + * c(argtype_0 x_0, ..., argtype_n x_n) throws thrown { + * super(x_0, ..., x_n) + * } + * + * or, if based == true: + * + * c(argtype_0 x_0, ..., argtype_n x_n) throws thrown { + * x_0.super(x_1, ..., x_n) + * } + * + * @param make The tree factory. + * @param c The class owning the default constructor. + * @param argtypes The parameter types of the constructor. + * @param thrown The thrown exceptions of the constructor. + * @param based Is first parameter a this$n? + */ + JCTree DefaultConstructor(TreeMaker make, + ClassSymbol c, + MethodSymbol baseInit, + List typarams, + List argtypes, + List thrown, + long flags, + boolean based) { + JCTree result; + if ((c.flags() & ENUM) != 0 && + (types.supertype(c.type).tsym == syms.enumSym)) { + // constructors of true enums are private + flags = (flags & ~AccessFlags) | PRIVATE | GENERATEDCONSTR; + } else + flags |= (c.flags() & AccessFlags) | GENERATEDCONSTR; + if (c.name.isEmpty()) { + flags |= ANONCONSTR; + } + Type mType = new MethodType(argtypes, null, thrown, c); + Type initType = typarams.nonEmpty() ? + new ForAll(typarams, mType) : + mType; + MethodSymbol init = new MethodSymbol(flags, names.init, + initType, c); + init.params = createDefaultConstructorParams(make, baseInit, init, + argtypes, based); + List params = make.Params(argtypes, init); + List stats = List.nil(); + if (c.type != syms.objectType) { + stats = stats.prepend(SuperCall(make, typarams, params, based)); + } + result = make.MethodDef(init, make.Block(0, stats)); + return result; + } + + private List createDefaultConstructorParams( + TreeMaker make, + MethodSymbol baseInit, + MethodSymbol init, + List argtypes, + boolean based) { + List initParams = null; + List argTypesList = argtypes; + if (based) { + /* In this case argtypes will have an extra type, compared to baseInit, + * corresponding to the type of the enclosing instance i.e.: + * + * Inner i = outer.new Inner(1){} + * + * in the above example argtypes will be (Outer, int) and baseInit + * will have parameter's types (int). So in this case we have to add + * first the extra type in argtypes and then get the names of the + * parameters from baseInit. + */ + initParams = List.nil(); + VarSymbol param = new VarSymbol(PARAMETER, make.paramName(0), argtypes.head, init); + initParams = initParams.append(param); + argTypesList = argTypesList.tail; + } + if (baseInit != null && baseInit.params != null && + baseInit.params.nonEmpty() && argTypesList.nonEmpty()) { + initParams = (initParams == null) ? List.nil() : initParams; + List baseInitParams = baseInit.params; + while (baseInitParams.nonEmpty() && argTypesList.nonEmpty()) { + VarSymbol param = new VarSymbol(baseInitParams.head.flags() | PARAMETER, + baseInitParams.head.name, argTypesList.head, init); + initParams = initParams.append(param); + baseInitParams = baseInitParams.tail; + argTypesList = argTypesList.tail; + } + } + return initParams; + } + + /** Generate call to superclass constructor. This is: + * + * super(id_0, ..., id_n) + * + * or, if based == true + * + * id_0.super(id_1,...,id_n) + * + * where id_0, ..., id_n are the names of the given parameters. + * + * @param make The tree factory + * @param params The parameters that need to be passed to super + * @param typarams The type parameters that need to be passed to super + * @param based Is first parameter a this$n? + */ + JCExpressionStatement SuperCall(TreeMaker make, + List typarams, + List params, + boolean based) { + JCExpression meth; + if (based) { + meth = make.Select(make.Ident(params.head), names._super); + params = params.tail; + } else { + meth = make.Ident(names._super); + } + List typeargs = typarams.nonEmpty() ? make.Types(typarams) : null; + return make.Exec(make.Apply(typeargs, meth, make.Idents(params))); + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileObject.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileObject.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileObject.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,19 @@ package com.sun.tools.javac.file; -import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.CharsetDecoder; +import java.nio.file.Path; + import javax.lang.model.element.Modifier; import javax.lang.model.element.NestingKind; import javax.tools.FileObject; import javax.tools.JavaFileObject; -import static javax.tools.JavaFileObject.Kind.*; - import com.sun.tools.javac.util.BaseFileManager; import com.sun.tools.javac.util.DefinedBy; import com.sun.tools.javac.util.DefinedBy.Api; @@ -78,7 +77,7 @@ throw new UnsupportedOperationException(); } - protected abstract String inferBinaryName(Iterable path); + protected abstract String inferBinaryName(Iterable path); protected static JavaFileObject.Kind getKind(String filename) { return BaseFileManager.getKind(filename); @@ -89,8 +88,8 @@ return (lastDot == -1 ? fileName : fileName.substring(0, lastDot)); } - protected static URI createJarUri(File jarFile, String entryName) { - URI jarURI = jarFile.toURI().normalize(); + protected static URI createJarUri(Path jarFile, String entryName) { + URI jarURI = jarFile.toUri().normalize(); String separator = entryName.startsWith("/") ? "!" : "!/"; try { // The jar URI convention appears to be not to re-encode the jarURI diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/CacheFSInfo.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/CacheFSInfo.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/CacheFSInfo.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,8 @@ package com.sun.tools.javac.file; -import java.io.File; import java.io.IOException; +import java.nio.file.Path; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -61,31 +61,31 @@ } @Override - public File getCanonicalFile(File file) { + public Path getCanonicalFile(Path file) { Entry e = getEntry(file); return e.canonicalFile; } @Override - public boolean exists(File file) { + public boolean exists(Path file) { Entry e = getEntry(file); return e.exists; } @Override - public boolean isDirectory(File file) { + public boolean isDirectory(Path file) { Entry e = getEntry(file); return e.isDirectory; } @Override - public boolean isFile(File file) { + public boolean isFile(Path file) { Entry e = getEntry(file); return e.isFile; } @Override - public List getJarClassPath(File file) throws IOException { + public List getJarClassPath(Path file) throws IOException { // don't bother to lock the cache, because it is thread-safe, and // because the worst that can happen would be to create two identical // jar class paths together and have one overwrite the other. @@ -95,7 +95,7 @@ return e.jarClassPath; } - private Entry getEntry(File file) { + private Entry getEntry(Path file) { // don't bother to lock the cache, because it is thread-safe, and // because the worst that can happen would be to create two identical // entries together and have one overwrite the other. @@ -112,13 +112,13 @@ } // could also be a Map> ? - private Map cache = new ConcurrentHashMap<>(); + private final Map cache = new ConcurrentHashMap<>(); private static class Entry { - File canonicalFile; + Path canonicalFile; boolean exists; boolean isFile; boolean isDirectory; - List jarClassPath; + List jarClassPath; } } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,8 +1,10 @@ package com.sun.tools.javac.file; -import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -42,29 +44,29 @@ context.put(FSInfo.class, this); } - public File getCanonicalFile(File file) { + public Path getCanonicalFile(Path file) { try { - return file.getCanonicalFile(); + return file.toRealPath(); } catch (IOException e) { - return file.getAbsoluteFile(); + return file.toAbsolutePath(); } } - public boolean exists(File file) { - return file.exists(); + public boolean exists(Path file) { + return Files.exists(file); } - public boolean isDirectory(File file) { - return file.isDirectory(); + public boolean isDirectory(Path file) { + return Files.isDirectory(file); } - public boolean isFile(File file) { - return file.isFile(); + public boolean isFile(Path file) { + return Files.isRegularFile(file); } - public List getJarClassPath(File file) throws IOException { - String parent = file.getParent(); - try (JarFile jarFile = new JarFile(file)) { + public List getJarClassPath(Path file) throws IOException { + Path parent = file.getParent(); + try (JarFile jarFile = new JarFile(file.toFile())) { Manifest man = jarFile.getManifest(); if (man == null) return Collections.emptyList(); @@ -77,14 +79,14 @@ if (path == null) return Collections.emptyList(); - List list = new ArrayList<>(); + List list = new ArrayList<>(); for (StringTokenizer st = new StringTokenizer(path); st.hasMoreTokens(); ) { String elt = st.nextToken(); - File f = new File(elt); + Path f = Paths.get(elt); if (!f.isAbsolute() && parent != null) - f = new File(parent,elt).getAbsoluteFile(); + f = parent.resolve(f).toAbsolutePath(); list.add(f); } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JRTIndex.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JRTIndex.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JRTIndex.java Thu Dec 04 15:22:53 2014 -0800 @@ -31,8 +31,10 @@ import java.nio.file.DirectoryStream; import java.nio.file.FileSystem; import java.nio.file.FileSystems; +import java.nio.file.FileSystemNotFoundException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.ProviderNotFoundException; import java.nio.file.spi.FileSystemProvider; import java.util.Collections; import java.util.HashMap; @@ -79,11 +81,12 @@ } public static boolean isAvailable() { - for (FileSystemProvider p: FileSystemProvider.installedProviders()) { - if (p.getScheme().equals("jrt")) - return true; + try { + FileSystems.getFileSystem(URI.create("jrt:/")); + return true; + } catch (ProviderNotFoundException | FileSystemNotFoundException e) { + return false; } - return false; } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java Thu Dec 04 15:22:53 2014 -0800 @@ -34,7 +34,12 @@ import java.net.URL; import java.nio.CharBuffer; import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.InvalidPathException; +import java.nio.file.LinkOption; +import java.nio.file.NoSuchFileException; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -45,6 +50,8 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import java.util.zip.ZipFile; import javax.lang.model.SourceVersion; @@ -97,17 +104,17 @@ protected boolean mmappedIO; protected boolean symbolFileEnabled; - protected enum SortFiles implements Comparator { + protected enum SortFiles implements Comparator { FORWARD { @Override - public int compare(File f1, File f2) { - return f1.getName().compareTo(f2.getName()); + public int compare(Path f1, Path f2) { + return f1.getFileName().compareTo(f2.getFileName()); } }, REVERSE { @Override - public int compare(File f1, File f2) { - return -f1.getName().compareTo(f2.getName()); + public int compare(Path f1, Path f2) { + return -f1.getFileName().compareTo(f2.getFileName()); } } } @@ -171,10 +178,10 @@ } public JavaFileObject getFileForInput(String name) { - return getRegularFile(new File(name)); + return getRegularFile(Paths.get(name)); } - public JavaFileObject getRegularFile(File file) { + public JavaFileObject getRegularFile(Path file) { return new RegularFileObject(this, file); } @@ -298,25 +305,36 @@ * Insert all files in subdirectory subdirectory of directory directory * which match fileKinds into resultList */ - private void listDirectory(File directory, + private void listDirectory(Path directory, RelativeDirectory subdirectory, Set fileKinds, boolean recurse, ListBuffer resultList) { - File d = subdirectory.getFile(directory); - if (!caseMapCheck(d, subdirectory)) + Path d; + try { + d = subdirectory.getFile(directory); + } catch (InvalidPathException ignore) { return; + } - File[] files = d.listFiles(); - if (files == null) + if (!Files.exists(d)) { + return; + } + + if (!caseMapCheck(d, subdirectory)) { return; - - if (sortFiles != null) - Arrays.sort(files, sortFiles); + } - for (File f: files) { - String fname = f.getName(); - if (f.isDirectory()) { + java.util.List files; + try (Stream s = Files.list(d)) { + files = (sortFiles == null ? s : s.sorted(sortFiles)).collect(Collectors.toList()); + } catch (IOException ignore) { + return; + } + + for (Path f: files) { + String fname = f.getFileName().toString(); + if (Files.isDirectory(f)) { if (recurse && SourceVersion.isIdentifier(fname)) { listDirectory(directory, new RelativeDirectory(subdirectory, fname), @@ -327,7 +345,7 @@ } else { if (isValidFile(fname, fileKinds)) { JavaFileObject fe = - new RegularFileObject(this, fname, new File(d, fname)); + new RegularFileObject(this, fname, d.resolve(fname)); resultList.append(fe); } } @@ -370,7 +388,7 @@ * Insert all files in subdirectory subdirectory of container which * match fileKinds into resultList */ - private void listContainer(File container, + private void listContainer(Path container, RelativeDirectory subdirectory, Set fileKinds, boolean recurse, @@ -378,10 +396,10 @@ Archive archive = archives.get(container); if (archive == null) { // Very temporary and obnoxious interim hack - if (container.getName().equals("bootmodules.jimage")) { + if (container.endsWith("bootmodules.jimage")) { System.err.println("Warning: reference to bootmodules.jimage replaced by jrt:"); container = Locations.JRT_MARKER_FILE; - } else if (container.getName().endsWith(".jimage")) { + } else if (container.getFileName().toString().endsWith(".jimage")) { System.err.println("Warning: reference to " + container + " ignored"); return; } @@ -436,13 +454,15 @@ * ends in a string of characters with the same case as given name. * Ignore file separators in both path and name. */ - private boolean caseMapCheck(File f, RelativePath name) { + private boolean caseMapCheck(Path f, RelativePath name) { if (fileSystemIsCaseSensitive) return true; - // Note that getCanonicalPath() returns the case-sensitive + // Note that toRealPath() returns the case-sensitive // spelled file name. String path; + char sep; try { - path = f.getCanonicalPath(); + path = f.toRealPath(LinkOption.NOFOLLOW_LINKS).toString(); + sep = f.getFileSystem().getSeparator().charAt(0); } catch (IOException ex) { return false; } @@ -451,7 +471,7 @@ int i = pcs.length - 1; int j = ncs.length - 1; while (i >= 0 && j >= 0) { - while (i >= 0 && pcs[i] == File.separatorChar) i--; + while (i >= 0 && pcs[i] == sep) i--; while (j >= 0 && ncs[j] == '/') j--; if (i >= 0 && j >= 0) { if (pcs[i] != ncs[j]) return false; @@ -479,8 +499,8 @@ } public class MissingArchive implements Archive { - final File zipFileName; - public MissingArchive(File name) { + final Path zipFileName; + public MissingArchive(Path name) { zipFileName = name; } @Override @@ -515,7 +535,7 @@ /** A directory of zip files already opened. */ - Map archives = new HashMap<>(); + Map archives = new HashMap<>(); /* * This method looks for a ZipFormatException and takes appropriate @@ -523,7 +543,7 @@ * fail over to the platform zip, and allow it to deal with a potentially * non compliant zip file. */ - protected Archive openArchive(File zipFilename) throws IOException { + protected Archive openArchive(Path zipFilename) throws IOException { try { return openArchive(zipFilename, contextUseOptimizedZip); } catch (IOException ioe) { @@ -537,7 +557,7 @@ /** Open a new zip file directory, and cache it. */ - private Archive openArchive(File zipFileName, boolean useOptimizedZip) throws IOException { + private Archive openArchive(Path zipFileName, boolean useOptimizedZip) throws IOException { Archive archive; try { @@ -547,7 +567,7 @@ String preindexCacheLocation = null; if (!useOptimizedZip) { - zdir = new ZipFile(zipFileName); + zdir = new ZipFile(zipFileName.toFile()); } else { usePreindexedCache = options.isSet("usezipindex"); preindexCacheLocation = options.get("java.io.tmpdir"); @@ -584,12 +604,12 @@ preindexCacheLocation, options.isSet("writezipindexfiles"))); } - } catch (FileNotFoundException ex) { + } catch (FileNotFoundException | NoSuchFileException ex) { archive = new MissingArchive(zipFileName); } catch (ZipFileIndex.ZipFormatException zfe) { throw zfe; } catch (IOException ex) { - if (zipFileName.exists()) + if (Files.exists(zipFileName)) log.error("error.reading.file", zipFileName, getMessage(ex)); archive = new MissingArchive(zipFileName); } @@ -649,13 +669,13 @@ nullCheck(packageName); nullCheck(kinds); - Iterable path = getLocation(location); + Iterable path = getLocationAsPaths(location); if (path == null) return List.nil(); RelativeDirectory subdirectory = RelativeDirectory.forPackage(packageName); ListBuffer results = new ListBuffer<>(); - for (File directory : path) + for (Path directory : path) listContainer(directory, subdirectory, kinds, recurse, results); return results.toList(); } @@ -665,7 +685,7 @@ file.getClass(); // null check location.getClass(); // null check // Need to match the path semantics of list(location, ...) - Iterable path = getLocation(location); + Iterable path = getLocationAsPaths(location); if (path == null) { return null; } @@ -730,11 +750,11 @@ } private JavaFileObject getFileForInput(Location location, RelativeFile name) throws IOException { - Iterable path = getLocation(location); + Iterable path = getLocationAsPaths(location); if (path == null) return null; - for (File file: path) { + for (Path file: path) { Archive a = archives.get(file); if (a == null) { // archives are not created for directories or jrt: images @@ -747,9 +767,12 @@ return PathFileObject.createJRTPathFileObject(this, p); continue; } else if (fsInfo.isDirectory(file)) { - File f = name.getFile(file); - if (f.exists()) - return new RegularFileObject(this, f); + try { + Path f = name.getFile(file); + if (Files.exists(f)) + return new RegularFileObject(this, f); + } catch (InvalidPathException ignore) { + } continue; } // Not a directory, create the archive @@ -802,31 +825,37 @@ FileObject sibling) throws IOException { - File dir; + Path dir; if (location == CLASS_OUTPUT) { if (getClassOutDir() != null) { dir = getClassOutDir(); } else { - File siblingDir = null; + Path siblingDir = null; if (sibling != null && sibling instanceof RegularFileObject) { - siblingDir = ((RegularFileObject)sibling).file.getParentFile(); + siblingDir = ((RegularFileObject)sibling).file.getParent(); } - return new RegularFileObject(this, new File(siblingDir, fileName.basename())); + if (siblingDir == null) + return new RegularFileObject(this, Paths.get(fileName.basename())); + else + return new RegularFileObject(this, siblingDir.resolve(fileName.basename())); } } else if (location == SOURCE_OUTPUT) { dir = (getSourceOutDir() != null ? getSourceOutDir() : getClassOutDir()); } else { - Iterable path = locations.getLocation(location); + Iterable path = locations.getLocation(location); dir = null; - for (File f: path) { + for (Path f: path) { dir = f; break; } } - File file = fileName.getFile(dir); // null-safe - return new RegularFileObject(this, file); - + try { + Path file = fileName.getFile(dir); // null-safe + return new RegularFileObject(this, file); + } catch (InvalidPathException e) { + throw new IOException("bad filename " + fileName, e); + } } @Override @DefinedBy(Api.COMPILER) @@ -839,7 +868,7 @@ else result = new ArrayList<>(); for (File f: files) - result.add(new RegularFileObject(this, nullCheck(f))); + result.add(new RegularFileObject(this, nullCheck(f).toPath())); return result; } @@ -850,24 +879,29 @@ @Override @DefinedBy(Api.COMPILER) public void setLocation(Location location, - Iterable path) + Iterable searchpath) throws IOException { nullCheck(location); - locations.setLocation(location, path); + locations.setLocation(location, asPaths(searchpath)); } @Override @DefinedBy(Api.COMPILER) public Iterable getLocation(Location location) { nullCheck(location); + return asFiles(locations.getLocation(location)); + } + + private Iterable getLocationAsPaths(Location location) { + nullCheck(location); return locations.getLocation(location); } - private File getClassOutDir() { + private Path getClassOutDir() { return locations.getOutputLocation(CLASS_OUTPUT); } - private File getSourceOutDir() { + private Path getSourceOutDir() { return locations.getOutputLocation(SOURCE_OUTPUT); } @@ -938,4 +972,50 @@ return s; return e.toString(); } + + /* Converters between files and paths. + * These are temporary until we can update the StandardJavaFileManager API. + */ + + private static Iterable asPaths(final Iterable files) { + if (files == null) + return null; + + return () -> new Iterator() { + Iterator iter = files.iterator(); + + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public Path next() { + return iter.next().toPath(); + } + }; + } + + private static Iterable asFiles(final Iterable paths) { + if (paths == null) + return null; + + return () -> new Iterator() { + Iterator iter = paths.iterator(); + + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public File next() { + return iter.next().toFile(); + } + }; + } + + private static File asFile(Path path) { + return path == null ? null : path.toFile(); + } } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java Thu Dec 04 15:22:53 2014 -0800 @@ -33,6 +33,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -44,7 +45,7 @@ import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; -import java.util.StringTokenizer; +import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.zip.ZipFile; @@ -104,7 +105,7 @@ // should use the jrt: file system. // When Locations has been converted to use java.nio.file.Path, // Locations can use Paths.get(URI.create("jrt:")) - static final File JRT_MARKER_FILE = new File("JRT_MARKER_FILE"); + static final Path JRT_MARKER_FILE = Paths.get("JRT_MARKER_FILE"); public Locations() { initHandlers(); @@ -117,7 +118,7 @@ this.fsInfo = fsInfo; } - public Collection bootClassPath() { + public Collection bootClassPath() { return getLocation(PLATFORM_CLASS_PATH); } @@ -127,50 +128,46 @@ return h.isDefault(); } - public Collection userClassPath() { + public Collection userClassPath() { return getLocation(CLASS_PATH); } - public Collection sourcePath() { - Collection p = getLocation(SOURCE_PATH); + public Collection sourcePath() { + Collection p = getLocation(SOURCE_PATH); // TODO: this should be handled by the LocationHandler return p == null || p.isEmpty() ? null : p; } /** - * Split a path into its elements. Empty path elements will be ignored. + * Split a search path into its elements. Empty path elements will be ignored. * - * @param path The path to be split + * @param searchPath The search path to be split * @return The elements of the path */ - private static Iterable getPathEntries(String path) { - return getPathEntries(path, null); + private static Iterable getPathEntries(String searchPath) { + return getPathEntries(searchPath, null); } /** - * Split a path into its elements. If emptyPathDefault is not null, all empty elements in the + * Split a search path into its elements. If emptyPathDefault is not null, all empty elements in the * path, including empty elements at either end of the path, will be replaced with the value of * emptyPathDefault. * - * @param path The path to be split + * @param searchPath The search path to be split * @param emptyPathDefault The value to substitute for empty path elements, or null, to ignore * empty path elements * @return The elements of the path */ - private static Iterable getPathEntries(String path, File emptyPathDefault) { - ListBuffer entries = new ListBuffer<>(); - int start = 0; - while (start <= path.length()) { - int sep = path.indexOf(File.pathSeparatorChar, start); - if (sep == -1) { - sep = path.length(); + private static Iterable getPathEntries(String searchPath, Path emptyPathDefault) { + ListBuffer entries = new ListBuffer<>(); + for (String s: searchPath.split(Pattern.quote(File.pathSeparator), -1)) { + if (s.isEmpty()) { + if (emptyPathDefault != null) { + entries.add(emptyPathDefault); + } + } else { + entries.add(Paths.get(s)); } - if (start < sep) { - entries.add(new File(path.substring(start, sep))); - } else if (emptyPathDefault != null) { - entries.add(emptyPathDefault); - } - start = sep + 1; } return entries; } @@ -179,12 +176,12 @@ * Utility class to help evaluate a path option. Duplicate entries are ignored, jar class paths * can be expanded. */ - private class SearchPath extends LinkedHashSet { + private class SearchPath extends LinkedHashSet { private static final long serialVersionUID = 0; private boolean expandJarClassPaths = false; - private final Set canonicalValues = new HashSet<>(); + private final Set canonicalValues = new HashSet<>(); public SearchPath expandJarClassPaths(boolean x) { expandJarClassPaths = x; @@ -194,9 +191,9 @@ /** * What to use when path element is the empty string */ - private File emptyPathDefault = null; + private Path emptyPathDefault = null; - public SearchPath emptyPathDefault(File x) { + public SearchPath emptyPathDefault(Path x) { emptyPathDefault = x; return this; } @@ -206,7 +203,7 @@ expandJarClassPaths = true; try { if (dirs != null) { - for (File dir : getPathEntries(dirs)) { + for (Path dir : getPathEntries(dirs)) { addDirectory(dir, warn); } } @@ -220,8 +217,8 @@ return addDirectories(dirs, warn); } - private void addDirectory(File dir, boolean warn) { - if (!dir.isDirectory()) { + private void addDirectory(Path dir, boolean warn) { + if (!Files.isDirectory(dir)) { if (warn) { log.warning(Lint.LintCategory.PATH, "dir.path.element.not.found", dir); @@ -229,15 +226,10 @@ return; } - File[] files = dir.listFiles(); - if (files == null) { - return; - } - - for (File direntry : files) { - if (isArchive(direntry)) { - addFile(direntry, warn); - } + try (Stream s = Files.list(dir)) { + s.filter(dirEntry -> isArchive(dirEntry)) + .forEach(dirEntry -> addFile(dirEntry, warn)); + } catch (IOException ignore) { } } @@ -252,20 +244,20 @@ return addFiles(files, warn); } - public SearchPath addFiles(Iterable files, boolean warn) { + public SearchPath addFiles(Iterable files, boolean warn) { if (files != null) { - for (File file : files) { + for (Path file : files) { addFile(file, warn); } } return this; } - public SearchPath addFiles(Iterable files) { + public SearchPath addFiles(Iterable files) { return addFiles(files, warn); } - public void addFile(File file, boolean warn) { + public void addFile(Path file, boolean warn) { if (contains(file)) { // discard duplicates return; @@ -281,7 +273,7 @@ return; } - File canonFile = fsInfo.getCanonicalFile(file); + Path canonFile = fsInfo.getCanonicalFile(file); if (canonicalValues.contains(canonFile)) { /* Discard duplicates and avoid infinite recursion */ return; @@ -289,11 +281,11 @@ if (fsInfo.isFile(file)) { /* File is an ordinary file. */ - if (!isArchive(file) && !file.getName().endsWith(".jimage")) { + if (!isArchive(file) && !file.getFileName().toString().endsWith(".jimage")) { /* Not a recognized extension; open it to see if it looks like a valid zip file. */ try { - ZipFile z = new ZipFile(file); + ZipFile z = new ZipFile(file.toFile()); z.close(); if (warn) { log.warning(Lint.LintCategory.PATH, @@ -315,7 +307,7 @@ super.add(file); canonicalValues.add(canonFile); - if (expandJarClassPaths && fsInfo.isFile(file) && !file.getName().endsWith(".jimage")) { + if (expandJarClassPaths && fsInfo.isFile(file) && !file.getFileName().toString().endsWith(".jimage")) { addJarClassPath(file, warn); } } @@ -324,9 +316,9 @@ // Manifest entry. In some future release, we may want to // update this code to recognize URLs rather than simple // filenames, but if we do, we should redo all path-related code. - private void addJarClassPath(File jarFile, boolean warn) { + private void addJarClassPath(Path jarFile, boolean warn) { try { - for (File f : fsInfo.getJarClassPath(jarFile)) { + for (Path f : fsInfo.getJarClassPath(jarFile)) { addFile(f, warn); } } catch (IOException e) { @@ -371,12 +363,12 @@ /** * @see StandardJavaFileManager#getLocation */ - abstract Collection getLocation(); + abstract Collection getLocation(); /** * @see StandardJavaFileManager#setLocation */ - abstract void setLocation(Iterable files) throws IOException; + abstract void setLocation(Iterable files) throws IOException; } /** @@ -386,7 +378,7 @@ */ private class OutputLocationHandler extends LocationHandler { - private File outputDir; + private Path outputDir; OutputLocationHandler(Location location, Option... options) { super(location, options); @@ -402,31 +394,31 @@ // need to decide how best to report issue for benefit of // direct API call on JavaFileManager.handleOption(specifies IAE) // vs. command line decoding. - outputDir = (value == null) ? null : new File(value); + outputDir = (value == null) ? null : Paths.get(value); return true; } @Override - Collection getLocation() { + Collection getLocation() { return (outputDir == null) ? null : Collections.singleton(outputDir); } @Override - void setLocation(Iterable files) throws IOException { + void setLocation(Iterable files) throws IOException { if (files == null) { outputDir = null; } else { - Iterator pathIter = files.iterator(); + Iterator pathIter = files.iterator(); if (!pathIter.hasNext()) { throw new IllegalArgumentException("empty path for directory"); } - File dir = pathIter.next(); + Path dir = pathIter.next(); if (pathIter.hasNext()) { throw new IllegalArgumentException("path too long for directory"); } - if (!dir.exists()) { + if (!Files.exists(dir)) { throw new FileNotFoundException(dir + ": does not exist"); - } else if (!dir.isDirectory()) { + } else if (!Files.isDirectory(dir)) { throw new IOException(dir + ": not a directory"); } outputDir = dir; @@ -441,7 +433,7 @@ */ private class SimpleLocationHandler extends LocationHandler { - protected Collection searchPath; + protected Collection searchPath; SimpleLocationHandler(Location location, Option... options) { super(location, options); @@ -458,12 +450,12 @@ } @Override - Collection getLocation() { + Collection getLocation() { return searchPath; } @Override - void setLocation(Iterable files) { + void setLocation(Iterable files) { SearchPath p; if (files == null) { p = computePath(null); @@ -494,7 +486,7 @@ } @Override - Collection getLocation() { + Collection getLocation() { lazy(); return searchPath; } @@ -526,7 +518,7 @@ protected SearchPath createPath() { return new SearchPath() .expandJarClassPaths(true) // Only search user jars for Class-Paths - .emptyPathDefault(new File(".")); // Empty path elt ==> current directory + .emptyPathDefault(Paths.get(".")); // Empty path elt ==> current directory } private void lazy() { @@ -545,7 +537,7 @@ */ private class BootClassPathLocationHandler extends LocationHandler { - private Collection searchPath; + private Collection searchPath; final Map optionValues = new EnumMap<>(Option.class); /** @@ -599,13 +591,13 @@ } @Override - Collection getLocation() { + Collection getLocation() { lazy(); return searchPath; } @Override - void setLocation(Iterable files) { + void setLocation(Iterable files) { if (files == null) { searchPath = null; // reset to "uninitialized" } else { @@ -638,7 +630,7 @@ path.addFiles(bootclasspathOpt); } else { // Standard system classes for this compiler's release. - Collection systemClasses = systemClasses(java_home); + Collection systemClasses = systemClasses(java_home); if (systemClasses != null) { path.addFiles(systemClasses, false); } else { @@ -657,8 +649,8 @@ path.addDirectories(extdirsOpt); } else { // Add lib/jfxrt.jar to the search path - File jfxrt = new File(new File(java_home, "lib"), "jfxrt.jar"); - if (jfxrt.exists()) { + Path jfxrt = Paths.get(java_home, "lib", "jfxrt.jar"); + if (Files.exists(jfxrt)) { path.addFile(jfxrt, false); } path.addDirectories(System.getProperty("java.ext.dirs"), false); @@ -678,7 +670,7 @@ * * @throws UncheckedIOException if an I/O errors occurs */ - private Collection systemClasses(String java_home) throws IOException { + private Collection systemClasses(String java_home) throws IOException { // Return .jimage files if available Path libModules = Paths.get(java_home, "lib", "modules"); if (Files.exists(libModules)) { @@ -695,7 +687,6 @@ if (Files.exists(libModules.resolve("java.base"))) { return Files.list(libModules) .map(d -> d.resolve("classes")) - .map(Path::toFile) .collect(Collectors.toList()); } @@ -703,7 +694,6 @@ Path modules = Paths.get(java_home, "modules"); if (Files.isDirectory(modules.resolve("java.base"))) { return Files.list(modules) - .map(Path::toFile) .collect(Collectors.toList()); } @@ -753,12 +743,12 @@ return (h == null ? false : h.handleOption(option, value)); } - Collection getLocation(Location location) { + Collection getLocation(Location location) { LocationHandler h = getHandler(location); return (h == null ? null : h.getLocation()); } - File getOutputLocation(Location location) { + Path getOutputLocation(Location location) { if (!location.isOutputLocation()) { throw new IllegalArgumentException(); } @@ -766,7 +756,7 @@ return ((OutputLocationHandler) h).outputDir; } - void setLocation(Location location, Iterable files) throws IOException { + void setLocation(Location location, Iterable files) throws IOException { LocationHandler h = getHandler(location); if (h == null) { if (location.isOutputLocation()) { @@ -787,8 +777,8 @@ /** * Is this the name of an archive file? */ - private boolean isArchive(File file) { - String n = StringUtils.toLowerCase(file.getName()); + private boolean isArchive(Path file) { + String n = StringUtils.toLowerCase(file.getFileName().toString()); return fsInfo.isFile(file) && (n.endsWith(".jar") || n.endsWith(".zip")); } @@ -797,50 +787,41 @@ * Utility method for converting a search path string to an array of directory and JAR file * URLs. * - * Note that this method is called by apt and the DocletInvoker. + * Note that this method is called by the DocletInvoker. * * @param path the search path string * @return the resulting array of directory and JAR file URLs */ public static URL[] pathToURLs(String path) { - StringTokenizer st = new StringTokenizer(path, File.pathSeparator); - URL[] urls = new URL[st.countTokens()]; - int count = 0; - while (st.hasMoreTokens()) { - URL url = fileToURL(new File(st.nextToken())); - if (url != null) { - urls[count++] = url; + java.util.List urls = new ArrayList<>(); + for (String s: path.split(Pattern.quote(File.pathSeparator))) { + if (!s.isEmpty()) { + URL url = fileToURL(Paths.get(s)); + if (url != null) { + urls.add(url); + } } } - urls = Arrays.copyOf(urls, count); - return urls; + return urls.toArray(new URL[urls.size()]); } /** * Returns the directory or JAR file URL corresponding to the specified local file name. * - * @param file the File object + * @param file the Path object * @return the resulting directory or JAR file URL, or null if unknown */ - private static URL fileToURL(File file) { - String name; + private static URL fileToURL(Path file) { + Path p; try { - name = file.getCanonicalPath(); + p = file.toRealPath(); } catch (IOException e) { - name = file.getAbsolutePath(); - } - name = name.replace(File.separatorChar, '/'); - if (!name.startsWith("/")) { - name = "/" + name; - } - // If the file does not exist, then assume that it's a directory - if (!file.isFile()) { - name = name + "/"; + p = file.toAbsolutePath(); } try { - return new URL("file", "", name); + return p.normalize().toUri().toURL(); } catch (MalformedURLException e) { - throw new IllegalArgumentException(file.toString()); + return null; } } } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/RegularFileObject.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/RegularFileObject.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/RegularFileObject.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,6 @@ package com.sun.tools.javac.file; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -39,8 +36,12 @@ import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharsetDecoder; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.Normalizer; + import javax.tools.JavaFileObject; -import java.text.Normalizer; import com.sun.tools.javac.util.DefinedBy; import com.sun.tools.javac.util.DefinedBy.Api; @@ -59,33 +60,33 @@ */ private boolean hasParents = false; private String name; - final File file; - private Reference absFileRef; + final Path file; + private Reference absFileRef; final static boolean isMacOS = System.getProperty("os.name", "").contains("OS X"); - public RegularFileObject(JavacFileManager fileManager, File f) { - this(fileManager, f.getName(), f); + public RegularFileObject(JavacFileManager fileManager, Path f) { + this(fileManager, f.getFileName().toString(), f); } - public RegularFileObject(JavacFileManager fileManager, String name, File f) { + public RegularFileObject(JavacFileManager fileManager, String name, Path f) { super(fileManager); - if (f.isDirectory()) { + if (Files.isDirectory(f)) { throw new IllegalArgumentException("directories not supported"); } this.name = name; this.file = f; - if (f.lastModified() > System.currentTimeMillis()) + if (getLastModified() > System.currentTimeMillis()) fileManager.log.warning("file.from.future", f); } @Override @DefinedBy(Api.COMPILER) public URI toUri() { - return file.toURI().normalize(); + return file.toUri().normalize(); } @Override @DefinedBy(Api.COMPILER) public String getName() { - return file.getPath(); + return file.toString(); } @Override @@ -100,21 +101,21 @@ @Override @DefinedBy(Api.COMPILER) public InputStream openInputStream() throws IOException { - return new FileInputStream(file); + return Files.newInputStream(file); } @Override @DefinedBy(Api.COMPILER) public OutputStream openOutputStream() throws IOException { fileManager.flushCache(this); ensureParentDirectoriesExist(); - return new FileOutputStream(file); + return Files.newOutputStream(file); } @Override @DefinedBy(Api.COMPILER) public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException { CharBuffer cb = fileManager.getCachedContent(this); if (cb == null) { - try (InputStream in = new FileInputStream(file)) { + try (InputStream in = Files.newInputStream(file)) { ByteBuffer bb = fileManager.makeByteBuffer(in); JavaFileObject prev = fileManager.log.useSource(this); try { @@ -135,17 +136,26 @@ public Writer openWriter() throws IOException { fileManager.flushCache(this); ensureParentDirectoriesExist(); - return new OutputStreamWriter(new FileOutputStream(file), fileManager.getEncodingName()); + return new OutputStreamWriter(Files.newOutputStream(file), fileManager.getEncodingName()); } @Override @DefinedBy(Api.COMPILER) public long getLastModified() { - return file.lastModified(); + try { + return Files.getLastModifiedTime(file).toMillis(); + } catch (IOException e) { + return 0; + } } @Override @DefinedBy(Api.COMPILER) public boolean delete() { - return file.delete(); + try { + Files.delete(file); + return true; + } catch (IOException e) { + return false; + } } @Override @@ -154,20 +164,21 @@ } @Override - protected String inferBinaryName(Iterable path) { - String fPath = file.getPath(); + protected String inferBinaryName(Iterable path) { + String fPath = file.toString(); //System.err.println("RegularFileObject " + file + " " +r.getPath()); - for (File dir: path) { + for (Path dir: path) { //System.err.println("dir: " + dir); - String dPath = dir.getPath(); + String sep = dir.getFileSystem().getSeparator(); + String dPath = dir.toString(); if (dPath.length() == 0) dPath = System.getProperty("user.dir"); - if (!dPath.endsWith(File.separator)) - dPath += File.separator; + if (!dPath.endsWith(sep)) + dPath += sep; if (fPath.regionMatches(true, 0, dPath, 0, dPath.length()) - && new File(fPath.substring(0, dPath.length())).equals(new File(dPath))) { + && Paths.get(fPath.substring(0, dPath.length())).equals(Paths.get(dPath))) { String relativeName = fPath.substring(dPath.length()); - return removeExtension(relativeName).replace(File.separatorChar, '.'); + return removeExtension(relativeName).replace(sep, "."); } } return null; @@ -199,7 +210,7 @@ if (name.equalsIgnoreCase(n)) { try { // allow for Windows - return file.getCanonicalFile().getName().equals(n); + return file.toRealPath().getFileName().toString().equals(n); } catch (IOException e) { } } @@ -208,12 +219,12 @@ private void ensureParentDirectoriesExist() throws IOException { if (!hasParents) { - File parent = file.getParentFile(); - if (parent != null && !parent.exists()) { - if (!parent.mkdirs()) { - if (!parent.exists() || !parent.isDirectory()) { - throw new IOException("could not create parent directories"); - } + Path parent = file.getParent(); + if (parent != null && !Files.isDirectory(parent)) { + try { + Files.createDirectories(parent); + } catch (IOException e) { + throw new IOException("could not create parent directories", e); } } hasParents = true; @@ -242,10 +253,10 @@ return getAbsoluteFile().hashCode(); } - private File getAbsoluteFile() { - File absFile = (absFileRef == null ? null : absFileRef.get()); + private Path getAbsoluteFile() { + Path absFile = (absFileRef == null ? null : absFileRef.get()); if (absFile == null) { - absFile = file.getAbsoluteFile(); + absFile = file.toAbsolutePath(); absFileRef = new SoftReference<>(absFile); } return absFile; diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/RelativePath.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/RelativePath.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/RelativePath.java Thu Dec 04 15:22:53 2014 -0800 @@ -57,12 +57,6 @@ public abstract String basename(); - public File getFile(File directory) { - if (path.length() == 0) - return directory; - return new File(directory, path.replace('/', File.separatorChar)); - } - public Path getFile(Path directory) throws /*unchecked*/ InvalidPathException { if (directory == null) { String sep = FileSystems.getDefault().getSeparator(); @@ -73,6 +67,7 @@ } } + @Override public int compareTo(RelativePath other) { return path.compareTo(other.path); } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/ZipArchive.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/ZipArchive.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/ZipArchive.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,15 +25,18 @@ package com.sun.tools.javac.file; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Writer; +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; import java.net.URI; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharsetDecoder; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; @@ -49,8 +52,6 @@ import com.sun.tools.javac.util.DefinedBy; import com.sun.tools.javac.util.DefinedBy.Api; import com.sun.tools.javac.util.List; -import java.lang.ref.Reference; -import java.lang.ref.SoftReference; /** *

This is NOT part of any supported API. @@ -131,10 +132,10 @@ return "ZipArchive[" + zfile.getName() + "]"; } - private File getAbsoluteFile() { - File absFile = (absFileRef == null ? null : absFileRef.get()); + private Path getAbsoluteFile() { + Path absFile = (absFileRef == null ? null : absFileRef.get()); if (absFile == null) { - absFile = new File(zfile.getName()).getAbsoluteFile(); + absFile = Paths.get(zfile.getName()).toAbsolutePath(); absFileRef = new SoftReference<>(absFile); } return absFile; @@ -155,7 +156,7 @@ /** * A reference to the absolute filename for the zip file for the archive. */ - protected Reference absFileRef; + protected Reference absFileRef; /** * A subclass of JavaFileObject representing zip entries. @@ -175,7 +176,7 @@ @DefinedBy(Api.COMPILER) public URI toUri() { - File zipFile = new File(zarch.zfile.getName()); + Path zipFile = Paths.get(zarch.zfile.getName()); return createJarUri(zipFile, entry.getName()); } @@ -186,7 +187,7 @@ @Override public String getShortName() { - return new File(zarch.zfile.getName()).getName() + "(" + entry + ")"; + return Paths.get(zarch.zfile.getName()).getFileName() + "(" + entry + ")"; } @Override @DefinedBy(Api.COMPILER) @@ -246,7 +247,7 @@ } @Override - protected String inferBinaryName(Iterable path) { + protected String inferBinaryName(Iterable path) { String entryName = entry.getName(); return removeExtension(entryName).replace('/', '.'); } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/ZipFileIndex.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/ZipFileIndex.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/ZipFileIndex.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,18 +26,20 @@ package com.sun.tools.javac.file; -import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.lang.ref.Reference; import java.lang.ref.SoftReference; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedHashMap; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -91,14 +93,14 @@ Collections.emptySet(); // ZipFileIndex data entries - final File zipFile; - private Reference absFileRef; + final Path zipFile; + private Reference absFileRef; long zipFileLastModified = NOT_MODIFIED; private RandomAccessFile zipRandomFile; private Entry[] entries; private boolean readFromIndex = false; - private File zipIndexFile = null; + private Path zipIndexFile = null; private boolean triedToReadIndex = false; final RelativeDirectory symbolFilePrefix; private final int symbolFilePrefixLength; @@ -117,7 +119,7 @@ return (zipRandomFile != null); } - ZipFileIndex(File zipFile, RelativeDirectory symbolFilePrefix, boolean writeIndex, + ZipFileIndex(Path zipFile, RelativeDirectory symbolFilePrefix, boolean writeIndex, boolean useCache, String cacheLocation) throws IOException { this.zipFile = zipFile; this.symbolFilePrefix = symbolFilePrefix; @@ -128,7 +130,7 @@ this.preindexedCacheLocation = cacheLocation; if (zipFile != null) { - this.zipFileLastModified = zipFile.lastModified(); + this.zipFileLastModified = Files.getLastModifiedTime(zipFile).toMillis(); } // Validate integrity of the zip file @@ -148,10 +150,11 @@ } private boolean isUpToDate() { - if (zipFile != null - && ((!NON_BATCH_MODE) || zipFileLastModified == zipFile.lastModified()) - && hasPopulatedData) { - return true; + try { + return (zipFile != null + && ((!NON_BATCH_MODE) || zipFileLastModified == Files.getLastModifiedTime(zipFile).toMillis()) + && hasPopulatedData); + } catch (IOException ignore) { } return false; @@ -199,7 +202,7 @@ private void openFile() throws FileNotFoundException { if (zipRandomFile == null && zipFile != null) { - zipRandomFile = new RandomAccessFile(zipFile, "r"); + zipRandomFile = new RandomAccessFile(zipFile.toFile(), "r"); } } @@ -785,11 +788,11 @@ entries.add(zipFileIndex.entries[i]); } } else { - File indexFile = zipFileIndex.getIndexFile(); + Path indexFile = zipFileIndex.getIndexFile(); if (indexFile != null) { RandomAccessFile raf = null; try { - raf = new RandomAccessFile(indexFile, "r"); + raf = new RandomAccessFile(indexFile.toFile(), "r"); raf.seek(writtenOffsetOffset); for (int nFiles = 0; nFiles < numEntries; nFiles++) { @@ -856,11 +859,11 @@ triedToReadIndex = true; RandomAccessFile raf = null; try { - File indexFileName = getIndexFile(); - raf = new RandomAccessFile(indexFileName, "r"); + Path indexFileName = getIndexFile(); + raf = new RandomAccessFile(indexFileName.toFile(), "r"); long fileStamp = raf.readLong(); - if (zipFile.lastModified() != fileStamp) { + if (Files.getLastModifiedTime(zipFile).toMillis() != fileStamp) { ret = false; } else { directories = new LinkedHashMap<>(); @@ -908,7 +911,7 @@ return true; } - File indexFile = getIndexFile(); + Path indexFile = getIndexFile(); if (indexFile == null) { return false; } @@ -916,7 +919,7 @@ RandomAccessFile raf = null; long writtenSoFar = 0; try { - raf = new RandomAccessFile(indexFile, "rw"); + raf = new RandomAccessFile(indexFile.toFile(), "rw"); raf.writeLong(zipFileLastModified); writtenSoFar += 8; @@ -1016,27 +1019,27 @@ } } - private File getIndexFile() { + private Path getIndexFile() { if (zipIndexFile == null) { if (zipFile == null) { return null; } - zipIndexFile = new File((preindexedCacheLocation == null ? "" : preindexedCacheLocation) + - zipFile.getName() + ".index"); + zipIndexFile = Paths.get((preindexedCacheLocation == null ? "" : preindexedCacheLocation) + + zipFile.getFileName() + ".index"); } return zipIndexFile; } - public File getZipFile() { + public Path getZipFile() { return zipFile; } - File getAbsoluteFile() { - File absFile = (absFileRef == null ? null : absFileRef.get()); + Path getAbsoluteFile() { + Path absFile = (absFileRef == null ? null : absFileRef.get()); if (absFile == null) { - absFile = zipFile.getAbsoluteFile(); + absFile = zipFile.toAbsolutePath(); absFileRef = new SoftReference<>(absFile); } return absFile; diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java Thu Dec 04 15:22:53 2014 -0800 @@ -25,12 +25,8 @@ package com.sun.tools.javac.file; +import java.io.ByteArrayInputStream; import java.io.IOException; -import java.util.Set; -import javax.tools.JavaFileObject; - -import java.io.ByteArrayInputStream; -import java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.io.Writer; @@ -38,6 +34,10 @@ import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharsetDecoder; +import java.nio.file.Path; +import java.util.Set; + +import javax.tools.JavaFileObject; import com.sun.tools.javac.file.JavacFileManager.Archive; import com.sun.tools.javac.file.RelativePath.RelativeDirectory; @@ -56,7 +56,7 @@ public class ZipFileIndexArchive implements Archive { private final ZipFileIndex zfIndex; - private JavacFileManager fileManager; + private final JavacFileManager fileManager; public ZipFileIndexArchive(JavacFileManager fileManager, ZipFileIndex zdir) throws IOException { super(); @@ -111,10 +111,10 @@ /** The name of the zip file where this entry resides. */ - File zipName; + Path zipName; - ZipFileIndexFileObject(JavacFileManager fileManager, ZipFileIndex zfIndex, ZipFileIndex.Entry entry, File zipFileName) { + ZipFileIndexFileObject(JavacFileManager fileManager, ZipFileIndex zfIndex, ZipFileIndex.Entry entry, Path zipFileName) { super(fileManager); this.name = entry.getFileName(); this.zfIndex = zfIndex; @@ -134,7 +134,7 @@ @Override public String getShortName() { - return zipName.getName() + "(" + entry.getName() + ")"; + return zipName.getFileName() + "(" + entry.getName() + ")"; } @Override @DefinedBy(Api.COMPILER) @@ -194,7 +194,7 @@ } @Override - protected String inferBinaryName(Iterable path) { + protected String inferBinaryName(Iterable path) { String entryName = entry.getName(); if (zfIndex.symbolFilePrefix != null) { String prefix = zfIndex.symbolFilePrefix.path; diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/ZipFileIndexCache.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/ZipFileIndexCache.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/ZipFileIndexCache.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,21 +25,22 @@ package com.sun.tools.javac.file; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import com.sun.tools.javac.file.RelativePath.RelativeDirectory; import com.sun.tools.javac.util.Context; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; /** A cache for ZipFileIndex objects. */ public class ZipFileIndexCache { - private final Map map = new HashMap<>(); + private final Map map = new HashMap<>(); /** Get a shared instance of the cache. */ private static ZipFileIndexCache sharedInstance; @@ -89,13 +90,13 @@ return zipFileIndexes; } - public synchronized ZipFileIndex getZipFileIndex(File zipFile, + public synchronized ZipFileIndex getZipFileIndex(Path zipFile, RelativeDirectory symbolFilePrefix, boolean useCache, String cacheLocation, boolean writeIndex) throws IOException { ZipFileIndex zi = getExistingZipIndex(zipFile); - if (zi == null || (zi != null && zipFile.lastModified() != zi.zipFileLastModified)) { + if (zi == null || (zi != null && Files.getLastModifiedTime(zipFile).toMillis() != zi.zipFileLastModified)) { zi = new ZipFileIndex(zipFile, symbolFilePrefix, writeIndex, useCache, cacheLocation); map.put(zipFile, zi); @@ -103,7 +104,7 @@ return zi; } - public synchronized ZipFileIndex getExistingZipIndex(File zipFile) { + public synchronized ZipFileIndex getExistingZipIndex(Path zipFile) { return map.get(zipFile); } @@ -112,7 +113,7 @@ } public synchronized void clearCache(long timeNotUsed) { - for (File cachedFile : map.keySet()) { + for (Path cachedFile : map.keySet()) { ZipFileIndex cachedZipIndex = map.get(cachedFile); if (cachedZipIndex != null) { long timeToTest = cachedZipIndex.lastReferenceTimeStamp + timeNotUsed; @@ -124,7 +125,7 @@ } } - public synchronized void removeFromCache(File file) { + public synchronized void removeFromCache(Path file) { map.remove(file); } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Thu Dec 04 15:22:53 2014 -0800 @@ -29,23 +29,27 @@ import java.net.URI; import java.net.URISyntaxException; import java.nio.CharBuffer; +import java.nio.file.Path; import java.util.Arrays; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; -import javax.tools.JavaFileObject; + import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; -import com.sun.tools.javac.comp.Annotate; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Lint.LintCategory; -import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.code.Scope.WriteableScope; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Symtab; +import com.sun.tools.javac.code.Type.*; +import com.sun.tools.javac.comp.Annotate; import com.sun.tools.javac.file.BaseFileObject; +import com.sun.tools.javac.jvm.ClassFile.NameAndType; +import com.sun.tools.javac.jvm.ClassFile.Version; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.DefinedBy.Api; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; @@ -2467,7 +2471,7 @@ } @Override - protected String inferBinaryName(Iterable path) { + protected String inferBinaryName(Iterable path) { return flatname.toString(); } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Thu Dec 04 15:22:53 2014 -0800 @@ -640,6 +640,27 @@ } + private void writeParamAnnotations(List params, + RetentionPolicy retention) { + for (VarSymbol s : params) { + ListBuffer buf = new ListBuffer<>(); + for (Attribute.Compound a : s.getRawAttributes()) + if (types.getRetention(a) == retention) + buf.append(a); + databuf.appendChar(buf.length()); + for (Attribute.Compound a : buf) + writeCompoundAttribute(a); + } + + } + + private void writeParamAnnotations(MethodSymbol m, + RetentionPolicy retention) { + databuf.appendByte(m.params.length() + m.extraParams.length()); + writeParamAnnotations(m.extraParams, retention); + writeParamAnnotations(m.params, retention); + } + /** Write method parameter annotations; * return number of attributes written. */ @@ -662,31 +683,13 @@ int attrCount = 0; if (hasVisible) { int attrIndex = writeAttr(names.RuntimeVisibleParameterAnnotations); - databuf.appendByte(m.params.length()); - for (VarSymbol s : m.params) { - ListBuffer buf = new ListBuffer<>(); - for (Attribute.Compound a : s.getRawAttributes()) - if (types.getRetention(a) == RetentionPolicy.RUNTIME) - buf.append(a); - databuf.appendChar(buf.length()); - for (Attribute.Compound a : buf) - writeCompoundAttribute(a); - } + writeParamAnnotations(m, RetentionPolicy.RUNTIME); endAttr(attrIndex); attrCount++; } if (hasInvisible) { int attrIndex = writeAttr(names.RuntimeInvisibleParameterAnnotations); - databuf.appendByte(m.params.length()); - for (VarSymbol s : m.params) { - ListBuffer buf = new ListBuffer<>(); - for (Attribute.Compound a : s.getRawAttributes()) - if (types.getRetention(a) == RetentionPolicy.CLASS) - buf.append(a); - databuf.appendChar(buf.length()); - for (Attribute.Compound a : buf) - writeCompoundAttribute(a); - } + writeParamAnnotations(m, RetentionPolicy.CLASS); endAttr(attrIndex); attrCount++; } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java Thu Dec 04 15:22:53 2014 -0800 @@ -29,10 +29,10 @@ import java.io.IOException; import java.io.PrintWriter; import java.net.URL; +import java.nio.file.NoSuchFileException; import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; - import java.util.Set; import javax.tools.JavaFileManager; @@ -160,13 +160,15 @@ Option.HELP.process(new OptionHelper.GrumpyHelper(log) { @Override public String getOwnName() { return ownName; } + @Override + public void put(String name, String value) { } }, "-help"); return Result.CMDERR; } try { argv = CommandLine.parse(argv); - } catch (FileNotFoundException e) { + } catch (FileNotFoundException | NoSuchFileException e) { warning("err.file.not.found", e.getMessage()); return Result.SYSERR; } catch (IOException ex) { diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java Thu Dec 04 15:22:53 2014 -0800 @@ -30,12 +30,13 @@ import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.Charset; -import java.nio.file.Files; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.FileVisitOption; import java.nio.file.FileVisitResult; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; @@ -48,6 +49,7 @@ import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; + import javax.lang.model.SourceVersion; import javax.tools.FileObject; import javax.tools.JavaFileManager; @@ -55,9 +57,6 @@ import javax.tools.JavaFileObject.Kind; import javax.tools.StandardLocation; -import static java.nio.file.FileVisitOption.*; -import static javax.tools.StandardLocation.*; - import com.sun.tools.javac.util.BaseFileManager; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.DefinedBy; @@ -65,6 +64,10 @@ import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; +import static java.nio.file.FileVisitOption.*; + +import static javax.tools.StandardLocation.*; + import static com.sun.tools.javac.main.Option.*; @@ -221,7 +224,7 @@ } private void setDefaultForLocation(Location locn) { - Collection files = null; + Collection files = null; if (locn instanceof StandardLocation) { switch ((StandardLocation) locn) { case CLASS_PATH: @@ -235,12 +238,12 @@ break; case CLASS_OUTPUT: { String arg = options.get(D); - files = (arg == null ? null : Collections.singleton(new File(arg))); + files = (arg == null ? null : Collections.singleton(Paths.get(arg))); break; } case SOURCE_OUTPUT: { String arg = options.get(S); - files = (arg == null ? null : Collections.singleton(new File(arg))); + files = (arg == null ? null : Collections.singleton(Paths.get(arg))); break; } } @@ -248,8 +251,8 @@ PathsForLocation pl = new PathsForLocation(); if (files != null) { - for (File f: files) - pl.add(f.toPath()); + for (Path f: files) + pl.add(f); } if (!pl.isEmpty()) pathsForLocation.put(locn, pl); diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Thu Dec 04 15:22:53 2014 -0800 @@ -145,6 +145,8 @@ this.names = fac.names; this.source = fac.source; this.allowTWR = source.allowTryWithResources(); + this.allowEffectivelyFinalVariablesInTWR = + source.allowEffectivelyFinalVariablesInTryWithResources(); this.allowDiamond = source.allowDiamond(); this.allowMulticatch = source.allowMulticatch(); this.allowStringFolding = fac.options.getBoolean("allowStringFolding", true); @@ -184,6 +186,10 @@ */ boolean allowTWR; + /** Switch: should we allow (effectively) final variables as resources in try-with-resources? + */ + boolean allowEffectivelyFinalVariablesInTWR; + /** Switch: should we fold strings? */ boolean allowStringFolding; @@ -3003,14 +3009,28 @@ return defs.toList(); } - /** Resource = VariableModifiersOpt Type VariableDeclaratorId = Expression + /** Resource = VariableModifiersOpt Type VariableDeclaratorId "=" Expression + * | Expression */ protected JCTree resource() { - JCModifiers optFinal = optFinal(Flags.FINAL); - JCExpression type = parseType(); - int pos = token.pos; - Name ident = ident(); - return variableDeclaratorRest(pos, optFinal, type, ident, true, null); + int startPos = token.pos; + if (token.kind == FINAL || token.kind == MONKEYS_AT) { + JCModifiers mods = optFinal(Flags.FINAL); + JCExpression t = parseType(); + return variableDeclaratorRest(token.pos, mods, t, ident(), true, null); + } + JCExpression t = term(EXPR | TYPE); + if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) { + JCModifiers mods = toP(F.at(startPos).Modifiers(Flags.FINAL)); + return variableDeclaratorRest(token.pos, mods, t, ident(), true, null); + } else { + checkVariableInTryWithResources(startPos); + if (!t.hasTag(IDENT) && !t.hasTag(SELECT)) { + log.error(t.pos(), "try.with.resources.expr.needs.var"); + } + + return t; + } } /** CompilationUnit = [ { "@" Annotation } PACKAGE Qualident ";"] {ImportDeclaration} {TypeDeclaration} @@ -3933,6 +3953,12 @@ allowTWR = true; } } + void checkVariableInTryWithResources(int startPos) { + if (!allowEffectivelyFinalVariablesInTWR) { + error(startPos, "var.in.try.with.resources.not.supported.in.source", source.name); + allowEffectivelyFinalVariablesInTWR = true; + } + } void checkLambda() { if (!allowLambda) { log.error(token.pos, "lambda.not.supported.in.source", source.name); diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Thu Dec 04 15:22:53 2014 -0800 @@ -252,6 +252,14 @@ compiler.err.cant.ref.non.effectively.final.var=\ local variables referenced from {1} must be final or effectively final +compiler.err.try.with.resources.expr.needs.var=\ + the try-with-resources resource must either be a variable declaration or an expression denoting \ +a reference to a final or effectively final variable + +# 0: symbol +compiler.err.try.with.resources.expr.effectively.final.var=\ + variable {0} used as a try-with-resources resource neither final nor effectively final + compiler.misc.lambda=\ a lambda expression @@ -2262,6 +2270,11 @@ try-with-resources is not supported in -source {0}\n\ (use -source 7 or higher to enable try-with-resources) +# 0: string +compiler.err.var.in.try.with.resources.not.supported.in.source=\ + variables in try-with-resources not supported in -source {0}\n\ + (use -source 9 or higher to enable variables in try-with-resources) + compiler.warn.underscore.as.identifier=\ ''_'' used as an identifier\n\ (use of ''_'' as an identifier might not be supported in releases after Java SE 8) diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_ja.properties --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_ja.properties Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_ja.properties Thu Dec 04 15:22:53 2014 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -1526,7 +1526,7 @@ compiler.warn.override.unchecked.thrown={0}\n\u30AA\u30FC\u30D0\u30FC\u30E9\u30A4\u30C9\u3055\u308C\u305F\u30E1\u30BD\u30C3\u30C9\u306F{1}\u3092\u30B9\u30ED\u30FC\u3057\u307E\u305B\u3093 # 0: symbol -compiler.warn.override.equals.but.not.hashcode=\u30AF\u30E9\u30B9{0}\u306F\u7B49\u53F7\u3092\u30AA\u30FC\u30D0\u30FC\u30E9\u30A4\u30C9\u3057\u307E\u3059\u304C\u3001\u3053\u306E\u30AF\u30E9\u30B9\u3082\u30B9\u30FC\u30D1\u30FC\u30AF\u30E9\u30B9\u3082hashCode\u30E1\u30BD\u30C3\u30C9\u3092\u30AA\u30FC\u30D0\u30FC\u30E9\u30A4\u30C9\u3057\u307E\u305B\u3093 +compiler.warn.override.equals.but.not.hashcode=\u30AF\u30E9\u30B9{0}\u306Fequals\u3092\u30AA\u30FC\u30D0\u30FC\u30E9\u30A4\u30C9\u3057\u307E\u3059\u304C\u3001\u3053\u306E\u30AF\u30E9\u30B9\u3082\u3001\u307E\u305F\u3001\u3044\u304B\u306A\u308B\u30B9\u30FC\u30D1\u30FC\u30AF\u30E9\u30B9\u3082\u3001hashCode\u30E1\u30BD\u30C3\u30C9\u3092\u30AA\u30FC\u30D0\u30FC\u30E9\u30A4\u30C9\u3057\u307E\u305B\u3093 ## The following are all possible strings for the first argument ({0}) of the ## above strings. diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_zh_CN.properties --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_zh_CN.properties Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_zh_CN.properties Thu Dec 04 15:22:53 2014 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -1526,7 +1526,7 @@ compiler.warn.override.unchecked.thrown={0}\n\u88AB\u8986\u76D6\u7684\u65B9\u6CD5\u672A\u629B\u51FA{1} # 0: symbol -compiler.warn.override.equals.but.not.hashcode=\u7C7B{0}\u8986\u76D6\u4E86\u7B49\u53F7, \u4F46\u8BE5\u7C7B\u6216\u4EFB\u4F55\u8D85\u7C7B\u90FD\u672A\u8986\u76D6 hashCode \u65B9\u6CD5 +compiler.warn.override.equals.but.not.hashcode=\u7C7B{0}\u8986\u76D6\u4E86 equals, \u4F46\u8BE5\u7C7B\u6216\u4EFB\u4F55\u8D85\u7C7B\u90FD\u672A\u8986\u76D6 hashCode \u65B9\u6CD5 ## The following are all possible strings for the first argument ({0}) of the ## above strings. diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java Thu Dec 04 15:22:53 2014 -0800 @@ -612,6 +612,7 @@ public boolean staticImport; /** The imported class(es). */ public JCTree qualid; + public com.sun.tools.javac.code.Scope importScope; protected JCImport(JCTree qualid, boolean importStatic) { this.qualid = qualid; this.staticImport = importStatic; diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ */ package com.sun.tools.javac.util; +import java.nio.file.Path; import java.util.Arrays; import java.util.Collection; import java.util.EnumSet; @@ -48,6 +49,7 @@ import com.sun.tools.javac.jvm.Profile; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.tree.Pretty; + import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticType.*; /** @@ -186,7 +188,7 @@ else if (arg instanceof JCExpression) { return expr2String((JCExpression)arg); } - else if (arg instanceof Iterable) { + else if (arg instanceof Iterable && !(arg instanceof Path)) { return formatIterable(d, (Iterable)arg, l); } else if (arg instanceof Type) { diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Dependencies.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Dependencies.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Dependencies.java Thu Dec 04 15:22:53 2014 -0800 @@ -73,7 +73,7 @@ return instance; } - Dependencies(Context context) { + protected Dependencies(Context context) { context.put(dependenciesKey, this); } @@ -122,7 +122,7 @@ /** * Push a new completion node on the stack. */ - abstract public void push(ClassSymbol s); + abstract public void push(ClassSymbol s, CompletionCause phase); /** * Push a new attribution node on the stack. @@ -134,6 +134,15 @@ */ abstract public void pop(); + public enum CompletionCause { + CLASS_READER, + HEADER_PHASE, + HIERARCHY_PHASE, + IMPORTS_PHASE, + MEMBER_ENTER, + MEMBERS_PHASE; + } + /** * This class creates a graph of all dependencies as symbols are completed; * when compilation finishes, the resulting dependecy graph is then dumped @@ -391,7 +400,7 @@ Map dependencyNodeMap = new LinkedHashMap<>(); @Override - public void push(ClassSymbol s) { + public void push(ClassSymbol s, CompletionCause phase) { Node n = new CompletionNode(s); if (n == push(n)) { s.completer = this; @@ -454,7 +463,7 @@ @Override public void complete(Symbol sym) throws CompletionFailure { - push((ClassSymbol) sym); + push((ClassSymbol) sym, null); pop(); sym.completer = this; } @@ -542,7 +551,7 @@ } @Override - public void push(ClassSymbol s) { + public void push(ClassSymbol s, CompletionCause phase) { //do nothing } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java Thu Dec 04 15:22:53 2014 -0800 @@ -24,6 +24,7 @@ */ package com.sun.tools.javac.util; +import java.nio.file.Path; import java.util.EnumMap; import java.util.EnumSet; import java.util.HashMap; @@ -39,8 +40,8 @@ import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.code.Types; +import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.TypeTag.*; -import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Kinds.*; import static com.sun.tools.javac.code.Kinds.Kind.*; import static com.sun.tools.javac.util.LayoutCharacters.*; @@ -186,7 +187,7 @@ else if (arg instanceof JCDiagnostic) { preprocessDiagnostic((JCDiagnostic)arg); } - else if (arg instanceof Iterable) { + else if (arg instanceof Iterable && !(arg instanceof Path)) { for (Object o : (Iterable)arg) { preprocessArgument(o); } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javah/Gen.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javah/Gen.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javah/Gen.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package com.sun.tools.javah; -import java.io.UnsupportedEncodingException; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.IOException; @@ -33,6 +32,8 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.nio.file.NoSuchFileException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -40,7 +41,6 @@ import java.util.Stack; import javax.annotation.processing.ProcessingEnvironment; - import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; @@ -48,7 +48,6 @@ import javax.lang.model.util.ElementFilter; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; - import javax.tools.FileObject; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; @@ -204,7 +203,7 @@ event = "[Overwriting file "; } - } catch (FileNotFoundException e) { + } catch (FileNotFoundException | NoSuchFileException e) { mustWrite = true; event = "[Creating file "; } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javah/JavahTask.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javah/JavahTask.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javah/JavahTask.java Thu Dec 04 15:22:53 2014 -0800 @@ -31,6 +31,7 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.io.Writer; +import java.nio.file.NoSuchFileException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; @@ -50,7 +51,6 @@ import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; - import javax.lang.model.SourceVersion; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; @@ -62,7 +62,6 @@ import javax.lang.model.util.ElementFilter; import javax.lang.model.util.SimpleTypeVisitor9; import javax.lang.model.util.Types; - import javax.tools.Diagnostic; import javax.tools.DiagnosticListener; import javax.tools.JavaCompiler; @@ -72,13 +71,15 @@ import javax.tools.StandardJavaFileManager; import javax.tools.StandardLocation; import javax.tools.ToolProvider; -import static javax.tools.Diagnostic.Kind.*; import com.sun.tools.javac.code.Symbol.CompletionFailure; import com.sun.tools.javac.main.CommandLine; import com.sun.tools.javac.util.DefinedBy; import com.sun.tools.javac.util.DefinedBy.Api; +import static javax.tools.Diagnostic.Kind.*; + + /** * Javah generates support files for native methods. * Parse commandline options and invokes javadoc to execute those commands. @@ -420,7 +421,7 @@ List l = new ArrayList<>(); for (String arg: args) l.add(arg); return Arrays.asList(CommandLine.parse(l.toArray(new String[l.size()]))); - } catch (FileNotFoundException e) { + } catch (FileNotFoundException | NoSuchFileException e) { throw new BadArgs("at.args.file.not.found", e.getLocalizedMessage()); } catch (IOException e) { throw new BadArgs("at.args.io.exception", e.getLocalizedMessage()); diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/javap/JavapTask.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javap/JavapTask.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javap/JavapTask.java Thu Dec 04 15:22:53 2014 -0800 @@ -36,6 +36,10 @@ import java.io.StringWriter; import java.io.Writer; import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.nio.file.NoSuchFileException; import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -61,10 +65,6 @@ import javax.tools.StandardLocation; import com.sun.tools.classfile.*; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLConnection; - import com.sun.tools.javac.util.DefinedBy; import com.sun.tools.javac.util.DefinedBy.Api; @@ -568,7 +568,7 @@ } catch (EOFException e) { reportError("err.end.of.file", className); result = EXIT_ERROR; - } catch (FileNotFoundException e) { + } catch (FileNotFoundException | NoSuchFileException e) { reportError("err.file.not.found", e.getLocalizedMessage()); result = EXIT_ERROR; } catch (IOException e) { @@ -668,9 +668,12 @@ if (fileManager instanceof StandardJavaFileManager) { StandardJavaFileManager sfm = (StandardJavaFileManager) fileManager; - fo = sfm.getJavaFileObjects(className).iterator().next(); - if (fo != null && fo.getLastModified() != 0) { - return fo; + try { + fo = sfm.getJavaFileObjects(className).iterator().next(); + if (fo != null && fo.getLastModified() != 0) { + return fo; + } + } catch (IllegalArgumentException ignore) { } } @@ -860,11 +863,15 @@ } private JavaFileObject getClassFileObject(String className) throws IOException { - JavaFileObject fo; - fo = fileManager.getJavaFileForInput(StandardLocation.PLATFORM_CLASS_PATH, className, JavaFileObject.Kind.CLASS); - if (fo == null) - fo = fileManager.getJavaFileForInput(StandardLocation.CLASS_PATH, className, JavaFileObject.Kind.CLASS); - return fo; + try { + JavaFileObject fo; + fo = fileManager.getJavaFileForInput(StandardLocation.PLATFORM_CLASS_PATH, className, JavaFileObject.Kind.CLASS); + if (fo == null) + fo = fileManager.getJavaFileForInput(StandardLocation.CLASS_PATH, className, JavaFileObject.Kind.CLASS); + return fo; + } catch (IllegalArgumentException e) { + return null; + } } private void showHelp() { diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/JavacState.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/JavacState.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/JavacState.java Thu Dec 04 15:22:53 2014 -0800 @@ -26,16 +26,17 @@ package com.sun.tools.sjavac; import java.io.*; +import java.net.URI; +import java.nio.file.NoSuchFileException; +import java.text.SimpleDateFormat; +import java.util.*; import java.util.Collections; import java.util.Date; -import java.util.Set; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.HashMap; -import java.text.SimpleDateFormat; -import java.net.URI; -import java.util.*; +import java.util.Set; import com.sun.tools.sjavac.options.Options; import com.sun.tools.sjavac.server.Sjavac; @@ -364,7 +365,7 @@ } } } - } catch (FileNotFoundException e) { + } catch (FileNotFoundException | NoSuchFileException e) { // Silently create a new javac_state file. noFileFound = true; } catch (IOException e) { @@ -841,7 +842,7 @@ } listedSources.add(l); } - } catch (FileNotFoundException e) { + } catch (FileNotFoundException | NoSuchFileException e) { throw new ProblemException("Could not open "+makefileSourceList.getPath()+" since it does not exist!"); } catch (IOException e) { throw new ProblemException("Could not read "+makefileSourceList.getPath()); diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SmartFileObject.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SmartFileObject.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SmartFileObject.java Thu Dec 04 15:22:53 2014 -0800 @@ -27,6 +27,8 @@ import java.io.*; import java.net.URI; +import java.nio.file.NoSuchFileException; + import javax.lang.model.element.Modifier; import javax.lang.model.element.NestingKind; import javax.tools.JavaFileObject; @@ -108,7 +110,7 @@ while (r.ready()) { s.append(r.readLine()+lineseparator); } - } catch (FileNotFoundException e) { + } catch (FileNotFoundException | NoSuchFileException e) { // Perfectly ok. } return new SmartWriter(file, s.toString(), file.getName(), stdout); diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/lib/annotations/annotations/classfile/ClassfileInspector.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/lib/annotations/annotations/classfile/ClassfileInspector.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,1733 @@ +/* + * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package annotations.classfile; + +import java.io.*; +import java.net.URL; +import java.util.List; + +import com.sun.tools.classfile.*; + +/** + * A class providing utilities for writing tests that inspect class + * files directly, looking for specific type annotations. + * + * Note: this framework does not currently handle repeating + * annotations. + */ +public class ClassfileInspector { + + /** + * A group of expected annotations to be found in a given class. + * If the class name is null, then the template will be applied to + * every class. + */ + public static class Expected { + /** + * The name of the class. If {@code null} this template will + * apply to every class; otherwise, it will only be applied to + * the named class. + */ + public final String classname; + + /** + * The expected class annotations. These will be checked + * against the class' attributes. + */ + public final ExpectedAnnotation[] classAnnos; + + /** + * The expected method annotations. These will be checked + * against all methods in the class. + */ + public final ExpectedMethodAnnotation[] methodAnnos; + + /** + * The expected method parameter annotations. These will be checked + * against all methods in the class. + */ + public final ExpectedParameterAnnotation[] methodParamAnnos; + + /** + * The expected field type annotations. These will be checked + * against all fields in the class. + */ + public final ExpectedFieldAnnotation[] fieldAnnos; + + /** + * The expected class type annotations. These will be checked + * against the class' attributes. + */ + public final ExpectedTypeAnnotation[] classTypeAnnos; + + /** + * The expected method type annotations. These will be checked + * against all methods in the class. + */ + public final ExpectedMethodTypeAnnotation[] methodTypeAnnos; + + /** + * The expected field type annotations. These will be checked + * against all fields in the class. + */ + public final ExpectedFieldTypeAnnotation[] fieldTypeAnnos; + + /** + * Create an {@code Expected} from all components. + * + * @param classname The name of the class to match, or {@code + * null} for all classes. + * @param classAnnos The expected class annotations. + * @param methodAnnos The expected method annotations. + * @param methodParamAnnos The expected method parameter annotations. + * @param fieldAnnos The expected field annotations. + * @param classTypeAnnos The expected class type annotations. + * @param methodTypeAnnos The expected method type annotations. + * @param fieldTypeAnnos The expected field type annotations. + */ + public Expected(String classname, + ExpectedAnnotation[] classAnnos, + ExpectedMethodAnnotation[] methodAnnos, + ExpectedParameterAnnotation[] methodParamAnnos, + ExpectedFieldAnnotation[] fieldAnnos, + ExpectedTypeAnnotation[] classTypeAnnos, + ExpectedMethodTypeAnnotation[] methodTypeAnnos, + ExpectedFieldTypeAnnotation[] fieldTypeAnnos) { + this.classname = classname; + this.classAnnos = classAnnos; + this.methodAnnos = methodAnnos; + this.methodParamAnnos = methodParamAnnos; + this.fieldAnnos = fieldAnnos; + this.classTypeAnnos = classTypeAnnos; + this.methodTypeAnnos = methodTypeAnnos; + this.fieldTypeAnnos = fieldTypeAnnos; + } + + /** + * Create an {@code Expected} from regular annotation components. + * + * @param classname The name of the class to match, or {@code + * null} for all classes. + * @param classAnnos The expected class annotations. + * @param methodAnnos The expected method annotations. + * @param methodParamAnnos The expected method parameter annotations. + * @param fieldAnnos The expected field annotations. + */ + public Expected(String classname, + ExpectedAnnotation[] classAnnos, + ExpectedMethodAnnotation[] methodAnnos, + ExpectedParameterAnnotation[] methodParamAnnos, + ExpectedFieldAnnotation[] fieldAnnos) { + this(classname, classAnnos, methodAnnos, methodParamAnnos, + fieldAnnos, null, null, null); + } + + /** + * Create an {@code Expected} from type annotation components. + * + * @param classname The name of the class to match, or {@code + * null} for all classes. + * @param classTypeAnnos The expected class type annotations. + * @param methodTypeAnnos The expected method type annotations. + * @param fieldTypeAnnos The expected field type annotations. + */ + public Expected(String classname, + ExpectedTypeAnnotation[] classTypeAnnos, + ExpectedMethodTypeAnnotation[] methodTypeAnnos, + ExpectedFieldTypeAnnotation[] fieldTypeAnnos) { + this(classname, null, null, null, null, + classTypeAnnos, methodTypeAnnos, fieldTypeAnnos); + } + + public String toString() { + final StringBuilder sb = new StringBuilder(); + final String newline = System.lineSeparator(); + sb.append("Expected on class ").append(classname); + if (null != classAnnos) { + sb.append(newline).append("Class annotations:").append(newline); + for(ExpectedAnnotation anno : classAnnos) { + sb.append(anno).append(newline); + } + } + if (null != methodAnnos) { + sb.append(newline).append("Method annotations:").append(newline); + for(ExpectedAnnotation anno : methodAnnos) { + sb.append(anno).append(newline); + } + } + if (null != methodParamAnnos) { + sb.append(newline).append("Method param annotations:").append(newline); + for(ExpectedAnnotation anno : methodParamAnnos) { + sb.append(anno).append(newline); + } + } + if (null != fieldAnnos) { + sb.append(newline).append("Field annotations:").append(newline); + for(ExpectedAnnotation anno : fieldAnnos) { + sb.append(anno).append(newline); + } + } + if (null != classTypeAnnos) { + sb.append(newline).append("Class type annotations:").append(newline); + for(ExpectedAnnotation anno : classTypeAnnos) { + sb.append(anno).append(newline); + } + } + if (null != methodTypeAnnos) { + sb.append(newline).append("Method type annotations:").append(newline); + for(ExpectedAnnotation anno : methodTypeAnnos) { + sb.append(anno).append(newline); + } + } + if (null != fieldTypeAnnos) { + sb.append(newline).append("Field type annotations:").append(newline); + for(ExpectedAnnotation anno : fieldTypeAnnos) { + sb.append(anno).append(newline); + } + } + return sb.toString(); + } + + /** + * See if this template applies to a class. + * + * @param classname The classname to check. + * @return Whether or not this template should apply. + */ + public boolean matchClassName(String classname) { + return this.classname == null || this.classname.equals(classname); + } + + /** + * After applying the template to all classes, check to see if + * any of the expected annotations weren't matched. + * + * @return The number of missed matches. + */ + public int check() { + int count = 0; + if (classAnnos != null) { + for(ExpectedAnnotation expected : classAnnos) { + if (!expected.check()) { + count++; + } + } + } + if (methodAnnos != null) { + for(ExpectedAnnotation expected : methodAnnos) { + if (!expected.check()) { + count++; + } + } + } + if (methodParamAnnos != null) { + for(ExpectedAnnotation expected : methodParamAnnos) { + if (!expected.check()) { + count++; + } + } + } + if (fieldAnnos != null) { + for(ExpectedAnnotation expected : fieldAnnos) { + if (!expected.check()) { + count++; + } + } + } + if (classTypeAnnos != null) { + for(ExpectedAnnotation expected : classTypeAnnos) { + if (!expected.check()) { + count++; + } + } + } + if (methodTypeAnnos != null) { + for(ExpectedAnnotation expected : methodTypeAnnos) { + if (!expected.check()) { + count++; + } + } + } + if (fieldTypeAnnos != null) { + for(ExpectedAnnotation expected : fieldTypeAnnos) { + if (!expected.check()) { + count++; + } + } + } + return count; + } + } + + /** + * An expected annotation. This is both a superclass for + * method, field, and type annotations, as well as a class for + * annotations on a class. + */ + public static class ExpectedAnnotation { + protected int count = 0; + protected final String expectedName; + protected final int expectedCount; + protected final boolean visibility; + + /** + * Create an {@code ExpectedAnnotation} from its + * components. It is usually a better idea to use a {@code + * Builder} to do this. + * + * @param expectedName The expected annotation name. + * @param visibility Whether this annotation should be runtime-visible. + * @param expectedCount The number of annotations that should + * be seen. If 0, this asserts that the + * described annotation is not present. + */ + public ExpectedAnnotation(String expectedName, + boolean visibility, + int expectedCount) { + this.expectedName = expectedName; + this.visibility = visibility; + this.expectedCount = expectedCount; + } + + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("Expected "); + sb.append(expectedCount); + sb.append(" annotation "); + sb.append(expectedName); + sb.append(visibility ? ", runtime visibile " : ", runtime invisibile "); + return sb.toString(); + } + + /** + * See if this template matches the given visibility. + * + * @param Whether or not the annotation is visible at runtime. + * @return Whether or not this template matches the visibility. + */ + public boolean matchVisibility(boolean visibility) { + return this.visibility == visibility; + } + + /** + * Attempty to match this template against an annotation. If + * it does match, then the match count for the template will + * be incremented. Otherwise, nothing will be done. + * + * @param anno The annotation to attempt to match. + */ + public void matchAnnotation(ConstantPool cpool, + Annotation anno) { + if (checkMatch(cpool, anno)) { + count++; + } + } + + /** + * Indicate whether an annotation matches this expected + * annotation. + * + * @param ConstantPool The constant pool to use. + * @param anno The annotation to check. + * @return Whether the annotation matches. + */ + protected boolean checkMatch(ConstantPool cpool, + Annotation anno) { + try { + return cpool.getUTF8Info(anno.type_index).value.equals("L" + expectedName + ";"); + } catch(Exception e) { + return false; + } + } + + /** + * After all matching, check to see if the expected number of + * matches equals the actual number. If not, then print a + * failure message and return {@code false}. + * + * @return Whether or not the expected number of matched + * equals the actual number. + */ + public boolean check() { + if (count != expectedCount) { + System.err.println(this + ", but saw " + count); + return false; + } else { + return true; + } + } + } + + /** + * An annotation found on a method. + */ + public static class ExpectedMethodAnnotation extends ExpectedAnnotation { + protected final String methodname; + + /** + * Create an {@code ExpectedMethodAnnotation} from its + * components. It is usually a better idea to use a {@code + * Builder} to do this. + * + * @param methodname The expected method name. + * @param expectedName The expected annotation name. + * @param visibility Whether this annotation should be runtime-visible. + * @param expectedCount The number of annotations that should be seen. + */ + public ExpectedMethodAnnotation(String methodname, + String expectedName, + boolean visibility, + int expectedCount) { + super(expectedName, visibility, expectedCount); + this.methodname = methodname; + } + + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("Expected "); + sb.append(expectedCount); + sb.append(" annotation "); + sb.append(expectedName); + sb.append(visibility ? ", runtime visibile " : ", runtime invisibile "); + sb.append(" on method "); + sb.append(methodname); + return sb.toString(); + } + + /** + * See if this template applies to a method. + * + * @param methodname The method name to check. + * @return Whether or not this template should apply. + */ + public boolean matchMethodName(String methodname) { + return this.methodname.equals(methodname); + } + + } + + /** + * An annotation found on a method parameter. + */ + public static class ExpectedParameterAnnotation + extends ExpectedMethodAnnotation { + protected final int index; + + /** + * Create an {@code ExpectedParameterAnnotation} from its + * components. It is usually a better idea to use a {@code + * Builder} to do this. + * + * @param methodname The expected method name. + * @param index The parameter index. + * @param expectedName The expected annotation name. + * @param visibility Whether this annotation should be runtime-visible. + * @param expectedCount The number of annotations that should be seen. + */ + public ExpectedParameterAnnotation(String methodname, + int index, + String expectedName, + boolean visibility, + int expectedCount) { + super(methodname, expectedName, visibility, expectedCount); + this.index = index; + } + + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("Expected "); + sb.append(expectedCount); + sb.append(" annotation "); + sb.append(expectedName); + sb.append(visibility ? ", runtime visibile " : ", runtime invisibile "); + sb.append(" on method "); + sb.append(methodname); + sb.append(" parameter " + index); + return sb.toString(); + } + + } + + /** + * An annotation found on a field. + */ + public static class ExpectedFieldAnnotation extends ExpectedAnnotation { + private final String fieldname; + + /** + * Create an {@code ExpectedFieldAnnotation} from its + * components. It is usually a better idea to use a {@code + * Builder} to do this. + * + * @param fieldname The expected field name. + * @param expectedName The expected annotation name. + * @param visibility Whether this annotation should be runtime-visible. + * @param expectedCount The number of annotations that should be seen. + */ + public ExpectedFieldAnnotation(String fieldname, + String expectedName, + boolean visibility, + int expectedCount) { + super(expectedName, visibility, expectedCount); + this.fieldname = fieldname; + } + + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("Expected ").append(expectedCount) + .append(" annotation ").append(expectedName) + .append(visibility ? ", runtime visibile " : ", runtime invisibile ") + .append(" on field ").append(fieldname); + return sb.toString(); + } + + /** + * See if this template applies to a field. + * + * @param fieldname The field name to check. + * @return Whether or not this template should apply. + */ + public boolean matchFieldName(String fieldname) { + return this.fieldname.equals(fieldname); + } + + } + + /** + * An expected type annotation. This is both a superclass for + * method and field type annotations, as well as a class for type + * annotations on a class. + */ + public static class ExpectedTypeAnnotation extends ExpectedAnnotation { + protected final TypeAnnotation.TargetType targetType; + protected final int bound_index; + protected final int parameter_index; + protected final int type_index; + protected final int exception_index; + protected final TypeAnnotation.Position.TypePathEntry[] typePath; + + /** + * Create an {@code ExpectedTypeAnnotation} from its + * components. It is usually a better idea to use a {@code + * Builder} to do this. + * + * @param expectedName The expected annotation name. + * @param visibility Whether this annotation should be runtime-visible. + * @param expectedCount The number of annotations that should + * be seen. If 0, this asserts that the + * described annotation is not present. + * @param targetType The expected target type. + * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}. + * @param parameter_index The expected parameter index, or + * {@code Integer.MIN_VALUE}. + * @param type_index The expected type index, or {@code Integer.MIN_VALUE}. + * @param exception_index The expected exception index, or + * {@code Integer.MIN_VALUE}. + * @param typePath The expected type path. + */ + public ExpectedTypeAnnotation(String expectedName, + boolean visibility, + int expectedCount, + TypeAnnotation.TargetType targetType, + int bound_index, + int parameter_index, + int type_index, + int exception_index, + TypeAnnotation.Position.TypePathEntry... typePath) { + super(expectedName, visibility, expectedCount); + this.targetType = targetType; + this.bound_index = bound_index; + this.parameter_index = parameter_index; + this.type_index = type_index; + this.exception_index = exception_index; + this.typePath = typePath; + } + + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("Expected "); + sb.append(expectedCount); + sb.append(" annotation "); + sb.append(expectedName); + sb.append(visibility ? ", runtime visibile " : ", runtime invisibile "); + sb.append(targetType); + sb.append(", bound_index = "); + sb.append(bound_index); + sb.append(", parameter_index = "); + sb.append(parameter_index); + sb.append(", type_index = "); + sb.append(type_index); + sb.append(", exception_index = "); + sb.append(exception_index); + sb.append(", type_path = ["); + for(int i = 0; i < typePath.length; i++) { + if (i != 0) { + sb.append(", "); + } + sb.append(typePath[i]); + } + sb.append("]"); + return sb.toString(); + } + + @Override + public void matchAnnotation(ConstantPool cpool, + Annotation anno) {} + + public void matchAnnotation(TypeAnnotation anno) { + if (checkMatch(anno)) { + count++; + } + } + + public boolean checkMatch(TypeAnnotation anno) { + boolean matches = checkMatch(anno.constant_pool, anno.annotation); + + matches = matches && anno.position.type == targetType; + matches = matches && anno.position.bound_index == bound_index; + matches = matches && anno.position.parameter_index == parameter_index; + matches = matches && anno.position.type_index == type_index; + matches = matches && anno.position.exception_index == exception_index; + matches = matches && anno.position.location.size() == typePath.length; + + if (matches) { + int i = 0; + for(TypeAnnotation.Position.TypePathEntry entry : + anno.position.location) { + matches = matches && typePath[i++].equals(entry); + } + } + + return matches; + } + + /** + * A builder class for creating {@code + * ExpectedTypeAnnotation}s in a more convenient fashion. The + * constructor for {@code ExpectedTypeAnnotation} takes a + * large number of parameters (by necessity). This class + * allows users to construct a {@code ExpectedTypeAnnotation}s + * using only the ones they need. + */ + public static class Builder { + protected final String expectedName; + protected final boolean visibility; + protected final int expectedCount; + protected final TypeAnnotation.TargetType targetType; + protected int bound_index = Integer.MIN_VALUE; + protected int parameter_index = Integer.MIN_VALUE; + protected int type_index = Integer.MIN_VALUE; + protected int exception_index = Integer.MIN_VALUE; + protected TypeAnnotation.Position.TypePathEntry[] typePath = + new TypeAnnotation.Position.TypePathEntry[0]; + + /** + * Create a {@code Builder} from the mandatory parameters. + * + * @param expectedName The expected annotation name. + * @param targetType The expected target type. + * @param visibility Whether this annotation should be runtime-visible. + * @param expectedCount The number of annotations that should be seen. + */ + public Builder(String expectedName, + TypeAnnotation.TargetType targetType, + boolean visibility, + int expectedCount) { + this.expectedName = expectedName; + this.visibility = visibility; + this.expectedCount = expectedCount; + this.targetType = targetType; + } + + /** + * Create an {@code ExpectedTypeAnnotation} from all + * parameters that have been provided. The default values + * will be used for those that have not. + * + * @return The cretaed {@code ExpectedTypeAnnotation}. + */ + public ExpectedTypeAnnotation build() { + return new ExpectedTypeAnnotation(expectedName, visibility, + expectedCount, targetType, + bound_index, parameter_index, + type_index, exception_index, + typePath); + } + + /** + * Provide a bound index parameter. + * + * @param bound_index The bound_index value. + */ + public Builder setBoundIndex(int bound_index) { + this.bound_index = bound_index; + return this; + } + + /** + * Provide a parameter index parameter. + * + * @param bound_index The parameter_index value. + */ + public Builder setParameterIndex(int parameter_index) { + this.parameter_index = parameter_index; + return this; + } + + /** + * Provide a type index parameter. + * + * @param type_index The type_index value. + */ + public Builder setTypeIndex(int type_index) { + this.type_index = type_index; + return this; + } + + /** + * Provide an exception index parameter. + * + * @param exception_index The exception_index value. + */ + public Builder setExceptionIndex(int exception_index) { + this.exception_index = exception_index; + return this; + } + + /** + * Provide a type path parameter. + * + * @param typePath The type path value. + */ + public Builder setTypePath(TypeAnnotation.Position.TypePathEntry[] typePath) { + this.typePath = typePath; + return this; + } + } + } + + /** + * A type annotation found on a method. + */ + public static class ExpectedMethodTypeAnnotation extends ExpectedTypeAnnotation { + private final String methodname; + + /** + * Create an {@code ExpectedMethodTypeAnnotation} from its + * components. It is usually a better idea to use a {@code + * Builder} to do this. + * + * @param methodname The expected method name. + * @param expectedName The expected annotation name. + * @param visibility Whether this annotation should be runtime-visible. + * @param expectedCount The number of annotations that should be seen. + * @param targetType The expected target type. + * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}. + * @param parameter_index The expected parameter index, or + * {@code Integer.MIN_VALUE}. + * @param type_index The expected type index, or {@code Integer.MIN_VALUE}. + * @param exception_index The expected exception index, or + * {@code Integer.MIN_VALUE}. + * @param typePath The expected type path. + */ + public ExpectedMethodTypeAnnotation(String methodname, + String expectedName, + boolean visibility, + int expectedCount, + TypeAnnotation.TargetType targetType, + int bound_index, + int parameter_index, + int type_index, + int exception_index, + TypeAnnotation.Position.TypePathEntry... typePath) { + super(expectedName, visibility, expectedCount, targetType, bound_index, + parameter_index, type_index, exception_index, typePath); + this.methodname = methodname; + } + + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("Expected "); + sb.append(expectedCount); + sb.append(" annotation "); + sb.append(expectedName); + sb.append(visibility ? ", runtime visibile " : ", runtime invisibile "); + sb.append(targetType); + sb.append(", bound_index = "); + sb.append(bound_index); + sb.append(", parameter_index = "); + sb.append(parameter_index); + sb.append(", type_index = "); + sb.append(type_index); + sb.append(", exception_index = "); + sb.append(exception_index); + sb.append(", type_path = ["); + for(int i = 0; i < typePath.length; i++) { + if (i != 0) { + sb.append(", "); + } + sb.append(typePath[i]); + } + sb.append("]"); + sb.append(" on method "); + sb.append(methodname); + return sb.toString(); + } + + /** + * See if this template applies to a method. + * + * @param methodname The method name to check. + * @return Whether or not this template should apply. + */ + public boolean matchMethodName(String methodname) { + return this.methodname.equals(methodname); + } + + /** + * A builder class for creating {@code + * ExpectedMethodTypeAnnotation}s in a more convenient fashion. The + * constructor for {@code ExpectedMethodTypeAnnotation} takes a + * large number of parameters (by necessity). This class + * allows users to construct a {@code ExpectedMethodTypeAnnotation}s + * using only the ones they need. + */ + public static class Builder extends ExpectedTypeAnnotation.Builder { + protected final String methodname; + + /** + * Create a {@code Builder} from the mandatory parameters. + * + * @param methodname The expected method name. + * @param expectedName The expected annotation name. + * @param targetType The expected target type. + * @param visibility Whether this annotation should be runtime-visible. + * @param expectedCount The number of annotations that should be seen. + */ + public Builder(String methodname, + String expectedName, + TypeAnnotation.TargetType targetType, + boolean visibility, + int expectedCount) { + super(expectedName, targetType, visibility, expectedCount); + this.methodname = methodname; + } + + /** + * Create an {@code ExpectedMethodTypeAnnotation} from all + * parameters that have been provided. The default values + * will be used for those that have not. + * + * @return The cretaed {@code ExpectedMethodTypeAnnotation}. + */ + public ExpectedMethodTypeAnnotation build() { + return new ExpectedMethodTypeAnnotation(methodname, expectedName, + visibility, expectedCount, + targetType, bound_index, + parameter_index, type_index, + exception_index, typePath); + } + } + } + + /** + * A type annotation found on a field. + */ + public static class ExpectedFieldTypeAnnotation extends ExpectedTypeAnnotation { + private final String fieldname; + + /** + * Create an {@code ExpectedFieldTypeAnnotation} from its + * components. It is usually a better idea to use a {@code + * Builder} to do this. + * + * @param fieldname The expected field name. + * @param expectedName The expected annotation name. + * @param visibility Whether this annotation should be runtime-visible. + * @param expectedCount The number of annotations that should be seen. + * @param targetType The expected target type. + * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}. + * @param parameter_index The expected parameter index, or + * {@code Integer.MIN_VALUE}. + * @param type_index The expected type index, or {@code Integer.MIN_VALUE}. + * @param exception_index The expected exception index, or + * {@code Integer.MIN_VALUE}. + * @param typePath The expected type path. + */ + public ExpectedFieldTypeAnnotation(String fieldname, + String expectedName, + boolean visibility, + int expectedCount, + TypeAnnotation.TargetType targetType, + int bound_index, + int parameter_index, + int type_index, + int exception_index, + TypeAnnotation.Position.TypePathEntry... typePath) { + super(expectedName, visibility, expectedCount, targetType, bound_index, + parameter_index, type_index, exception_index, typePath); + this.fieldname = fieldname; + } + + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("Expected ").append(expectedCount) + .append(" annotation ").append(expectedName) + .append(visibility ? ", runtime visibile " : ", runtime invisibile ") + .append(targetType) + .append(", bound_index = ").append(bound_index) + .append(", parameter_index = ").append(parameter_index) + .append(", type_index = ").append(type_index) + .append(", exception_index = ").append(exception_index) + .append(", type_path = ["); + + for(int i = 0; i < typePath.length; i++) { + if (i != 0) { + sb.append(", "); + } + sb.append(typePath[i]); + } + sb.append("]") + .append(" on field ").append(fieldname); + return sb.toString(); + } + + /** + * See if this template applies to a field. + * + * @param fieldname The field name to check. + * @return Whether or not this template should apply. + */ + public boolean matchFieldName(String fieldname) { + return this.fieldname.equals(fieldname); + } + + /** + * A builder class for creating {@code + * ExpectedFieldTypeAnnotation}s in a more convenient fashion. The + * constructor for {@code ExpectedFieldTypeAnnotation} takes a + * large number of parameters (by necessity). This class + * allows users to construct a {@code ExpectedFieldTypeAnnotation}s + * using only the ones they need. + */ + public static class Builder extends ExpectedTypeAnnotation.Builder { + protected final String fieldname; + + /** + * Create a {@code Builder} from the mandatory parameters. + * + * @param fieldname The expected field name. + * @param expectedName The expected annotation name. + * @param targetType The expected target type. + * @param visibility Whether this annotation should be runtime-visible. + * @param expectedCount The number of annotations that should be seen. + */ + public Builder(String fieldname, + String expectedName, + TypeAnnotation.TargetType targetType, + boolean visibility, + int expectedCount) { + super(expectedName, targetType, visibility, expectedCount); + this.fieldname = fieldname; + } + + /** + * Create an {@code ExpectedFieldTypeAnnotation} from all + * parameters that have been provided. The default values + * will be used for those that have not. + * + * @return The cretaed {@code ExpectedFieldTypeAnnotation}. + */ + public ExpectedFieldTypeAnnotation build() { + return new ExpectedFieldTypeAnnotation(fieldname, expectedName, + visibility, expectedCount, + targetType, bound_index, + parameter_index, type_index, + exception_index, typePath); + } + } + } + + private void matchClassAnnotation(ClassFile classfile, + ExpectedAnnotation expected) + throws ConstantPoolException { + for(Attribute attr : classfile.attributes) { + attr.accept(annoMatcher(classfile.constant_pool), expected); + } + } + + private void matchMethodAnnotation(ClassFile classfile, + ExpectedMethodAnnotation expected) + throws ConstantPoolException { + for(Method meth : classfile.methods) { + if (expected.matchMethodName(meth.getName(classfile.constant_pool))) { + for(Attribute attr : meth.attributes) { + attr.accept(annoMatcher(classfile.constant_pool), expected); + } + } + } + } + + private void matchParameterAnnotation(ClassFile classfile, + ExpectedParameterAnnotation expected) + throws ConstantPoolException { + for(Method meth : classfile.methods) { + if (expected.matchMethodName(meth.getName(classfile.constant_pool))) { + for(Attribute attr : meth.attributes) { + attr.accept(paramMatcher(classfile.constant_pool), expected); + } + } + } + } + + private void matchFieldAnnotation(ClassFile classfile, + ExpectedFieldAnnotation expected) + throws ConstantPoolException { + for(Field field : classfile.fields) { + if (expected.matchFieldName(field.getName(classfile.constant_pool))) { + for(Attribute attr : field.attributes) { + attr.accept(annoMatcher(classfile.constant_pool), expected); + } + } + } + } + + private void matchClassTypeAnnotation(ClassFile classfile, + ExpectedTypeAnnotation expected) + throws ConstantPoolException { + for(Attribute attr : classfile.attributes) { + attr.accept(typeAnnoMatcher, expected); + } + } + + private void matchMethodTypeAnnotation(ClassFile classfile, + ExpectedMethodTypeAnnotation expected) + throws ConstantPoolException { + for(Method meth : classfile.methods) { + if (expected.matchMethodName(meth.getName(classfile.constant_pool))) { + for(Attribute attr : meth.attributes) { + attr.accept(typeAnnoMatcher, expected); + } + } + } + } + + private void matchFieldTypeAnnotation(ClassFile classfile, + ExpectedFieldTypeAnnotation expected) + throws ConstantPoolException { + for(Field field : classfile.fields) { + if (expected.matchFieldName(field.getName(classfile.constant_pool))) { + for(Attribute attr : field.attributes) { + attr.accept(typeAnnoMatcher, expected); + } + } + } + } + + private void matchClassAnnotations(ClassFile classfile, + ExpectedAnnotation[] expected) + throws ConstantPoolException { + for(ExpectedAnnotation one : expected) { + matchClassAnnotation(classfile, one); + } + } + + private void matchMethodAnnotations(ClassFile classfile, + ExpectedMethodAnnotation[] expected) + throws ConstantPoolException { + for(ExpectedMethodAnnotation one : expected) { + matchMethodAnnotation(classfile, one); + } + } + + private void matchParameterAnnotations(ClassFile classfile, + ExpectedParameterAnnotation[] expected) + throws ConstantPoolException { + for(ExpectedParameterAnnotation one : expected) { + matchParameterAnnotation(classfile, one); + } + } + + private void matchFieldAnnotations(ClassFile classfile, + ExpectedFieldAnnotation[] expected) + throws ConstantPoolException { + for(ExpectedFieldAnnotation one : expected) { + matchFieldAnnotation(classfile, one); + } + } + + private void matchClassTypeAnnotations(ClassFile classfile, + ExpectedTypeAnnotation[] expected) + throws ConstantPoolException { + for(ExpectedTypeAnnotation one : expected) { + matchClassTypeAnnotation(classfile, one); + } + } + + private void matchMethodTypeAnnotations(ClassFile classfile, + ExpectedMethodTypeAnnotation[] expected) + throws ConstantPoolException { + for(ExpectedMethodTypeAnnotation one : expected) { + matchMethodTypeAnnotation(classfile, one); + } + } + + private void matchFieldTypeAnnotations(ClassFile classfile, + ExpectedFieldTypeAnnotation[] expected) + throws ConstantPoolException { + for(ExpectedFieldTypeAnnotation one : expected) { + matchFieldTypeAnnotation(classfile, one); + } + } + + /** + * Run a template on a single {@code ClassFile}. + * + * @param classfile The {@code ClassFile} on which to run tests. + * @param expected The expected annotation template. + */ + public void run(ClassFile classfile, + Expected... expected) + throws ConstantPoolException { + run(new ClassFile[] { classfile }, expected); + } + + /** + * Run a template on multiple {@code ClassFile}s. + * + * @param classfile The {@code ClassFile}s on which to run tests. + * @param expected The expected annotation template. + */ + public void run(ClassFile[] classfiles, + Expected... expected) + throws ConstantPoolException { + for(ClassFile classfile : classfiles) { + for(Expected one : expected) { + if (one.matchClassName(classfile.getName())) { + if (one.classAnnos != null) + matchClassAnnotations(classfile, one.classAnnos); + if (one.methodAnnos != null) + matchMethodAnnotations(classfile, one.methodAnnos); + if (one.methodParamAnnos != null) + matchParameterAnnotations(classfile, one.methodParamAnnos); + if (one.fieldAnnos != null) + matchFieldAnnotations(classfile, one.fieldAnnos); + if (one.classTypeAnnos != null) + matchClassTypeAnnotations(classfile, one.classTypeAnnos); + if (one.methodTypeAnnos != null) + matchMethodTypeAnnotations(classfile, one.methodTypeAnnos); + if (one.fieldTypeAnnos != null) + matchFieldTypeAnnotations(classfile, one.fieldTypeAnnos); + } + } + } + int count = 0; + for (Expected one : expected) { + count += one.check(); + } + + if (count != 0) { + throw new RuntimeException(count + " errors occurred in test"); + } + } + + /** + * Get a {@code ClassFile} from its file name. + * + * @param name The class' file name. + * @param host A class in the same package. + * @return The {@code ClassFile} + */ + public static ClassFile getClassFile(String name, + Class host) + throws IOException, ConstantPoolException { + final URL url = host.getResource(name); + final InputStream in = url.openStream(); + try { + return ClassFile.read(in); + } finally { + in.close(); + } + } + + private static final Attribute.Visitor typeAnnoMatcher = + new Attribute.Visitor() { + + @Override + public Void visitBootstrapMethods(BootstrapMethods_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitDefault(DefaultAttribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitAnnotationDefault(AnnotationDefault_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitCode(Code_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitCompilationID(CompilationID_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitConstantValue(ConstantValue_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitDeprecated(Deprecated_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitEnclosingMethod(EnclosingMethod_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitExceptions(Exceptions_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitInnerClasses(InnerClasses_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitLineNumberTable(LineNumberTable_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitLocalVariableTable(LocalVariableTable_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitMethodParameters(MethodParameters_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitSignature(Signature_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitSourceFile(SourceFile_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitSourceID(SourceID_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitStackMap(StackMap_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitStackMapTable(StackMapTable_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitSynthetic(Synthetic_attribute attr, + ExpectedTypeAnnotation expected) { + return null; + } + + @Override + public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, + ExpectedTypeAnnotation expected) { + if (expected.matchVisibility(true)) { + for(TypeAnnotation anno : attr.annotations) { + expected.matchAnnotation(anno); + } + } + + return null; + } + + @Override + public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, + ExpectedTypeAnnotation expected) { + if (expected.matchVisibility(false)) { + for(TypeAnnotation anno : attr.annotations) { + expected.matchAnnotation(anno); + } + } + + return null; + } + }; + + private static Attribute.Visitor annoMatcher(ConstantPool cpool) { + return new Attribute.Visitor() { + + @Override + public Void visitBootstrapMethods(BootstrapMethods_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitDefault(DefaultAttribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitAnnotationDefault(AnnotationDefault_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitCode(Code_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitCompilationID(CompilationID_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitConstantValue(ConstantValue_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitDeprecated(Deprecated_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitEnclosingMethod(EnclosingMethod_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitExceptions(Exceptions_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitInnerClasses(InnerClasses_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitLineNumberTable(LineNumberTable_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitLocalVariableTable(LocalVariableTable_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitMethodParameters(MethodParameters_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitSignature(Signature_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitSourceFile(SourceFile_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitSourceID(SourceID_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitStackMap(StackMap_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitStackMapTable(StackMapTable_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitSynthetic(Synthetic_attribute attr, + ExpectedAnnotation expected) { + return null; + } + + @Override + public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, + ExpectedAnnotation expected) { + if (expected.matchVisibility(true)) { + for(Annotation anno : attr.annotations) { + expected.matchAnnotation(cpool, anno); + } + } + + return null; + } + + @Override + public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, + ExpectedAnnotation expected) { + if (expected.matchVisibility(false)) { + for(Annotation anno : attr.annotations) { + expected.matchAnnotation(cpool, anno); + } + } + + return null; + } + }; + } + + private static Attribute.Visitor paramMatcher(ConstantPool cpool) { + return new Attribute.Visitor() { + + @Override + public Void visitBootstrapMethods(BootstrapMethods_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitDefault(DefaultAttribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitAnnotationDefault(AnnotationDefault_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitCode(Code_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitCompilationID(CompilationID_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitConstantValue(ConstantValue_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitDeprecated(Deprecated_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitEnclosingMethod(EnclosingMethod_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitExceptions(Exceptions_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitInnerClasses(InnerClasses_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitLineNumberTable(LineNumberTable_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitLocalVariableTable(LocalVariableTable_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitMethodParameters(MethodParameters_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitSignature(Signature_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitSourceFile(SourceFile_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitSourceID(SourceID_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitStackMap(StackMap_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitStackMapTable(StackMapTable_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitSynthetic(Synthetic_attribute attr, + ExpectedParameterAnnotation expected) { + return null; + } + + @Override + public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, + ExpectedParameterAnnotation expected) { + if (expected.matchVisibility(true)) { + if (expected.index < attr.parameter_annotations.length) { + for(Annotation anno : + attr.parameter_annotations[expected.index]) { + expected.matchAnnotation(cpool, anno); + } + } + } + + return null; + } + + @Override + public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, + ExpectedParameterAnnotation expected) { + if (expected.matchVisibility(false)) { + if (expected.index < attr.parameter_annotations.length) { + for(Annotation anno : + attr.parameter_annotations[expected.index]) { + expected.matchAnnotation(cpool, anno); + } + } + } + + return null; + } + }; + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/4980495/std/NonStatic2StaticImportClash.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/4980495/std/NonStatic2StaticImportClash.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,14 @@ +/* + * @test /nodynamiccopyright/ + * @bug 7101822 + * @summary Check the when clashing types are imported through an ordinary and static import, + * the compile-time error is properly reported. + * @compile/fail/ref=NonStatic2StaticImportClash.out -XDrawDiagnostics NonStatic2StaticImportClash.java p1/A1.java p2/A2.java + * + */ + +import p1.A1.f; +import static p2.A2.f; + +public class NonStatic2StaticImportClash { +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/4980495/std/NonStatic2StaticImportClash.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/4980495/std/NonStatic2StaticImportClash.out Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,2 @@ +NonStatic2StaticImportClash.java:11:1: compiler.err.already.defined.static.single.import: p1.A1.f +1 error diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/4980495/std/Static2NonStaticImportClash.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/4980495/std/Static2NonStaticImportClash.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,14 @@ +/* + * @test /nodynamiccopyright/ + * @bug 7101822 + * @summary Check the when clashing types are imported through an ordinary and static import, + * the compile-time error is properly reported. + * @compile/fail/ref=Static2NonStaticImportClash.out -XDrawDiagnostics Static2NonStaticImportClash.java p1/A1.java p2/A2.java + * + */ + +import static p2.A2.f; +import p1.A1.f; + +public class Static2NonStaticImportClash { +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/4980495/std/Static2NonStaticImportClash.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/4980495/std/Static2NonStaticImportClash.out Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,2 @@ +Static2NonStaticImportClash.java:11:1: compiler.err.already.defined.single.import: p2.A2.f +1 error diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/4980495/std/Test.out --- a/langtools/test/tools/javac/4980495/std/Test.out Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/4980495/std/Test.out Thu Dec 04 15:22:53 2014 -0800 @@ -1,2 +1,3 @@ Test.java:11:1: compiler.err.already.defined.single.import: p1.A1.f -1 error +Test.java:16:13: compiler.err.ref.ambiguous: f, kindname.class, p1.A1.f, p1.A1, kindname.class, p2.A2.f, p2.A2 +2 errors diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/8062359/UnresolvableClassNPEInAttrTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/8062359/UnresolvableClassNPEInAttrTest.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,17 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8062359 + * @summary NullPointerException in Attr when type-annotating an anonymous + * inner class in an unresolvable class + * @compile/fail/ref=UnresolvableClassNPEInAttrTest.out -XDrawDiagnostics UnresolvableClassNPEInAttrTest.java + */ + +public class UnresolvableClassNPEInAttrTest { + public static void main(String[] args) { + new Undefined() { + void test() { + new Object() {}; + } + }; + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/8062359/UnresolvableClassNPEInAttrTest.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/8062359/UnresolvableClassNPEInAttrTest.out Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,2 @@ +UnresolvableClassNPEInAttrTest.java:11:13: compiler.err.cant.resolve.location: kindname.class, Undefined, , , (compiler.misc.location: kindname.class, UnresolvableClassNPEInAttrTest, null) +1 error diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/T6181889/EmptyFinallyTest.java --- a/langtools/test/tools/javac/T6181889/EmptyFinallyTest.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/T6181889/EmptyFinallyTest.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,8 +1,3 @@ - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.nio.file.Paths; - /* * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -32,6 +27,10 @@ * @summary Empty try/finally results in bytecodes being generated */ +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.file.Paths; + public class EmptyFinallyTest { private static final String assertionErrorMsg = "No \"Exception table\" should be generated in this case"; diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/T6725036.java --- a/langtools/test/tools/javac/T6725036.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/T6725036.java Thu Dec 04 15:22:53 2014 -0800 @@ -60,7 +60,7 @@ long jarEntryTime = je.getTime(); ZipFileIndexCache zfic = ZipFileIndexCache.getSharedInstance(); - ZipFileIndex zfi = zfic.getZipFileIndex(testJar, null, false, null, false); + ZipFileIndex zfi = zfic.getZipFileIndex(testJar.toPath(), null, false, null, false); long zfiTime = zfi.getLastModified(TEST_ENTRY_NAME); check(je, jarEntryTime, zfi + ":" + TEST_ENTRY_NAME.getPath(), zfiTime); @@ -85,7 +85,7 @@ try (JavaFileManager fm = comp.getStandardFileManager(null, null, null)) { File f = new File(name); ToolBox tb = new ToolBox(); - tb.new JarTask(f.getPath()) + tb.new JarTask(name) .files(fm, StandardLocation.PLATFORM_CLASS_PATH, paths) .run(); return f; diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/T8020997/CannotCompileRepeatedAnnoTest.java --- a/langtools/test/tools/javac/T8020997/CannotCompileRepeatedAnnoTest.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/T8020997/CannotCompileRepeatedAnnoTest.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,4 +1,3 @@ - /* * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/T8059921/ForbidAccessToFieldUsingSuperTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/T8059921/ForbidAccessToFieldUsingSuperTest.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,31 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8059921 + * @summary Missing compile error in Java 8 mode for Interface.super.field access + * @compile/fail/ref=ForbidAccessToFieldUsingSuperTest.out -XDrawDiagnostics ForbidAccessToFieldUsingSuperTest.java + */ + +public class ForbidAccessToFieldUsingSuperTest { + class C { + int m() { return 0; } + } + + interface T { + int f = 0; + C c = null; + default int mm() { + return 0; + } + } + + interface T1 extends T {} + + class X implements T1 { + int i = T1.super.f; //fail + int j = T1.super.c.m(); //fail + + void foo(Runnable r) { + foo(T1.super::mm); //should'n fail + } + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/T8059921/ForbidAccessToFieldUsingSuperTest.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/T8059921/ForbidAccessToFieldUsingSuperTest.out Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,3 @@ +ForbidAccessToFieldUsingSuperTest.java:24:19: compiler.err.not.encl.class: ForbidAccessToFieldUsingSuperTest.T1 +ForbidAccessToFieldUsingSuperTest.java:25:19: compiler.err.not.encl.class: ForbidAccessToFieldUsingSuperTest.T1 +2 errors diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/TryWithResources/BadTwrSyntax.out --- a/langtools/test/tools/javac/TryWithResources/BadTwrSyntax.out Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/TryWithResources/BadTwrSyntax.out Thu Dec 04 15:22:53 2014 -0800 @@ -1,2 +1,2 @@ -BadTwrSyntax.java:14:43: compiler.err.illegal.start.of.type +BadTwrSyntax.java:14:43: compiler.err.illegal.start.of.expr 1 error diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/TryWithResources/ResDeclOutsideTry.java --- a/langtools/test/tools/javac/TryWithResources/ResDeclOutsideTry.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/TryWithResources/ResDeclOutsideTry.java Thu Dec 04 15:22:53 2014 -0800 @@ -13,6 +13,11 @@ String test1() { try (tr1 = new ResDeclOutsideTry(); tr2;) { } + return null; + } + + @Override + public void close() throws Exception { } } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/TryWithResources/ResDeclOutsideTry.out --- a/langtools/test/tools/javac/TryWithResources/ResDeclOutsideTry.out Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/TryWithResources/ResDeclOutsideTry.out Thu Dec 04 15:22:53 2014 -0800 @@ -1,3 +1,2 @@ -ResDeclOutsideTry.java:14:17: compiler.err.expected: token.identifier -ResDeclOutsideTry.java:14:48: compiler.err.expected: token.identifier -2 errors +ResDeclOutsideTry.java:14:18: compiler.err.try.with.resources.expr.needs.var +1 error diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/TryWithResources/TwrForVariable1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/TryWithResources/TwrForVariable1.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,69 @@ +/* @test /nodynamiccopyright/ + * @bug 7196163 + * @summary Verify that variables can be used as operands to try-with-resources + * @compile/fail/ref=TwrForVariable1.out -source 8 -XDrawDiagnostics -Xlint:-options TwrForVariable1.java + * @compile TwrForVariable1.java + * @run main TwrForVariable1 + */ +public class TwrForVariable1 implements AutoCloseable { + private static int closeCount = 0; + public static void main(String... args) { + TwrForVariable1 v = new TwrForVariable1(); + + try (v) { + assertCloseCount(0); + } + try (/**@deprecated*/v) { + assertCloseCount(1); + } + try (v.finalWrapper.finalField) { + assertCloseCount(2); + } catch (Exception ex) { + } + try (new TwrForVariable1() { }.finalWrapper.finalField) { + assertCloseCount(3); + } catch (Exception ex) { + } + try ((args.length > 0 ? v : new TwrForVariable1()).finalWrapper.finalField) { + assertCloseCount(4); + } catch (Exception ex) { + } + try { + throw new CloseableException(); + } catch (CloseableException ex) { + try (ex) { + assertCloseCount(5); + } + } + + assertCloseCount(6); + } + + static void assertCloseCount(int expectedCloseCount) { + if (closeCount != expectedCloseCount) + throw new RuntimeException("bad closeCount: " + closeCount + + "; expected: " + expectedCloseCount); + } + + public void close() { + closeCount++; + } + + final FinalWrapper finalWrapper = new FinalWrapper(); + + static class FinalWrapper { + public final AutoCloseable finalField = new AutoCloseable() { + @Override + public void close() throws Exception { + closeCount++; + } + }; + } + + static class CloseableException extends Exception implements AutoCloseable { + @Override + public void close() { + closeCount++; + } + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/TryWithResources/TwrForVariable1.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/TryWithResources/TwrForVariable1.out Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,2 @@ +TwrForVariable1.java:13:14: compiler.err.var.in.try.with.resources.not.supported.in.source: 1.8 +1 error diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/TryWithResources/TwrForVariable2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/TryWithResources/TwrForVariable2.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,39 @@ +/* @test /nodynamiccopyright/ + * @bug 7196163 + * @summary Verify that an improper combination of modifiers and variable is rejected + * in an operand to try-with-resources + * @compile/fail/ref=TwrForVariable2.out -XDrawDiagnostics -Xlint:-options TwrForVariable2.java + */ +public class TwrForVariable2 implements AutoCloseable { + public static void main(String... args) { + TwrForVariable2 v = new TwrForVariable2(); + TwrForVariable3[] v2 = new TwrForVariable3[1]; + + try (final v) { + fail("no modifiers before variables"); + } + try (@Deprecated v) { + fail("no annotations before variables"); + } + try (v;;) { + fail("illegal double semicolon"); + } + try ((v)) { + fail("parentheses not allowed"); + } + try (v2[0]) { + fail("array access not allowed"); + } + try (args.length == 0 ? v : v) { + fail("general expressions not allowed"); + } + } + + static void fail(String reason) { + throw new RuntimeException(reason); + } + + public void close() { + } + +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/TryWithResources/TwrForVariable2.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/TryWithResources/TwrForVariable2.out Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,7 @@ +TwrForVariable2.java:12:21: compiler.err.expected: token.identifier +TwrForVariable2.java:15:27: compiler.err.expected: token.identifier +TwrForVariable2.java:18:16: compiler.err.illegal.start.of.expr +TwrForVariable2.java:21:14: compiler.err.try.with.resources.expr.needs.var +TwrForVariable2.java:24:16: compiler.err.try.with.resources.expr.needs.var +TwrForVariable2.java:27:31: compiler.err.try.with.resources.expr.needs.var +6 errors diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/TryWithResources/TwrForVariable3.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/TryWithResources/TwrForVariable3.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,29 @@ +/* @test /nodynamiccopyright/ + * @bug 7196163 + * @summary Verify that improper expressions used as an operand to try-with-resources are rejected. + * @compile/fail/ref=TwrForVariable3.out -XDrawDiagnostics -Xlint:-options TwrForVariable3.java + */ +public class TwrForVariable3 implements AutoCloseable { + public static void main(String... args) { + TwrForVariable3 v1 = new TwrForVariable3(); + Object v2 = new Object(); + + try (v2) { + fail("no an AutoCloseable"); + } + try (java.lang.Object) { + fail("not a variable access"); + } + try (java.lang) { + fail("not a variable access"); + } + } + + static void fail(String reason) { + throw new RuntimeException(reason); + } + + public void close() { + } + +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/TryWithResources/TwrForVariable3.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/TryWithResources/TwrForVariable3.out Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,4 @@ +TwrForVariable3.java:11:14: compiler.err.prob.found.req: (compiler.misc.try.not.applicable.to.type: (compiler.misc.inconvertible.types: java.lang.Object, java.lang.AutoCloseable)) +TwrForVariable3.java:14:18: compiler.err.cant.resolve.location: kindname.class, lang, , , (compiler.misc.location: kindname.package, java, null) +TwrForVariable3.java:17:14: compiler.err.cant.resolve.location: kindname.variable, java, , , (compiler.misc.location: kindname.class, TwrForVariable3, null) +3 errors diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/TryWithResources/TwrForVariable4.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/TryWithResources/TwrForVariable4.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,45 @@ +/* @test /nodynamiccopyright/ + * @bug 7196163 + * @summary Verify that variable used as an operand to try-with-resources is rejected if it is not + * definitelly assigned before use and or not final or effectivelly final. + * @compile/fail/ref=TwrForVariable4.out -XDrawDiagnostics -Xlint:-options TwrForVariable4.java + */ +public class TwrForVariable4 implements AutoCloseable { + public static void main(String... args) { + TwrForVariable4 uninitialized; + + try (uninitialized) { + fail("must be initialized before use"); + } + uninitialized = new TwrForVariable4(); + + TwrForVariable4 notEffectivellyFinal1 = new TwrForVariable4(); + + notEffectivellyFinal1 = new TwrForVariable4(); + + try (notEffectivellyFinal1) { + fail("not effectivelly final"); + } + + TwrForVariable4 notEffectivellyFinal2 = new TwrForVariable4(); + + try (notEffectivellyFinal2) { + notEffectivellyFinal2 = new TwrForVariable4(); + fail("not effectivelly final"); + } + + try (notFinal) { + fail("not final"); + } + } + + static TwrForVariable4 notFinal = new TwrForVariable4(); + + static void fail(String reason) { + throw new RuntimeException(reason); + } + + public void close() { + } + +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/TryWithResources/TwrForVariable4.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/TryWithResources/TwrForVariable4.out Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,5 @@ +TwrForVariable4.java:11:14: compiler.err.var.might.not.have.been.initialized: uninitialized +TwrForVariable4.java:20:14: compiler.err.try.with.resources.expr.effectively.final.var: notEffectivellyFinal1 +TwrForVariable4.java:26:14: compiler.err.try.with.resources.expr.effectively.final.var: notEffectivellyFinal2 +TwrForVariable4.java:31:14: compiler.err.try.with.resources.expr.effectively.final.var: notFinal +4 errors diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/VersionOpt.java --- a/langtools/test/tools/javac/VersionOpt.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/VersionOpt.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,4 +1,3 @@ - /* * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/annotations/SyntheticParameters.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/annotations/SyntheticParameters.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test SyntheticParameters + * @bug 8065132 + * @summary Test generation of annotations on inner class parameters. + * @library /lib/annotations/ + * @run main SyntheticParameters + */ + +import annotations.classfile.ClassfileInspector; + +import java.io.*; +import java.lang.annotation.*; + +import com.sun.tools.classfile.*; + +public class SyntheticParameters extends ClassfileInspector { + + private static final String Inner_class = "SyntheticParameters$Inner.class"; + private static final String Foo_class = "SyntheticParameters$Foo.class"; + private static final Expected Inner_expected = + new Expected("SyntheticParameters$Inner", + null, + null, + new ExpectedParameterAnnotation[] { + (ExpectedParameterAnnotation) + // Assert there is no annotation on the + // this$0 parameter. + new ExpectedParameterAnnotation( + "", + 0, + "A", + true, + 0), + (ExpectedParameterAnnotation) + // Assert there is an annotation on the + // first parameter. + new ExpectedParameterAnnotation( + "", + 1, + "A", + true, + 1), + (ExpectedParameterAnnotation) + new ExpectedParameterAnnotation( + "foo", + 0, + "A", + true, + 1), + (ExpectedParameterAnnotation) + new ExpectedParameterAnnotation( + "foo", + 1, + "A", + true, + 0), + (ExpectedParameterAnnotation) + // Assert there is no annotation on the + // this$0 parameter. + new ExpectedParameterAnnotation( + "", + 0, + "B", + false, + 0), + (ExpectedParameterAnnotation) + // Assert there is an annotation on the + // first parameter. + new ExpectedParameterAnnotation( + "", + 1, + "B", + false, + 1), + (ExpectedParameterAnnotation) + new ExpectedParameterAnnotation( + "foo", + 0, + "B", + false, + 1), + (ExpectedParameterAnnotation) + new ExpectedParameterAnnotation( + "foo", + 1, + "B", + false, + 0) + }, + null); + private static final Expected Foo_expected = + new Expected("SyntheticParameters$Foo", + null, + null, + new ExpectedParameterAnnotation[] { + (ExpectedParameterAnnotation) + // Assert there is no annotation on the + // $enum$name parameter. + new ExpectedParameterAnnotation( + "", + 0, + "A", + true, + 0), + (ExpectedParameterAnnotation) + // Assert there is no annotation on the + // $enum$ordinal parameter. + new ExpectedParameterAnnotation( + "", + 1, + "A", + true, + 0), + (ExpectedParameterAnnotation) + // Assert there is an annotation on the + // first parameter. + new ExpectedParameterAnnotation( + "", + 2, + "A", + true, + 1), + (ExpectedParameterAnnotation) + // Assert there is no annotation on the + // $enum$name parameter. + new ExpectedParameterAnnotation( + "", + 0, + "B", + false, + 0), + (ExpectedParameterAnnotation) + // Assert there is no annotation on the + // $enum$ordinal parameter. + new ExpectedParameterAnnotation( + "", + 1, + "B", + false, + 0), + (ExpectedParameterAnnotation) + // Assert there is an annotation on the + // first parameter. + new ExpectedParameterAnnotation( + "", + 2, + "B", + false, + 1) + }, + null); + + public static void main(String... args) throws Exception { + new SyntheticParameters().run( + new ClassFile[] { getClassFile(Inner_class, Inner.class), + getClassFile(Foo_class, Foo.class) }, + new Expected[] { Inner_expected, Foo_expected }); + } + + public class Inner { + public Inner(@A @B int a) {} + public void foo(@A @B int a, int b) {} + } + + public static enum Foo { + ONE(null); + Foo(@A @B Object a) {} + } +} + +@Retention(RetentionPolicy.RUNTIME) +@interface A {} + +@Retention(RetentionPolicy.CLASS) +@interface B {} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/annotations/typeAnnotations/InnerClass.java --- a/langtools/test/tools/javac/annotations/typeAnnotations/InnerClass.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/annotations/typeAnnotations/InnerClass.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,5 +1,3 @@ -import java.lang.annotation.ElementType; - /* * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/annotations/typeAnnotations/classfile/ClassfileInspector.java --- a/langtools/test/tools/javac/annotations/typeAnnotations/classfile/ClassfileInspector.java Thu Dec 04 12:58:21 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,950 +0,0 @@ -/* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.lang.annotation.*; -import java.io.*; -import java.net.URL; -import java.util.List; - -import com.sun.tools.classfile.*; - -/** - * A class providing utilities for writing tests that inspect class - * files directly, looking for specific type annotations. - * - * Note: this framework does not currently handle repeating - * annotations. - */ -public class ClassfileInspector { - - /** - * A group of expected annotations to be found in a given class. - * If the class name is null, then the template will be applied to - * every class. - */ - public static class Expected { - /** - * The name of the class. If {@code null} this template will - * apply to every class; otherwise, it will only be applied to - * the named class. - */ - public final String classname; - - /** - * The expected class annotations. These will be checked - * against the class' attributes. - */ - public final ExpectedTypeAnnotation[] classAnnos; - - /** - * The expected method annotations. These will be checked - * against all methods in the class. - */ - public final ExpectedMethodTypeAnnotation[] methodAnnos; - - /** - * The expected field annotations. These will be checked - * against all fields in the class. - */ - public final ExpectedFieldTypeAnnotation[] fieldAnnos; - - /** - * Create an {@code Expected} from its components. - * - * @param classname The name of the class to match, or {@code - * null} for all classes. - * @param classAnnos The expected class annotations. - * @param methodAnnos The expected method annotations. - * @param fieldAnnos The expected field annotations. - */ - public Expected(String classname, - ExpectedTypeAnnotation[] classAnnos, - ExpectedMethodTypeAnnotation[] methodAnnos, - ExpectedFieldTypeAnnotation[] fieldAnnos) { - this.classname = classname; - this.classAnnos = classAnnos; - this.methodAnnos = methodAnnos; - this.fieldAnnos = fieldAnnos; - } - - public String toString() { - final StringBuilder sb = new StringBuilder(); - final String newline = System.lineSeparator(); - sb.append("Expected on class ").append(classname); - if (null != classAnnos) { - sb.append(newline).append("Class annotations:").append(newline); - for(ExpectedTypeAnnotation anno : classAnnos) { - sb.append(anno).append(newline); - } - } - if (null != methodAnnos) { - sb.append(newline).append("Method annotations:").append(newline); - for(ExpectedTypeAnnotation anno : methodAnnos) { - sb.append(anno).append(newline); - } - } - if (null != fieldAnnos) { - sb.append(newline).append("Field annotations:").append(newline); - for(ExpectedTypeAnnotation anno : fieldAnnos) { - sb.append(anno).append(newline); - } - } - return sb.toString(); - } - - /** - * See if this template applies to a class. - * - * @param classname The classname to check. - * @return Whether or not this template should apply. - */ - public boolean matchClassName(String classname) { - return this.classname == null || this.classname.equals(classname); - } - - /** - * After applying the template to all classes, check to see if - * any of the expected annotations weren't matched. - * - * @return The number of missed matches. - */ - public int check() { - int count = 0; - if (classAnnos != null) { - for(ExpectedTypeAnnotation expected : classAnnos) { - if (!expected.check()) { - count++; - } - } - } - if (methodAnnos != null) { - for(ExpectedMethodTypeAnnotation expected : methodAnnos) { - if (!expected.check()) { - count++; - } - } - } - if (fieldAnnos != null) { - for(ExpectedFieldTypeAnnotation expected : fieldAnnos) { - if (!expected.check()) { - count++; - } - } - } - return count; - } - } - - /** - * An expected type annotation. This is both a superclass for - * method and field type annotations, as well as a class for type - * annotations on a class. - */ - public static class ExpectedTypeAnnotation { - private int count = 0; - protected final String expectedName; - protected final int expectedCount; - protected final TypeAnnotation.TargetType targetType; - protected final int bound_index; - protected final int parameter_index; - protected final int type_index; - protected final int exception_index; - protected final TypeAnnotation.Position.TypePathEntry[] typePath; - protected final boolean visibility; - - /** - * Create an {@code ExpectedTypeAnnotation} from its - * components. It is usually a better idea to use a {@code - * Builder} to do this. - * - * @param expectedName The expected annotation name. - * @param visibility Whether this annotation should be runtime-visible. - * @param expectedCount The number of annotations that should - * be seen. If 0, this asserts that the - * described annotation is not present. - * @param targetType The expected target type. - * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}. - * @param parameter_index The expected parameter index, or - * {@code Integer.MIN_VALUE}. - * @param type_index The expected type index, or {@code Integer.MIN_VALUE}. - * @param exception_index The expected exception index, or - * {@code Integer.MIN_VALUE}. - * @param typePath The expected type path. - */ - public ExpectedTypeAnnotation(String expectedName, - boolean visibility, - int expectedCount, - TypeAnnotation.TargetType targetType, - int bound_index, - int parameter_index, - int type_index, - int exception_index, - TypeAnnotation.Position.TypePathEntry... typePath) { - this.expectedName = expectedName; - this.visibility = visibility; - this.expectedCount = expectedCount; - this.targetType = targetType; - this.bound_index = bound_index; - this.parameter_index = parameter_index; - this.type_index = type_index; - this.exception_index = exception_index; - this.typePath = typePath; - } - - public String toString() { - final StringBuilder sb = new StringBuilder(); - sb.append("Expected "); - sb.append(expectedCount); - sb.append(" annotation "); - sb.append(expectedName); - sb.append(visibility ? ", runtime visibile " : ", runtime invisibile "); - sb.append(targetType); - sb.append(", bound_index = "); - sb.append(bound_index); - sb.append(", parameter_index = "); - sb.append(parameter_index); - sb.append(", type_index = "); - sb.append(type_index); - sb.append(", exception_index = "); - sb.append(exception_index); - sb.append(", type_path = ["); - for(int i = 0; i < typePath.length; i++) { - if (i != 0) { - sb.append(", "); - } - sb.append(typePath[i]); - } - sb.append("]"); - return sb.toString(); - } - - /** - * See if this template matches the given visibility. - * - * @param Whether or not the annotation is visible at runtime. - * @return Whether or not this template matches the visibility. - */ - public boolean matchVisibility(boolean visibility) { - return this.visibility == visibility; - } - - /** - * Attempty to match this template against an annotation. If - * it does match, then the match count for the template will - * be incremented. Otherwise, nothing will be done. - * - * @param anno The annotation to attempt to match. - */ - public void matchAnnotation(TypeAnnotation anno) { - boolean matches = true; - - try { - matches = anno.constant_pool.getUTF8Info(anno.annotation.type_index).value.equals("L" + expectedName + ";"); - } catch(Exception e) { - matches = false; - } - - matches = matches && anno.position.type == targetType; - matches = matches && anno.position.bound_index == bound_index; - matches = matches && anno.position.parameter_index == parameter_index; - matches = matches && anno.position.type_index == type_index; - matches = matches && anno.position.exception_index == exception_index; - matches = matches && anno.position.location.size() == typePath.length; - - if (matches) { - int i = 0; - for(TypeAnnotation.Position.TypePathEntry entry : - anno.position.location) { - matches = matches && typePath[i++].equals(entry); - } - } - - if (matches) { - count++; - } - } - - /** - * After all matching, check to see if the expected number of - * matches equals the actual number. If not, then print a - * failure message and return {@code false}. - * - * @return Whether or not the expected number of matched - * equals the actual number. - */ - public boolean check() { - if (count != expectedCount) { - System.err.println(this + ", but saw " + count); - return false; - } else { - return true; - } - } - - /** - * A builder class for creating {@code - * ExpectedTypeAnnotation}s in a more convenient fashion. The - * constructor for {@code ExpectedTypeAnnotation} takes a - * large number of parameters (by necessity). This class - * allows users to construct a {@code ExpectedTypeAnnotation}s - * using only the ones they need. - */ - public static class Builder { - protected final String expectedName; - protected final int expectedCount; - protected final TypeAnnotation.TargetType targetType; - protected final boolean visibility; - protected int bound_index = Integer.MIN_VALUE; - protected int parameter_index = Integer.MIN_VALUE; - protected int type_index = Integer.MIN_VALUE; - protected int exception_index = Integer.MIN_VALUE; - protected TypeAnnotation.Position.TypePathEntry[] typePath = - new TypeAnnotation.Position.TypePathEntry[0]; - - /** - * Create a {@code Builder} from the mandatory parameters. - * - * @param expectedName The expected annotation name. - * @param targetType The expected target type. - * @param visibility Whether this annotation should be runtime-visible. - * @param expectedCount The number of annotations that should be seen. - */ - public Builder(String expectedName, - TypeAnnotation.TargetType targetType, - boolean visibility, - int expectedCount) { - this.expectedName = expectedName; - this.visibility = visibility; - this.expectedCount = expectedCount; - this.targetType = targetType; - } - - /** - * Create an {@code ExpectedTypeAnnotation} from all - * parameters that have been provided. The default values - * will be used for those that have not. - * - * @return The cretaed {@code ExpectedTypeAnnotation}. - */ - public ExpectedTypeAnnotation build() { - return new ExpectedTypeAnnotation(expectedName, visibility, - expectedCount, targetType, - bound_index, parameter_index, - type_index, exception_index, - typePath); - } - - /** - * Provide a bound index parameter. - * - * @param bound_index The bound_index value. - */ - public Builder setBoundIndex(int bound_index) { - this.bound_index = bound_index; - return this; - } - - /** - * Provide a parameter index parameter. - * - * @param bound_index The parameter_index value. - */ - public Builder setParameterIndex(int parameter_index) { - this.parameter_index = parameter_index; - return this; - } - - /** - * Provide a type index parameter. - * - * @param type_index The type_index value. - */ - public Builder setTypeIndex(int type_index) { - this.type_index = type_index; - return this; - } - - /** - * Provide an exception index parameter. - * - * @param exception_index The exception_index value. - */ - public Builder setExceptionIndex(int exception_index) { - this.exception_index = exception_index; - return this; - } - - /** - * Provide a type path parameter. - * - * @param typePath The type path value. - */ - public Builder setTypePath(TypeAnnotation.Position.TypePathEntry[] typePath) { - this.typePath = typePath; - return this; - } - } - } - - /** - * A type annotation found on a method. - */ - public static class ExpectedMethodTypeAnnotation extends ExpectedTypeAnnotation { - private final String methodname; - - /** - * Create an {@code ExpectedMethodTypeAnnotation} from its - * components. It is usually a better idea to use a {@code - * Builder} to do this. - * - * @param methodname The expected method name. - * @param expectedName The expected annotation name. - * @param visibility Whether this annotation should be runtime-visible. - * @param expectedCount The number of annotations that should be seen. - * @param targetType The expected target type. - * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}. - * @param parameter_index The expected parameter index, or - * {@code Integer.MIN_VALUE}. - * @param type_index The expected type index, or {@code Integer.MIN_VALUE}. - * @param exception_index The expected exception index, or - * {@code Integer.MIN_VALUE}. - * @param typePath The expected type path. - */ - public ExpectedMethodTypeAnnotation(String methodname, - String expectedName, - boolean visibility, - int expectedCount, - TypeAnnotation.TargetType targetType, - int bound_index, - int parameter_index, - int type_index, - int exception_index, - TypeAnnotation.Position.TypePathEntry... typePath) { - super(expectedName, visibility, expectedCount, targetType, bound_index, - parameter_index, type_index, exception_index, typePath); - this.methodname = methodname; - } - - public String toString() { - final StringBuilder sb = new StringBuilder(); - sb.append("Expected "); - sb.append(expectedCount); - sb.append(" annotation "); - sb.append(expectedName); - sb.append(visibility ? ", runtime visibile " : ", runtime invisibile "); - sb.append(targetType); - sb.append(", bound_index = "); - sb.append(bound_index); - sb.append(", parameter_index = "); - sb.append(parameter_index); - sb.append(", type_index = "); - sb.append(type_index); - sb.append(", exception_index = "); - sb.append(exception_index); - sb.append(", type_path = ["); - for(int i = 0; i < typePath.length; i++) { - if (i != 0) { - sb.append(", "); - } - sb.append(typePath[i]); - } - sb.append("]"); - sb.append(" on method "); - sb.append(methodname); - return sb.toString(); - } - - /** - * See if this template applies to a method. - * - * @param methodname The method name to check. - * @return Whether or not this template should apply. - */ - public boolean matchMethodName(String methodname) { - return this.methodname.equals(methodname); - } - - /** - * A builder class for creating {@code - * ExpectedMethodTypeAnnotation}s in a more convenient fashion. The - * constructor for {@code ExpectedMethodTypeAnnotation} takes a - * large number of parameters (by necessity). This class - * allows users to construct a {@code ExpectedMethodTypeAnnotation}s - * using only the ones they need. - */ - public static class Builder extends ExpectedTypeAnnotation.Builder { - protected final String methodname; - - /** - * Create a {@code Builder} from the mandatory parameters. - * - * @param methodname The expected method name. - * @param expectedName The expected annotation name. - * @param targetType The expected target type. - * @param visibility Whether this annotation should be runtime-visible. - * @param expectedCount The number of annotations that should be seen. - */ - public Builder(String methodname, - String expectedName, - TypeAnnotation.TargetType targetType, - boolean visibility, - int expectedCount) { - super(expectedName, targetType, visibility, expectedCount); - this.methodname = methodname; - } - - /** - * Create an {@code ExpectedMethodTypeAnnotation} from all - * parameters that have been provided. The default values - * will be used for those that have not. - * - * @return The cretaed {@code ExpectedMethodTypeAnnotation}. - */ - public ExpectedMethodTypeAnnotation build() { - return new ExpectedMethodTypeAnnotation(methodname, expectedName, - visibility, expectedCount, - targetType, bound_index, - parameter_index, type_index, - exception_index, typePath); - } - } - } - - /** - * A type annotation found on a field. - */ - public static class ExpectedFieldTypeAnnotation extends ExpectedTypeAnnotation { - private final String fieldname; - - /** - * Create an {@code ExpectedFieldTypeAnnotation} from its - * components. It is usually a better idea to use a {@code - * Builder} to do this. - * - * @param fieldname The expected field name. - * @param expectedName The expected annotation name. - * @param visibility Whether this annotation should be runtime-visible. - * @param expectedCount The number of annotations that should be seen. - * @param targetType The expected target type. - * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}. - * @param parameter_index The expected parameter index, or - * {@code Integer.MIN_VALUE}. - * @param type_index The expected type index, or {@code Integer.MIN_VALUE}. - * @param exception_index The expected exception index, or - * {@code Integer.MIN_VALUE}. - * @param typePath The expected type path. - */ - public ExpectedFieldTypeAnnotation(String fieldname, - String expectedName, - boolean visibility, - int expectedCount, - TypeAnnotation.TargetType targetType, - int bound_index, - int parameter_index, - int type_index, - int exception_index, - TypeAnnotation.Position.TypePathEntry... typePath) { - super(expectedName, visibility, expectedCount, targetType, bound_index, - parameter_index, type_index, exception_index, typePath); - this.fieldname = fieldname; - } - - public String toString() { - final StringBuilder sb = new StringBuilder(); - sb.append("Expected ").append(expectedCount) - .append(" annotation ").append(expectedName) - .append(visibility ? ", runtime visibile " : ", runtime invisibile ") - .append(targetType) - .append(", bound_index = ").append(bound_index) - .append(", parameter_index = ").append(parameter_index) - .append(", type_index = ").append(type_index) - .append(", exception_index = ").append(exception_index) - .append(", type_path = ["); - - for(int i = 0; i < typePath.length; i++) { - if (i != 0) { - sb.append(", "); - } - sb.append(typePath[i]); - } - sb.append("]") - .append(" on field ").append(fieldname); - return sb.toString(); - } - - /** - * See if this template applies to a field. - * - * @param fieldname The field name to check. - * @return Whether or not this template should apply. - */ - public boolean matchFieldName(String fieldname) { - return this.fieldname.equals(fieldname); - } - - /** - * A builder class for creating {@code - * ExpectedFieldTypeAnnotation}s in a more convenient fashion. The - * constructor for {@code ExpectedFieldTypeAnnotation} takes a - * large number of parameters (by necessity). This class - * allows users to construct a {@code ExpectedFieldTypeAnnotation}s - * using only the ones they need. - */ - public static class Builder extends ExpectedTypeAnnotation.Builder { - protected final String fieldname; - - /** - * Create a {@code Builder} from the mandatory parameters. - * - * @param fieldname The expected field name. - * @param expectedName The expected annotation name. - * @param targetType The expected target type. - * @param visibility Whether this annotation should be runtime-visible. - * @param expectedCount The number of annotations that should be seen. - */ - public Builder(String fieldname, - String expectedName, - TypeAnnotation.TargetType targetType, - boolean visibility, - int expectedCount) { - super(expectedName, targetType, visibility, expectedCount); - this.fieldname = fieldname; - } - - /** - * Create an {@code ExpectedFieldTypeAnnotation} from all - * parameters that have been provided. The default values - * will be used for those that have not. - * - * @return The cretaed {@code ExpectedFieldTypeAnnotation}. - */ - public ExpectedFieldTypeAnnotation build() { - return new ExpectedFieldTypeAnnotation(fieldname, expectedName, - visibility, expectedCount, - targetType, bound_index, - parameter_index, type_index, - exception_index, typePath); - } - } - } - - private void matchClassTypeAnnotation(ClassFile classfile, - ExpectedTypeAnnotation expected) - throws ConstantPoolException { - for(Attribute attr : classfile.attributes) { - attr.accept(typeAnnoMatcher, expected); - } - } - - private void matchMethodTypeAnnotation(ClassFile classfile, - ExpectedMethodTypeAnnotation expected) - throws ConstantPoolException { - for(Method meth : classfile.methods) { - if (expected.matchMethodName(meth.getName(classfile.constant_pool))) { - for(Attribute attr : meth.attributes) { - attr.accept(typeAnnoMatcher, expected); - } - } - } - } - - private void matchFieldTypeAnnotation(ClassFile classfile, - ExpectedFieldTypeAnnotation expected) - throws ConstantPoolException { - for(Field field : classfile.fields) { - if (expected.matchFieldName(field.getName(classfile.constant_pool))) { - for(Attribute attr : field.attributes) { - attr.accept(typeAnnoMatcher, expected); - } - } - } - } - - private void matchClassTypeAnnotations(ClassFile classfile, - ExpectedTypeAnnotation[] expected) - throws ConstantPoolException { - for(ExpectedTypeAnnotation one : expected) { - matchClassTypeAnnotation(classfile, one); - } - } - - private void matchMethodTypeAnnotations(ClassFile classfile, - ExpectedMethodTypeAnnotation[] expected) - throws ConstantPoolException { - for(ExpectedMethodTypeAnnotation one : expected) { - matchMethodTypeAnnotation(classfile, one); - } - } - - private void matchFieldTypeAnnotations(ClassFile classfile, - ExpectedFieldTypeAnnotation[] expected) - throws ConstantPoolException { - for(ExpectedFieldTypeAnnotation one : expected) { - matchFieldTypeAnnotation(classfile, one); - } - } - - /** - * Run a template on a single {@code ClassFile}. - * - * @param classfile The {@code ClassFile} on which to run tests. - * @param expected The expected annotation template. - */ - public void run(ClassFile classfile, - Expected... expected) - throws ConstantPoolException { - run(new ClassFile[] { classfile }, expected); - } - - /** - * Run a template on multiple {@code ClassFile}s. - * - * @param classfile The {@code ClassFile}s on which to run tests. - * @param expected The expected annotation template. - */ - public void run(ClassFile[] classfiles, - Expected... expected) - throws ConstantPoolException { - for(ClassFile classfile : classfiles) { - for(Expected one : expected) { - if (one.matchClassName(classfile.getName())) { - if (one.classAnnos != null) - matchClassTypeAnnotations(classfile, one.classAnnos); - if (one.methodAnnos != null) - matchMethodTypeAnnotations(classfile, one.methodAnnos); - if (one.fieldAnnos != null) - matchFieldTypeAnnotations(classfile, one.fieldAnnos); - } - } - } - int count = 0; - for (Expected one : expected) { - count += one.check(); - } - - if (count != 0) { - throw new RuntimeException(count + " errors occurred in test"); - } - } - - /** - * Get a {@code ClassFile} from its file name. - * - * @param name The class' file name. - * @return The {@code ClassFile} - */ - public static ClassFile getClassFile(String name) - throws IOException, ConstantPoolException { - final URL url = ClassfileInspector.class.getResource(name); - final InputStream in = url.openStream(); - try { - return ClassFile.read(in); - } finally { - in.close(); - } - } - - private static final Attribute.Visitor typeAnnoMatcher = - new Attribute.Visitor() { - - @Override - public Void visitBootstrapMethods(BootstrapMethods_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitDefault(DefaultAttribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitAnnotationDefault(AnnotationDefault_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitCode(Code_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitCompilationID(CompilationID_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitConstantValue(ConstantValue_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitDeprecated(Deprecated_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitEnclosingMethod(EnclosingMethod_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitExceptions(Exceptions_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitInnerClasses(InnerClasses_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitLineNumberTable(LineNumberTable_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitLocalVariableTable(LocalVariableTable_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitMethodParameters(MethodParameters_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitSignature(Signature_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitSourceFile(SourceFile_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitSourceID(SourceID_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitStackMap(StackMap_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitStackMapTable(StackMapTable_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitSynthetic(Synthetic_attribute attr, - ExpectedTypeAnnotation expected) { - return null; - } - - @Override - public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, - ExpectedTypeAnnotation expected) { - if (expected.matchVisibility(true)) { - for(TypeAnnotation anno : attr.annotations) { - expected.matchAnnotation(anno); - } - } - - return null; - } - - @Override - public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, - ExpectedTypeAnnotation expected) { - if (expected.matchVisibility(false)) { - for(TypeAnnotation anno : attr.annotations) { - expected.matchAnnotation(anno); - } - } - - return null; - } - }; -} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/annotations/typeAnnotations/classfile/SyntheticParameters.java --- a/langtools/test/tools/javac/annotations/typeAnnotations/classfile/SyntheticParameters.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/annotations/typeAnnotations/classfile/SyntheticParameters.java Thu Dec 04 15:22:53 2014 -0800 @@ -24,10 +24,12 @@ /* * @test SyntheticParameters * @summary Test generation of annotations on inner class parameters. - * @build ClassfileInspector + * @library /lib/annotations/ * @run main SyntheticParameters */ +import annotations.classfile.ClassfileInspector; + import java.io.*; import java.lang.annotation.*; @@ -111,7 +113,8 @@ public static void main(String... args) throws Exception { new SyntheticParameters().run( - new ClassFile[] { getClassFile(Inner_class), getClassFile(Foo_class) }, + new ClassFile[] { getClassFile(Inner_class, Inner.class), + getClassFile(Foo_class, Foo.class) }, new Expected[] { Inner_expected, Foo_expected }); } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/annotations/typeAnnotations/newlocations/BasicTest.java --- a/langtools/test/tools/javac/annotations/typeAnnotations/newlocations/BasicTest.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/annotations/typeAnnotations/newlocations/BasicTest.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,4 +1,3 @@ - /* * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/api/6440528/T6440528.java --- a/langtools/test/tools/javac/api/6440528/T6440528.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/api/6440528/T6440528.java Thu Dec 04 15:22:53 2014 -0800 @@ -34,6 +34,7 @@ import java.io.File; import java.lang.reflect.Field; +import java.nio.file.Path; import java.util.Arrays; import static javax.tools.StandardLocation.CLASS_OUTPUT; import javax.tools.*; @@ -59,10 +60,10 @@ System.err.println("Got: " + got); } - private File getUnderlyingFile(Object o) throws Exception { - Field file = o.getClass().getDeclaredField("file"); + private File getUnderlyingFile(FileObject o) throws Exception { + Field file = o.getClass().getDeclaredField("file"); // assumes RegularFileObject file.setAccessible(true); - return (File)file.get(o); + return ((Path)file.get(o)).toFile(); } public static void main(String... args) throws Exception { diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/api/TestJavacTask.java --- a/langtools/test/tools/javac/api/TestJavacTask.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/api/TestJavacTask.java Thu Dec 04 15:22:53 2014 -0800 @@ -61,7 +61,10 @@ try { getTask(testFile); } catch (IllegalArgumentException iae) { - if (!iae.getMessage().contains("\"" + testFile.getName() + "\"")) { + // The following check is somewhat fragile, since the content of the ILA is not + // formally specified. If we want to fix this, we should catch/rewrap ILA coming + // from use of java.nio.file.Path inside javac's impl of JavaFileManager. + if (!iae.getMessage().contains(testFile.getName())) { System.err.println("Got message: " + iae.getMessage()); throw new RuntimeException("Error: expected string not found"); } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/diags/Example.java --- a/langtools/test/tools/javac/diags/Example.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/diags/Example.java Thu Dec 04 15:22:53 2014 -0800 @@ -321,12 +321,17 @@ first = opts.get(0); rest = opts.subList(1, opts.size()).toArray(new String[opts.size() - 1]); } + // For more details on the different compilers, + // see their respective class doc comments. + // See also README.examples.txt in this directory. if (first == null || first.equals("jsr199")) return new Jsr199Compiler(verbose, rest); else if (first.equals("simple")) return new SimpleCompiler(verbose); else if (first.equals("backdoor")) return new BackdoorCompiler(verbose); + else if (first.equals("exec")) + return new ExecCompiler(verbose); else throw new IllegalArgumentException(first); } @@ -506,6 +511,84 @@ } } + /** + * Run the test in a separate process. + */ + static class ExecCompiler extends Compiler { + ExecCompiler(boolean verbose) { + super(verbose); + } + + @Override + boolean run(PrintWriter out, Set keys, boolean raw, List opts, List files) { + if (out != null && keys != null) + throw new IllegalArgumentException(); + + if (verbose) + System.err.println("run_exec: " + opts + " " + files); + + List args = new ArrayList(); + + File javaHome = new File(System.getProperty("java.home")); + if (javaHome.getName().equals("jre")) + javaHome = javaHome.getParentFile(); + File javaExe = new File(new File(javaHome, "bin"), "java"); + args.add(javaExe.getPath()); + + File toolsJar = new File(new File(javaHome, "lib"), "tools.jar"); + if (toolsJar.exists()) { + args.add("-classpath"); + args.add(toolsJar.getPath()); + } + + addOpts(args, "test.vm.opts"); + addOpts(args, "test.java.opts"); + args.add(com.sun.tools.javac.Main.class.getName()); + + if (keys != null || raw) + args.add("-XDrawDiagnostics"); + + args.addAll(opts); + for (File f: files) + args.add(f.getPath()); + + try { + ProcessBuilder pb = new ProcessBuilder(args); + pb.redirectErrorStream(true); + Process p = pb.start(); + BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream())); + String line; + while ((line = in.readLine()) != null) { + if (keys != null) + scanForKeys(line, keys); + } + int rc = p.waitFor(); + + return (rc == 0); + } catch (IOException | InterruptedException e) { + System.err.println("Exception execing javac" + e); + System.err.println("Command line: " + opts); + return false; + } + } + + private static void scanForKeys(String text, Set keys) { + StringTokenizer st = new StringTokenizer(text, " ,\r\n():"); + while (st.hasMoreElements()) { + String t = st.nextToken(); + if (t.startsWith("compiler.")) + keys.add(t); + } + } + + private static void addOpts(List args, String propName) { + String propValue = System.getProperty(propName); + if (propValue == null || propValue.isEmpty()) + return; + args.addAll(Arrays.asList(propValue.split(" +", 0))); + } + } + static class BackdoorCompiler extends Compiler { BackdoorCompiler(boolean verbose) { super(verbose); diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/diags/README.examples.txt --- a/langtools/test/tools/javac/diags/README.examples.txt Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/diags/README.examples.txt Thu Dec 04 15:22:53 2014 -0800 @@ -123,6 +123,9 @@ is required to detect and track messages that bypass the normal diagnostic mechanisms, such as output generated by the -verbose option. + exec -- The example will be run in a subprocess. This mode is useful when + the example will leave files open, such that the only way to close + them is to exit the process. The "jsr199" run mode accepts the following options: -cantRead:pattern diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/diags/examples/ImportRequiresCanonical/ImportRequiresCanonical.java --- a/langtools/test/tools/javac/diags/examples/ImportRequiresCanonical/ImportRequiresCanonical.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/diags/examples/ImportRequiresCanonical/ImportRequiresCanonical.java Thu Dec 04 15:22:53 2014 -0800 @@ -23,6 +23,6 @@ // key: compiler.err.import.requires.canonical -import p.ExtendsBase.NestedInBase; +import java.util.HashMap.Entry; class ImportRequiredCanonical { } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/diags/examples/ProcUnclosedTypeFiles/ProcUnclosedTypeFiles.java --- a/langtools/test/tools/javac/diags/examples/ProcUnclosedTypeFiles/ProcUnclosedTypeFiles.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/diags/examples/ProcUnclosedTypeFiles/ProcUnclosedTypeFiles.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,5 +23,6 @@ // key: compiler.warn.proc.unclosed.type.files // options: -Xlint:processing -processor AnnoProc +// run: exec class ProcUnclosedTypeFiles { } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/diags/examples/TryWithResourcesExprEffectivelyFinalVar.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/diags/examples/TryWithResourcesExprEffectivelyFinalVar.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// key: compiler.err.try.with.resources.expr.effectively.final.var + +class TryWithResourcesExprEffectivelyFinalVar { + void m() { + CloseableImpl ac = new CloseableImpl(); + + try (ac) { + ac = null; + } + } +} + +class CloseableImpl implements AutoCloseable { + @Override + public void close() { + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/diags/examples/TryWithResourcesExprNeedsVar.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/diags/examples/TryWithResourcesExprNeedsVar.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// key: compiler.err.try.with.resources.expr.needs.var + +class TryWithResourcesExprNeedsVar { + void m() { + try (new CloseableImpl()) { + } + } +} + +class CloseableImpl implements AutoCloseable { + @Override + public void close() throws Exception { + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/diags/examples/VarInTryWithResourcesNotSupportedInSource.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/diags/examples/VarInTryWithResourcesNotSupportedInSource.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// key: compiler.err.var.in.try.with.resources.not.supported.in.source +// key: compiler.warn.source.no.bootclasspath +// options: -source 8 + +class VarInTryWithResourcesNotSupportedInSource { + void m() { + AutoCloseable ac = new CloseableImpl(); + + try (ac) { + } + } +} + +class CloseableImpl implements AutoCloseable { + @Override + public void close() throws Exception { + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/file/T7018098.java --- a/langtools/test/tools/javac/file/T7018098.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/file/T7018098.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -99,7 +99,7 @@ round++; if (round == 1) { boolean expect = Boolean.valueOf(options.get("expect")); - checkEqual("cache result", fsInfo.isDirectory(testDir), expect); + checkEqual("cache result", fsInfo.isDirectory(testDir.toPath()), expect); initialFSInfo = fsInfo; } else { checkEqual("fsInfo", fsInfo, initialFSInfo); diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/file/T7068437.java --- a/langtools/test/tools/javac/file/T7068437.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/file/T7068437.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.Writer; +import java.nio.file.NoSuchFileException; import java.util.Arrays; import java.util.Collections; import java.util.Map; @@ -104,7 +105,7 @@ messager.printMessage(Kind.NOTE, "found previous content of length " + filer.getResource(StandardLocation.SOURCE_OUTPUT, "p", "C.java").getCharContent(false).length()); found = true; - } catch (FileNotFoundException x) { + } catch (FileNotFoundException | NoSuchFileException x) { messager.printMessage(Kind.NOTE, "not previously there"); found = false; } catch (IOException x) { diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/file/T7068451.java --- a/langtools/test/tools/javac/file/T7068451.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/file/T7068451.java Thu Dec 04 15:22:53 2014 -0800 @@ -33,6 +33,7 @@ import java.io.FileWriter; import java.io.IOException; import java.io.Writer; +import java.nio.file.NoSuchFileException; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -143,7 +144,7 @@ try { int len = filer.getResource(StandardLocation.SOURCE_OUTPUT, "p", "C.java").getCharContent(false).length(); messager.printMessage(Kind.NOTE, "C.java: found previous content of length " + len); - } catch (FileNotFoundException x) { + } catch (FileNotFoundException | NoSuchFileException x) { messager.printMessage(Kind.NOTE, "C.java: not previously there"); } catch (IOException x) { messager.printMessage(Kind.ERROR, "while reading: " + x); diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/flow/T8062747.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/flow/T8062747.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,24 @@ +/** + * @test + * @bug 8062747 + * @summary Avoiding an error for lambdas with thrown types inference inside an anonymous class. + * @compile T8062747.java + */ +public class T8062747 { + + public interface Throwing { + void canThrow() throws Y; + } + + public static void wrap(Throwing action) { + } + + public static void invoke(String a) { + Runnable r = new Runnable() { + @Override + public void run() { + wrap(() -> System.out.println(a)); + } + }; + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/generics/8064803/T8064803.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/generics/8064803/T8064803.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8064803 + * @summary Javac erroneously uses instantiated signatures when merging abstract most-specific methods + */ +public class T8064803 { + interface ParentA { + T process() throws Exception; + } + + interface ParentB { + T process() throws Exception; + } + + interface Child extends ParentA, ParentB { } + + static class ChildImpl implements Child { + @Override + public T process() { + return null; + } + } + + public static void main(String[] args) throws Exception { + Child child = new ChildImpl(); + child.process(); + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/generics/diamond/8065986/T8065986a.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/generics/diamond/8065986/T8065986a.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,33 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8065986 + * + * @summary Compiler fails to NullPointerException when calling super with Object<>() + * @compile/fail/ref=T8065986a.out T8065986a.java -XDrawDiagnostics + * + */ +import java.util.ArrayList; + +class T8065986a { + T8065986a() { + super(new Object<>()); + } + + T8065986a(boolean b) { + super(new ArrayList<>()); + } + + T8065986a(boolean b1, boolean b2) { + super(()->{}); + } + + T8065986a(boolean b1, boolean b2, boolean b3) { + super(T8065986a::m); + } + + T8065986a(boolean cond, Object o1, Object o2) { + super(cond ? o1 : o2); + } + + static void m() { } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/generics/diamond/8065986/T8065986a.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/generics/diamond/8065986/T8065986a.out Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,6 @@ +T8065986a.java:13:25: compiler.err.cant.apply.diamond.1: java.lang.Object, (compiler.misc.diamond.non.generic: java.lang.Object) +T8065986a.java:17:9: compiler.err.cant.apply.symbol: kindname.constructor, Object, compiler.misc.no.args, java.util.ArrayList, kindname.class, java.lang.Object, (compiler.misc.arg.length.mismatch) +T8065986a.java:21:9: compiler.err.cant.apply.symbol: kindname.constructor, Object, compiler.misc.no.args, @438, kindname.class, java.lang.Object, (compiler.misc.arg.length.mismatch) +T8065986a.java:25:9: compiler.err.cant.apply.symbol: kindname.constructor, Object, compiler.misc.no.args, @520, kindname.class, java.lang.Object, (compiler.misc.arg.length.mismatch) +T8065986a.java:29:9: compiler.err.cant.apply.symbol: kindname.constructor, Object, compiler.misc.no.args, @608, kindname.class, java.lang.Object, (compiler.misc.arg.length.mismatch) +5 errors diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/generics/diamond/8065986/T8065986b.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/generics/diamond/8065986/T8065986b.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,33 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8065986 + * + * @summary Compiler fails to NullPointerException when calling super with Object<>() + * @compile/fail/ref=T8065986b.out T8065986b.java -XDrawDiagnostics + * + */ +import java.util.ArrayList; + +class T8065986b { + T8065986b() { + this(new Object<>()); + } + + T8065986b(boolean b) { + this(new ArrayList<>()); + } + + T8065986b(boolean b1, boolean b2) { + this(()->{}); + } + + T8065986b(boolean b1, boolean b2, boolean b3) { + this(T8065986b::m); + } + + T8065986b(boolean cond, Object o1, Object o2) { + this(cond ? o1 : o2); + } + + static void m() { } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/generics/diamond/8065986/T8065986b.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/generics/diamond/8065986/T8065986b.out Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,6 @@ +T8065986b.java:13:24: compiler.err.cant.apply.diamond.1: java.lang.Object, (compiler.misc.diamond.non.generic: java.lang.Object) +T8065986b.java:17:9: compiler.err.cant.apply.symbols: kindname.constructor, T8065986b, java.util.ArrayList,{(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(boolean), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: java.util.ArrayList), (compiler.misc.infer.no.conforming.instance.exists: E, java.util.ArrayList, boolean)))),(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(boolean,boolean), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(boolean,boolean,boolean), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(boolean,java.lang.Object,java.lang.Object), (compiler.misc.arg.length.mismatch))} +T8065986b.java:21:9: compiler.err.cant.apply.symbols: kindname.constructor, T8065986b, @435,{(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(boolean), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.not.a.functional.intf: boolean))),(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(boolean,boolean), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(boolean,boolean,boolean), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(boolean,java.lang.Object,java.lang.Object), (compiler.misc.arg.length.mismatch))} +T8065986b.java:25:9: compiler.err.cant.apply.symbols: kindname.constructor, T8065986b, @516,{(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(boolean), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.not.a.functional.intf: boolean))),(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(boolean,boolean), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(boolean,boolean,boolean), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(boolean,java.lang.Object,java.lang.Object), (compiler.misc.arg.length.mismatch))} +T8065986b.java:29:9: compiler.err.cant.apply.symbols: kindname.constructor, T8065986b, @603,{(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(boolean), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.type.in.conditional: (compiler.misc.inconvertible.types: java.lang.Object, boolean)))),(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(boolean,boolean), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(boolean,boolean,boolean), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.constructor, T8065986b, T8065986b(boolean,java.lang.Object,java.lang.Object), (compiler.misc.arg.length.mismatch))} +5 errors diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importChecks/NoImportedNoClasses.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importChecks/NoImportedNoClasses.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,10 @@ +/* + * @test /nodynamiccopyright/ + * @bug 7101822 + * @summary Verify that statically importing non-existing constant causes a compile-time error + * for files without a class. + * + * @compile/fail/ref=NoImportedNoClasses.out -XDrawDiagnostics NoImportedNoClasses.java + */ + +import static java.lang.Runnable.UNKNOWN; diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importChecks/NoImportedNoClasses.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importChecks/NoImportedNoClasses.out Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,2 @@ +NoImportedNoClasses.java:10:1: compiler.err.cant.resolve.location: kindname.static, UNKNOWN, , , kindname.interface, java.lang.Runnable +1 error \ No newline at end of file diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importscope/ImportResolvedTooSoon.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importscope/ImportResolvedTooSoon.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 7101822 + * @summary Verify that imports are declarations are processed in the correct order. + * @compile ImportResolvedTooSoon.java + */ +package pkg; + +import static pkg.B.SubInner.Foo; + +class B extends A { + static class SubInner extends Inner { } +} + +class A { + static class Inner { + static class Foo { } + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importscope/T7101822A.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importscope/T7101822A.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 7101822 + * @summary Verify that imports are declarations are processed in the correct order. + * @compile T7101822A.java T7101822Z.java + */ +package a; + +import a.T7101822A.B.C; +import z.T7101822Z; + +public class T7101822A { + + class B extends T7101822Z { + + class C { + } + } + + class D { + + Class foo() { + return C.class; + } + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importscope/T7101822Z.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importscope/T7101822Z.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package z; +public class T7101822Z {} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importscope/TestDuplicateImport.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importscope/TestDuplicateImport.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2011-2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 7101822 + * @summary static import fails to resolve interfaces on nested enums via import statements + */ + +import com.sun.source.util.JavacTask; +import java.net.URI; +import java.util.Arrays; +import javax.tools.Diagnostic; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; + + +public class TestDuplicateImport { + + static int checkCount = 0; + + enum ImportKind { + NORMAL("import a.#Q.#N;"), + STATIC("import static a.#Q.#N;"); + + String importStr; + + ImportKind(String importStr) { + this.importStr = importStr; + } + + String getImportStatement(QualifierKind qk, NameKind nk) { + return importStr.replaceAll("#Q", qk.qualifierStr) + .replaceAll("#N", nk.nameStr); + } + + boolean isStatic() { + return this == STATIC; + } + } + + enum QualifierKind { + A("A"), + B("B"), + C("C"); + + String qualifierStr; + + QualifierKind(String qualifierStr) { + this.qualifierStr = qualifierStr; + } + + public boolean compatible(QualifierKind ik) { + return this == ik || (this != A && ik != A); + } + } + + enum NameKind { + D("D"), + E("E"), + M("m"), + F("f"), + STAR("*"), + NON_EXISTENT("NonExistent"); + + String nameStr; + + NameKind(String nameStr) { + this.nameStr = nameStr; + } + + boolean exists() { + return this != NON_EXISTENT; + } + + boolean isMember() { + return this == M || this == F; + } + + boolean isType() { + return this == D || this == E; + } + } + + public static void main(String... args) throws Exception { + + //create default shared JavaCompiler - reused across multiple compilations + JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null); + + for (ImportKind ik1 : ImportKind.values()) { + for (ImportKind ik2 : ImportKind.values()) { + for (QualifierKind qk1 : QualifierKind.values()) { + for (QualifierKind qk2 : QualifierKind.values()) { + for (NameKind nk1 : NameKind.values()) { + for (NameKind nk2 : NameKind.values()) { + new TestDuplicateImport(ik1, ik2, qk1, qk2, nk1, nk2).run(comp, fm); + } + } + } + } + } + } + System.out.println("Total check executed: " + checkCount); + } + + ImportKind ik1; + ImportKind ik2; + QualifierKind qk1; + QualifierKind qk2; + NameKind nk1; + NameKind nk2; + JavaSource source; + DiagnosticChecker diagChecker; + + TestDuplicateImport(ImportKind ik1, ImportKind ik2, QualifierKind qk1, QualifierKind qk2, NameKind nk1, NameKind nk2) { + this.ik1 = ik1; + this.ik2 = ik2; + this.qk1 = qk1; + this.qk2 = qk2; + this.nk1 = nk1; + this.nk2 = nk2; + this.source = new JavaSource(); + this.diagChecker = new DiagnosticChecker(); + } + class JavaSource extends SimpleJavaFileObject { + + String bodyTemplate = "package a;\n" + + "#I1\n" + + "#I2\n" + + "class A {\n" + + " static class D { }\n" + + " static class E { }\n" + + " static Object f;\n" + + " static void m() { }\n" + + "}\n" + + "class B {\n" + + " static class D { }\n" + + " static class E { }\n" + + " static Object f;\n" + + " static void m() { }\n" + + "}\n" + + "class C extends B {\n" + + "}\n"; + + String source; + + public JavaSource() { + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); + source = bodyTemplate.replaceAll("#I1", ik1.getImportStatement(qk1, nk1)) + .replaceAll("#I2", ik2.getImportStatement(qk2, nk2)); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return source; + } + } + + void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception { + JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker, + null, null, Arrays.asList(source)); + try { + ct.analyze(); + } catch (Throwable ex) { + throw new AssertionError("Error thrown when compiling the following code:\n" + source.getCharContent(true)); + } + check(); + } + + void check() { + checkCount++; + + boolean errorExpected = false; + + //error if the import refers to a non-existent symbol + if (!nk1.exists() || !nk2.exists()) { + errorExpected = true; + } + + //error if a non-static import refers to a non-type symbol + if ((nk1.isMember() && !ik1.isStatic()) || + (nk2.isMember() && !ik2.isStatic())) { + errorExpected = true; + } + + //error if two single non-static (or one static and one non-static) + //imports import same names from different places + if (nk1 == nk2 && nk1 != NameKind.STAR && !qk1.compatible(qk2) && + (!ik1.isStatic() || !ik2.isStatic())) { + errorExpected = true; + } + + if ((qk1 == QualifierKind.C && !ik1.isStatic() && nk1 != NameKind.STAR) || + (qk2 == QualifierKind.C && !ik2.isStatic() && nk2 != NameKind.STAR)) { + errorExpected = true; + } + + if (errorExpected != diagChecker.errorFound) { + throw new Error("invalid diagnostics for source:\n" + + source.getCharContent(true) + + "\nFound error: " + diagChecker.errorFound + + "\nExpected error: " + errorExpected); + } + } + + static class DiagnosticChecker implements javax.tools.DiagnosticListener { + + boolean errorFound; + + public void report(Diagnostic diagnostic) { + if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { + errorFound = true; + } + } + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importscope/TestLazyImportScope.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importscope/TestLazyImportScope.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2011-2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 7101822 + * @summary static import fails to resolve interfaces on nested enums via import statements + */ + +import com.sun.source.util.JavacTask; +import java.net.URI; +import java.util.Arrays; +import javax.tools.Diagnostic; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; + +public class TestLazyImportScope { + + static int checkCount = 0; + + enum ImportOrder { + NORMAL("import a.C.D;\n" + + "#I"), + REVERSE("#I\n" + + "import a.C.D;"); + + String importLayout; + + ImportOrder(String importLayout) { + this.importLayout = importLayout; + } + + String getImportString(ImportKind ik) { + return importLayout.replaceAll("#I", ik.importStr); + } + } + + enum ImportKind { + NAMED("import a.A.B.E;"), + ON_DEMAND("import a.A.B.*;"), + STATIC_NAMED_TYPE("import static a.A.B.E;"), + STATIC_NAMED_MEMBER("import static a.A.B.bm;"), + STATIC_ON_DEMAND("import static a.A.B.*;"); + + String importStr; + + private ImportKind(String importStr) { + this.importStr = importStr; + } + } + + enum TypeRefKind { + NONE(""), + E("E e = null;"), + F("F f = null;"), + BOTH("E e = null; F f = null;"); + + String typeRefStr; + + private TypeRefKind(String typeRefStr) { + this.typeRefStr = typeRefStr; + } + + boolean isImported(ImportKind ik) { + switch (ik) { + case NAMED: + case STATIC_NAMED_TYPE: return this == NONE || this == E; + case ON_DEMAND: + case STATIC_ON_DEMAND: return true; + default: return this == NONE; + } + } + } + + enum MemberRefKind { + NONE(""), + FIELD("Object o = bf;"), + METHOD("bm();"), + BOTH("Object o = bf; bm();"); + + String memberRefStr; + + private MemberRefKind(String memberRefStr) { + this.memberRefStr = memberRefStr; + } + + boolean isImported(ImportKind ik) { + switch (ik) { + case STATIC_NAMED_MEMBER: return this == NONE || this == METHOD; + case STATIC_ON_DEMAND: return true; + default: return this == NONE; + } + } + } + + public static void main(String... args) throws Exception { + + //create default shared JavaCompiler - reused across multiple compilations + JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null); + + for (ImportOrder ord : ImportOrder.values()) { + for (ImportKind ik : ImportKind.values()) { + for (TypeRefKind tk : TypeRefKind.values()) { + for (MemberRefKind mk : MemberRefKind.values()) { + new TestLazyImportScope(ord, ik, tk, mk).run(comp, fm); + } + } + } + } + System.out.println("Total check executed: " + checkCount); + } + + ImportOrder ord; + ImportKind ik; + TypeRefKind tk; + MemberRefKind mk; + JavaSource source; + DiagnosticChecker diagChecker; + + TestLazyImportScope(ImportOrder ord, ImportKind ik, TypeRefKind tk, MemberRefKind mk) { + this.ord = ord; + this.ik = ik; + this.tk = tk; + this.mk = mk; + this.source = new JavaSource(); + this.diagChecker = new DiagnosticChecker(); + } + + class JavaSource extends SimpleJavaFileObject { + + String bodyTemplate = "package a;\n" + + "#I\n" + + "class A {\n" + + " static class B extends D {\n" + + " static class E { }\n" + + " static class F { }\n" + + " static Object bf;\n" + + " static void bm() { }\n" + + " }\n" + + "}\n" + + "class C {\n" + + " static class D { }\n" + + "}\n" + + "class Test {\n" + + " void test() {\n" + + " #T\n" + + " #M\n" + + " }\n" + + "}"; + + String source; + + public JavaSource() { + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); + source = bodyTemplate.replaceAll("#I", ord.getImportString(ik)) + .replaceAll("#T", tk.typeRefStr) + .replaceAll("#M", mk.memberRefStr); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return source; + } + } + + void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception { + JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker, + null, null, Arrays.asList(source)); + try { + ct.analyze(); + } catch (Throwable ex) { + throw new AssertionError("Error thrown when compiling the following code:\n" + source.getCharContent(true)); + } + check(); + } + + void check() { + checkCount++; + + boolean errorExpected = !tk.isImported(ik) || !mk.isImported(ik); + + if (errorExpected != diagChecker.errorFound) { + throw new Error("invalid diagnostics for source:\n" + + source.getCharContent(true) + + "\nFound error: " + diagChecker.errorFound + + "\nExpected error: " + errorExpected); + } + } + + static class DiagnosticChecker implements javax.tools.DiagnosticListener { + + boolean errorFound; + + public void report(Diagnostic diagnostic) { + if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { + errorFound = true; + } + } + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importscope/TypeParamCycle.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importscope/TypeParamCycle.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 7101822 + * @summary Verify that cycles between type parameter bounds and imports/class nesting + * are not a problem. + * @compile TypeParamCycle.java + */ +package pkg; + +import pkg.A.Outer.Inner; + +class A { + static class Outer { static class Inner {} } +} + diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importscope/TypeParamCycle2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importscope/TypeParamCycle2.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 7101822 + * @summary Verify that cycles between type parameter bounds and imports/class nesting + * are not a problem. + * @compile TypeParamCycle2.java + */ +package pkg; + +import pkg.A.Outer.Inner; + +class B extends Inner { +} + +class A { + static class Outer { static class Inner {} } +} + diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importscope/TypeParamCycle3.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importscope/TypeParamCycle3.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 7101822 + * @summary Verify that cycles between type parameter bounds and imports/class nesting + * are not a problem. + * @compile TypeParamCycle3.java + */ +package pkg; + +import static pkg.A.Outer.Inner; + +class A { + static class Outer extends B { } +} + +class B { + static class Inner {} +} + diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importscope/dependencies/DependenciesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importscope/dependencies/DependenciesTest.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 7101822 + * @summary Verify that the processing of classes in TypeEnter runs in the correct order. + * @library /tools/lib + * @build annotations.TriggersComplete annotations.TriggersCompleteRepeat annotations.Phase + * @build DependenciesTest + * @run main DependenciesTest + */ + +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.Stack; +import java.util.stream.Stream; + +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Name; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Elements; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; + +import annotations.*; +import com.sun.source.tree.AnnotationTree; + +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.ImportTree; +import com.sun.source.tree.Tree; +import com.sun.source.util.JavacTask; +import com.sun.source.util.SourcePositions; +import com.sun.source.util.TreePathScanner; +import com.sun.source.util.Trees; +import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.api.JavacTrees; +import com.sun.tools.javac.code.Symbol.ClassSymbol; +import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Context.Factory; +import com.sun.tools.javac.util.Dependencies; + + +public class DependenciesTest { + public static void main(String... args) throws IOException { + new DependenciesTest().run(); + } + + void run() throws IOException { + Path src = Paths.get(System.getProperty("test.src"), "tests"); + + try (Stream tests = Files.list(src)) { + tests.map(p -> Files.isRegularFile(p) ? Stream.of(p) : silentWalk(p)) + .forEach(this :: runTest); + } + } + + Stream silentWalk(Path src) { + try { + return Files.walk(src).filter(Files :: isRegularFile); + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + + void runTest(Stream inputs) { + JavacTool tool = JavacTool.create(); + try (JavacFileManager fm = tool.getStandardFileManager(null, null, null)) { + Path classes = Paths.get(System.getProperty("test.classes")); + Iterable reconFiles = + fm.getJavaFileObjectsFromFiles(inputs.sorted().map(p -> p.toFile()) :: iterator); + List options = Arrays.asList("-classpath", classes.toAbsolutePath().toString()); + JavacTask reconTask = tool.getTask(null, fm, null, options, null, reconFiles); + Iterable reconUnits = reconTask.parse(); + JavacTrees reconTrees = JavacTrees.instance(reconTask); + SearchAnnotations scanner = new SearchAnnotations(reconTrees, + reconTask.getElements()); + List validateFiles = new ArrayList<>(); + + reconTask.analyze(); + scanner.scan(reconUnits, null); + + for (CompilationUnitTree cut : reconUnits) { + validateFiles.add(ClearAnnotations.clearAnnotations(reconTrees, cut)); + } + + Context validateContext = new Context(); + TestDependencies.preRegister(validateContext); + JavacTask validateTask = + tool.getTask(null, fm, null, options, null, validateFiles, validateContext); + + validateTask.analyze(); + + TestDependencies deps = (TestDependencies) Dependencies.instance(validateContext); + + if (!scanner.topLevel2Expected.equals(deps.topLevel2Completing)) { + throw new IllegalStateException( "expected=" + scanner.topLevel2Expected + + "; actual=" + deps.topLevel2Completing); + } + } catch (IOException ex) { + throw new IllegalStateException(ex); + } finally { + inputs.close(); + } + } + + static final class TestDependencies extends Dependencies { + + public static void preRegister(Context context) { + context.put(dependenciesKey, (Factory) TestDependencies :: new); + } + + public TestDependencies(Context context) { + super(context); + } + + final Stack inProcess = new Stack<>(); + + String topLevelMemberEnter; + Map> topLevel2Completing = new HashMap<>(); + + @Override + public void push(ClassSymbol s, CompletionCause phase) { + String flatname = s.flatName().toString(); + for (Phase p : Phase.values()) { + if (phase == p.cause) { + inProcess.push(new PhaseDescription(flatname, p)); + return ; + } + } + if (phase == CompletionCause.MEMBER_ENTER) { + if (inProcess.isEmpty()) { + topLevelMemberEnter = flatname; + } else { + for (PhaseDescription running : inProcess) { + if (running == null) + continue; + + Set completing = + topLevel2Completing.computeIfAbsent(running.flatname, $ -> new HashSet<>()); + + completing.add(new PhaseDescription(flatname, running.phase)); + } + } + } + inProcess.push(null); + } + + @Override + public void push(AttributionKind ak, JCTree t) { + inProcess.push(null); + } + + @Override + public void pop() { + inProcess.pop(); + } + + } + + static final class SearchAnnotations extends TreePathScanner { + final Trees trees; + final Elements elements; + final TypeElement triggersCompleteAnnotation; + final TypeElement triggersCompleteRepeatAnnotation; + final Map> topLevel2Expected = + new HashMap<>(); + + public SearchAnnotations(Trees trees, Elements elements) { + this.trees = trees; + this.elements = elements; + this.triggersCompleteAnnotation = + elements.getTypeElement(TriggersComplete.class.getName()); + this.triggersCompleteRepeatAnnotation = + elements.getTypeElement(TriggersCompleteRepeat.class.getName()); + } + + @Override + public Void visitClass(ClassTree node, Void p) { + TypeElement te = (TypeElement) trees.getElement(getCurrentPath()); + Set expected = new HashSet<>(); + + for (AnnotationMirror am : getTriggersCompleteAnnotation(te)) { + TypeMirror of = (TypeMirror) findAttribute(am, "of").getValue(); + Name ofName = elements.getBinaryName((TypeElement) ((DeclaredType) of).asElement()); + Element at = (Element) findAttribute(am, "at").getValue(); + Phase phase = Phase.valueOf(at.getSimpleName().toString()); + expected.add(new PhaseDescription(ofName.toString(), phase)); + } + + if (!expected.isEmpty()) + topLevel2Expected.put(elements.getBinaryName(te).toString(), expected); + + return super.visitClass(node, p); + } + + Collection getTriggersCompleteAnnotation(TypeElement te) { + for (AnnotationMirror am : te.getAnnotationMirrors()) { + if (triggersCompleteAnnotation.equals(am.getAnnotationType().asElement())) { + return Collections.singletonList(am); + } + if (triggersCompleteRepeatAnnotation.equals(am.getAnnotationType().asElement())) { + return (Collection) findAttribute(am, "value").getValue(); + } + } + return Collections.emptyList(); + } + + AnnotationValue findAttribute(AnnotationMirror mirror, String name) { + for (Entry e : + mirror.getElementValues().entrySet()) { + if (e.getKey().getSimpleName().contentEquals(name)) { + return e.getValue(); + } + } + + throw new IllegalStateException("Could not find " + name + " in " + mirror); + } + } + + static final class ClearAnnotations extends TreePathScanner { + final SourcePositions positions; + final List spans2Clear = new ArrayList<>(); + + ClearAnnotations(Trees trees) { + this.positions = trees.getSourcePositions(); + } + + @Override + public Void visitAnnotation(AnnotationTree node, Void p) { + removeCurrentNode(); + return null; + } + + @Override + public Void visitImport(ImportTree node, Void p) { + if (node.getQualifiedIdentifier().toString().startsWith("annotations.")) { + removeCurrentNode(); + return null; + } + return super.visitImport(node, p); + } + + void removeCurrentNode() { + CompilationUnitTree topLevel = getCurrentPath().getCompilationUnit(); + Tree node = getCurrentPath().getLeaf(); + spans2Clear.add(new int[] {(int) positions.getStartPosition(topLevel, node), + (int) positions.getEndPosition(topLevel, node)}); + } + + static JavaFileObject clearAnnotations(Trees trees, CompilationUnitTree cut) + throws IOException { + ClearAnnotations a = new ClearAnnotations(trees); + a.scan(cut, null); + Collections.sort(a.spans2Clear, (s1, s2) -> s2[0] - s1[0]); + StringBuilder result = new StringBuilder(cut.getSourceFile().getCharContent(true)); + for (int[] toClear : a.spans2Clear) { + result.delete(toClear[0], toClear[1]); + } + return new TestJavaFileObject(cut.getSourceFile().toUri(), result.toString()); + } + + } + + static final class PhaseDescription { + final String flatname; + final Phase phase; + + public PhaseDescription(String flatname, Phase phase) { + this.flatname = flatname; + this.phase = phase; + } + + @Override + public String toString() { + return "@annotations.TriggersComplete(of=" + flatname + ".class," + + "at=annotations.Phase." + phase + ')'; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 89 * hash + Objects.hashCode(this.flatname); + hash = 89 * hash + Objects.hashCode(this.phase); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final PhaseDescription other = (PhaseDescription) obj; + if (!Objects.equals(this.flatname, other.flatname)) { + return false; + } + if (this.phase != other.phase) { + return false; + } + return true; + } + + } + + static final class TestJavaFileObject extends SimpleJavaFileObject { + private final String content; + + public TestJavaFileObject(URI uri, String content) { + super(uri, Kind.SOURCE); + this.content = content; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return content; + } + + } +} + + diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importscope/dependencies/annotations/Phase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importscope/dependencies/annotations/Phase.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package annotations; + +import com.sun.tools.javac.util.Dependencies.CompletionCause; + +public enum Phase { + IMPORTS(CompletionCause.IMPORTS_PHASE), + HIERARCHY(CompletionCause.HIERARCHY_PHASE), + HEADER(CompletionCause.HEADER_PHASE), + MEMBERS(CompletionCause.MEMBERS_PHASE); + + public final CompletionCause cause; + + private Phase(CompletionCause cause) { + this.cause = cause; + } + +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importscope/dependencies/annotations/TriggersComplete.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importscope/dependencies/annotations/TriggersComplete.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package annotations; + +import java.lang.annotation.Repeatable; + +@Repeatable(TriggersCompleteRepeat.class) +public @interface TriggersComplete { + public Class of(); + public Phase at(); +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importscope/dependencies/annotations/TriggersCompleteRepeat.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importscope/dependencies/annotations/TriggersCompleteRepeat.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package annotations; + +public @interface TriggersCompleteRepeat { + TriggersComplete[] value(); +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importscope/dependencies/tests/ImportResolvedTooSoon.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importscope/dependencies/tests/ImportResolvedTooSoon.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pkg; + +import annotations.*; + +import static pkg.B.SubInner.Foo; + +@TriggersComplete(of=A.class, at=Phase.HIERARCHY) +@TriggersComplete(of=B.SubInner.class, at=Phase.IMPORTS) +class B extends A { + @TriggersComplete(of=A.Inner.class, at=Phase.HIERARCHY) + static class SubInner extends Inner { } +} + +class A { + static class Inner { + static class Foo { } + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importscope/dependencies/tests/Simple.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importscope/dependencies/tests/Simple.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import annotations.*; + +@TriggersComplete(of = Bar.class, at = Phase.HEADER) +@TriggersComplete(of = Sup.class, at = Phase.HIERARCHY) +class Foo extends Sup { +} +class Bar { +} +class Sup { +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importscope/dependencies/tests/T7101822/T7101822.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importscope/dependencies/tests/T7101822/T7101822.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package a; + +import annotations.*; + +import a.T7101822.B.C; +import z.T7101822Aux; + +@TriggersComplete(of=T7101822.B.class, at=Phase.IMPORTS) +public class T7101822 { + + @TriggersComplete(of=z.T7101822Aux.class, at=Phase.HIERARCHY) + class B extends T7101822Aux { + + class C { + } + } + + class D { + + Class foo() { + return C.class; + } + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importscope/dependencies/tests/T7101822/T7101822Aux.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importscope/dependencies/tests/T7101822/T7101822Aux.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package z; +public class T7101822Aux {} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importscope/dependencies/tests/TypeParamCycle.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importscope/dependencies/tests/TypeParamCycle.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pkg; + +import annotations.*; + +import pkg.A.Outer.Inner; + +@TriggersComplete(of=A.Outer.class, at=Phase.IMPORTS) +class A { + @TriggersComplete(of=A.Outer.Inner.class, at=Phase.HEADER) + static class Outer { static class Inner {} } +} + diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importscope/dependencies/tests/TypeParamCycle2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importscope/dependencies/tests/TypeParamCycle2.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pkg; + +import pkg.A.Outer.Inner; + +@annotations.TriggersComplete(of=A.class, at=annotations.Phase.IMPORTS) +@annotations.TriggersComplete(of=A.Outer.class, at=annotations.Phase.IMPORTS) +@annotations.TriggersComplete(of=A.Outer.Inner.class, at=annotations.Phase.HIERARCHY) +class B extends Inner { +} + +class A { + static class Outer { static class Inner {} } +} + diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/importscope/dependencies/tests/TypeParamCycle3.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/importscope/dependencies/tests/TypeParamCycle3.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pkg; + +import static pkg.A.Outer.Inner; + +@annotations.TriggersComplete(of=A.Outer.class, at=annotations.Phase.IMPORTS) +class A { + @annotations.TriggersComplete(of=B.class, at=annotations.Phase.HIERARCHY) + @annotations.TriggersComplete(of=B.Inner.class, at=annotations.Phase.HEADER) + static class Outer extends B { } +} + +class B { + static class Inner {} +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/lambda/methodReference/MethodRef8.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/methodReference/MethodRef8.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8063052 + * @summary Inference chokes on wildcard derived from method reference + * @compile MethodRef8.java + */ + +public class MethodRef8 { + void test(Box> b) { + Number n1 = b.map(Box::get).get(); + Number n2 = b.map(Box::get).get(); + } + + interface Func { T apply(S arg); } + + interface Box { + T get(); + Box map(Func f); + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/lambda/methodReferenceExecution/MethodReferenceIntersection1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/methodReferenceExecution/MethodReferenceIntersection1.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8058112 + * @summary Invalid BootstrapMethod for constructor/method reference + */ + +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +import static java.util.stream.Collectors.toList; + +public class MethodReferenceIntersection1 { + + public static void main(String[] args) { + MethodReferenceIntersection1 main = new MethodReferenceIntersection1(); + List list = main.toInfoListError(Arrays.asList(new Base_MRI1())); + System.out.printf("result %d\n", list.size()); + } + + public List toInfoListError(List list) { + Comparator byNameComparator = + (B_MRI1 b1, B_MRI1 b2) -> b1.getB().compareToIgnoreCase(b2.getB()); + return list.stream().sorted(byNameComparator).map(Info_MRI1::new).collect(toList()); + } + + public List toInfoListWorks(List list) { + Comparator byNameComparator = + (B_MRI1 b1, B_MRI1 b2) -> b1.getB().compareToIgnoreCase(b2.getB()); + return list.stream().sorted(byNameComparator).map(s -> new Info_MRI1(s)).collect(toList()); + } +} + +interface B_MRI1 { + public String getB(); +} + +interface A_MRI1 { + public long getA(); +} + +class Info_MRI1 { + private final long a; + private final String b; + + Info_MRI1(H h) { + a = h.getA(); + b = h.getB(); + } +} + +class Base_MRI1 implements A_MRI1, B_MRI1 { + + @Override + public long getA() { + return 7L; + } + + @Override + public String getB() { + return "hello"; + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/lambda/methodReferenceExecution/MethodReferenceIntersection2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/methodReferenceExecution/MethodReferenceIntersection2.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8058112 + * @summary Invalid BootstrapMethod for constructor/method reference + */ + +import java.util.function.Function; + +public class MethodReferenceIntersection2 { + + interface B { } + + interface A { } + + static class C implements A, B { } + + static class Info { + Info(H h) { } + + static Info info(H h) { + return new Info(h); + } + } + + public static void main(String[] args) { + test(); + } + + // Note the switch in order compared to that on Info + static void test() { + Function f1L = _h -> new Info(_h); + Function f1 = Info::new; + Function f2L = _h -> Info.info(_h); + Function f2 = Info::info; + H c = (H) new C(); + if(f1.apply(c) instanceof Info && + f2.apply(c) instanceof Info) { + System.out.println("Passes."); + } else { + throw new AssertionError(); + } + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/lambda/methodReferenceExecution/MethodReferenceIntersection3.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/methodReferenceExecution/MethodReferenceIntersection3.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8058112 + * @summary Invalid BootstrapMethod for constructor/method reference + */ + +/** + * @author Remi Forax + */ + +public class MethodReferenceIntersection3 { + interface A {} + + interface Foo { + void foo(T t); + } + + static void bar(T t) { + } + + public static void main(String[] args) { + Foo foo = MethodReferenceIntersection3::bar; + foo.foo(new A(){}); + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/lib/DPrinter.java --- a/langtools/test/tools/javac/lib/DPrinter.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/lib/DPrinter.java Thu Dec 04 15:22:53 2014 -0800 @@ -398,8 +398,8 @@ } out.println(); } else if (FILTER_SCOPE_CLASS.equals(scope.getClass().getName())) { - printScope("delegate", - (Scope) getField(scope, scope.getClass(), "delegate"), Details.FULL); + printScope("origin", + (Scope) getField(scope, scope.getClass(), "origin"), Details.FULL); } else if (scope instanceof CompoundScope) { printList("delegates", (List) getField(scope, CompoundScope.class, "subScopes")); } else { diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/links/LinksTest.java --- a/langtools/test/tools/javac/links/LinksTest.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/links/LinksTest.java Thu Dec 04 15:22:53 2014 -0800 @@ -30,6 +30,7 @@ * @run main LinksTest */ +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; @@ -48,17 +49,24 @@ ToolBox tb = new ToolBox(); tb.writeFile("tmp/B.java", BSrc); + // Try to set up a symbolic link for the test. try { Files.createSymbolicLink(Paths.get("a"), Paths.get("tmp")); + System.err.println("Created symbolic link"); + } catch (UnsupportedOperationException | IOException e) { + System.err.println("Problem creating symbolic link: " + e); + System.err.println("Test cannot continue; test passed by default"); + return; + } - tb.new JavacTask() - .sourcepath(".") - .outdir(".") - .sources(TSrc) - .run(); - } catch (UnsupportedOperationException e) { - System.err.println("Symbolic links not supported on this system. The test can't finish"); - } + // If symbolic link was successfully created, + // try a compilation that will use it. + tb.new JavacTask() + .sourcepath(".") + .outdir(".") + .sources(TSrc) + .run() + .writeAll(); } } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/main/Option_J_At_Test.java --- a/langtools/test/tools/javac/main/Option_J_At_Test.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/main/Option_J_At_Test.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,7 +1,3 @@ - -import java.io.PrintWriter; -import java.io.StringWriter; - /* * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -31,6 +27,9 @@ * @summary extra space in javac -help for -J and @ options */ +import java.io.PrintWriter; +import java.io.StringWriter; + public class Option_J_At_Test { public static void main(String... args) throws Exception { new Option_J_At_Test().run(); diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/main/T8058445.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/main/T8058445.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8058445 + * @summary javac throws exception when displaying info + */ + +public class T8058445 { + public static void main(String... ignore) throws Exception { + String[] args = { }; + com.sun.tools.javac.Main.compile(args); + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/processing/errors/CrashOnNonExistingAnnotation/Processor.java --- a/langtools/test/tools/javac/processing/errors/CrashOnNonExistingAnnotation/Processor.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/processing/errors/CrashOnNonExistingAnnotation/Processor.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,7 +88,7 @@ if (!testFile.canRead()) throw new IllegalStateException("Cannot read the test source"); JavacTool compiler = JavacTool.create(); JavacFileManager fm = compiler.getStandardFileManager(null, null, null); - testContent = fm.getRegularFile(testFile).getCharContent(true).toString(); + testContent = fm.getRegularFile(testFile.toPath()).getCharContent(true).toString(); JavaFileObject testFileObject = new TestFO(new URI("mem://" + args[0]), testContent); TestFM testFileManager = new TestFM(fm); JavacTask task = compiler.getTask(null, diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/processing/errors/StopOnInapplicableAnnotations/Processor.java --- a/langtools/test/tools/javac/processing/errors/StopOnInapplicableAnnotations/Processor.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/processing/errors/StopOnInapplicableAnnotations/Processor.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,7 +71,7 @@ File inp = new File(sp, args[0]); if (inp.canRead()) { - testContent = fm.getRegularFile(inp).getCharContent(true).toString(); + testContent = fm.getRegularFile(inp.toPath()).getCharContent(true).toString(); } } if (testContent == null) throw new IllegalStateException(); @@ -167,4 +167,4 @@ } } -} \ No newline at end of file +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/processing/model/util/elements/Foo.java --- a/langtools/test/tools/javac/processing/model/util/elements/Foo.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/processing/model/util/elements/Foo.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,4 +1,3 @@ - /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/scope/HashCollisionTest.java --- a/langtools/test/tools/javac/scope/HashCollisionTest.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/scope/HashCollisionTest.java Thu Dec 04 15:22:53 2014 -0800 @@ -55,6 +55,7 @@ names = Names.instance(context); // Name.Table impls tied to an instance of Names symtab = Symtab.instance(context); trees = JavacTrees.instance(context); + types = Types.instance(context); // determine hashMask for an empty scope Scope emptyScope = WriteableScope.create(symtab.unnamedPackage); // any owner will do @@ -121,12 +122,12 @@ return sym.kind == TYP; } }; - starImportScope.importAll(fromScope, fromScope, typeFilter, false); + starImportScope.importAll(types, fromScope, typeFilter, false); dump("imported p", starImportScope); // 7. Insert the class from 3. - starImportScope.importAll(cc.members_field, cc.members_field, typeFilter, false); + starImportScope.importAll(types, cc.members_field, typeFilter, false); dump("imported ce", starImportScope); /* @@ -196,4 +197,5 @@ Names names; Symtab symtab; Trees trees; + Types types; } diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/scope/StarImportTest.java --- a/langtools/test/tools/javac/scope/StarImportTest.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/scope/StarImportTest.java Thu Dec 04 15:22:53 2014 -0800 @@ -135,6 +135,7 @@ JavacFileManager.preRegister(context); // required by ClassReader which is required by Symtab names = Names.instance(context); // Name.Table impls tied to an instance of Names symtab = Symtab.instance(context); + types = Types.instance(context); int setupCount = rgen.nextInt(MAX_SETUP_COUNT); for (int i = 0; i < setupCount; i++) { switch (random(SetupKind.values())) { @@ -204,7 +205,7 @@ } /** - * Create a star-import scope and a model therof, from the packages and + * Create a star-import scope and a model thereof, from the packages and * classes created by setupPackages and setupClasses. * @throws Exception for fatal errors, such as from reflection */ @@ -218,7 +219,7 @@ for (Symbol imp: imports) { Scope members = imp.members(); // log("importAll", members); - starImportScope.importAll(members, members, new ImportFilter() { + starImportScope.importAll(types, members, new ImportFilter() { @Override public boolean accepts(Scope origin, Symbol t) { return t.kind == TYP; @@ -292,6 +293,7 @@ Context context; Symtab symtab; Names names; + Types types; int nextNameSerial; List packages = new ArrayList(); int nextPackageSerial; diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/unicode/SupplementaryJavaID6.java --- a/langtools/test/tools/javac/unicode/SupplementaryJavaID6.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/unicode/SupplementaryJavaID6.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,8 @@ * @bug 4914724 4973116 5014511 * @summary Ensure that a supplementary character can be used as part/whole of a * class name on platforms that have Unicode aware filesystems. - * @run main SupplementaryJavaID6 + * @build Wrapper + * @run main Wrapper SupplementaryJavaID6 */ public class SupplementaryJavaID6 { diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/unicode/Wrapper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/unicode/Wrapper.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.File; +import java.lang.reflect.Method; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; + + +public class Wrapper { + public static void main(String... args) throws Exception { + if (!isSupplementaryCharactersSupported()) { + System.out.println("Unicode supplementary characters in filenames not supported: pass by default"); + return; + } + + String testClassName = args[0]; + String[] testArgs = Arrays.copyOfRange(args, 1, args.length); + + File srcDir = new File(System.getProperty("test.src")); + File clsDir = new File(System.getProperty("test.classes")); + + File src = new File(srcDir, testClassName + ".java"); + File cls = new File(clsDir, testClassName + ".class"); + + if (cls.lastModified() < src.lastModified()) { + System.err.println("Recompiling test class..."); + String[] javacArgs = { "-d", clsDir.getPath(), src.getPath() }; + int rc = com.sun.tools.javac.Main.compile(javacArgs); + if (rc != 0) + throw new Exception("compilation failed"); + } + + Class mainClass = Class.forName(testClassName); + Method main = mainClass.getMethod("main", String[].class); + main.invoke(null, new Object[] { testArgs }); + } + + private static boolean isSupplementaryCharactersSupported() { + try { + String s = "p--\ud801\udc00--"; + System.err.println("Trying: Paths.get(" + s + ")"); + Path p1 = Paths.get(s); + System.err.println("Found: " + p1); + System.err.println("Trying: p1.resolve(" + s + ")"); + Path p2 = p1.resolve(s); + System.err.println("Found: " + p2); + return p1.toString().equals(s) && p2.toString().equals(s + java.io.File.separator + s); + } catch (InvalidPathException e) { + System.err.println(e); + return false; + } + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/warnings/6594914/ImplicitCompilation.java --- a/langtools/test/tools/javac/warnings/6594914/ImplicitCompilation.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/warnings/6594914/ImplicitCompilation.java Thu Dec 04 15:22:53 2014 -0800 @@ -3,9 +3,9 @@ * @bug 8020586 * @summary Warnings in the imports section should be attributed to the correct source file * @clean Auxiliary ImplicitCompilation - * @compile/ref=ImplicitCompilation.out -XDrawDiagnostics -Xlint:deprecation -sourcepath . ImplicitCompilation.java + * @compile/ref=ImplicitCompilation.out -source 8 -XDrawDiagnostics -Xlint:deprecation,-options -sourcepath . ImplicitCompilation.java * @clean Auxiliary ImplicitCompilation - * @compile/ref=ExplicitCompilation.out -XDrawDiagnostics -Xlint:deprecation ImplicitCompilation.java Auxiliary.java + * @compile/ref=ExplicitCompilation.out -source 8 -XDrawDiagnostics -Xlint:deprecation,-options ImplicitCompilation.java Auxiliary.java */ public class ImplicitCompilation { diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/warnings/Deprecation.java --- a/langtools/test/tools/javac/warnings/Deprecation.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/warnings/Deprecation.java Thu Dec 04 15:22:53 2014 -0800 @@ -1,11 +1,13 @@ /** * @test /nodynamiccopyright/ - * @bug 4986256 - * @compile/ref=Deprecation.noLint.out -XDrawDiagnostics Deprecation.java - * @compile/ref=Deprecation.lintDeprecation.out -Xlint:deprecation -XDrawDiagnostics Deprecation.java - * @compile/ref=Deprecation.lintAll.out -Xlint:all,-path -XDrawDiagnostics Deprecation.java + * @bug 4986256 6598104 8032211 + * @compile/ref=Deprecation.noLint.out -XDrawDiagnostics Deprecation.java + * @compile/ref=Deprecation.lintDeprecation.out -Xlint:deprecation -XDrawDiagnostics Deprecation.java + * @compile/ref=Deprecation.lintDeprecation8.out -Xlint:deprecation,-options -source 8 -XDrawDiagnostics Deprecation.java */ +import java.io.StringBufferInputStream; + @Deprecated class Deprecation { diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/warnings/Deprecation.lintAll.out --- a/langtools/test/tools/javac/warnings/Deprecation.lintAll.out Thu Dec 04 12:58:21 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -Deprecation.java:18:24: compiler.warn.has.been.deprecated: Deprecation, compiler.misc.unnamed.package -Deprecation.java:55:24: compiler.warn.has.been.deprecated: Deprecation, compiler.misc.unnamed.package -2 warnings diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/warnings/Deprecation.lintDeprecation.out --- a/langtools/test/tools/javac/warnings/Deprecation.lintDeprecation.out Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/warnings/Deprecation.lintDeprecation.out Thu Dec 04 15:22:53 2014 -0800 @@ -1,3 +1,3 @@ -Deprecation.java:18:24: compiler.warn.has.been.deprecated: Deprecation, compiler.misc.unnamed.package -Deprecation.java:55:24: compiler.warn.has.been.deprecated: Deprecation, compiler.misc.unnamed.package +Deprecation.java:20:24: compiler.warn.has.been.deprecated: Deprecation, compiler.misc.unnamed.package +Deprecation.java:57:24: compiler.warn.has.been.deprecated: Deprecation, compiler.misc.unnamed.package 2 warnings diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/warnings/Deprecation.lintDeprecation8.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/warnings/Deprecation.lintDeprecation8.out Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,4 @@ +Deprecation.java:9:15: compiler.warn.has.been.deprecated: java.io.StringBufferInputStream, java.io +Deprecation.java:20:24: compiler.warn.has.been.deprecated: Deprecation, compiler.misc.unnamed.package +Deprecation.java:57:24: compiler.warn.has.been.deprecated: Deprecation, compiler.misc.unnamed.package +3 warnings diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/warnings/NestedDeprecation/NestedDeprecation.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/warnings/NestedDeprecation/NestedDeprecation.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,29 @@ +/** + * @test /nodynamiccopyright/ + * @bug 6598104 8032211 + * @build p.Dep1 p.Dep2 + * @compile/ref=NestedDeprecation.out -Xlint:deprecation -XDrawDiagnostics NestedDeprecation.java + */ + +package p; + +import p.Dep1.A; +import static p.Dep1.B; +import static p.Dep1.method; +import static p.Dep1.field; +import p.Dep2.C; +import p.Dep2.D; + +class NestedDeprecation { + Dep1 f1; + A f2; + Dep2 f3; + B f4; + C f5; + D f6; + + static { + method(); + String f = field; + } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/warnings/NestedDeprecation/NestedDeprecation.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/warnings/NestedDeprecation/NestedDeprecation.out Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,9 @@ +NestedDeprecation.java:14:9: compiler.warn.has.been.deprecated: p.Dep2, p +NestedDeprecation.java:15:9: compiler.warn.has.been.deprecated: p.Dep2, p +NestedDeprecation.java:19:5: compiler.warn.has.been.deprecated: p.Dep1.A, p.Dep1 +NestedDeprecation.java:20:5: compiler.warn.has.been.deprecated: p.Dep2, p +NestedDeprecation.java:21:5: compiler.warn.has.been.deprecated: p.Dep1.B, p.Dep1 +NestedDeprecation.java:23:5: compiler.warn.has.been.deprecated: p.Dep2.D, p.Dep2 +NestedDeprecation.java:26:9: compiler.warn.has.been.deprecated: method(), p.Dep1 +NestedDeprecation.java:27:20: compiler.warn.has.been.deprecated: field, p.Dep1 +8 warnings diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/warnings/NestedDeprecation/p/Dep1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/warnings/NestedDeprecation/p/Dep1.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,12 @@ +package p; + +class Dep1 { + @Deprecated + static class A { } + @Deprecated + static class B { } + @Deprecated + static void method() { } + @Deprecated + static String field; +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/warnings/NestedDeprecation/p/Dep2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/warnings/NestedDeprecation/p/Dep2.java Thu Dec 04 15:22:53 2014 -0800 @@ -0,0 +1,8 @@ +package p; + +@Deprecated +class Dep2 { + class C { } + @Deprecated + class D { } +} diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/warnings/suppress/ImplicitTest.java --- a/langtools/test/tools/javac/warnings/suppress/ImplicitTest.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/warnings/suppress/ImplicitTest.java Thu Dec 04 15:22:53 2014 -0800 @@ -27,5 +27,5 @@ * @summary Verify that deprecated warning is printed correctly for import * statement when processing a file on demand while attributing another file. * @clean pack.ImplicitUse pack.ImplicitMain pack.Dep - * @compile/ref=ImplicitTest.out -XDrawDiagnostics -Xlint:deprecation pack/ImplicitMain.java + * @compile/ref=ImplicitTest.out -source 8 -XDrawDiagnostics -Xlint:deprecation,-options pack/ImplicitMain.java */ diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/warnings/suppress/PackageInfo.java --- a/langtools/test/tools/javac/warnings/suppress/PackageInfo.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/warnings/suppress/PackageInfo.java Thu Dec 04 15:22:53 2014 -0800 @@ -26,5 +26,5 @@ * @bug 8021112 * @summary Verify that deprecated warnings are printed correctly for package-info.java * @clean pack.package-info pack.DeprecatedClass - * @compile/ref=PackageInfo.out -XDrawDiagnostics -Xlint:deprecation pack/package-info.java pack/DeprecatedClass.java + * @compile/ref=PackageInfo.out -source 8 -XDrawDiagnostics -Xlint:deprecation,-options pack/package-info.java pack/DeprecatedClass.java */ diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javac/warnings/suppress/VerifySuppressWarnings.java --- a/langtools/test/tools/javac/warnings/suppress/VerifySuppressWarnings.java Thu Dec 04 12:58:21 2014 -0800 +++ b/langtools/test/tools/javac/warnings/suppress/VerifySuppressWarnings.java Thu Dec 04 15:22:53 2014 -0800 @@ -74,7 +74,7 @@ File inp = new File(sp, args[0]); if (inp.canRead()) { - testContent = fm.getRegularFile(inp).getCharContent(true).toString(); + testContent = fm.getRegularFile(inp.toPath()).getCharContent(true).toString(); } } if (testContent == null) throw new IllegalStateException(); diff -r 66e93fa62eb3 -r a48998a1fc72 langtools/test/tools/javap/WhitespaceTest.java