use of com.sun.tools.javac.code.Symbol.TypeVariableSymbol in project error-prone by google.
the class FutureReturnValueIgnored method checkLostType.
private Description checkLostType(MethodInvocationTree tree, VisitorState state) {
Type futureType = Objects.requireNonNull(state.getTypeFromString("java.util.concurrent.Future"));
MethodSymbol sym = ASTHelpers.getSymbol(tree);
Type returnType = ASTHelpers.getResultType(tree);
Type returnedFutureType = state.getTypes().asSuper(returnType, futureType.tsym);
if (returnedFutureType != null && !returnedFutureType.isRaw()) {
if (ASTHelpers.isSubtype(ASTHelpers.getUpperBound(returnedFutureType.getTypeArguments().get(0), state.getTypes()), futureType, state)) {
return buildDescription(tree).setMessage(String.format("Method returns a nested type, %s", returnType)).build();
}
// The type variable that determines the generic on the returned future was not a Future.
// However, many methods (like guava's Futures.transform) have signatures like this:
// Future<O> do(SomeObject<? extends O>). If O resolves to java.lang.Object or ?, then a
// SomeObject<Future> is a valid parameter to pass, but results in a nested future.
Type methodReturnType = sym.getReturnType();
List<TypeVariableSymbol> typeParameters = sym.getTypeParameters();
Set<TypeVariableSymbol> returnTypeChoosing = new HashSet<>();
// of Future, that means that a nested Future is being returned.
for (TypeVariableSymbol tvs : typeParameters) {
Queue<TypeVariableSymbol> queue = new ArrayDeque<>();
queue.add(tvs);
while (!queue.isEmpty()) {
TypeVariableSymbol currentTypeParam = queue.poll();
for (Type typeParam : methodReturnType.getTypeArguments()) {
if (typeParam.tsym == currentTypeParam) {
returnTypeChoosing.add(tvs);
}
}
for (Type toAdd : currentTypeParam.getBounds()) {
if (toAdd.tsym instanceof TypeVariableSymbol) {
queue.add((TypeVariableSymbol) toAdd.tsym);
}
}
}
}
// of Future.
if (!returnTypeChoosing.isEmpty()) {
Multimap<TypeVariableSymbol, TypeInfo> resolved = getResolvedGenerics(tree);
for (TypeVariableSymbol returnTypeChoosingSymbol : returnTypeChoosing) {
Collection<TypeInfo> types = resolved.get(returnTypeChoosingSymbol);
for (TypeInfo type : types) {
if (ASTHelpers.isSubtype(type.resolvedVariableType, futureType, state)) {
return buildDescription(type.tree).setMessage(String.format("Invocation produces a nested type - Type variable %s, as part of return " + "type %s resolved to %s.", returnTypeChoosingSymbol, methodReturnType, type.resolvedVariableType)).build();
}
}
}
}
}
if (allOf(allOf(parentNode(FutureReturnValueIgnored::isObjectReturningLambdaExpression), not(AbstractReturnValueIgnored::expectedExceptionTest)), specializedMatcher(), not((t, s) -> ASTHelpers.isVoidType(ASTHelpers.getType(t), s))).matches(tree, state)) {
return describe(tree, state);
}
return Description.NO_MATCH;
}
use of com.sun.tools.javac.code.Symbol.TypeVariableSymbol in project error-prone by google.
the class FutureReturnValueIgnored method getResolvedGenerics.
private static Multimap<TypeVariableSymbol, TypeInfo> getResolvedGenerics(MethodInvocationTree tree) {
Type type = ASTHelpers.getType(tree.getMethodSelect());
List<Type> from = new ArrayList<>();
List<Type> to = new ArrayList<>();
getSubst(type, from, to);
Multimap<TypeVariableSymbol, TypeInfo> result = Streams.zip(from.stream(), to.stream(), (f, t) -> new TypeInfo((TypeVariableSymbol) f.asElement(), t, tree)).collect(toMultimap(k -> k.sym, k -> k, MultimapBuilder.linkedHashKeys().arrayListValues()::build));
return result;
}
use of com.sun.tools.javac.code.Symbol.TypeVariableSymbol in project error-prone by google.
the class TypeParameterShadowing method renameTypeVariable.
static SuggestedFix renameTypeVariable(TypeParameterTree typeParameter, Tree owningTree, String typeVarReplacement, VisitorState state) {
Symbol typeVariableSymbol = ASTHelpers.getSymbol(typeParameter);
// replace only the type parameter name (and not any upper bounds)
String name = typeParameter.getName().toString();
int pos = ((JCTree) typeParameter).getStartPosition();
SuggestedFix.Builder fixBuilder = SuggestedFix.builder().replace(pos, pos + name.length(), typeVarReplacement);
((JCTree) owningTree).accept(new TreeScanner() {
@Override
public void visitIdent(JCTree.JCIdent tree) {
Symbol identSym = ASTHelpers.getSymbol(tree);
if (Objects.equal(identSym, typeVariableSymbol)) {
// }
if (Objects.equal(state.getSourceForNode(tree), name)) {
fixBuilder.replace(tree, typeVarReplacement);
}
}
}
});
return fixBuilder.build();
}
use of com.sun.tools.javac.code.Symbol.TypeVariableSymbol in project checker-framework by typetools.
the class TypeFromTypeTreeVisitor method updateWildcardBounds.
/**
* Work around a bug in javac 9 where sometimes the bound field is set to the transitive
* supertype's type parameter instead of the type parameter which the wildcard directly
* instantiates. See https://github.com/eisop/checker-framework/issues/18
*
* <p>Sets each wildcard type argument's bound from typeArgs to the corresponding type parameter
* from typeParams.
*
* <p>If typeArgs.size() == 0 the method does nothing and returns. Otherwise, typeArgs.size() has
* to be equal to typeParams.size().
*
* <p>For each wildcard type argument and corresponding type parameter, sets the
* WildcardType.bound field to the corresponding type parameter, if and only if the owners of the
* existing bound and the type parameter are different.
*
* <p>In scenarios where the bound's owner is the same, we don't want to replace a
* capture-converted bound in the wildcard type with a non-capture-converted bound given by the
* type parameter declaration.
*
* @param typeArgs the type of the arguments at (e.g., at the call side)
* @param typeParams the type of the formal parameters (e.g., at the method declaration)
*/
// workaround for javac bug
@SuppressWarnings("interning:not.interned")
private void updateWildcardBounds(List<? extends Tree> typeArgs, List<TypeVariableSymbol> typeParams) {
if (typeArgs.isEmpty()) {
// Nothing to do for empty type arguments.
return;
}
assert typeArgs.size() == typeParams.size();
Iterator<? extends Tree> typeArgsItr = typeArgs.iterator();
Iterator<TypeVariableSymbol> typeParamsItr = typeParams.iterator();
while (typeArgsItr.hasNext()) {
Tree typeArg = typeArgsItr.next();
TypeVariableSymbol typeParam = typeParamsItr.next();
if (typeArg instanceof WildcardTree) {
TypeVar typeVar = (TypeVar) typeParam.asType();
WildcardType wcType = (WildcardType) ((JCWildcard) typeArg).type;
if (wcType.bound != null && wcType.bound.tsym != null && typeVar.tsym != null && wcType.bound.tsym.owner != typeVar.tsym.owner) {
wcType.withTypeVar(typeVar);
}
}
}
}
use of com.sun.tools.javac.code.Symbol.TypeVariableSymbol in project error-prone by google.
the class ImmutableAnalysis method immutableInstantiation.
/**
* Check that a type-use of an {@code @Immutable}-annotated type is instantiated with immutable
* type arguments where required by its annotation's containerOf element.
*
* @param immutableTyParams the in-scope immutable type parameters, declared on some enclosing
* class.
* @param annotation the type's {@code @Immutable} info
* @param type the type to check
*/
Violation immutableInstantiation(ImmutableSet<String> immutableTyParams, ImmutableAnnotationInfo annotation, Type type) {
if (!annotation.containerOf().isEmpty() && type.tsym.getTypeParameters().size() != type.getTypeArguments().size()) {
return Violation.of(String.format("'%s' required immutable instantiation of '%s', but was raw", getPrettyName(type.tsym), Joiner.on(", ").join(annotation.containerOf())));
}
for (int i = 0; i < type.tsym.getTypeParameters().size(); i++) {
TypeVariableSymbol typaram = type.tsym.getTypeParameters().get(i);
if (annotation.containerOf().contains(typaram.getSimpleName().toString())) {
Type tyarg = type.getTypeArguments().get(i);
Violation info = isImmutableType(immutableTyParams, tyarg);
if (info.isPresent()) {
return info.plus(String.format("'%s' was instantiated with mutable type for '%s'", getPrettyName(type.tsym), typaram.getSimpleName()));
}
}
}
return Violation.absent();
}
Aggregations