use of com.sun.tools.javac.code.Symbol.MethodSymbol in project error-prone by google.
the class FunctionalInterfaceClash method matchClass.
@Override
public Description matchClass(ClassTree tree, VisitorState state) {
ClassSymbol origin = getSymbol(tree);
Types types = state.getTypes();
// collect declared and inherited methods whose signature contains a functional interface
Multimap<String, MethodSymbol> methods = HashMultimap.create();
for (Symbol sym : types.membersClosure(getType(tree), /*skipInterface=*/
false).getSymbols()) {
if (!(sym instanceof MethodSymbol)) {
continue;
}
if (isBugCheckerSuppressed((MethodSymbol) sym)) {
continue;
}
MethodSymbol msym = (MethodSymbol) sym;
if (msym.getParameters().stream().noneMatch(p -> maybeFunctionalInterface(p.type, types, state))) {
continue;
}
if (msym.isConstructor() && !msym.owner.equals(origin)) {
continue;
}
methods.put(functionalInterfaceSignature(state, msym), msym);
}
// (don't report clashes between inherited members)
for (Tree member : tree.getMembers()) {
if (!(member instanceof MethodTree)) {
continue;
}
MethodSymbol msym = getSymbol((MethodTree) member);
if (msym.getParameters().stream().noneMatch(p -> maybeFunctionalInterface(p.type, types, state))) {
continue;
}
Collection<MethodSymbol> clash = new ArrayList<>(methods.removeAll(functionalInterfaceSignature(state, msym)));
// Ignore inherited methods that are overridden in the original class. Note that we have to
// handle transitive inheritance explicitly to handle cases where the visibility of an
// overridded method is expanded somewhere in the type hierarchy.
Deque<MethodSymbol> worklist = new ArrayDeque<>();
worklist.push(msym);
clash.remove(msym);
while (!worklist.isEmpty()) {
MethodSymbol msym2 = worklist.removeFirst();
ImmutableList<MethodSymbol> overrides = clash.stream().filter(m -> msym2.overrides(m, origin, types, /*checkResult=*/
false)).collect(toImmutableList());
worklist.addAll(overrides);
clash.removeAll(overrides);
}
if (!clash.isEmpty()) {
// ignore if there are overridden clashing methods in class
if (ASTHelpers.findSuperMethod(msym, types).isPresent() && clash.stream().anyMatch(methodSymbol -> ASTHelpers.findSuperMethod(methodSymbol, types).isPresent())) {
return NO_MATCH;
}
String message = "When passing lambda arguments to this function, callers will need a cast to" + " disambiguate with: " + clash.stream().map(m -> Signatures.prettyMethodSignature(origin, m)).collect(joining("\n "));
state.reportMatch(buildDescription(member).setMessage(message).build());
}
}
return NO_MATCH;
}
use of com.sun.tools.javac.code.Symbol.MethodSymbol in project error-prone by google.
the class FutureReturnValueIgnored method matchReturn.
/**
* Returning a type of Future from a lambda or method that returns Object loses the Future type,
* which can result in suppressed errors or race conditions.
*/
@Override
public Description matchReturn(ReturnTree tree, VisitorState state) {
Type objectType = Objects.requireNonNull(state.getTypeFromString("java.lang.Object"));
Type futureType = Objects.requireNonNull(state.getTypeFromString("java.util.concurrent.Future"));
Type resultType = ASTHelpers.getResultType(tree.getExpression());
if (resultType == null) {
return Description.NO_MATCH;
}
if (resultType.getKind() == TypeKind.NULL || resultType.getKind() == TypeKind.NONE) {
return Description.NO_MATCH;
}
if (ASTHelpers.isSubtype(resultType, futureType, state)) {
// Traverse enclosing nodes of this return tree until either a lambda or a Method is reached.
for (Tree enclosing : state.getPath()) {
if (enclosing instanceof MethodTree) {
MethodTree methodTree = (MethodTree) enclosing;
MethodSymbol symbol = ASTHelpers.getSymbol(methodTree);
if (ASTHelpers.isSubtype(objectType, symbol.getReturnType(), state) && !isWhitelistedInterfaceMethod(symbol, state)) {
return buildDescription(tree).setMessage(String.format("Returning %s from method that returns %s. Errors from the returned future" + " may be ignored.", resultType, symbol.getReturnType())).build();
} else {
break;
}
}
if (enclosing instanceof LambdaExpressionTree) {
LambdaExpressionTree lambdaTree = (LambdaExpressionTree) enclosing;
if (isObjectReturningLambdaExpression(lambdaTree, state)) {
return buildDescription(tree).setMessage(String.format("Returning %s from method that returns Object. Errors from the returned" + " future will be ignored.", resultType)).build();
} else {
break;
}
}
}
}
return Description.NO_MATCH;
}
use of com.sun.tools.javac.code.Symbol.MethodSymbol in project error-prone by google.
the class CanonicalDuration method matchMethodInvocation.
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
Api api;
if (JAVA_TIME_MATCHER.matches(tree, state)) {
api = Api.JAVA;
} else if (JODA_MATCHER.matches(tree, state)) {
api = Api.JODA;
} else {
return NO_MATCH;
}
if (tree.getArguments().size() != 1) {
// TODO(cushon): ofSeconds w/ nano adjustment?
return NO_MATCH;
}
Tree arg = getOnlyElement(tree.getArguments());
if (!(arg instanceof LiteralTree)) {
// don't inline constants
return NO_MATCH;
}
Number value = constValue(arg, Number.class);
if (value == null) {
return NO_MATCH;
}
if (value.intValue() == 0) {
switch(api) {
case JODA:
ExpressionTree receiver = getReceiver(tree);
SuggestedFix fix;
if (receiver == null) {
// static import of the method
fix = SuggestedFix.builder().addImport(api.getDurationFullyQualifiedName()).replace(tree, "Duration.ZERO").build();
} else {
fix = SuggestedFix.replace(state.getEndPosition(getReceiver(tree)), state.getEndPosition(tree), ".ZERO");
}
return buildDescription(tree).setMessage("Duration can be expressed more clearly without units, as Duration.ZERO").addFix(fix).build();
case JAVA:
// don't rewrite e.g. `ofMillis(0)` to `ofDays(0)`
return NO_MATCH;
}
throw new AssertionError(api);
}
MethodSymbol sym = getSymbol(tree);
if (!METHOD_NAME_TO_UNIT.containsKey(sym.getSimpleName().toString())) {
return NO_MATCH;
}
TemporalUnit unit = METHOD_NAME_TO_UNIT.get(sym.getSimpleName().toString());
if (Objects.equals(BLACKLIST.get(unit), value.longValue())) {
return NO_MATCH;
}
Duration duration = Duration.of(value.longValue(), unit);
// largest unit that can be used to exactly express the duration.
for (Map.Entry<ChronoUnit, Converter<Duration, Long>> entry : CONVERTERS.entrySet()) {
ChronoUnit nextUnit = entry.getKey();
if (unit.equals(nextUnit)) {
// We reached the original unit, no simplification is possible.
break;
}
Converter<Duration, Long> converter = entry.getValue();
long nextValue = converter.convert(duration);
if (converter.reverse().convert(nextValue).equals(duration)) {
// We reached a larger than original unit that precisely expresses the duration, rewrite to
// use it instead.
String name = FACTORIES.get(api, nextUnit);
String replacement = String.format("%s(%d%s)", name, nextValue, nextValue == ((int) nextValue) ? "" : "L");
ExpressionTree receiver = getReceiver(tree);
if (receiver == null) {
// static import of the method
SuggestedFix fix = SuggestedFix.builder().addStaticImport(api.getDurationFullyQualifiedName() + "." + name).replace(tree, replacement).build();
return describeMatch(tree, fix);
} else {
return describeMatch(tree, SuggestedFix.replace(state.getEndPosition(receiver), state.getEndPosition(tree), "." + replacement));
}
}
}
return NO_MATCH;
}
use of com.sun.tools.javac.code.Symbol.MethodSymbol in project error-prone by google.
the class InexactVarargsConditional method matchMethodInvocation.
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
MethodSymbol sym = ASTHelpers.getSymbol(tree);
if (!sym.isVarArgs()) {
return NO_MATCH;
}
if (tree.getArguments().size() != sym.getParameters().size()) {
// explicit varargs call with more actuals than formals
return NO_MATCH;
}
Tree arg = getLast(tree.getArguments());
if (!(arg instanceof ConditionalExpressionTree)) {
return NO_MATCH;
}
Types types = state.getTypes();
if (types.isArray(getType(arg))) {
return NO_MATCH;
}
ConditionalExpressionTree cond = (ConditionalExpressionTree) arg;
boolean trueIsArray = types.isArray(getType(cond.getTrueExpression()));
if (!(trueIsArray ^ types.isArray(getType(cond.getFalseExpression())))) {
return NO_MATCH;
}
SuggestedFix.Builder fix = SuggestedFix.builder();
String qualified = SuggestedFixes.qualifyType(state, fix, types.elemtype(getLast(sym.getParameters()).asType()));
Tree toFix = !trueIsArray ? cond.getTrueExpression() : cond.getFalseExpression();
fix.prefixWith(toFix, String.format("new %s[] {", qualified)).postfixWith(toFix, "}");
return describeMatch(tree, fix.build());
}
use of com.sun.tools.javac.code.Symbol.MethodSymbol in project error-prone by google.
the class InfiniteRecursion method matchMethod.
@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
if (tree.getBody() == null || tree.getBody().getStatements().size() != 1) {
return NO_MATCH;
}
Tree statement = stripParentheses(getOnlyElement(tree.getBody().getStatements()));
ExpressionTree expr = statement.accept(new SimpleTreeVisitor<ExpressionTree, Void>() {
@Override
public ExpressionTree visitExpressionStatement(ExpressionStatementTree tree, Void unused) {
return tree.getExpression();
}
@Override
public ExpressionTree visitReturn(ReturnTree tree, Void unused) {
return tree.getExpression();
}
}, null);
if (!(expr instanceof MethodInvocationTree)) {
return NO_MATCH;
}
ExpressionTree select = ((MethodInvocationTree) expr).getMethodSelect();
switch(select.getKind()) {
case IDENTIFIER:
break;
case MEMBER_SELECT:
ExpressionTree receiver = ((MemberSelectTree) select).getExpression();
if (receiver.getKind() != Kind.IDENTIFIER) {
return NO_MATCH;
}
if (!((IdentifierTree) receiver).getName().contentEquals("this")) {
return NO_MATCH;
}
break;
default:
return NO_MATCH;
}
MethodSymbol sym = ASTHelpers.getSymbol(tree);
if (sym == null || !sym.equals(ASTHelpers.getSymbol(expr))) {
return NO_MATCH;
}
return describeMatch(statement);
}
Aggregations