Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1863,10 +1863,10 @@ public static String castTree(ExpressionTree expressionTree, String toType, Visi
public static Optional<SuggestedFix> replaceVariableType(
VariableTree tree, String replacementType, VisitorState state) {
Tree type = tree.getType();
if (hasExplicitSource(type, state)) {
if (type != null && hasExplicitSource(type, state)) {
return Optional.of(SuggestedFix.replace(type, replacementType));
}
int pos = getStartPosition(type);
int pos = type != null ? getStartPosition(type) : Position.NOPOS;
if (pos == Position.NOPOS) {
pos = getStartPosition(tree);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@

package com.google.errorprone.bugpatterns;

import static com.google.common.truth.TruthJUnit.assume;

import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.CompilationTestHelper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
Expand All @@ -27,6 +30,9 @@ public final class VarWithPrimitiveTest {
private final BugCheckerRefactoringTestHelper refactoringHelper =
BugCheckerRefactoringTestHelper.newInstance(VarWithPrimitive.class, getClass());

private final CompilationTestHelper compilationHelper =
CompilationTestHelper.newInstance(VarWithPrimitive.class, getClass());

// from https://openjdk.org/projects/amber/guides/lvti-style-guide#G7
@Test
public void lvtiExamples() {
Expand Down Expand Up @@ -194,6 +200,229 @@ long getAgeAsLong() {
.doTest();
}

@Test
public void enhancedForLoop() {
refactoringHelper
.addInputLines(
"Test.java",
"""
class Test {
void t() {
int[] arr = {1, 2, 3};
for (var x : arr) {
System.out.println(x);
}
}
}
""")
.addOutputLines(
"Test.java",
"""
class Test {
void t() {
int[] arr = {1, 2, 3};
for (int x : arr) {
System.out.println(x);
}
}
}
""")
.doTest();
}

@Test
public void forLoopInitializer() {
refactoringHelper
.addInputLines(
"Test.java",
"""
class Test {
void t() {
for (var i = 0; i < 10; i++) {
System.out.println(i);
}
}
}
""")
.addOutputLines(
"Test.java",
"""
class Test {
void t() {
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}
}
""")
.doTest();
}

@Test
public void implicitLambdaParameter_noMatch() {
refactoringHelper
.addInputLines(
"Test.java",
"""
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
class Test {
void foo() {
byte[] bar = new byte[6];
Map<Byte, List<Byte>> indicesMap =
IntStream.range(0, 6)
.mapToObj(n -> n)
.collect(
Collectors.groupingBy(
n -> bar[n],
Collectors.mapping(
n -> (byte) n.intValue(), Collectors.toList())));
}
}
""")
.expectUnchanged()
.doTest();
}

@Test
public void varLambdaParam() {
refactoringHelper
.addInputLines(
"Test.java",
"""
import java.util.function.IntUnaryOperator;
class Test {
void t() {
IntUnaryOperator op = (var n) -> n * 2;
}
}
""")
.addOutputLines(
"Test.java",
"""
import java.util.function.IntUnaryOperator;
class Test {
void t() {
IntUnaryOperator op = (int n) -> n * 2;
}
}
""")
.doTest();
}

@Test
public void annotatedVarLambdaParam() {
refactoringHelper
.addInputLines("A.java", "@interface A { int var() default 0; }")
.expectUnchanged()
.addInputLines(
"Test.java",
"""
import java.util.function.IntUnaryOperator;
class Test {
void t() {
IntUnaryOperator op = (@A(var = 0) var n) -> n * 2;
}
}
""")
.addOutputLines(
"Test.java",
"""
import java.util.function.IntUnaryOperator;
class Test {
void t() {
IntUnaryOperator op = (@A(var = 0) int n) -> n * 2;
}
}
""")
.doTest();
}

@Test
public void annotatedVarLocalVariable_beforeJdk27() {
// Before JDK 27 there is no AST node for the var type, so the token scan finds two 'var'
// tokens (@A(var=0) attribute + type keyword) and safely returns no fix.
assume().that(Runtime.version().feature()).isLessThan(27);
refactoringHelper
.addInputLines("A.java", "@interface A { int var() default 0; }")
.expectUnchanged()
.addInputLines(
"Test.java",
"""
class Test {
void t() {
@A(var = 0) var n = 5;
}
}
""")
.expectUnchanged()
.doTest();
}

@Test
public void annotatedVarLocalVariable_jdk27AndAbove() {
// On JDK 27+ there is an AST node for the var type with source positions, so hasExplicitSource
// returns true and the replacement targets the type keyword directly, preserving the
// annotation.
assume().that(Runtime.version().feature()).isAtLeast(27);
refactoringHelper
.addInputLines("A.java", "@interface A { int var() default 0; }")
.expectUnchanged()
.addInputLines(
"Test.java",
"""
class Test {
void t() {
@A(var = 0) var n = 5;
}
}
""")
.addOutputLines(
"Test.java",
"""
class Test {
void t() {
@A(var = 0) int n = 5;
}
}
""")
.doTest();
}

@Test
public void multiParamImplicitLambda_noMatch() {
compilationHelper
.addSourceLines(
"Test.java",
"""
import java.util.function.IntBinaryOperator;
class Test {
void t() {
IntBinaryOperator op = (a, b) -> a + b;
}
}
""")
.doTest();
}

@Test
public void explicitLambdaParam_noMatch() {
compilationHelper
.addSourceLines(
"Test.java",
"""
import java.util.function.IntUnaryOperator;
class Test {
void t() {
IntUnaryOperator op = (int n) -> n * 2;
}
}
""")
.doTest();
}

@Test
public void explicitType() {
refactoringHelper
Expand Down
Loading