Skip to content
Merged
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 @@ -16,6 +16,7 @@

package com.google.errorprone.fixes;

import static com.google.common.collect.Streams.stream;
import static com.google.common.truth.Truth.assertThat;
import static com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode.TEXT_MATCH;
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
Expand Down Expand Up @@ -102,7 +103,7 @@ enum EditKind {
/** Test checker that adds or removes modifiers. */
@BugPattern(summary = "Edits modifiers", severity = ERROR)
public static final class EditModifiersChecker extends BugChecker
implements VariableTreeMatcher, MethodTreeMatcher {
implements ClassTreeMatcher, VariableTreeMatcher, MethodTreeMatcher {

static final ImmutableMap<String, Modifier> MODIFIERS_BY_NAME = createModifiersByName();

Expand All @@ -124,10 +125,26 @@ public Description matchMethod(MethodTree tree, VisitorState state) {
return editModifiers(tree, state);
}

@Override
public Description matchClass(ClassTree tree, VisitorState state) {
return editModifiers(tree, state);
}

private Description editModifiers(Tree tree, VisitorState state) {
EditModifiers editModifiers =
ASTHelpers.getAnnotation(
ASTHelpers.findEnclosingNode(state.getPath(), ClassTree.class), EditModifiers.class);
stream(state.getPath())
.skip(1)
.map(
t ->
t instanceof ClassTree ct
? ASTHelpers.getAnnotation(ct, EditModifiers.class)
: null)
.filter(x -> x != null)
.findFirst()
.orElse(null);
if (editModifiers == null) {
return NO_MATCH;
}
SuggestedFix.Builder fix = SuggestedFix.builder();
Modifier[] mods =
Arrays.stream(editModifiers.value())
Expand All @@ -137,7 +154,7 @@ private Description editModifiers(Tree tree, VisitorState state) {
case ADD -> fix.merge(SuggestedFixes.addModifiers(tree, state, mods).orElse(null));
case REMOVE -> fix.merge(SuggestedFixes.removeModifiers(tree, state, mods).orElse(null));
}
return describeMatch(tree, fix.build());
return fix.isEmpty() ? NO_MATCH : describeMatch(tree, fix.build());
}
}

Expand Down Expand Up @@ -201,6 +218,47 @@ class Test {
.doTest();
}

@Test
public void addModifiers_nonSealed() {
CompilationTestHelper.newInstance(EditModifiersChecker.class, getClass())
.addSourceLines(
"Test.java",
"""
import com.google.errorprone.fixes.SuggestedFixesTest.EditModifiers;
import javax.annotation.Nullable;

@EditModifiers(value = "non-sealed", kind = EditModifiers.EditKind.ADD)
sealed interface Test {
// BUG: Diagnostic contains: non-sealed final class One
final class One extends Object {}

public non-sealed class Two implements Test {}
}
""")
.doTest();
}

@Test
public void addModifiers_nonSealedClass() {
// Note the wrong ordering.
CompilationTestHelper.newInstance(EditModifiersChecker.class, getClass())
.addSourceLines(
"Test.java",
"""
import com.google.errorprone.fixes.SuggestedFixesTest.EditModifiers;

@EditModifiers(value = "public", kind = EditModifiers.EditKind.ADD)
class Test {
// BUG: Diagnostic contains: sealed public interface A
sealed interface A {}

// BUG: Diagnostic contains: non-sealed public class B
non-sealed class B implements A {}
}
""")
.doTest();
}

@Test
public void addModifiersComment() {
CompilationTestHelper.newInstance(EditModifiersChecker.class, getClass())
Expand Down
Loading