📄 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 + -