--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Wed Jan 23 13:27:24 2013 -0800
@@ -26,9 +26,9 @@
package com.sun.tools.javac.comp;
import java.util.*;
-import java.util.Set;
import javax.lang.model.element.ElementKind;
+import javax.lang.model.type.TypeKind;
import javax.tools.JavaFileObject;
import com.sun.source.tree.IdentifierTree;
@@ -45,7 +45,6 @@
import com.sun.tools.javac.comp.Infer.InferenceContext;
import com.sun.tools.javac.comp.Infer.InferenceContext.FreeTypeListener;
import com.sun.tools.javac.jvm.*;
-import com.sun.tools.javac.jvm.Target;
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
@@ -880,6 +879,7 @@
deferredLintHandler.flush(tree.pos());
chk.checkDeprecatedAnnotation(tree.pos(), m);
+
// Create a new environment with local scope
// for attributing the method.
Env<AttrContext> localEnv = memberEnter.methodEnv(tree, env);
@@ -923,6 +923,21 @@
// Check that result type is well-formed.
chk.validate(tree.restype, localEnv);
+ // Check that receiver type is well-formed.
+ if (tree.recvparam != null) {
+ // Use a new environment to check the receiver parameter.
+ // Otherwise I get "might not have been initialized" errors.
+ // Is there a better way?
+ Env<AttrContext> newEnv = memberEnter.methodEnv(tree, env);
+ attribType(tree.recvparam, newEnv);
+ chk.validate(tree.recvparam, newEnv);
+ if (!(tree.recvparam.type == m.owner.type || types.isSameType(tree.recvparam.type, m.owner.type))) {
+ // The == covers the common non-generic case, but for generic classes we need isSameType;
+ // note that equals didn't work.
+ log.error(tree.recvparam.pos(), "incorrect.receiver.type");
+ }
+ }
+
// annotation method checks
if ((owner.flags() & ANNOTATION) != 0) {
// annotation method cannot have throws clause
@@ -996,9 +1011,14 @@
}
}
+ // Attribute all type annotations in the body
+ memberEnter.typeAnnotate(tree.body, localEnv, m);
+ annotate.flush();
+
// Attribute method body.
attribStat(tree.body, localEnv);
}
+
localEnv.info.scope.leave();
result = tree.type = m.type;
chk.validateAnnotations(tree.mods.annotations, m);
@@ -1019,6 +1039,12 @@
memberEnter.memberEnter(tree, env);
annotate.flush();
}
+ } else {
+ if (tree.init != null) {
+ // Field initializer expression need to be entered.
+ memberEnter.typeAnnotate(tree.init, env, tree.sym);
+ annotate.flush();
+ }
}
VarSymbol v = tree.sym;
@@ -1076,6 +1102,11 @@
new MethodSymbol(tree.flags | BLOCK, names.empty, null,
env.info.scope.owner);
if ((tree.flags & STATIC) != 0) localEnv.info.staticLevel++;
+
+ // Attribute all type annotations in the block
+ memberEnter.typeAnnotate(tree, localEnv, localEnv.info.scope.owner);
+ annotate.flush();
+
attribStats(tree.stats, localEnv);
} else {
// Create a new local environment with a local scope.
@@ -1847,10 +1878,24 @@
// If enclosing class is given, attribute it, and
// complete class name to be fully qualified
JCExpression clazz = tree.clazz; // Class field following new
- JCExpression clazzid = // Identifier in class field
- (clazz.hasTag(TYPEAPPLY))
- ? ((JCTypeApply) clazz).clazz
- : clazz;
+ JCExpression clazzid; // Identifier in class field
+ JCAnnotatedType annoclazzid; // Annotated type enclosing clazzid
+ annoclazzid = null;
+
+ if (clazz.hasTag(TYPEAPPLY)) {
+ clazzid = ((JCTypeApply) clazz).clazz;
+ if (clazzid.hasTag(ANNOTATED_TYPE)) {
+ annoclazzid = (JCAnnotatedType) clazzid;
+ clazzid = annoclazzid.underlyingType;
+ }
+ } else {
+ if (clazz.hasTag(ANNOTATED_TYPE)) {
+ annoclazzid = (JCAnnotatedType) clazz;
+ clazzid = annoclazzid.underlyingType;
+ } else {
+ clazzid = clazz;
+ }
+ }
JCExpression clazzid1 = clazzid; // The same in fully qualified form
@@ -1865,14 +1910,30 @@
// yields a clazz T.C.
Type encltype = chk.checkRefType(tree.encl.pos(),
attribExpr(tree.encl, env));
+ // TODO 308: in <expr>.new C, do we also want to add the type annotations
+ // from expr to the combined type, or not? Yes, do this.
clazzid1 = make.at(clazz.pos).Select(make.Type(encltype),
((JCIdent) clazzid).name);
- if (clazz.hasTag(TYPEAPPLY))
- clazz = make.at(tree.pos).
+
+ if (clazz.hasTag(ANNOTATED_TYPE)) {
+ JCAnnotatedType annoType = (JCAnnotatedType) clazz;
+ List<JCAnnotation> annos = annoType.annotations;
+
+ if (annoType.underlyingType.hasTag(TYPEAPPLY)) {
+ clazzid1 = make.at(tree.pos).
+ TypeApply(clazzid1,
+ ((JCTypeApply) clazz).arguments);
+ }
+
+ clazzid1 = make.at(tree.pos).
+ AnnotatedType(annos, clazzid1);
+ } else if (clazz.hasTag(TYPEAPPLY)) {
+ clazzid1 = make.at(tree.pos).
TypeApply(clazzid1,
((JCTypeApply) clazz).arguments);
- else
- clazz = clazzid1;
+ }
+
+ clazz = clazzid1;
}
// Attribute clazz expression and store
@@ -1889,6 +1950,9 @@
tree.clazz.type = clazztype;
TreeInfo.setSymbol(clazzid, TreeInfo.symbol(clazzid1));
clazzid.type = ((JCIdent) clazzid).sym.type;
+ if (annoclazzid != null) {
+ annoclazzid.type = clazzid.type;
+ }
if (!clazztype.isErroneous()) {
if (cdef != null && clazztype.tsym.isInterface()) {
log.error(tree.encl.pos(), "anon.class.impl.intf.no.qual.for.new");
@@ -3255,8 +3319,18 @@
// Tree<Point>.Visitor.
else if (ownOuter.hasTag(CLASS) && site != ownOuter) {
Type normOuter = site;
- if (normOuter.hasTag(CLASS))
+ if (normOuter.hasTag(CLASS)) {
normOuter = types.asEnclosingSuper(site, ownOuter.tsym);
+ if (site.getKind() == TypeKind.ANNOTATED) {
+ // Propagate any type annotations.
+ // TODO: should asEnclosingSuper do this?
+ // Note that the type annotations in site will be updated
+ // by annotateType. Therefore, modify site instead
+ // of creating a new AnnotatedType.
+ ((AnnotatedType)site).underlyingType = normOuter;
+ normOuter = site;
+ }
+ }
if (normOuter == null) // perhaps from an import
normOuter = types.erasure(ownOuter);
if (normOuter != ownOuter)
@@ -3644,8 +3718,15 @@
tree.type = result = checkIntersection(tree, tree.bounds);
}
- public void visitTypeParameter(JCTypeParameter tree) {
- TypeVar typeVar = (TypeVar)tree.type;
+ public void visitTypeParameter(JCTypeParameter tree) {
+ TypeVar typeVar = (TypeVar) tree.type;
+
+ if (tree.annotations != null && tree.annotations.nonEmpty()) {
+ AnnotatedType antype = new AnnotatedType(typeVar);
+ annotateType(antype, tree.annotations);
+ tree.type = antype;
+ }
+
if (!typeVar.bound.isErroneous()) {
//fixup type-parameter bound computed in 'attribTypeVariables'
typeVar.bound = checkIntersection(tree, tree.bounds);
@@ -3741,6 +3822,44 @@
result = tree.type = syms.errType;
}
+ public void visitAnnotatedType(JCAnnotatedType tree) {
+ Type underlyingType = attribType(tree.getUnderlyingType(), env);
+ this.attribAnnotationTypes(tree.annotations, env);
+ AnnotatedType antype = new AnnotatedType(underlyingType);
+ annotateType(antype, tree.annotations);
+ result = tree.type = antype;
+ }
+
+ /**
+ * Apply the annotations to the particular type.
+ */
+ public void annotateType(final AnnotatedType type, final List<JCAnnotation> annotations) {
+ if (annotations.isEmpty())
+ return;
+ annotate.typeAnnotation(new Annotate.Annotator() {
+ @Override
+ public String toString() {
+ return "annotate " + annotations + " onto " + type;
+ }
+ @Override
+ public void enterAnnotation() {
+ List<Attribute.TypeCompound> compounds = fromAnnotations(annotations);
+ type.typeAnnotations = compounds;
+ }
+ });
+ }
+
+ private static List<Attribute.TypeCompound> fromAnnotations(List<JCAnnotation> annotations) {
+ if (annotations.isEmpty())
+ return List.nil();
+
+ ListBuffer<Attribute.TypeCompound> buf = ListBuffer.lb();
+ for (JCAnnotation anno : annotations) {
+ buf.append((Attribute.TypeCompound) anno.attribute);
+ }
+ return buf.toList();
+ }
+
public void visitErroneous(JCErroneous tree) {
if (tree.errs != null)
for (JCTree err : tree.errs)
@@ -3972,6 +4091,12 @@
(c.flags() & ABSTRACT) == 0) {
checkSerialVersionUID(tree, c);
}
+
+ // Correctly organize the postions of the type annotations
+ TypeAnnotations.organizeTypeAnnotationsBodies(this.syms, this.names, this.log, tree);
+
+ // Check type annotations applicability rules
+ validateTypeAnnotations(tree);
}
// where
/** get a diagnostic position for an attribute of Type t, or null if attribute missing */
@@ -4029,6 +4154,94 @@
return types.capture(type);
}
+ private void validateTypeAnnotations(JCTree tree) {
+ tree.accept(typeAnnotationsValidator);
+ }
+ //where
+ private final JCTree.Visitor typeAnnotationsValidator =
+ new TreeScanner() {
+ public void visitAnnotation(JCAnnotation tree) {
+ if (tree.hasTag(TYPE_ANNOTATION)) {
+ // TODO: It seems to WMD as if the annotation in
+ // parameters, in particular also the recvparam, are never
+ // of type JCTypeAnnotation and therefore never checked!
+ // Luckily this check doesn't really do anything that isn't
+ // also done elsewhere.
+ chk.validateTypeAnnotation(tree, false);
+ }
+ super.visitAnnotation(tree);
+ }
+ public void visitTypeParameter(JCTypeParameter tree) {
+ chk.validateTypeAnnotations(tree.annotations, true);
+ scan(tree.bounds);
+ // Don't call super.
+ // This is needed because above we call validateTypeAnnotation with
+ // false, which would forbid annotations on type parameters.
+ // super.visitTypeParameter(tree);
+ }
+ public void visitMethodDef(JCMethodDecl tree) {
+ // Static methods cannot have receiver type annotations.
+ // In test case FailOver15.java, the nested method getString has
+ // a null sym, because an unknown class is instantiated.
+ // I would say it's safe to skip.
+ if (tree.sym != null && (tree.sym.flags() & Flags.STATIC) != 0) {
+ if (tree.recvparam != null) {
+ // TODO: better error message. Is the pos good?
+ log.error(tree.recvparam.pos(), "annotation.type.not.applicable");
+ }
+ }
+ if (tree.restype != null && tree.restype.type != null) {
+ validateAnnotatedType(tree.restype, tree.restype.type);
+ }
+ super.visitMethodDef(tree);
+ }
+ public void visitVarDef(final JCVariableDecl tree) {
+ if (tree.sym != null && tree.sym.type != null)
+ validateAnnotatedType(tree, tree.sym.type);
+ super.visitVarDef(tree);
+ }
+ public void visitTypeCast(JCTypeCast tree) {
+ if (tree.clazz != null && tree.clazz.type != null)
+ validateAnnotatedType(tree.clazz, tree.clazz.type);
+ super.visitTypeCast(tree);
+ }
+ public void visitTypeTest(JCInstanceOf tree) {
+ if (tree.clazz != null && tree.clazz.type != null)
+ validateAnnotatedType(tree.clazz, tree.clazz.type);
+ super.visitTypeTest(tree);
+ }
+ // TODO: what else do we need?
+ // public void visitNewClass(JCNewClass tree) {
+ // public void visitNewArray(JCNewArray tree) {
+
+ /* I would want to model this after
+ * com.sun.tools.javac.comp.Check.Validator.visitSelectInternal(JCFieldAccess)
+ * and override visitSelect and visitTypeApply.
+ * However, we only set the annotated type in the top-level type
+ * of the symbol.
+ * Therefore, we need to override each individual location where a type
+ * can occur.
+ */
+ private void validateAnnotatedType(final JCTree errtree, final Type type) {
+ if (type.getEnclosingType() != null &&
+ type != type.getEnclosingType()) {
+ validateEnclosingAnnotatedType(errtree, type.getEnclosingType());
+ }
+ for (Type targ : type.getTypeArguments()) {
+ validateAnnotatedType(errtree, targ);
+ }
+ }
+ private void validateEnclosingAnnotatedType(final JCTree errtree, final Type type) {
+ validateAnnotatedType(errtree, type);
+ if (type.tsym != null &&
+ type.tsym.isStatic() &&
+ type.getAnnotations().nonEmpty()) {
+ // Enclosing static classes cannot have type annotations.
+ log.error(errtree.pos(), "cant.annotate.static.class");
+ }
+ }
+ };
+
// <editor-fold desc="post-attribution visitor">
/**