diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/TypeParameterShadowing.java b/core/src/main/java/com/google/errorprone/bugpatterns/TypeParameterShadowing.java index 140f82a46aa..b7eeb374908 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/TypeParameterShadowing.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/TypeParameterShadowing.java @@ -60,7 +60,7 @@ public Description matchMethod(MethodTree tree, VisitorState state) { if (tree.getTypeParameters().isEmpty()) { return Description.NO_MATCH; } - return findDuplicatesOf(tree, tree.getTypeParameters()); + return findDuplicatesOf(tree, tree.getTypeParameters(), state); } @Override @@ -68,11 +68,11 @@ public Description matchClass(ClassTree tree, VisitorState state) { if (tree.getTypeParameters().isEmpty()) { return Description.NO_MATCH; } - return findDuplicatesOf(tree, tree.getTypeParameters()); + return findDuplicatesOf(tree, tree.getTypeParameters(), state); } private Description findDuplicatesOf( - Tree tree, List typeParameters) { + Tree tree, List typeParameters, VisitorState state) { Symbol symbol = ASTHelpers.getSymbol(tree); if (symbol == null) { @@ -118,7 +118,8 @@ private Description findDuplicatesOf( tree, typeParameters, v.name, - replacementTypeVarName(v.name, typeVarsInScope))) + replacementTypeVarName(v.name, typeVarsInScope), + state)) .forEach(fixBuilder::merge); descriptionBuilder.addFix(fixBuilder.build()); @@ -151,7 +152,8 @@ private static SuggestedFix renameTypeVariable( Tree sourceTree, List typeParameters, Name typeVariable, - String typeVarReplacement) { + String typeVarReplacement, + VisitorState state) { TypeParameterTree matchingTypeParam = typeParameters.stream().filter(t -> t.getName().contentEquals(typeVariable)).collect( @@ -169,8 +171,22 @@ private static SuggestedFix renameTypeVariable( new TreeScanner() { @Override public void visitIdent(JCTree.JCIdent tree) { - if (Objects.equal(ASTHelpers.getSymbol(tree), typeVariableSymbol)) { - fixBuilder.replace(tree, typeVarReplacement); + Symbol identSym = ASTHelpers.getSymbol(tree); + if (Objects.equal(identSym, typeVariableSymbol)) { + // Lambda parameters can be desugared early, so we need to make sure the source + // is there. In the example below, we would try to suggest replacing the node 't' + // with T2, since the compiler desugars to g((T t) -> false). The extra condition + // prevents us from doing that. + + // Foo { + // void g(Predicate p) {}, + // void blah() { + // g(t -> false); + // } + // } + if (Objects.equal(state.getSourceForNode(tree), name)) { + fixBuilder.replace(tree, typeVarReplacement); + } } } }); diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/TypeParameterShadowingTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/TypeParameterShadowingTest.java index f0426fc8ede..7b53acf64dd 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/TypeParameterShadowingTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/TypeParameterShadowingTest.java @@ -19,7 +19,6 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper; import com.google.errorprone.CompilationTestHelper; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -314,11 +313,10 @@ public void symbolWithoutTypeParameters() { .doTest(); } - @Ignore("b/35809355") @Test - public void b35809355() throws Exception { - compilationHelper - .addSourceLines( + public void lambdaParameterDesugaring() throws Exception { + refactoring + .addInputLines( "in/A.java", "import java.util.function.Consumer;", "class A {", @@ -329,6 +327,46 @@ public void b35809355() throws Exception { " abstract void g(Consumer c);", " }", "}") + .addOutputLines( + "out/A.java", + "import java.util.function.Consumer;", + "class A {", + " abstract class B {", + " void f() {", + " g(t -> {});", + " }", + " abstract void g(Consumer c);", + " }", + "}") + .doTest(); + } + + @Test + public void typesWithBounds() throws Exception { + refactoring + .addInputLines( + "in/Test.java", + "import java.util.function.Predicate;", + "class Test {", + " void something(B b) {", + " class Foo implements Predicate {", + " public boolean test(B b) { return false; }", + " }", + " new Foo<>();", + " }", + "}") + .addOutputLines( + "out/Test.java", + "import java.util.function.Predicate;", + "class Test {", + " void something(B b) {", + " class Foo implements Predicate {", + " public boolean test(B2 b) { return false; }", + " }", + " new Foo<>();", + " }", + "}") .doTest(); } + }