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
--- 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 {
--- 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<Scope> 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<Scope> 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<Symbol> getSymbols(Filter<Symbol> sf, LookupKind lookupKind) {
+ public Iterable<Symbol> getSymbols(final Filter<Symbol> 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<Symbol> doLookup(TypeSymbol tsym) {
+ return tsym.members().getSymbols(sf, lookupKind);
+ }
+ };
+ return si.importFrom((TypeSymbol) origin.owner) :: iterator;
}
@Override
- public Iterable<Symbol> getSymbolsByName(Name name,
- Filter<Symbol> sf,
- LookupKind lookupKind) {
+ public Iterable<Symbol> getSymbolsByName(final Name name,
+ final Filter<Symbol> 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<Symbol> 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<Symbol> {
- private final Iterator<Symbol> delegate;
- private Symbol next;
+ abstract class SymbolImporter {
+ Set<Symbol> processed = new HashSet<>();
+ List<Iterable<Symbol>> delegates = List.nil();
+ final boolean inspectSuperTypes;
+ public SymbolImporter(boolean inspectSuperTypes) {
+ this.inspectSuperTypes = inspectSuperTypes;
+ }
+ Stream<Symbol> importFrom(TypeSymbol tsym) {
+ if (tsym == null || !processed.add(tsym))
+ return Stream.empty();
- public FilteredIterator(Iterator<Symbol> delegate) {
- this.delegate = delegate;
- update();
- }
+ Stream<Symbol> 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<Symbol> {
-
- private final Iterable<Symbol> unfiltered;
-
- public FilteredIterable(Iterable<Symbol> unfiltered) {
- this.unfiltered = unfiltered;
- }
-
- @Override
- public Iterator<Symbol> iterator() {
- return new FilteredIterator(unfiltered.iterator());
- }
+ abstract Iterable<Symbol> doLookup(TypeSymbol tsym);
}
}
--- 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.<Type>nil(),
List.<JCVariableDecl>nil(),
false));
--- 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<Symbol> 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<Symbol>())) {
- log.error(imp.pos(), "cant.resolve.location",
- KindName.STATIC,
- select.name, List.<Type>nil(), List.<Type>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<Symbol>())) {
+ log.error(imp.pos(), "cant.resolve.location",
+ KindName.STATIC,
+ select.name, List.<Type>nil(), List.<Type>nil(),
+ Kinds.typeKindName(TreeInfo.symbol(select.selected).type),
+ TreeInfo.symbol(select.selected).type);
}
}
}
--- 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:
*
* <p>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.
*
* <p>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.
*
* <p>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.
*
* <p>Classes migrate from one phase to the next via queues:
*
* <pre>{@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)
* }</pre>
@@ -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<JCCompilationUnit> trees, ClassSymbol c) {
annotate.enterStart();
ListBuffer<ClassSymbol> 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<AttrContext> topEnv = topLevelEnv(tree);
- memberEnter.memberEnter(tree, topEnv);
- log.useSource(prev);
- }
- }
+ typeEnter.ensureImportsChecked(trees);
}
} finally {
uncompleted = prevUncompleted;
--- 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.
*
* <p><b>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.</b>
*/
-public class MemberEnter extends JCTree.Visitor implements Completer {
+public class MemberEnter extends JCTree.Visitor {
protected static final Context.Key<MemberEnter> 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<Env<AttrContext>> 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<AttrContext> 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<AttrContext> 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<AttrContext> 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<Symbol> 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<Symbol, Boolean>());
- 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<Symbol> maskedOut;
-
- public MaskedImportFilter(ImportFilter delegate, Set<Symbol> 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<Symbol> 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<AttrContext> 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<AttrContext> 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<AttrContext> env;
@@ -397,122 +176,6 @@
memberEnter(l.head, env);
}
- /** Enter members for a class.
- */
- void finishClass(JCClassDecl tree, Env<AttrContext> 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<AttrContext> 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.<JCTypeParameter>nil(),
- List.<JCVariableDecl>nil(),
- List.<JCExpression>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.<JCTypeParameter>nil(),
- List.of(make.VarDef(make.Modifiers(Flags.PARAMETER |
- Flags.MANDATED),
- names.fromString("name"),
- make.Type(syms.stringType), null)),
- List.<JCExpression>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<AttrContext> 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<AttrContext> 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<JCAnnotation> annotations) {
- for (List<JCAnnotation> 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<AttrContext> 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<AttrContext> 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<AttrContext> 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<Type> interfaces = new ListBuffer<>();
- ListBuffer<Type> all_interfaces = null; // lazy init
- Set<Type> interfaceSet = new HashSet<>();
- List<JCExpression> 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<Type>().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<Type> argtypes = List.nil();
- List<Type> typarams = List.nil();
- List<Type> 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<JCCompilationUnit> topLevels = new HashSet<>();
- try {
- while (halfcompleted.nonEmpty()) {
- Env<AttrContext> 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<AttrContext> baseEnv(JCClassDecl tree, Env<AttrContext> 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<JCTypeParameter> typarams = tree.typarams;
- typarams.nonEmpty();
- typarams = typarams.tail)
- baseScope.enter(typarams.head.type.tsym);
- Env<AttrContext> outer = env.outer; // the base clause can't see members of this class
- Env<AttrContext> 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<AttrContext> 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.<JCExpression>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<ClassSymbol> 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<Type> visit(List<? extends JCTree> trees) {
- ListBuffer<Type> 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<Type> actuals = visit(tree.arguments);
- result = new ErrorType(tree.type, clazzType.tsym) {
- @Override @DefinedBy(Api.LANGUAGE_MODEL)
- public List<Type> 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<Type> 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<Type> typarams,
- List<Type> argtypes,
- List<Type> 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<JCVariableDecl> params = make.Params(argtypes, init);
- List<JCStatement> 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<VarSymbol> createDefaultConstructorParams(
- TreeMaker make,
- MethodSymbol baseInit,
- MethodSymbol init,
- List<Type> argtypes,
- boolean based) {
- List<VarSymbol> initParams = null;
- List<Type> 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.<VarSymbol>nil() : initParams;
- List<VarSymbol> 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<Type> typarams,
- List<JCVariableDecl> 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<JCExpression> typeargs = typarams.nonEmpty() ? make.Types(typarams) : null;
- return make.Exec(make.Apply(typeargs, meth, make.Idents(params)));
- }
}
--- /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.
+ *
+ * <p><b>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.</b>
+ */
+public class TypeEnter implements Completer {
+ protected static final Context.Key<TypeEnter> 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<JCCompilationUnit> 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<AttrContext> 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<Env<AttrContext>> 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<JCCompilationUnit> seen = new HashSet<>();
+
+ for (Env<AttrContext> 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<Env<AttrContext>> queue = new ListBuffer<>();
+ private final Phase next;
+ private final CompletionCause phaseName;
+
+ Phase(CompletionCause phaseName, Phase next) {
+ this.phaseName = phaseName;
+ this.next = next;
+ }
+
+ public List<Env<AttrContext>> runPhase(List<Env<AttrContext>> envs) {
+ boolean firstToComplete = queue.isEmpty();
+
+ for (Env<AttrContext> 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<Env<AttrContext>> out = queue.toList();
+
+ queue.clear();
+ return next != null ? next.runPhase(out) : out;
+ } else {
+ return List.nil();
+ }
+ }
+
+ protected abstract void doRunPhase(Env<AttrContext> 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<AttrContext> env;
+ ImportFilter staticImportFilter;
+ ImportFilter typeImportFilter = new ImportFilter() {
+ @Override
+ public boolean accepts(Scope origin, Symbol t) {
+ return t.kind == TYP;
+ }
+ };
+
+ @Override
+ protected void doRunPhase(Env<AttrContext> 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<AttrContext> 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<AttrContext> 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<AttrContext> 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<AttrContext> 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<AttrContext> 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<AttrContext> 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<AttrContext> 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<AttrContext> 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<AttrContext> baseEnv(JCClassDecl tree, Env<AttrContext> 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<JCTypeParameter> typarams = tree.typarams;
+ typarams.nonEmpty();
+ typarams = typarams.tail)
+ baseScope.enter(typarams.head.type.tsym);
+ Env<AttrContext> outer = env.outer; // the base clause can't see members of this class
+ Env<AttrContext> 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.<JCExpression>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<ClassSymbol> 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<Type> visit(List<? extends JCTree> trees) {
+ ListBuffer<Type> 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<Type> actuals = visit(tree.arguments);
+ result = new ErrorType(tree.type, clazzType.tsym) {
+ @Override @DefinedBy(Api.LANGUAGE_MODEL)
+ public List<Type> 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<Type> 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<AttrContext> env, Env<AttrContext> 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<Type> interfaces = new ListBuffer<>();
+ ListBuffer<Type> all_interfaces = null; // lazy init
+ List<JCExpression> 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<Type>().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<AttrContext> env) {
+ JCClassDecl tree = env.enclClass;
+ ClassSymbol sym = tree.sym;
+ ClassType ct = (ClassType)sym.type;
+
+ Env<AttrContext> 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<JCAnnotation> annotations) {
+ for (List<JCAnnotation> 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<AttrContext> env) {
+ JCClassDecl tree = env.enclClass;
+ ClassSymbol sym = tree.sym;
+ ClassType ct = (ClassType)sym.type;
+
+ // create an environment for evaluating the base clauses
+ Env<AttrContext> 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<Type> 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<AttrContext> 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<Type> argtypes = List.nil();
+ List<Type> typarams = List.nil();
+ List<Type> 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<AttrContext> 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<AttrContext> 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.<JCTypeParameter>nil(),
+ List.<JCVariableDecl>nil(),
+ List.<JCExpression>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.<JCTypeParameter>nil(),
+ List.of(make.VarDef(make.Modifiers(Flags.PARAMETER |
+ Flags.MANDATED),
+ names.fromString("name"),
+ make.Type(syms.stringType), null)),
+ List.<JCExpression>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<Type> typarams,
+ List<Type> argtypes,
+ List<Type> 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<JCVariableDecl> params = make.Params(argtypes, init);
+ List<JCStatement> 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<VarSymbol> createDefaultConstructorParams(
+ TreeMaker make,
+ MethodSymbol baseInit,
+ MethodSymbol init,
+ List<Type> argtypes,
+ boolean based) {
+ List<VarSymbol> initParams = null;
+ List<Type> 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.<VarSymbol>nil() : initParams;
+ List<VarSymbol> 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<Type> typarams,
+ List<JCVariableDecl> 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<JCExpression> typeargs = typarams.nonEmpty() ? make.Types(typarams) : null;
+ return make.Exec(make.Apply(typeargs, meth, make.Idents(params)));
+ }
+}
--- 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;
--- 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<String, Node> 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
}
--- /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 {
+}
--- /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
--- /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 {
+}
--- /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
--- 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
--- 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 { }
--- /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;
--- /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
--- /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 { }
+ }
+}
--- /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;
+ }
+ }
+}
--- /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 {}
--- /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<JavaFileObject> {
+
+ boolean errorFound;
+
+ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+ if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
+ errorFound = true;
+ }
+ }
+ }
+}
--- /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<JavaFileObject> {
+
+ boolean errorFound;
+
+ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+ if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
+ errorFound = true;
+ }
+ }
+ }
+}
--- /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<X extends Inner> { static class Inner {} }
+}
+
--- /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<X extends Inner> { static class Inner {} }
+}
+
--- /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<X extends Inner> extends B { }
+}
+
+class B {
+ static class Inner {}
+}
+
--- /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<Path> tests = Files.list(src)) {
+ tests.map(p -> Files.isRegularFile(p) ? Stream.of(p) : silentWalk(p))
+ .forEach(this :: runTest);
+ }
+ }
+
+ Stream<Path> silentWalk(Path src) {
+ try {
+ return Files.walk(src).filter(Files :: isRegularFile);
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ void runTest(Stream<Path> inputs) {
+ JavacTool tool = JavacTool.create();
+ try (JavacFileManager fm = tool.getStandardFileManager(null, null, null)) {
+ Path classes = Paths.get(System.getProperty("test.classes"));
+ Iterable<? extends JavaFileObject> reconFiles =
+ fm.getJavaFileObjectsFromFiles(inputs.sorted().map(p -> p.toFile()) :: iterator);
+ List<String> options = Arrays.asList("-classpath", classes.toAbsolutePath().toString());
+ JavacTask reconTask = tool.getTask(null, fm, null, options, null, reconFiles);
+ Iterable<? extends CompilationUnitTree> reconUnits = reconTask.parse();
+ JavacTrees reconTrees = JavacTrees.instance(reconTask);
+ SearchAnnotations scanner = new SearchAnnotations(reconTrees,
+ reconTask.getElements());
+ List<JavaFileObject> 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<Dependencies>) TestDependencies :: new);
+ }
+
+ public TestDependencies(Context context) {
+ super(context);
+ }
+
+ final Stack<PhaseDescription> inProcess = new Stack<>();
+
+ String topLevelMemberEnter;
+ Map<String, Set<PhaseDescription>> 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<PhaseDescription> 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<Void, Void> {
+ final Trees trees;
+ final Elements elements;
+ final TypeElement triggersCompleteAnnotation;
+ final TypeElement triggersCompleteRepeatAnnotation;
+ final Map<String, Set<PhaseDescription>> 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<PhaseDescription> 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<AnnotationMirror> 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<AnnotationMirror>) findAttribute(am, "value").getValue();
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ AnnotationValue findAttribute(AnnotationMirror mirror, String name) {
+ for (Entry<? extends ExecutableElement, ? extends AnnotationValue> 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<Void, Void> {
+ final SourcePositions positions;
+ final List<int[]> 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;
+ }
+
+ }
+}
+
+
--- /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;
+ }
+
+}
--- /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();
+}
--- /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();
+}
--- /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 { }
+ }
+}
--- /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<X extends Bar> extends Sup {
+}
+class Bar {
+}
+class Sup {
+}
--- /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;
+ }
+ }
+}
--- /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 {}
--- /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<X extends Inner> { static class Inner {} }
+}
+
--- /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<X extends Inner> { static class Inner {} }
+}
+
--- /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<X extends Inner> extends B { }
+}
+
+class B {
+ static class Inner {}
+}
--- 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 {
--- 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;
}
--- 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<PackageSymbol> packages = new ArrayList<PackageSymbol>();
int nextPackageSerial;