Skip to content

Commit

Permalink
CORE-97 Refinements
Browse files Browse the repository at this point in the history
Getting there...
  • Loading branch information
ferdinand-swoboda committed May 31, 2022
1 parent e7adcc1 commit 59e5ba7
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,22 @@
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
import static com.google.errorprone.BugPattern.StandardTags.LIKELY_ERROR;
import static com.google.errorprone.matchers.Matchers.hasAnnotation;
import static com.google.errorprone.matchers.Matchers.hasAnyAnnotation;
import static com.google.errorprone.matchers.Matchers.isSameType;
import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
import static com.google.errorprone.matchers.Matchers.isType;
import static com.google.errorprone.matchers.Matchers.methodReturns;

import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableSortedSet;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
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.MethodTree;
import com.sun.source.tree.Tree;
import org.immutables.value.Value;

/**
Expand All @@ -27,43 +32,43 @@
@BugPattern(
name = "MissingImmutableSortedSetDefault",
summary =
"Properties of type `ImmutableSortedSet` within an @Value.Immutable or @Value.Modifiable class "
"Methods returning an `ImmutableSortedSet` within an @Value.Immutable or @Value.Modifiable class "
+ "should provide a default value or specify the comparator.",
linkType = NONE,
severity = ERROR,
tags = LIKELY_ERROR)
public final class MissingImmutableSortedSetDefaultCheck extends BugChecker
implements MethodTreeMatcher {
private static final long serialVersionUID = 1L;
private static final String VALUE_NATURAL_ORDER_ANNOTATION =
"org.immutables.value.Value.NaturalOrder";
private static final Matcher<Tree> HAS_NATURAL_ORDER =
hasAnnotation(VALUE_NATURAL_ORDER_ANNOTATION);

@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
// is not within immutable or modifiable class -> no match
if (tree.getClass().isAnnotationPresent(org.immutables.value.Value.Immutable.class)
|| tree.getClass().isAnnotationPresent(Value.Modifiable.class)) {
// has no return type ImmutableSortedSet -> no match
if (!methodReturns(isSameType(ImmutableSortedSet.class)).matches(tree, state)) {
return Description.NO_MATCH;
}

// has implementation -> no match
if (tree.getDefaultValue() != null) {
if (tree.getBody() != null && !tree.getBody().getStatements().isEmpty()) {
return Description.NO_MATCH;
}

// is not within immutable or modifiable class -> no match
if (!ASTHelpers.hasAnnotation(tree, org.immutables.value.Value.Immutable.class, state)
&& !ASTHelpers.hasAnnotation(tree, Value.Modifiable.class, state)) {
return Description.NO_MATCH;
}

// is annotated with @Value.NaturalOrder -> no match
if (HAS_NATURAL_ORDER.matches(tree, state)) {
if (hasAnnotation(Value.NaturalOrder.class).matches(tree, state)) {
return Description.NO_MATCH;
}

// The ImmutableSortedSet has no empty default -> add the `@Value.NaturalOrder` annotation.
return describeMatch(
tree,
SuggestedFix.builder()
.addStaticImport(VALUE_NATURAL_ORDER_ANNOTATION)
.prefixWith(tree, "@Value.NaturalOrder ")
.build());
// The ImmutableSortedSet has no empty default -> add the `@Value.NaturalOrder` annotation or
// provide a default implementation.
return buildDescription(tree)
.addFix(SuggestedFix.builder().prefixWith(tree, "@Value.NaturalOrder ").build())
.addFix(SuggestedFix.postfixWith(tree, "return ImmutableSortedSet.of();"))
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public final class MissingImmutableSortedSetDefaultCheckTest {
.expectErrorMessage(
"X",
containsPattern(
"Properties of type `ImmutableSortedSet` within an @Value.Immutable or @Value.Modifiable class should provide a default value or specify the comparator."));
"Methods returning an `ImmutableSortedSet` within an @Value.Immutable or @Value.Modifiable class should provide a default value or specify the comparator."));
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(
MissingImmutableSortedSetDefaultCheck.class, getClass());
Expand Down Expand Up @@ -85,12 +85,25 @@ void identification() {
" }",
" @Value.NaturalOrder",
" abstract ImmutableSortedSet<String> defaultSortedSet3();",
"}",
"",
"abstract class E {",
" abstract ImmutableSortedSet<String> sortedSet();",
" ImmutableSortedSet<String> defaultSortedSet() {",
" return ImmutableSortedSet.of();",
" }",
" @Value.Default",
" ImmutableSortedSet<String> defaultSortedSet2() {",
" return ImmutableSortedSet.of();",
" }",
" @Value.NaturalOrder",
" abstract ImmutableSortedSet<String> defaultSortedSet3();",
"}")
.doTest();
}

@Test
void replacement() {
void replacementInImmutableInterface() {
refactoringTestHelper
.addInputLines(
"A.java",
Expand All @@ -110,7 +123,38 @@ void replacement() {
" }",
" @Value.NaturalOrder",
" ImmutableSortedSet<String> defaultSortedSet3();",
"}",
"}")
.addOutputLines(
"A.java",
"import org.immutables.value.Value;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.common.collect.ImmutableSortedSet;",
"",
"@Value.Immutable",
"interface A {",
" @Value.NaturalOrder",
" ImmutableSortedSet<String> sortedSet();",
" default ImmutableSortedSet<String> defaultSortedSet() {",
" return ImmutableSortedSet.of();",
" }",
" @Value.Default",
" default ImmutableSortedSet<String> defaultSortedSet2() {",
" return ImmutableSortedSet.of();",
" }",
" @Value.NaturalOrder",
" ImmutableSortedSet<String> defaultSortedSet3();",
"}")
.doTest(TestMode.TEXT_MATCH);
}

@Test
void replacementInModifiableInterface() {
refactoringTestHelper
.addInputLines(
"A.java",
"import org.immutables.value.Value;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.common.collect.ImmutableSortedSet;",
"",
"@Value.Modifiable",
"interface B {",
Expand All @@ -124,7 +168,38 @@ void replacement() {
" }",
" @Value.NaturalOrder",
" ImmutableSortedSet<String> defaultSortedSet3();",
"}",
"}")
.addOutputLines(
"A.java",
"import org.immutables.value.Value;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.common.collect.ImmutableSortedSet;",
"",
"@Value.Modifiable",
"interface B {",
" @Value.NaturalOrder",
" ImmutableSortedSet<String> sortedSet();",
" default ImmutableSortedSet<String> defaultSortedSet() {",
" return ImmutableSortedSet.of();",
" }",
" @Value.Default",
" default ImmutableSortedSet<String> defaultSortedSet2() {",
" return ImmutableSortedSet.of();",
" }",
" @Value.NaturalOrder",
" ImmutableSortedSet<String> defaultSortedSet3();",
"}")
.doTest(TestMode.TEXT_MATCH);
}

@Test
void replacementInImmutableAbstractClass() {
refactoringTestHelper
.addInputLines(
"A.java",
"import org.immutables.value.Value;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.common.collect.ImmutableSortedSet;",
"",
"@Value.Immutable",
"abstract class C {",
Expand All @@ -138,10 +213,16 @@ void replacement() {
" }",
" @Value.NaturalOrder",
" abstract ImmutableSortedSet<String> defaultSortedSet3();",
"}",
"}")
.addOutputLines(
"A.java",
"import org.immutables.value.Value;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.common.collect.ImmutableSortedSet;",
"",
"@Value.Modifiable",
"abstract class D {",
"@Value.Immutable",
"abstract class C {",
" @Value.NaturalOrder",
" abstract ImmutableSortedSet<String> sortedSet();",
" ImmutableSortedSet<String> defaultSortedSet() {",
" return ImmutableSortedSet.of();",
Expand All @@ -153,45 +234,64 @@ void replacement() {
" @Value.NaturalOrder",
" abstract ImmutableSortedSet<String> defaultSortedSet3();",
"}")
.addOutputLines(
.doTest(TestMode.TEXT_MATCH);
}

@Test
void replacementInModifiableAbstractClass() {
refactoringTestHelper
.addInputLines(
"A.java",
"import org.immutables.value.Value;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.common.collect.ImmutableSortedSet;",
"",
"@Value.Immutable",
"interface A {",
" @Value.NaturalOrder",
" ImmutableSortedSet<String> sortedSet();",
" default ImmutableSortedSet<String> defaultSortedSet() {",
"@Value.Modifiable",
"abstract class D {",
" abstract ImmutableSortedSet<String> sortedSet();",
" ImmutableSortedSet<String> defaultSortedSet() {",
" return ImmutableSortedSet.of();",
" }",
" @Value.Default",
" default ImmutableSortedSet<String> defaultSortedSet2() {",
" ImmutableSortedSet<String> defaultSortedSet2() {",
" return ImmutableSortedSet.of();",
" }",
" @Value.NaturalOrder",
" ImmutableSortedSet<String> defaultSortedSet3();",
"}",
" abstract ImmutableSortedSet<String> defaultSortedSet3();",
"}")
.addOutputLines(
"A.java",
"import org.immutables.value.Value;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.common.collect.ImmutableSortedSet;",
"",
"@Value.Modifiable",
"interface B {",
"abstract class D {",
" @Value.NaturalOrder",
" ImmutableSortedSet<String> sortedSet();",
" default ImmutableSortedSet<String> defaultSortedSet() {",
" abstract ImmutableSortedSet<String> sortedSet();",
" ImmutableSortedSet<String> defaultSortedSet() {",
" return ImmutableSortedSet.of();",
" }",
" @Value.Default",
" default ImmutableSortedSet<String> defaultSortedSet2() {",
" ImmutableSortedSet<String> defaultSortedSet2() {",
" return ImmutableSortedSet.of();",
" }",
" @Value.NaturalOrder",
" ImmutableSortedSet<String> defaultSortedSet3();",
"}",
" abstract ImmutableSortedSet<String> defaultSortedSet3();",
"}")
.doTest(TestMode.TEXT_MATCH);
}

@Test
void noReplacementInNormalClass() {
refactoringTestHelper
.addInputLines(
"A.java",
"import org.immutables.value.Value;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.common.collect.ImmutableSortedSet;",
"",
"@Value.Immutable",
"abstract class C {",
" @Value.NaturalOrder",
"abstract class E {",
" abstract ImmutableSortedSet<String> sortedSet();",
" ImmutableSortedSet<String> defaultSortedSet() {",
" return ImmutableSortedSet.of();",
Expand All @@ -202,11 +302,14 @@ void replacement() {
" }",
" @Value.NaturalOrder",
" abstract ImmutableSortedSet<String> defaultSortedSet3();",
"}",
"}")
.addOutputLines(
"A.java",
"import org.immutables.value.Value;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.common.collect.ImmutableSortedSet;",
"",
"@Value.Modifiable",
"abstract class D {",
" @Value.NaturalOrder",
"abstract class E {",
" abstract ImmutableSortedSet<String> sortedSet();",
" ImmutableSortedSet<String> defaultSortedSet() {",
" return ImmutableSortedSet.of();",
Expand Down

0 comments on commit 59e5ba7

Please sign in to comment.