📄 attr.java
字号:
Type site = env.enclClass.sym.type;
if (methName == names._super)
site = site.supertype();
if (site.tag == CLASS) {
if (site.outer().tag == CLASS) {
if (tree.meth.tag == Tree.SELECT) {
Tree qualifier = ((Select) tree.meth).selected;
chk.checkRefType(qualifier.pos,
attribExpr(qualifier, localEnv, site.outer()));
} else if (methName == names._super) {
rs.resolveImplicitThis(tree.meth.pos, localEnv, site);
}
} else if (tree.meth.tag == Tree.SELECT) {
log.error(tree.meth.pos, "illegal.qual.not.icls",
site.tsym.toJava());
}
boolean selectSuperPrev =
((AttrContext) localEnv.info).selectSuper;
((AttrContext) localEnv.info).selectSuper = true;
Symbol sym = rs.resolveConstructor(tree.meth.pos, localEnv, site,
argtypes);
((AttrContext) localEnv.info).selectSuper = selectSuperPrev;
TreeInfo.setSymbol(tree.meth, sym);
List saved = methTemplateSupply.elems;
Type mpt = newMethTemplate(argtypes);
checkId(tree.meth, site, sym, env, MTH, mpt);
methTemplateSupply.elems = saved;
}
}
result = syms.voidType;
} else {
argtypes = attribArgs(tree.args, localEnv);
List saved = methTemplateSupply.elems;
Type mpt = newMethTemplate(argtypes);
Type mtype = attribExpr(tree.meth, localEnv, mpt);
methTemplateSupply.elems = saved;
result = check(tree, mtype.restype(), VAL, pkind, pt);
}
}
/**
* Check that given application node appears as first statement
* in a constructor call.
* @param tree The application node
* @param env The environment current at the application.
*/
boolean checkFirstConstructorStat(Apply tree, Env env) {
MethodDef enclMethod = env.enclMethod;
if (enclMethod != null && enclMethod.name == names.init) {
Block body = (Block) enclMethod.body;
if (((Tree) body.stats.head).tag == Tree.EXEC &&
((Exec) body.stats.head).expr == tree)
return true;
}
log.error(tree.pos, "call.must.be.first.stmt.in.ctor",
TreeInfo.name(tree.meth).toJava());
return false;
}
/**
* Optimization: To avoid allocating a new methodtype for every
* attribution of an Apply node, we use a reservoir.
*/
ListBuffer methTemplateSupply = new ListBuffer();
/**
* Obtain an otherwise unused method type with given argument types.
* Take it from the reservoir if non-empty, or create a new one.
*/
Type newMethTemplate(List argtypes) {
if (methTemplateSupply.elems == methTemplateSupply.last)
methTemplateSupply.append(
new MethodType(null, null, null, syms.methodClass));
MethodType mt = (Type.MethodType) methTemplateSupply.elems.head;
methTemplateSupply.elems = methTemplateSupply.elems.tail;
mt.argtypes = argtypes;
return mt;
}
public void visitNewClass(NewClass tree) {
Type owntype = syms.errType;
ClassDef cdef = tree.def;
Tree clazz = tree.clazz;
Tree clazzid = clazz;
Tree clazzid1 = clazzid;
if (tree.encl != null) {
Type encltype =
chk.checkRefType(tree.encl.pos, attribExpr(tree.encl, env));
clazzid1 = make.at(clazz.pos).Select(make.Type(encltype),
((Ident) clazzid).name);
clazz = clazzid1;
}
Type clazztype = chk.checkClassType(tree.clazz.pos, attribType(clazz, env));
chk.validate(clazz);
if (tree.encl != null) {
tree.clazz.type = clazztype;
TreeInfo.setSymbol(clazzid, TreeInfo.symbol(clazzid1));
clazzid.type = ((Ident) clazzid).sym.type;
if ((clazztype.tsym.flags() & STATIC) != 0 && !clazztype.isErroneous()) {
log.error(tree.pos, "qualified.new.of.static.class",
clazztype.tsym.toJava());
}
} else if ((clazztype.tsym.flags() & INTERFACE) == 0 &&
clazztype.outer().tag == CLASS) {
rs.resolveImplicitThis(tree.pos, env, clazztype);
}
List argtypes = attribArgs(tree.args, env);
if (clazztype.tag == CLASS) {
if (cdef == null &&
(clazztype.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) {
log.error(tree.pos, "abstract.cant.be.instantiated",
clazztype.tsym.toJava());
} else if (cdef != null && (clazztype.tsym.flags() & INTERFACE) != 0) {
if (argtypes.nonEmpty()) {
log.error(tree.pos, "anon.class.impl.intf.no.args");
argtypes = Type.emptyList;
} else if (tree.encl != null) {
log.error(tree.pos, "anon.class.impl.intf.no.qual.for.new");
}
} else {
boolean selectSuperPrev = ((AttrContext) env.info).selectSuper;
if (cdef != null)
((AttrContext) env.info).selectSuper = true;
tree.constructor =
rs.resolveConstructor(tree.pos, env, clazztype, argtypes);
((AttrContext) env.info).selectSuper = selectSuperPrev;
}
if (cdef != null) {
if (Resolve.isStatic(env))
cdef.flags |= STATIC;
if ((clazztype.tsym.flags() & INTERFACE) != 0) {
cdef.implementing = List.make(clazz);
} else {
cdef.extending = clazz;
}
attribStat(cdef, env.dup(tree));
if (tree.encl != null) {
tree.args = tree.args.prepend(makeNullCheck(tree.encl));
argtypes = argtypes.prepend(tree.encl.type);
tree.encl = null;
}
clazztype = cdef.sym.type;
tree.constructor =
rs.resolveConstructor(tree.pos, env, clazztype, argtypes);
}
if (tree.constructor != null && tree.constructor.kind == MTH) {
owntype = clazztype;
}
}
result = check(tree, owntype, VAL, pkind, pt);
}
/**
* Make an attributed null check tree.
*/
public Tree makeNullCheck(Tree arg) {
Name name = TreeInfo.name(arg);
if (name == names._this || name == names._super)
return arg;
int optag = Tree.NULLCHK;
Unary tree = make.at(arg.pos).Unary(optag, arg);
tree.operator = syms.nullcheck;
tree.type = arg.type;
return tree;
}
public void visitNewArray(NewArray tree) {
Type owntype = syms.errType;
Type elemtype;
if (tree.elemtype != null) {
elemtype = attribType(tree.elemtype, env);
chk.validate(tree.elemtype);
owntype = elemtype;
for (List l = tree.dims; l.nonEmpty(); l = l.tail) {
attribExpr((Tree) l.head, env, syms.intType);
owntype = new ArrayType(owntype, syms.arrayClass);
}
} else {
if (pt.tag == ARRAY) {
elemtype = pt.elemtype();
} else {
if (pt.tag != ERROR) {
log.error(tree.pos, "illegal.initializer.for.type", pt.toJava());
}
elemtype = syms.errType;
}
}
if (tree.elems != null) {
attribExprs(tree.elems, env, elemtype);
owntype = new ArrayType(elemtype, syms.arrayClass);
}
result = check(tree, owntype, VAL, pkind, pt);
}
public void visitParens(Parens tree) {
Type owntype = attribTree(tree.expr, env, pkind, pt);
result = check(tree, owntype, pkind, pkind, pt);
Symbol sym = TreeInfo.symbol(tree);
if (isType(sym)) {
log.error(tree.pos, "illegal.start.of.expr");
}
}
public void visitAssign(Assign tree) {
Type owntype = attribTree(tree.lhs, env.dup(tree), VAR, pt);
attribExpr(tree.rhs, env, owntype);
result = check(tree, owntype, VAL, pkind, pt);
}
public void visitAssignop(Assignop tree) {
List argtypes = List.make(attribTree(tree.lhs, env, VAR, Type.noType),
attribExpr(tree.rhs, env));
Symbol operator = tree.operator =
rs.resolveOperator(tree.pos, tree.tag - Tree.ASGOffset, env,
argtypes);
Type owntype = (Type) argtypes.head;
if (operator.kind == MTH) {
if (owntype.tag <= DOUBLE)
chk.checkCastable(tree.rhs.pos, operator.type.restype(), owntype);
else if (owntype.tag == CLASS)
chk.checkType(tree.lhs.pos, owntype, syms.stringType);
else
chk.checkType(tree.rhs.pos, operator.type.restype(), owntype);
}
result = check(tree, owntype, VAL, pkind, pt);
}
public void visitUnary(Unary tree) {
Type argtype = (Tree.PREINC <= tree.tag && tree.tag <= Tree.POSTDEC) ?
attribTree(tree.arg, env, VAR, Type.noType) :
chk.checkNonVoid(tree.arg.pos, attribExpr(tree.arg, env));
Symbol operator = tree.operator =
rs.resolveUnaryOperator(tree.pos, tree.tag, env, argtype);
Type owntype = syms.errType;
if (operator.kind == MTH) {
owntype = operator.type.restype();
int opc = ((OperatorSymbol) operator).opcode;
if (argtype.constValue != null) {
Type ctype = cfolder.fold1(opc, argtype);
if (ctype != null) {
owntype = cfolder.coerce(ctype, owntype);
if (tree.arg.type.tsym == syms.stringType.tsym) {
tree.arg.type = syms.stringType;
}
}
}
}
result = check(tree, owntype, VAL, pkind, pt);
}
public void visitBinary(Binary tree) {
Type left = chk.checkNonVoid(tree.lhs.pos, attribExpr(tree.lhs, env));
Type right = chk.checkNonVoid(tree.lhs.pos, attribExpr(tree.rhs, env));
Symbol operator = tree.operator =
rs.resolveBinaryOperator(tree.pos, tree.tag, env, left, right);
Type owntype = syms.errType;
if (operator.kind == MTH) {
owntype = operator.type.restype();
int opc = ((OperatorSymbol) operator).opcode;
if (opc == ByteCodes.error) {
log.error(tree.lhs.pos, "operator.cant.be.applied",
treeinfo.operatorName(tree.tag).toJava(),
left.toJava() + "," + right.toJava());
}
if (left.constValue != null && right.constValue != null) {
Type ctype = cfolder.fold2(opc, left, right);
if (ctype != null) {
owntype = cfolder.coerce(ctype, owntype);
if (tree.lhs.type.tsym == syms.stringType.tsym) {
tree.lhs.type = syms.stringType;
}
if (tree.rhs.type.tsym == syms.stringType.tsym) {
tree.rhs.type = syms.stringType;
}
}
}
if (opc == ByteCodes.if_acmpeq || opc == ByteCodes.if_acmpne) {
if (!left.isCastable(right.erasure()) &&
!right.isCastable(left.erasure())) {
log.error(tree.pos, "incomparable.types", left.toJava(),
right.toJava());
} else {
chk.checkCompatible(tree.pos, left, right);
}
}
}
result = check(tree, owntype, VAL, pkind, pt);
}
public void visitTypeCast(TypeCast tree) {
Type clazztype = attribType(tree.clazz, env);
Type exprtype = attribExpr(tree.expr, env, Type.noType);
Type owntype = chk.checkCastable(tree.expr.pos, exprtype, clazztype);
if (exprtype.constValue != null)
owntype = cfolder.coerce(exprtype, owntype);
result = check(tree, owntype, VAL, pkind, pt);
}
public void visitTypeTest(TypeTest tree) {
Type exprtype = attribExpr(tree.expr, env);
Type clazztype = chk.checkClassOrArrayType(tree.clazz.pos,
attribType(tree.clazz, env));
chk.checkCastable(tree.expr.pos, exprtype, clazztype);
result = check(tree, syms.booleanType, VAL, pkind, pt);
}
public void visitIndexed(Indexed tree) {
Type owntype = syms.errType;
Type atype = attribExpr(tree.indexed, env);
attribExpr(tree.index, env, syms.intType);
if (atype.tag == ARRAY)
owntype = atype.elemtype();
else if (atype.tag != ERROR)
log.error(tree.pos, "array.req.but.found", atype.toJava());
result = check(tree, owntype, VAR, pkind, pt);
}
public void visitIdent(Ident tree) {
Symbol sym;
if (pt.tag == METHOD) {
sym = rs.resolveMethod(tree.pos, env, tree.name, pt.argtypes());
} else if (tree.sym != null && tree.sym.kind != VAR) {
sym = tree.sym;
} else {
sym = rs.resolveIdent(tree.pos, env, tree.name, pkind);
}
tree.sym = sym;
Env symEnv = env;
boolean noOuterThisPath = false;
if (env.enclClass.sym.owner.kind != PCK &&
(sym.kind & (VAR | MTH | TYP)) != 0 && sym.owner.kind == TYP &&
tree.name != names._this && tree.name != names._super) {
while (symEnv.outer != null && !sym.isMemberOf(symEnv.enclClass.sym)) {
if ((symEnv.enclClass.sym.flags() & NOOUTERTHIS) != 0)
noOuterThisPath = true;
symEnv = symEnv.outer;
}
}
if (sym.kind == VAR) {
VarSymbol v = (VarSymbol) sym;
checkInit(tree, env, v);
if (v.owner.kind == MTH &&
v.owner != ((AttrContext) env.info).scope.owner) {
if ((v.flags_field & FINAL) == 0) {
log.error(tree.pos, "local.var.accessed.from.icls.needs.final",
v.toJava());
}
}
if (pkind == VAR)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -