/*
* Copyright 2008-2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.visage.tools.comp;
import com.sun.tools.mjavac.code.*;
import com.sun.tools.mjavac.jvm.*;
import com.sun.tools.mjavac.util.*;
import com.sun.tools.mjavac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.mjavac.code.Symbol.*;
import com.sun.tools.mjavac.code.Type.*;
import static com.sun.tools.mjavac.code.Flags.*;
import static com.sun.tools.mjavac.code.Kinds.*;
import static com.sun.tools.mjavac.code.TypeTags.*;
import org.visage.tools.tree.*;
import org.visage.tools.code.VisageClassSymbol;
import org.visage.tools.code.VisageFlags;
import org.visage.tools.code.VisageSymtab;
import org.visage.tools.code.VisageTypes;
import org.visage.tools.code.VisageVarSymbol;
import org.visage.tools.util.MsgSym;
import javax.tools.JavaFileObject;
import java.util.Set;
import java.util.HashSet;
/**
* Add local declarations to current environment.
* The main entry point is {@code memberEnter}, which is called from
* {@link VisageAttr} when {@code visit}-ing a tree that contains local
* declarations.
*
* <p><b>This is NOT part of any API supported by Sun Microsystems. 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 VisageMemberEnter extends VisageTreeScanner implements VisageVisitor, Completer {
protected static final Context.Key<VisageMemberEnter> visageMemberEnterKey =
new Context.Key<VisageMemberEnter>();
protected final static boolean checkClash = true;
private final Name.Table names;
private final VisageEnter enter;
private final Log log;
private final VisageCheck chk;
private final VisageAttr attr;
private final VisageSymtab syms;
private final VisageTreeMaker visagemake;
private final ClassReader reader;
private final VisageTodo todo;
private final VisageAnnotate annotate;
private final VisageTypes types;
private final Target target;
private final VisageBoundContextAnalysis boundAnalysis;
public static VisageMemberEnter instance(Context context) {
VisageMemberEnter instance = context.get(visageMemberEnterKey);
if (instance == null) {
instance = new VisageMemberEnter(context);
}
return instance;
}
protected VisageMemberEnter(Context context) {
context.put(visageMemberEnterKey, this);
names = Name.Table.instance(context);
enter = VisageEnter.instance(context);
log = Log.instance(context);
chk = (VisageCheck) VisageCheck.instance(context);
attr = VisageAttr.instance(context);
syms = (VisageSymtab) VisageSymtab.instance(context);
visagemake = (VisageTreeMaker) VisageTreeMaker.instance(context);
reader = VisageClassReader.instance(context);
boundAnalysis = VisageBoundContextAnalysis.instance(context);
todo = VisageTodo.instance(context);
annotate = VisageAnnotate.instance(context);
types = VisageTypes.instance(context);
target = Target.instance(context);
}
/** A queue for classes whose members still need to be entered into the
* symbol table.
*/
ListBuffer<VisageEnv<VisageAttrContext>> halfcompleted = new ListBuffer<VisageEnv<VisageAttrContext>>();
/** Set to true only when the first of a set of classes is
* processed from the halfcompleted 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 toScope The (import) scope in which imported classes
* are entered.
*/
void importAll(int pos,
final TypeSymbol tsym,
VisageEnv<VisageAttrContext> env) {
// Check that packages imported from exist (JLS ???).
if (tsym.kind == PCK && tsym.members().elems == null && !tsym.exists()) {
// If we can't find java.lang, exit immediately.
if (((PackageSymbol) tsym).fullname.equals(names.java_lang)) {
JCDiagnostic msg = JCDiagnostic.fragment(MsgSym.MESSAGE_FATAL_ERR_NO_JAVA_LANG);
throw new FatalError(msg);
} else {
log.error(pos, MsgSym.MESSAGE_DOES_NOT_EXIST, tsym);
}
}
final Scope fromScope = tsym.members();
final Scope toScope = env.toplevel.starImportScope;
for (Scope.Entry e = fromScope.elems; e != null; e = e.sibling) {
if (e.sym.kind == TYP && !toScope.includes(e.sym)) {
toScope.enter(e.sym, fromScope);
}
}
}
/** 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 toScope The (import) scope in which imported classes
* are entered.
*/
private void importStaticAll(int pos,
final TypeSymbol tsym,
VisageEnv<VisageAttrContext> env) {
final JavaFileObject sourcefile = env.toplevel.sourcefile;
final Scope toScope = env.toplevel.starImportScope;
final PackageSymbol packge = env.toplevel.packge;
final TypeSymbol origin = tsym;
// enter imported types immediately
new Object() {
Set<Symbol> processed = new HashSet<Symbol>();
void importFrom(TypeSymbol tsym) {
if (tsym == null || !processed.add(tsym)) {
return;
}
if (tsym instanceof ClassSymbol) {
// also import inherited names
if (tsym instanceof VisageClassSymbol) {
for (Type superType : types.supertypes(tsym.type)) {
importFrom(superType.tsym);
}
} else {
importFrom(types.supertype(tsym.type).tsym);
}
for (Type t : types.interfaces(tsym.type)) {
importFrom(t.tsym);
}
}
final Scope fromScope = tsym.members();
for (Scope.Entry e = fromScope.elems; e != null; e = e.sibling) {
Symbol sym = e.sym;
if (sym.kind == TYP
&& (sym.flags() & STATIC) != 0
&& staticImportAccessible(sym, packge)
&& sym.isMemberOf(origin, types)
&& !toScope.includes(sym)) {
toScope.enter(sym, fromScope, origin.members());
}
}
}
}.importFrom(tsym);
// enter non-types before annotations that might use them
annotate.earlier(new VisageAnnotate.Annotator() {
Set<Symbol> processed = new HashSet<Symbol>();
@Override
public String toString() {
return "import static " + tsym + ".*" + " in " + sourcefile;
}
void importFrom(TypeSymbol tsym) {
if (tsym == null || !processed.add(tsym)) {
return;
}
if (tsym instanceof ClassSymbol) {
// also import inherited names
if (tsym instanceof VisageClassSymbol) {
for (Type superType : types.supertypes(tsym.type)) {
importFrom(superType.tsym);
}
} else {
importFrom(types.supertype(tsym.type).tsym);
}
for (Type t : types.interfaces(tsym.type)) {
importFrom(t.tsym);
}
}
final Scope fromScope = tsym.members();
for (Scope.Entry e = fromScope.elems; e != null; e = e.sibling) {
Symbol sym = e.sym;
if (sym.isStatic() && sym.kind != TYP
&& staticImportAccessible(sym, packge)
&& !toScope.includes(sym)
&& sym.isMemberOf(origin, types)) {
toScope.enter(sym, fromScope, origin.members());
}
}
}
public void enterAnnotation() {
importFrom(tsym);
}
});
}
// is the sym accessible everywhere in packge?
boolean staticImportAccessible(Symbol sym, PackageSymbol packge) {
// because the PACKAGE_ACCESS bit is too high for the switch, test it later
int flags = (short) (sym.flags() & Flags.AccessFlags);
switch (flags) {
default:
case PUBLIC:
return true;
case PRIVATE:
return false;
case 0:
// 'package' vs script-private
return (flags & VisageFlags.SCRIPT_PRIVATE) == 0;
case PROTECTED:
return sym.packge() == packge;
}
}
/** 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 VisageEnv<VisageAttrContext> env) {
if (tsym.kind != TYP) {
log.error(pos, MsgSym.MESSAGE_STATIC_IMP_ONLY_CLASSES_AND_INTERFACES);
return;
}
final Scope toScope = env.toplevel.namedImportScope;
final PackageSymbol packge = env.toplevel.packge;
final TypeSymbol origin = tsym;
// enter imported types immediately
new Object() {
Set<Symbol> processed = new HashSet<Symbol>();
void importFrom(TypeSymbol tsym) {
if (tsym == null || !processed.add(tsym)) {
return;
}
// also import inherited names
if (tsym instanceof VisageClassSymbol) {
for (Type superType : types.supertypes(tsym.type)) {
importFrom(superType.tsym);
}
} else {
importFrom(types.supertype(tsym.type).tsym);
}
for (Type t : types.interfaces(tsym.type)) {
importFrom(t.tsym);
}
for (Scope.Entry e = tsym.members().lookup(name);
e.scope != null;
e = e.next()) {
Symbol sym = e.sym;
if (sym.isStatic()
&& sym.kind == TYP
&& staticImportAccessible(sym, packge)
&& sym.isMemberOf(origin, types)
&& chk.checkUniqueStaticImport(pos, sym, toScope)) {
toScope.enter(sym, sym.owner.members(), origin.members());
}
}
}
}.importFrom(tsym);
// enter non-types before annotations that might use them
annotate.earlier(new VisageAnnotate.Annotator() {
Set<Symbol> processed = new HashSet<Symbol>();
boolean found = false;
@Override
public String toString() {
return "import static " + tsym + "." + name;
}
void importFrom(TypeSymbol tsym) {
if (tsym == null || !processed.add(tsym)) {
return;
}
// also import inherited names
if (tsym instanceof VisageClassSymbol) {
for (Type superType : types.supertypes(tsym.type)) {
importFrom(superType.tsym);
}
} else {
importFrom(types.supertype(tsym.type).tsym);
}
for (Type t : types.interfaces(tsym.type)) {
importFrom(t.tsym);
}
for (Scope.Entry e = tsym.members().lookup(name);
e.scope != null;
e = e.next()) {
Symbol sym = e.sym;
if (sym.isStatic()
&& staticImportAccessible(sym, packge)
&& sym.isMemberOf(origin, types)) {
found = true;
if (sym.kind == MTH
|| sym.kind != TYP && chk.checkUniqueStaticImport(pos, sym, toScope)) {
toScope.enter(sym, sym.owner.members(), origin.members());
}
}
}
}
public void enterAnnotation() {
JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
try {
importFrom(tsym);
if (!found) {
log.error(pos, MsgSym.MESSAGE_CANNOT_RESOLVE_LOCATION,
JCDiagnostic.fragment(MsgSym.KINDNAME_STATIC),
name, "", "", VisageResolve.typeKindName(tsym.type),
tsym.type);
}
} finally {
log.useSource(prev);
}
}
});
}
/** 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.
*/
void importNamed(DiagnosticPosition pos, Symbol tsym, VisageEnv<VisageAttrContext> env) {
if (tsym.kind == TYP
&& chk.checkUniqueImport(pos, tsym, env.toplevel.namedImportScope)) {
env.toplevel.namedImportScope.enter(tsym, tsym.owner.members());
}
}
private static void importNamed(Symbol tsym, Scope scope) {
scope.enter(tsym, tsym.owner.members());
}
public static void importPredefs(VisageSymtab syms, Scope scope) {
// Import-on-demand the Visage types
importNamed(syms.objectType.tsym, scope);
importNamed(syms.visage_BooleanType.tsym, scope);
importNamed(syms.visage_CharacterType.tsym, scope);
importNamed(syms.visage_ByteType.tsym, scope);
importNamed(syms.visage_ShortType.tsym, scope);
importNamed(syms.visage_IntegerType.tsym, scope);
importNamed(syms.visage_LongType.tsym, scope);
importNamed(syms.visage_FloatType.tsym, scope);
importNamed(syms.visage_DoubleType.tsym, scope);
importNamed(syms.visage_StringType.tsym, scope);
importNamed(syms.visage_DurationType.tsym, scope);
importNamed(syms.visage_LengthType.tsym, scope);
importNamed(syms.visage_AngleType.tsym, scope);
importNamed(syms.visage_ColorType.tsym, scope);
importNamed(syms.visage_RuntimeType.tsym, scope);
}
/* ********************************************************************
* Visitor methods for member enter
*********************************************************************/
/** Visitor argument: the current environment
*/
protected VisageEnv<VisageAttrContext> env;
/** Enter field and method definitions and process import
* clauses, catching any completion failure exceptions.
*/
void memberEnter(VisageTree tree, VisageEnv<VisageAttrContext> env) {
VisageEnv<VisageAttrContext> prevEnv = this.env;
try {
this.env = env;
if (tree != null) {
tree.accept(this);
}
} catch (CompletionFailure ex) {
chk.completionError(tree.pos(), ex);
} finally {
this.env = prevEnv;
}
}
/** Enter members from a list of trees.
*/
void memberEnter(List<? extends VisageTree> trees, VisageEnv<VisageAttrContext> env) {
for (List<? extends VisageTree> l = trees; l.nonEmpty(); l = l.tail) {
memberEnter(l.head, env);
}
}
@Override
public void visitTree(VisageTree tree) {
if (tree instanceof VisageBlock) {
visitBlockExpression((VisageBlock) tree);
} else {
super.visitTree(tree); //super.visitTree is a no-op because scan is overridden!!
}
}
@Override
public void visitErroneous(VisageErroneous tree) {
memberEnter(tree.getErrorTrees(), env);
}
@Override
public void visitScript(VisageScript tree) {
if (tree.isEntered) {
// we must have already processed this toplevel
return;
}
tree.isEntered = true;
// check that no class exists with same fully qualified name as
// toplevel package
if (checkClash && tree.pid != null) {
Symbol p = tree.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,
MsgSym.MESSAGE_PKG_CLASHES_WITH_CLASS_OF_SAME_NAME,
p);
}
p = p.owner;
}
}
importStaticAll(-1, syms.visage_AutoImportRuntimeType.tsym, env);
// Process all import clauses.
memberEnter(tree.defs, env);
}
@Override
public void visitImport(VisageImport tree) {
VisageExpression imp = tree.qualid;
Name name = VisageTreeInfo.name(imp);
// Create a local environment pointing to this tree to disable
// effects of other imports in Resolve.findGlobalType
VisageEnv<VisageAttrContext> localEnv = env.dup(tree);
// Attribute qualifying package or class.
//
boolean all = false;
// Attribute qualifying package or class and all descendants
//
boolean allAndSundry = false;
if (imp instanceof VisageSelect) {
if (name == names.asterisk) {
all = true;
imp = ((VisageSelect) imp).getExpression();
} else if (name.contentEquals("**")) {
allAndSundry = true;
// TODO: Implement .**
// Just cause an assertion error so that we locate this code quickly
//
assert (allAndSundry == false);
}
}
if (all) {
TypeSymbol p = attr.attribTree(imp,
localEnv,
TYP | PCK,
Type.noType).tsym;
// Import on demand.
chk.checkCanonical(imp);
if (p instanceof ClassSymbol) {
importStaticAll(tree.pos, p, env);
} else {
importAll(tree.pos, p, env);
}
return;
} else if (imp instanceof VisageSelect) {
VisageSelect s = (VisageSelect) imp;
TypeSymbol p = attr.attribTree(s.selected,
localEnv,
(TYP | PCK),
Type.noType).tsym;
// Named type import.
if (p instanceof ClassSymbol) {
chk.checkCanonical(s.selected);
importNamedStatic(tree.pos(), p, name, localEnv);
return;
}
}
TypeSymbol c = attribImportType(imp, localEnv).tsym;
chk.checkCanonical(imp);
importNamed(tree.pos(), c, env);
}
/** Create a fresh environment for method bodies.
* @param tree The method definition.
* @param env The environment current outside of the method definition.
*/
public VisageEnv<VisageAttrContext> methodEnv(VisageFunctionDefinition tree, VisageEnv<VisageAttrContext> env) {
Scope localScope = new Scope(tree.sym);
localScope.next = env.info.scope;
VisageEnv<VisageAttrContext> localEnv =
env.dup(tree, env.info.dup(localScope));
localEnv.outer = env;
localEnv.enclFunction = tree;
if ((tree.mods.flags & STATIC) != 0) {
localEnv.info.staticLevel++;
}
return localEnv;
}
public VisageEnv<VisageAttrContext> getMethodEnv(VisageFunctionDefinition tree, VisageEnv<VisageAttrContext> env) {
VisageEnv<VisageAttrContext> mEnv = methodEnv(tree, env);
mEnv.info.lint = mEnv.info.lint.augment(tree.sym.attributes_field, tree.sym.flags());
for (List<VisageVar> l = tree.getParams(); l.nonEmpty(); l = l.tail) {
mEnv.info.scope.enterIfAbsent(l.head.sym);
}
return mEnv;
}
/** Create a fresh environment for a variable's initializer.
* If the variable is a field, the owner of the environment's scope
* is be the variable itself, otherwise the owner is the method
* enclosing the variable definition.
*
* @param tree The variable definition.
* @param env The environment current outside of the variable definition.
*/
public VisageEnv<VisageAttrContext> initEnv(VisageVar tree, VisageEnv<VisageAttrContext> env) {
VisageEnv<VisageAttrContext> localEnv = env.dupto(new VisageAttrContextEnv(tree, env.info.dup()));
if (tree.sym.isMember()) {
localEnv.info.scope = new Scope.DelegatedScope(env.info.scope);
localEnv.info.scope.owner = tree.sym;
}
if ((tree.mods.flags & STATIC) != 0
|| (env.enclClass.sym.flags() & INTERFACE) != 0) {
localEnv.info.staticLevel++;
}
return localEnv;
}
public VisageEnv<VisageAttrContext> getInitEnv(VisageVar tree, VisageEnv<VisageAttrContext> env) {
VisageEnv<VisageAttrContext> iEnv = initEnv(tree, env);
return iEnv;
}
@Override
public void scan(VisageTree tree) {
//do nothing!
}
private void addDefault(VisageAbstractVar tree) {
Scope enclScope = VisageEnter.enterScope(env);
if (enclScope.owner.kind == TYP && (tree.mods.flags & VisageFlags.DEFAULT) != 0) {
VisageClassSymbol owner = (VisageClassSymbol) enclScope.owner;
Name defaultVar = owner.getDefaultVar();
if (defaultVar != null) {
log.error(tree.pos, MsgSym.MESSAGE_VISAGE_MULTIPLE_DEFAULT_VARS, defaultVar, tree.name);
}
owner.setDefaultVar(tree.name);
}
}
@Override
public void visitOverrideClassVar(VisageOverrideClassVar tree) {
addDefault(tree);
}
@Override
public void visitVar(VisageVar tree) {
VisageEnv<VisageAttrContext> localEnv = env;
if ((tree.mods.flags & STATIC) != 0
|| (env.info.scope.owner.flags() & INTERFACE) != 0) {
localEnv = env.dup(tree, env.info.dup());
localEnv.info.staticLevel++;
}
Scope enclScope = VisageEnter.enterScope(env);
VisageVarSymbol v = new VisageVarSymbol(types, names, 0, tree.name, null, enclScope.owner);
if (enclScope.owner.kind == TYP) {
((VisageClassSymbol) enclScope.owner).addVar(v, (tree.mods.flags & STATIC) != 0);
}
addDefault(tree);
attr.varSymToTree.put(v, tree);
tree.sym = v;
SymbolCompleter completer = new SymbolCompleter();
completer.env = env;
completer.tree = tree;
completer.attr = attr;
v.completer = completer;
v.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, v, tree);
if (tree.getInitializer() != null) {
v.flags_field |= HASINIT;
}
if (tree.isBound()) {
v.flags_field |= VisageFlags.VARUSE_BOUND_INIT;
}
if (chk.checkUnique(tree.pos(), v, env)) {
chk.checkTransparentVar(tree.pos(), v, enclScope);
enclScope.enter(v);
}
v.pos = tree.pos;
}
static class SymbolCompleter implements Completer {
VisageEnv<VisageAttrContext> env;
VisageTree tree;
VisageAttr attr;
public void complete(Symbol m) throws CompletionFailure {
if (tree instanceof VisageVar) {
attr.finishVar((VisageVar) tree, env);
} else if (attr.pt != Type.noType) {
// finishOperationDefinition makes use of the expected type pt.
// This is useful when coming from visitFunctionValue - i.e.
// attributing an anonymous function. However, using the
// expected type from a random call-site (which can happen if
// we're called via complete) is a bit too flakey.
// (ML can do it, because they unify across all the call-sites.)
// This is a trick to run finishOperationDefinition, but in a
// context where we're cleared the expected type attr.pt.
m.completer = this;
attr.attribExpr(tree, env);
} else {
attr.finishFunctionDefinition((VisageFunctionDefinition) tree, env);
}
}
}
@Override
public void visitFunctionDefinition(VisageFunctionDefinition tree) {
// If the function defintion is contained within an Erroneous
// block, the enclosing scope may not be defined. In this case
// we do not enter the function into any scope as it belongs to
// the class and the tree is too erroneous to make any sense of
// it. Doing nothing is the best course of action as at worst
// other parst of the tree will complain that they don't know
// anything about this function. So, just try the operation, but
// forget about it if anything goes wrong...
//
// Note that it is only possible to get here with an erroneous tree
// if the IDE is calling the attribution, trying to work out what it has.
// We don't otherwise attribute erroneous trees, hence it is safe to
// ignore any exception. Further, the parser recovers sensibly from
// most class definition errors (an erroneous class containing a function
// definition is the most likely case to throw this method out), so the
// case is rare.
//
try {
Scope enclScope = VisageEnter.enterScope(env);
MethodSymbol m = new MethodSymbol(0, tree.name, null, enclScope.owner);
m.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, m, tree);
tree.sym = m;
enclScope.enter(m);
SymbolCompleter completer = new SymbolCompleter();
completer.env = env;
completer.tree = tree;
completer.attr = attr;
m.completer = completer;
attr.methodSymToTree.put(m, tree);
} catch (NullPointerException e) {
// Looks like we could not enter the function into any symbol
// table. Just ignore it.
}
}
// @Override
// public void visitClassDeclaration(VisageClassDeclaration that) {
// for (VisageExpression superClass : that.getSupertypes()) {
// attr.attribType(superClass, env);
// }
// }
/* ********************************************************************
* Type completion
*********************************************************************/
Type attribImportType(VisageTree tree, VisageEnv<VisageAttrContext> env) {
assert completionEnabled;
try {
// To prevent deep recursion, suppress completion of some
// types.
completionEnabled = false;
return attr.attribType(tree, env);
} finally {
completionEnabled = true;
}
}
/* ********************************************************************
* 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 (sym.flags() & Flags.COMPOUND) == 0;
sym.completer = this;
return;
}
ClassSymbol c = (ClassSymbol) sym;
ClassType ct = (ClassType) c.type;
VisageEnv<VisageAttrContext> localEnv = enter.typeEnvs.get(c);
VisageClassDeclaration tree = (VisageClassDeclaration) localEnv.tree;
boolean wasFirst = isFirst;
isFirst = false;
JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
try {
// Save class environment for later member enter (2) processing.
halfcompleted.append(localEnv);
// Mark class as not yet attributed.
c.flags_field |= UNATTRIBUTED;
// If this is a toplevel script-class, make sure any preceding import
// clauses have been seen.
if (c.owner.kind == PCK) {
memberEnter(localEnv.toplevel, localEnv.enclosing(VisageTag.TOPLEVEL));
todo.append(localEnv);
}
if (c.owner.kind == TYP) {
c.owner.complete();
}
boundAnalysis.analyzeBindContexts(localEnv);
// create an environment for evaluating the base clauses
VisageEnv<VisageAttrContext> baseEnv = baseEnv(tree, localEnv);
Type supertype = null;
ListBuffer<Type> interfaces = new ListBuffer<Type>();
Set<Type> interfaceSet = new HashSet<Type>();
Set<Type> mixinSet = new HashSet<Type>();
{
ListBuffer<VisageExpression> extending = ListBuffer.<VisageExpression>lb();
ListBuffer<VisageExpression> implementing = ListBuffer.<VisageExpression>lb();
ListBuffer<VisageExpression> mixing = ListBuffer.<VisageExpression>lb();
for (VisageExpression stype : tree.getSupertypes()) {
Type st = attr.attribType(stype, localEnv);
if (st.isInterface()) {
implementing.append(stype);
} else {
long flags = st.tsym.flags_field;
boolean isMixin = (flags & VisageFlags.MIXIN) != 0;
if (isMixin) {
mixing.append(stype);
chk.checkNotRepeated(stype.pos(), types.erasure(st), mixinSet);
} else {
supertype = extending.isEmpty() ? st : null;
extending.append(stype);
}
interfaces.append(st);
}
}
if ((sym.flags() & VisageFlags.MIXIN) != 0) {
c.flags_field |= VisageFlags.MIXIN;
}
tree.setDifferentiatedExtendingImplementingMixing(extending.toList(), implementing.toList(), mixing.toList());
}
if (supertype == null) {
if (c.fullname == names.java_lang_Object) {
supertype = Type.noType;
} else {
supertype = syms.visage_BaseType;
}
}
ct.supertype_field = supertype;
// Determine interfaces.
List<VisageExpression> interfaceTrees = tree.getImplementing();
if ((tree.mods.flags & Flags.ENUM) != 0 && target.compilerBootstrap(c)) {
// add interface Comparable<T>
interfaceTrees =
interfaceTrees.prepend(visagemake.Type(new ClassType(syms.comparableType.getEnclosingType(),
List.of(c.type),
syms.comparableType.tsym)));
// add interface Serializable
interfaceTrees =
interfaceTrees.prepend(visagemake.Type(syms.serializableType));
}
for (VisageExpression iface : interfaceTrees) {
Type i = attr.attribBase(iface, baseEnv, false, true, true);
if (i.tag == CLASS) {
interfaces.append(i);
chk.checkNotRepeated(iface.pos(), types.erasure(i), interfaceSet);
}
}
if ((c.flags_field & ANNOTATION) != 0) {
ct.interfaces_field = List.of(syms.annotationType);
} else {
ct.interfaces_field = interfaces.toList();
}
if (c.fullname == names.java_lang_Object) {
if (tree.getExtending().head != null) {
chk.checkNonCyclic(tree.getExtending().head.pos(),
supertype);
ct.supertype_field = Type.noType;
} else if (tree.getImplementing().nonEmpty()) {
chk.checkNonCyclic(tree.getImplementing().head.pos(),
ct.interfaces_field.head);
ct.interfaces_field = List.nil();
}
}
chk.checkNonCyclic(tree.pos(), c.type);
// If this is a class, enter symbols for this and super into
// current scope.
if ((c.flags_field & INTERFACE) == 0) {
VisageVarSymbol thisSym = visagemake.ThisSymbol(c.type);
thisSym.pos = Position.FIRSTPOS;
localEnv.info.scope.enter(thisSym);
if (ct.supertype_field.tag == CLASS && supertype != null) {
VisageVarSymbol superSym = visagemake.SuperSymbol(supertype, c);
superSym.pos = Position.FIRSTPOS;
localEnv.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
&& reader.packageExists(c.fullname)) {
log.error(tree.pos, MsgSym.MESSAGE_CLASH_WITH_PKG_OF_SAME_NAME, c);
}
} catch (CompletionFailure ex) {
chk.completionError(tree.pos(), ex);
} finally {
log.useSource(prev);
}
// Enter all member fields and methods of a set of half completed
// classes in a second phase.
if (wasFirst) {
try {
while (halfcompleted.nonEmpty()) {
finish(halfcompleted.next());
}
} finally {
isFirst = true;
}
// commit pending annotations
annotate.flush();
}
}
private VisageEnv<VisageAttrContext> baseEnv(VisageClassDeclaration tree, VisageEnv<VisageAttrContext> env) {
Scope typaramScope = new Scope(tree.sym);
VisageEnv<VisageAttrContext> outer = env.outer; // the base clause can't see members of this class
VisageEnv<VisageAttrContext> localEnv = outer.dup(tree, outer.info.dup(typaramScope));
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(VisageEnv<VisageAttrContext> env) {
JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
try {
VisageClassDeclaration tree = (VisageClassDeclaration) env.tree;
memberEnter(tree.getMembers(), env);
} finally {
log.useSource(prev);
}
}
}