use of com.sun.tools.javac.code.Type.TypeVar in project error-prone by google.
the class ASTHelpersTest method testGetUpperBoundCapturedTypeVariable.
@Test
public void testGetUpperBoundCapturedTypeVariable() {
writeFile("A.java", "import java.lang.Number;", "import java.util.List;", "public class A {", " public void doSomething(List<? extends Number> list) {", " list.get(0);", " }", "}");
TestScanner scanner = new TestScanner() {
@Override
public Void visitMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (!"super()".equals(tree.toString())) {
// ignore synthetic super call
setAssertionsComplete();
Type type = ASTHelpers.getType(tree);
assertThat(type instanceof TypeVar).isTrue();
assertThat(((TypeVar) type).isCaptured()).isTrue();
assertThat(ASTHelpers.getUpperBound(type, state.getTypes()).toString()).isEqualTo("java.lang.Number");
}
return super.visitMethodInvocation(tree, state);
}
};
tests.add(scanner);
assertCompiles(scanner);
}
use of com.sun.tools.javac.code.Type.TypeVar in project error-prone by google.
the class TypeParameterUnusedInFormals method matchMethod.
@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
MethodSymbol methodSymbol = ASTHelpers.getSymbol(tree);
if (methodSymbol == null) {
return Description.NO_MATCH;
}
// Only match methods where the return type is just a type parameter.
// e.g. the following is OK: <T> List<T> newArrayList();
TypeVar retType;
switch(methodSymbol.getReturnType().getKind()) {
case TYPEVAR:
retType = (TypeVar) methodSymbol.getReturnType();
break;
default:
return Description.NO_MATCH;
}
if (!methodSymbol.equals(retType.tsym.owner)) {
return Description.NO_MATCH;
}
// e.g.: <T extends Enum<T>> T unsafeEnumDeserializer();
if (retType.bound != null && TypeParameterFinder.visit(retType.bound).contains(retType.tsym)) {
return Description.NO_MATCH;
}
// e.g.: <T> T noop(T t);
for (VarSymbol formalParam : methodSymbol.getParameters()) {
if (TypeParameterFinder.visit(formalParam.type).contains(retType.tsym)) {
return Description.NO_MATCH;
}
}
return describeMatch(tree);
}
use of com.sun.tools.javac.code.Type.TypeVar in project ceylon-compiler by ceylon.
the class TypeMaker method typeParametersString.
/**
* Return the formal type parameters of a class or method as an
* angle-bracketed string. Each parameter is a type variable with
* optional bounds. Class names are qualified if "full" is true.
* Return "" if there are no type parameters or we're hiding generics.
*/
static String typeParametersString(DocEnv env, Symbol sym, boolean full) {
if (env.legacyDoclet || sym.type.getTypeArguments().isEmpty()) {
return "";
}
StringBuilder s = new StringBuilder();
for (Type t : sym.type.getTypeArguments()) {
s.append(s.length() == 0 ? "<" : ", ");
s.append(TypeVariableImpl.typeVarToString(env, (TypeVar) t, full));
}
s.append(">");
return s.toString();
}
use of com.sun.tools.javac.code.Type.TypeVar in project error-prone by google.
the class Inliner method inlineAsVar.
public TypeVar inlineAsVar(UTypeVar var) throws CouldNotResolveImportException {
/*
* In order to handle recursively bounded type variables without a stack overflow,
* we first cache a type var with no bounds, then we inline the bounds.
*/
TypeVar typeVar = typeVarCache.get(var.getName());
if (typeVar != null) {
return typeVar;
}
Name name = asName(var.getName());
TypeSymbol sym = new TypeVariableSymbol(0, name, null, symtab().noSymbol);
typeVar = new TypeVar(sym, null, null);
sym.type = typeVar;
typeVarCache.put(var.getName(), typeVar);
// Any recursive uses of var will point to the same TypeVar object generated above.
typeVar.bound = var.getUpperBound().inline(this);
typeVar.lower = var.getLowerBound().inline(this);
return typeVar;
}
use of com.sun.tools.javac.code.Type.TypeVar in project ceylon-compiler by ceylon.
the class Attr method visitTypeParameter.
public void visitTypeParameter(JCTypeParameter tree) {
TypeVar a = (TypeVar) tree.type;
Set<Type> boundSet = new HashSet<Type>();
if (a.bound.isErroneous())
return;
List<Type> bs = types.getBounds(a);
if (tree.bounds.nonEmpty()) {
// accept class or interface or typevar as first bound.
Type b = checkBase(bs.head, tree.bounds.head, env, false, false, false);
boundSet.add(types.erasure(b));
if (b.isErroneous()) {
a.bound = b;
} else if (b.tag == TYPEVAR) {
// if first bound was a typevar, do not accept further bounds.
if (tree.bounds.tail.nonEmpty()) {
log.error(tree.bounds.tail.head.pos(), "type.var.may.not.be.followed.by.other.bounds");
tree.bounds = List.of(tree.bounds.head);
a.bound = bs.head;
}
} else {
// as further bounds.
for (JCExpression bound : tree.bounds.tail) {
bs = bs.tail;
Type i = checkBase(bs.head, bound, env, false, true, false);
if (i.isErroneous())
a.bound = i;
else if (i.tag == CLASS)
chk.checkNotRepeated(bound.pos(), types.erasure(i), boundSet);
}
}
}
bs = types.getBounds(a);
// in case of multiple bounds ...
if (bs.length() > 1) {
// ... the variable's bound is a class type flagged COMPOUND
// (see comment for TypeVar.bound).
// In this case, generate a class tree that represents the
// bound class, ...
JCExpression extending;
List<JCExpression> implementing;
if ((bs.head.tsym.flags() & INTERFACE) == 0) {
extending = tree.bounds.head;
implementing = tree.bounds.tail;
} else {
extending = null;
implementing = tree.bounds;
}
JCClassDecl cd = make.at(tree.pos).ClassDef(make.Modifiers(PUBLIC | ABSTRACT), tree.name, List.<JCTypeParameter>nil(), extending, implementing, List.<JCTree>nil());
ClassSymbol c = (ClassSymbol) a.getUpperBound().tsym;
Assert.check((c.flags() & COMPOUND) != 0);
cd.sym = c;
c.sourcefile = env.toplevel.sourcefile;
// ... and attribute the bound class
c.flags_field |= UNATTRIBUTED;
Env<AttrContext> cenv = enter.classEnv(cd, env);
enter.typeEnvs.put(c, cenv);
}
}
Aggregations