📄 attr.java
字号:
/**
* @(#)Attr.java 1.93 03/01/23
*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package com.sun.tools.javac.v8.comp;
import com.sun.tools.javac.v8.util.*;
import com.sun.tools.javac.v8.code.*;
import com.sun.tools.javac.v8.tree.*;
import com.sun.tools.javac.v8.code.Symbol.*;
import com.sun.tools.javac.v8.tree.Tree.*;
import com.sun.tools.javac.v8.code.Type.*;
/**
* This is the main context-dependent analysis phase in GJC. It
* encompasses name resolution, type checking and constant folding as
* subtasks. Some subtasks involve auxiliary classes.
* @see Check
* @see Resolve
* @see ConstFold
* @see Infer
*/
public class Attr extends Tree.Visitor implements Flags, Kinds, TypeTags {
private static final Context.Key attrKey = new Context.Key();
private Name.Table names;
private Log log;
private Symtab syms;
private Resolve rs;
private Check chk;
private TreeMaker make;
private ConstFold cfolder;
private Enter enter;
private TreeInfo treeinfo;
private Target target;
public static Attr instance(Context context) {
Attr instance = (Attr) context.get(attrKey);
if (instance == null)
instance = new Attr(context);
return instance;
}
private Attr(Context context) {
super();
context.put(attrKey, this);
names = Name.Table.instance(context);
log = Log.instance(context);
syms = Symtab.instance(context);
rs = Resolve.instance(context);
chk = Check.instance(context);
make = TreeMaker.instance(context);
enter = Enter.instance(context);
cfolder = ConstFold.instance(context);
treeinfo = TreeInfo.instance(context);
target = Target.instance(context);
Options options = Options.instance(context);
retrofit = options.get("-retrofit") != null;
}
/**
* Switch: retrofit mode?
*/
boolean retrofit;
/**
* Check kind and type of given tree against protokind and prototype.
* If check succeeds, store type in tree and return it.
* If check fails, store errType in tree and return it.
* No checks are performed if the prototype is a method type.
* Its not necessary in this case since we know that kind and type
* are correct.
*
* @param tree The tree whose kind and type is checked
* @param owntype The computed type of the tree
* @param ownkind The computed kind of the tree
* @param pkind The expected kind (or: protokind) of the tree
* @param pt The expected type (or: prototype) of the tree
*/
Type check(Tree tree, Type owntype, int ownkind, int pkind, Type pt) {
if (owntype.tag != ERROR && pt.tag != METHOD) {
if ((ownkind & ~pkind) == 0) {
owntype = chk.checkType(tree.pos, owntype, pt);
} else {
log.error(tree.pos, "unexpected.type", Resolve.kindNames(pkind),
Resolve.kindName(ownkind));
owntype = syms.errType;
}
}
tree.type = owntype;
return owntype;
}
/**
* Is given blank final variable assignable, i.e. in a scope where it
* may be assigned to even though it is final?
* @param v The blank final variable.
* @param env The current environment.
*/
boolean isAssignableAsBlankFinal(VarSymbol v, Env env) {
Symbol owner = ((AttrContext) env.info).scope.owner;
return v.owner == owner || ((owner.name == names.init || owner.kind == VAR ||
(owner.flags() & BLOCK) != 0) && v.owner == owner.owner &&
((v.flags() & STATIC) != 0) == Resolve.isStatic(env));
}
/**
* Check that variable can be assigned to.
* @param pos The current source code position.
* @param v The assigned varaible
* @param base If the variable is referred to in a Select, the part
* to the left of the `.', null otherwise.
* @env The current environment.
*/
void checkAssignable(int pos, VarSymbol v, Tree base, Env env) {
if ((v.flags() & FINAL) != 0 && ((v.flags() & HASINIT) != 0 ||
!((base == null ||
(base.tag == Tree.IDENT && TreeInfo.name(base) == names._this))
&& isAssignableAsBlankFinal(v, env)))) {
log.error(pos, "cant.assign.val.to.final.var", v.toJava());
}
}
/**
* Does tree represent a static reference to an identifier?
* It is assumed that tree is either a SELECT or an IDENT.
* We have to weed out selects from non-type names here.
* @param tree The candidate tree.
*/
boolean isStaticReference(Tree tree) {
if (tree.tag == Tree.SELECT) {
Symbol lsym = TreeInfo.symbol(((Select) tree).selected);
if (lsym == null || lsym.kind != TYP) {
return false;
}
}
return true;
}
/**
* Is this symbol a type?
*/
static boolean isType(Symbol sym) {
return sym != null && sym.kind == TYP;
}
/**
* The current `this' symbol.
* @param env The current environment.
*/
Symbol thisSym(Env env) {
return rs.resolveSelf(Position.NOPOS, env, env.enclClass.sym, names._this);
}
/**
* Visitor argument: the current environment.
*/
Env env;
/**
* Visitor argument: the currently expected proto-kind.
*/
int pkind;
/**
* Visitor argument: the currently expected proto-type.
*/
Type pt;
/**
* Visitor result: the computed type.
*/
Type result;
/**
* Visitor method: attribute a tree, catching any completion failure
* exceptions. Return the tree's type.
*
* @param tree The tree to be visited.
* @param env The environment visitor argument.
* @param pkind The protokind visitor argument.
* @param pt The prototype visitor argument.
*/
Type attribTree(Tree tree, Env env, int pkind, Type pt) {
Env prevEnv = this.env;
int prevPkind = this.pkind;
Type prevPt = this.pt;
try {
this.env = env;
this.pkind = pkind;
this.pt = pt;
tree.accept(this);
return result;
} catch (CompletionFailure ex) {
tree.type = syms.errType;
return chk.completionError(tree.pos, ex);
}
finally { this.env = prevEnv;
this.pkind = prevPkind;
this.pt = prevPt;
} }
/**
* Derived visitor method: attribute an expression tree.
*/
Type attribExpr(Tree tree, Env env, Type pt) {
return attribTree(tree, env, VAL, pt);
}
/**
* Derived visitor method: attribute an expression tree with
* no constraints on the computed type.
*/
Type attribExpr(Tree tree, Env env) {
return attribTree(tree, env, VAL, Type.noType);
}
/**
* Derived visitor method: attribute a type tree.
*/
Type attribType(Tree tree, Env env) {
return attribTree(tree, env, TYP, Type.noType);
}
/**
* Derived visitor method: attribute a statement or definition tree.
*/
Type attribStat(Tree tree, Env env) {
return attribTree(tree, env, NIL, Type.noType);
}
/**
* Attribute a list of expressions, returning a list of types.
*/
List attribExprs(List trees, Env env, Type pt) {
ListBuffer ts = new ListBuffer();
for (List l = trees; l.nonEmpty(); l = l.tail)
ts.append(attribExpr((Tree) l.head, env, pt));
return ts.toList();
}
/**
* Attribute a list of statements, returning nothing.
*/
void attribStats(List trees, Env env) {
for (List l = trees; l.nonEmpty(); l = l.tail)
attribStat((Tree) l.head, env);
}
/**
* Attribute the arguments in a method call, returning a list of types.
*/
List attribArgs(List trees, Env env) {
ListBuffer argtypes = new ListBuffer();
for (List l = trees; l.nonEmpty(); l = l.tail)
argtypes.append( chk.checkNonVoid(((Tree) l.head).pos,
attribTree((Tree) l.head, env, VAL, Infer.anyPoly)));
return argtypes.toList();
}
/**
* Attribute type reference in an `extends' or `implements' clause.
*
* @param tree The tree making up the type reference.
* @param env The environment current at the reference.
* @param classExpected true if only a class is expected here.
* @param interfaceExpected true if only an interface is expected here.
*/
Type attribBase(Tree tree, Env env, boolean classExpected,
boolean interfaceExpected) {
Type t = attribType(tree, env);
t = chk.checkClassType(tree.pos, t);
if (interfaceExpected & (t.tsym.flags() & INTERFACE) == 0) {
log.error(tree.pos, "intf.expected.here");
return syms.errType;
} else if (classExpected & (t.tsym.flags() & INTERFACE) != 0) {
log.error(tree.pos, "no.intf.expected.here");
return syms.errType;
}
if ((t.tsym.flags() & FINAL) != 0) {
log.error(tree.pos, "cant.inherit.from.final", t.tsym.toJava());
}
return t;
}
public void visitClassDef(ClassDef tree) {
if ((((AttrContext) env.info).scope.owner.kind & (VAR | MTH)) != 0)
enter.classEnter(tree, env);
ClassSymbol c = tree.sym;
if (c == null) {
result = null;
} else {
c.complete();
if (((AttrContext) env.info).isSelfCall &&
env.tree.tag == Tree.NEWCLASS &&
((NewClass) env.tree).encl == null) {
c.flags_field |= NOOUTERTHIS;
}
attribClass(tree.pos, c);
result = tree.type = c.type;
}
}
public void visitMethodDef(MethodDef tree) {
MethodSymbol m = tree.sym;
chk.checkOverride(tree, m);
Env localEnv = enter.methodEnv((MethodDef) tree, env);
for (List l = tree.params; l.nonEmpty(); l = l.tail)
attribStat((Tree) l.head, localEnv);
chk.validate(tree.restype);
for (List l = tree.thrown; l.nonEmpty(); l = l.tail)
chk.checkType(((Tree) l.head).pos, ((Tree) l.head).type,
syms.throwableType);
ClassSymbol owner = env.enclClass.sym;
if (tree.body == null) {
if ((owner.flags() & INTERFACE) == 0 &&
(tree.flags & (ABSTRACT | NATIVE)) == 0 && !retrofit)
log.error(tree.pos, "missing.meth.body.or.decl.abstract");
} else if ((owner.flags() & INTERFACE) != 0) {
log.error(tree.body.pos, "intf.meth.cant.have.body");
} else if ((tree.flags & ABSTRACT) != 0) {
log.error(tree.pos, "abstract.meth.cant.have.body");
} else if ((tree.flags & NATIVE) != 0) {
log.error(tree.pos, "native.meth.cant.have.body");
} else {
if (tree.name == names.init && owner.type != syms.objectType) {
Block body = tree.body;
if (body.stats.isEmpty() ||
!TreeInfo.isSelfCall((Tree) body.stats.head)) {
body.stats = body.stats.prepend(
enter.SuperCall(make.at(body.pos), VarDef.emptyList,
false));
}
}
attribStat(tree.body, localEnv);
}
((AttrContext) localEnv.info).scope.leave();
result = tree.type = m.type;
}
public void visitVarDef(VarDef tree) {
if (((AttrContext) env.info).scope.owner.kind == MTH)
enter.phase2.memberEnter(tree, env);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -