Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2017 The Error Prone Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod;
import static com.google.errorprone.util.ASTHelpers.hasAnnotation;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.bugpatterns.BugChecker.ReturnTreeMatcher;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.suppliers.Supplier;
import com.google.errorprone.suppliers.Suppliers;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ExpressionTree;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Type;
import java.util.Optional;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ForkJoinTask;
/** See BugPattern annotation. */
@BugPattern(
summary =
"Return value of methods returning Future must be checked. Ignoring returned Futures "
+ "suppresses exceptions thrown from the code that completes the Future.",
severity = WARNING,
tags = StandardTags.FRAGILE_CODE,
documentSuppression = false)
public final class FutureReturnValueIgnored extends AbstractReturnValueIgnored
implements ReturnTreeMatcher {
private static final Matcher IGNORED_METHODS =
anyOf(
// ForkJoinTask#fork has side-effects and returns 'this', so it's reasonable to ignore
// the return value.
instanceMethod()
.onDescendantOf(ForkJoinTask.class.getName())
.named("fork")
.withNoParameters(),
// CompletionService is intended to be used in a way where the Future returned
// from submit is discarded, because the Futures are available later via e.g. take()
instanceMethod().onDescendantOf(CompletionService.class.getName()).named("submit"),
// IntelliJ's executeOnPooledThread wraps the Callable/Runnable in one that catches
// Throwable, so it can't fail (unless logging the Throwable also throws, but there's
// nothing much to be done at that point).
instanceMethod()
.onDescendantOf("com.intellij.openapi.application.Application")
.named("executeOnPooledThread"),
// ChannelFuture#addListener(s) returns itself for chaining. Any exception during the
// future execution should be dealt by the listener(s).
instanceMethod()
.onDescendantOf("io.netty.util.concurrent.Future")
.namedAnyOf(
"addListener",
"addListeners",
"removeListener",
"removeListeners",
"sync",
"syncUninterruptibly",
"await",
"awaitUninterruptibly"),
instanceMethod()
.onDescendantOf("io.netty.util.concurrent.Promise")
.namedAnyOf("setSuccess", "setFailure"),
instanceMethod()
.onExactClass("java.util.concurrent.CompletableFuture")
.namedAnyOf("exceptionally", "completeAsync", "orTimeout", "completeOnTimeout"));
private static final Matcher MATCHER =
new Matcher() {
@Override
public boolean matches(ExpressionTree tree, VisitorState state) {
Type futureType = JAVA_UTIL_CONCURRENT_FUTURE.get(state);
if (futureType == null) {
return false;
}
Symbol untypedSymbol = ASTHelpers.getSymbol(tree);
if (!(untypedSymbol instanceof MethodSymbol)) {
Type resultType = ASTHelpers.getResultType(tree);
return resultType != null
&& ASTHelpers.isSubtype(
ASTHelpers.getUpperBound(resultType, state.getTypes()), futureType, state);
}
MethodSymbol sym = (MethodSymbol) untypedSymbol;
if (hasAnnotation(sym, CanIgnoreReturnValue.class, state)) {
return false;
}
for (MethodSymbol superSym : ASTHelpers.findSuperMethods(sym, state.getTypes())) {
// There are interfaces annotated with @CanIgnoreReturnValue (like Guava's Function)
// whose return value really shouldn't be ignored - as a heuristic, check if the super's
// method is returning a future subtype.
if (hasAnnotation(superSym, CanIgnoreReturnValue.class, state)
&& ASTHelpers.isSubtype(
ASTHelpers.getUpperBound(superSym.getReturnType(), state.getTypes()),
futureType,
state)) {
return false;
}
}
if (IGNORED_METHODS.matches(tree, state)) {
return false;
}
Type returnType = sym.getReturnType();
return ASTHelpers.isSubtype(
ASTHelpers.getUpperBound(returnType, state.getTypes()), futureType, state);
}
};
@Override
public Matcher specializedMatcher() {
return MATCHER;
}
@Override
protected Optional lostType(VisitorState state) {
return Optional.ofNullable(futureType.get(state));
}
@Override
protected String lostTypeMessage(String returnedType, String declaredReturnType) {
return String.format(
"Returning %s from method that returns %s. Errors from the returned future may be ignored.",
returnedType, declaredReturnType);
}
private final Supplier futureType = Suppliers.typeFromString("java.util.concurrent.Future");
private static final Supplier JAVA_UTIL_CONCURRENT_FUTURE =
VisitorState.memoize(state -> state.getTypeFromString("java.util.concurrent.Future"));
}