# HG changeset patch # User jlahoda # Date 1417610772 -3600 # Node ID 7e913a5357369eb255a1c3bc13c75a1d60081fab # Parent d4711a6931e2ffbdeb5a457d9e78d0f3955e0c24 7101822: Compiling depends on order of imports 7177813: Static import to local nested class fails Summary: MemberEnter overhaul - TypeEnter is split out of MemberEnter; the TypeEnter consists of several Phases which ensure actions are done in the correct order. Reviewed-by: mcimadamore, jfranck, aeremeev Contributed-by: jan.lahoda@oracle.com, maurizio.cimadamore@oracle.com diff -r d4711a6931e2 -r 7e913a535736 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 Fri Nov 28 11:45:56 2014 +0000 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java Wed Dec 03 13:46:12 2014 +0100 @@ -46,6 +46,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 @@ -186,7 +187,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 d4711a6931e2 -r 7e913a535736 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 Fri Nov 28 11:45:56 2014 +0000 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Scope.java Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Fri Nov 28 11:45:56 2014 +0000 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Wed Dec 03 13:46:12 2014 +0100 @@ -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); @@ -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)); diff -r d4711a6931e2 -r 7e913a535736 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 Fri Nov 28 11:45:56 2014 +0000 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Fri Nov 28 11:45:56 2014 +0000 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Fri Nov 28 11:45:56 2014 +0000 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java Wed Dec 03 13:46:12 2014 +0100 @@ -25,76 +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.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.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); @@ -105,178 +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(); - allowDeprecationOnImport = source.allowDeprecationOnImport(); - } - - /** Switch: support type annotations. - */ - boolean allowTypeAnnos; - - /** - * Switch: should deprecation warnings be issued on import - */ - boolean allowDeprecationOnImport; - - /** 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. @@ -345,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; @@ -397,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); @@ -772,38 +435,6 @@ return iEnv; } -/* ******************************************************************** - * Type completion - *********************************************************************/ - - 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); - } - } - - /** - * 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, @@ -849,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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Fri Nov 28 11:45:56 2014 +0000 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Fri Nov 28 11:45:56 2014 +0000 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Dependencies.java Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -0,0 +1,2 @@ +NonStatic2StaticImportClash.java:11:1: compiler.err.already.defined.static.single.import: p1.A1.f +1 error diff -r d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -0,0 +1,2 @@ +Static2NonStaticImportClash.java:11:1: compiler.err.already.defined.single.import: p2.A2.f +1 error diff -r d4711a6931e2 -r 7e913a535736 langtools/test/tools/javac/4980495/std/Test.out --- a/langtools/test/tools/javac/4980495/std/Test.out Fri Nov 28 11:45:56 2014 +0000 +++ b/langtools/test/tools/javac/4980495/std/Test.out Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 langtools/test/tools/javac/diags/examples/ImportRequiresCanonical/ImportRequiresCanonical.java --- a/langtools/test/tools/javac/diags/examples/ImportRequiresCanonical/ImportRequiresCanonical.java Fri Nov 28 11:45:56 2014 +0000 +++ b/langtools/test/tools/javac/diags/examples/ImportRequiresCanonical/ImportRequiresCanonical.java Wed Dec 03 13:46:12 2014 +0100 @@ -23,6 +23,6 @@ // key: compiler.err.import.requires.canonical -import p.ExtendsBase.NestedInBase; +import java.util.HashMap.Entry; class ImportRequiredCanonical { } diff -r d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 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 Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 langtools/test/tools/javac/lib/DPrinter.java --- a/langtools/test/tools/javac/lib/DPrinter.java Fri Nov 28 11:45:56 2014 +0000 +++ b/langtools/test/tools/javac/lib/DPrinter.java Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 langtools/test/tools/javac/scope/HashCollisionTest.java --- a/langtools/test/tools/javac/scope/HashCollisionTest.java Fri Nov 28 11:45:56 2014 +0000 +++ b/langtools/test/tools/javac/scope/HashCollisionTest.java Wed Dec 03 13:46:12 2014 +0100 @@ -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 d4711a6931e2 -r 7e913a535736 langtools/test/tools/javac/scope/StarImportTest.java --- a/langtools/test/tools/javac/scope/StarImportTest.java Fri Nov 28 11:45:56 2014 +0000 +++ b/langtools/test/tools/javac/scope/StarImportTest.java Wed Dec 03 13:46:12 2014 +0100 @@ -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;