/** * Process a single compound annotation, returning its Attribute. Used from MemberEnter for * attaching the attributes to the annotated symbol. */ Attribute.Compound enterAnnotation(JCAnnotation a, Type expected, Env<AttrContext> env) { // The annotation might have had its type attributed (but not checked) // by attr.attribAnnotationTypes during MemberEnter, in which case we do not // need to do it again. Type at = (a.annotationType.type != null ? a.annotationType.type : attr.attribType(a.annotationType, env)); a.type = chk.checkType(a.annotationType.pos(), at, expected); if (a.type.isErroneous()) return new Attribute.Compound(a.type, List.<Pair<MethodSymbol, Attribute>>nil()); if ((a.type.tsym.flags() & Flags.ANNOTATION) == 0) { log.error(a.annotationType.pos(), "not.annotation.type", a.type.toString()); return new Attribute.Compound(a.type, List.<Pair<MethodSymbol, Attribute>>nil()); } List<JCExpression> args = a.args; if (args.length() == 1 && args.head.getTag() != JCTree.ASSIGN) { // special case: elided "value=" assumed args.head = make.at(args.head.pos).Assign(make.Ident(names.value), args.head); } ListBuffer<Pair<MethodSymbol, Attribute>> buf = new ListBuffer<Pair<MethodSymbol, Attribute>>(); for (List<JCExpression> tl = args; tl.nonEmpty(); tl = tl.tail) { JCExpression t = tl.head; if (t.getTag() != JCTree.ASSIGN) { log.error(t.pos(), "annotation.value.must.be.name.value"); continue; } JCAssign assign = (JCAssign) t; if (assign.lhs.getTag() != JCTree.IDENT) { log.error(t.pos(), "annotation.value.must.be.name.value"); continue; } JCIdent left = (JCIdent) assign.lhs; Symbol method = rs.resolveQualifiedMethod(left.pos(), env, a.type, left.name, List.<Type>nil(), null); left.sym = method; left.type = method.type; if (method.owner != a.type.tsym) log.error(left.pos(), "no.annotation.member", left.name, a.type); Type result = method.type.getReturnType(); Attribute value = enterAttributeValue(result, assign.rhs, env); if (!method.type.isErroneous()) buf.append(new Pair<MethodSymbol, Attribute>((MethodSymbol) method, value)); t.type = result; } return new Attribute.Compound(a.type, buf.toList()); }
/** Add a name usage to the simplifier's internal cache */ protected void addUsage(Symbol sym) { Name n = sym.getSimpleName(); List<Symbol> conflicts = nameClashes.get(n); if (conflicts == null) { conflicts = List.nil(); } if (!conflicts.contains(sym)) nameClashes.put(n, conflicts.append(sym)); }
/** * Build a list of multiline diagnostics containing detailed info about type-variables, captured * types, and intersection types * * @return where clause list */ protected List<JCDiagnostic> getWhereClauses() { List<JCDiagnostic> clauses = List.nil(); for (WhereClauseKind kind : WhereClauseKind.values()) { List<JCDiagnostic> lines = List.nil(); for (Map.Entry<Type, JCDiagnostic> entry : whereClauses.get(kind).entrySet()) { lines = lines.prepend(entry.getValue()); } if (!lines.isEmpty()) { String key = kind.key(); if (lines.size() > 1) key += ".1"; JCDiagnostic d = diags.fragment(key, whereClauses.get(kind).keySet()); d = new JCDiagnostic.MultilineDiagnostic(d, lines.reverse()); clauses = clauses.prepend(d); } } return clauses.reverse(); }
@Override public Void visitTypeVar(TypeVar t, Void ignored) { if (indexOf(t, WhereClauseKind.TYPEVAR) == -1) { // access the bound type and skip error types Type bound = t.bound; while ((bound instanceof ErrorType)) bound = ((ErrorType) bound).getOriginalType(); // retrieve the bound list - if the type variable // has not been attributed the bound is not set List<Type> bounds = (bound != null && bound.tsym != null) ? types.getBounds(t) : List.<Type>nil(); nameSimplifier.addUsage(t.tsym); boolean boundErroneous = bounds.head == null || bounds.head.tag == NONE || bounds.head.tag == ERROR; if ((t.tsym.flags() & SYNTHETIC) == 0) { // this is a true typevar JCDiagnostic d = diags.fragment( "where.typevar" + (boundErroneous ? ".1" : ""), t, bounds, Kinds.kindName(t.tsym.location()), t.tsym.location()); whereClauses.get(WhereClauseKind.TYPEVAR).put(t, d); symbolPreprocessor.visit(t.tsym.location(), null); visit(bounds); } else { Assert.check(!boundErroneous); // this is a fresh (synthetic) tvar JCDiagnostic d = diags.fragment("where.fresh.typevar", t, bounds); whereClauses.get(WhereClauseKind.TYPEVAR).put(t, d); visit(bounds); } } return null; }
public String simplify(Symbol s) { String name = s.getQualifiedName().toString(); if (!s.type.isCompound()) { List<Symbol> conflicts = nameClashes.get(s.getSimpleName()); if (conflicts == null || (conflicts.size() == 1 && conflicts.contains(s))) { List<Name> l = List.nil(); Symbol s2 = s; while (s2.type.getEnclosingType().tag == CLASS && s2.owner.kind == Kinds.TYP) { l = l.prepend(s2.getSimpleName()); s2 = s2.owner; } l = l.prepend(s2.getSimpleName()); StringBuilder buf = new StringBuilder(); String sep = ""; for (Name n2 : l) { buf.append(sep); buf.append(n2); sep = "."; } name = buf.toString(); } } return name; }
Attribute enterAttributeValue(Type expected, JCExpression tree, Env<AttrContext> env) { // first, try completing the attribution value sym - if a completion // error is thrown, we should recover gracefully, and display an // ordinary resolution diagnostic. try { expected.tsym.complete(); } catch (CompletionFailure e) { log.error(tree.pos(), "cant.resolve", Kinds.kindName(e.sym), e.sym); return new Attribute.Error(expected); } if (expected.isPrimitive() || types.isSameType(expected, syms.stringType)) { Type result = attr.attribExpr(tree, env, expected); if (result.isErroneous()) return new Attribute.Error(expected); if (result.constValue() == null) { log.error(tree.pos(), "attribute.value.must.be.constant"); return new Attribute.Error(expected); } result = cfolder.coerce(result, expected); return new Attribute.Constant(expected, result.constValue()); } if (expected.tsym == syms.classType.tsym) { Type result = attr.attribExpr(tree, env, expected); if (result.isErroneous()) return new Attribute.Error(expected); if (TreeInfo.name(tree) != names._class) { log.error(tree.pos(), "annotation.value.must.be.class.literal"); return new Attribute.Error(expected); } return new Attribute.Class(types, (((JCFieldAccess) tree).selected).type); } if ((expected.tsym.flags() & Flags.ANNOTATION) != 0 || types.isSameType(expected, syms.annotationType)) { if (tree.getTag() != JCTree.ANNOTATION) { log.error(tree.pos(), "annotation.value.must.be.annotation"); expected = syms.errorType; } return enterAnnotation((JCAnnotation) tree, expected, env); } if (expected.tag == TypeTags.ARRAY) { // should really be isArray() if (tree.getTag() != JCTree.NEWARRAY) { tree = make.at(tree.pos).NewArray(null, List.<JCExpression>nil(), List.of(tree)); } JCNewArray na = (JCNewArray) tree; if (na.elemtype != null) { log.error(na.elemtype.pos(), "new.not.allowed.in.annotation"); return new Attribute.Error(expected); } ListBuffer<Attribute> buf = new ListBuffer<Attribute>(); for (List<JCExpression> l = na.elems; l.nonEmpty(); l = l.tail) { buf.append(enterAttributeValue(types.elemtype(expected), l.head, env)); } na.type = expected; return new Attribute.Array(expected, buf.toArray(new Attribute[buf.length()])); } if (expected.tag == TypeTags.CLASS && (expected.tsym.flags() & Flags.ENUM) != 0) { attr.attribExpr(tree, env, expected); Symbol sym = TreeInfo.symbol(tree); if (sym == null || TreeInfo.nonstaticSelect(tree) || sym.kind != Kinds.VAR || (sym.flags() & Flags.ENUM) == 0) { log.error(tree.pos(), "enum.annotation.must.be.enum.constant"); return new Attribute.Error(expected); } VarSymbol enumerator = (VarSymbol) sym; return new Attribute.Enum(expected, enumerator); } if (!expected.isErroneous()) log.error(tree.pos(), "annotation.value.not.allowable.type"); return new Attribute.Error(attr.attribExpr(tree, env, expected)); }