/*
* 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.code.Symbol.ClassSymbol;
import static com.sun.tools.mjavac.code.Kinds.*;
import com.sun.tools.mjavac.comp.Attr;
import com.sun.tools.mjavac.comp.AttrContext;
import com.sun.tools.mjavac.comp.Env;
import com.sun.tools.mjavac.tree.JCTree;
import com.sun.tools.mjavac.tree.JCTree.*;
import com.sun.tools.mjavac.util.*;
import org.visage.tools.tree.*;
import org.visage.tools.util.MsgSym;
/** 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
*
* <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 BlockExprAttr extends Attr {
public static Attr instance0(Context context) {
Attr instance = context.get(attrKey);
if (instance == null)
instance = new BlockExprAttr(context);
return instance;
}
public static void preRegister(final Context context) {
context.put(attrKey, new Context.Factory<Attr>() {
public Attr make() {
return new BlockExprAttr(context);
}
});
}
protected BlockExprAttr(Context context) {
super(context);
}
public void visitBlockExpression(BlockExprJCBlockExpression tree) {
// Create a new local environment with a local scope.
Env<AttrContext> localEnv =
env.dup(tree,
env.info.dup(env.info.scope.dup()));
for (List<JCStatement> l = tree.stats; l.nonEmpty(); l = l.tail)
attribStat(l.head, localEnv);
if (tree.value == null) {
result = check(tree, syms.voidType, VAL, pkind, pt);
} else {
Type valtype = attribExpr(tree.value, localEnv);
valtype = valtype.baseType();
result = check(tree, valtype, VAL, pkind, pt);
}
localEnv.info.scope.leave();
}
/** Finish the attribution of a class. */
@Override
protected void attribClassBody(Env<AttrContext> env, ClassSymbol c) {
JCClassDecl tree = (JCClassDecl)env.tree;
assert c == tree.sym;
// Validate annotations
chk.validateAnnotations(tree.mods.annotations, c);
// Validate type parameters, supertype and interfaces.
attribBounds(tree.typarams);
chk.validateTypeParams(tree.typarams);
chk.validate(tree.extending);
chk.validate(tree.implementing);
// If this is a non-abstract class, check that it has no abstract
// methods or unimplemented methods of an implemented interface.
if ((c.flags() & (Flags.ABSTRACT | Flags.INTERFACE)) == 0) {
if (!relax)
chk.checkAllDefined(tree.pos(), c);
}
if ((c.flags() & Flags.ANNOTATION) != 0) {
if (tree.implementing.nonEmpty())
log.error(tree.implementing.head.pos(),
MsgSym.MESSAGE_CANNOT_EXTEND_INTERFACE_ANNOTATION);
if (tree.typarams.nonEmpty())
log.error(tree.typarams.head.pos(),
MsgSym.MESSAGE_INTF_ANNOTATION_CANNOT_HAVE_TYPE_PARAMS);
} else {
// Check that all extended classes and interfaces
// are compatible (i.e. no two define methods with same arguments
// yet different return types). (JLS 8.4.6.3)
chk.checkCompatibleSupertypes(tree.pos(), c.type);
}
// Check that class does not import the same parameterized interface
// with two different argument lists.
chk.checkClassBounds(tree.pos(), c.type);
tree.type = c.type;
boolean assertsEnabled = false;
assert assertsEnabled = true;
if (assertsEnabled) {
for (List<JCTypeParameter> l = tree.typarams;
l.nonEmpty(); l = l.tail)
assert env.info.scope.lookup(l.head.name).scope != null;
}
// Check that a generic class doesn't extend Throwable
if (!c.type.allparams().isEmpty() && types.isSubtype(c.type, syms.throwableType))
log.error(tree.extending.pos(), MsgSym.MESSAGE_GENERIC_THROWABLE);
// Check that all methods which implement some
// method conform to the method they implement.
chk.checkImplementations(tree);
for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
// Attribute declaration
attribStat(l.head, env);
// Check that declarations in inner classes are not static (JLS 8.1.2)
// Make an exception for static constants.
// Visage doesn't have this restriction
// if (c.owner.kind != PCK &&
// ((c.flags() & STATIC) == 0 || c.name == names.empty) &&
// (TreeInfo.flags(l.head) & (STATIC | INTERFACE)) != 0) {
// Symbol sym = null;
// if (l.head.getTag() == JCTree.VARDEF) sym = ((JCVariableDecl) l.head).sym;
// if (sym == null ||
// sym.kind != VAR ||
// ((VisageVarSymbol) sym).getConstValue() == null)
// log.error(l.head.pos(), "icls.cant.have.static.decl");
// }
}
// Check for cycles among non-initial constructors.
chk.checkCyclicConstructors(tree);
// Check for cycles among annotation elements.
chk.checkNonCyclicElements(tree);
// Check for proper use of serialVersionUID
if (env.info.lint.isEnabled(Lint.LintCategory.SERIAL) &&
isSerializable(c) &&
(c.flags() & Flags.ENUM) == 0 &&
(c.flags() & Flags.ABSTRACT) == 0) {
checkSerialVersionUID(tree, c);
}
}
/**
* Force an expected kind that was provided by the Visage front-end
*/
public void visitAugmentedIdent(AugmentedJCIdent tree) {
if (tree.pkind != Kinds.NIL && tree.sym == null) {
pkind = tree.pkind;
}
visitIdent(tree);
}
}