diff --git a/baseline-error-prone/src/main/java/com/palantir/baseline/errorprone/ImmutablesInterfaceDefaultValue.java b/baseline-error-prone/src/main/java/com/palantir/baseline/errorprone/ImmutablesInterfaceDefaultValue.java
new file mode 100644
index 000000000..0bf1175d8
--- /dev/null
+++ b/baseline-error-prone/src/main/java/com/palantir/baseline/errorprone/ImmutablesInterfaceDefaultValue.java
@@ -0,0 +1,73 @@
+/*
+ * (c) Copyright 2020 Palantir Technologies Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.palantir.baseline.errorprone;
+
+import com.google.auto.service.AutoService;
+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.fixes.SuggestedFixes;
+import com.google.errorprone.matchers.Description;
+import com.google.errorprone.matchers.Matcher;
+import com.google.errorprone.matchers.Matchers;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.Tree;
+import javax.lang.model.element.Modifier;
+
+/**
+ * Checks that interface default methods in an immutables.org @Value.Immutable are
+ * annotated with
+ * @Value.Default ,
+ * @Value.Derived , or
+ * @Value.Lazy .
+ *
+ * This check only applies to interfaces annotated with @ImmutablesConfigStyle.
+ */
+@AutoService(BugChecker.class)
+@BugPattern(
+ linkType = BugPattern.LinkType.CUSTOM,
+ link = "https://github.com/palantir/gradle-baseline#baseline-error-prone-checks",
+ severity = BugPattern.SeverityLevel.ERROR,
+ summary = "@Value.Immutable interface default methods should be annotated with"
+ + " @Value.Default, @Value.Derived, @Value.Lazy, or @JsonIgnore")
+public final class ImmutablesInterfaceDefaultValue extends BugChecker implements MethodTreeMatcher {
+
+ private static final Matcher MISSING_ANNOTATION_MATCHER = Matchers.allOf(
+ Matchers.enclosingClass(Matchers.allOf(
+ Matchers.hasAnnotation("org.immutables.value.Value.Immutable"),
+ Matchers.hasAnnotation("com.palantir.immutables.style.ImmutablesConfigStyle"))),
+ Matchers.hasModifier(Modifier.DEFAULT),
+ Matchers.not(Matchers.anyOf(
+ Matchers.hasAnnotation("org.immutables.value.Value.Default"),
+ Matchers.hasAnnotation("org.immutables.value.Value.Derived"),
+ Matchers.hasAnnotation("org.immutables.value.Value.Lazy"),
+ Matchers.hasAnnotation("com.fasterxml.jackson.annotation.JsonIgnore"))));
+
+ @Override
+ public Description matchMethod(MethodTree tree, VisitorState state) {
+ if (MISSING_ANNOTATION_MATCHER.matches(tree, state)) {
+ SuggestedFix.Builder builder = SuggestedFix.builder();
+ String annotation = SuggestedFixes.qualifyType(state, builder, "org.immutables.value.Value.Default");
+ return buildDescription(tree)
+ .addFix(builder.prefixWith(tree, "@" + annotation + " ").build())
+ .build();
+ }
+ return Description.NO_MATCH;
+ }
+}
diff --git a/baseline-error-prone/src/test/java/com/palantir/baseline/errorprone/ImmutablesInterfaceDefaultValueTest.java b/baseline-error-prone/src/test/java/com/palantir/baseline/errorprone/ImmutablesInterfaceDefaultValueTest.java
new file mode 100644
index 000000000..7ee57dafe
--- /dev/null
+++ b/baseline-error-prone/src/test/java/com/palantir/baseline/errorprone/ImmutablesInterfaceDefaultValueTest.java
@@ -0,0 +1,208 @@
+/*
+ * (c) Copyright 2020 Palantir Technologies Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.palantir.baseline.errorprone;
+
+import com.google.errorprone.CompilationTestHelper;
+import org.junit.jupiter.api.Test;
+
+public class ImmutablesInterfaceDefaultValueTest {
+
+ @Test
+ public void testFailsWhenDefaultMethodNotAnnotated() {
+ helper().addSourceLines(
+ "Test.java",
+ "import org.immutables.value.*;",
+ "import com.palantir.immutables.style.ImmutablesConfigStyle;",
+ "public class Test {",
+ " @Value.Immutable",
+ " @ImmutablesConfigStyle",
+ " public interface InterfaceWithValueDefault {",
+ " String value();",
+ "",
+ " // BUG: Diagnostic contains: @Value.Immutable interface"
+ + " default methods should be annotated with"
+ + " @Value.Default, @Value.Derived, @Value.Lazy, or @JsonIgnore",
+ " default String defaultValue() {",
+ " return \"default\";",
+ " }",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testPassesWhenInterfaceIsNotConfig() {
+ helper().addSourceLines(
+ "Test.java",
+ "import org.immutables.value.*;",
+ "public class Test {",
+ " @Value.Immutable",
+ " public interface InterfaceWithValueDefault {",
+ " String value();",
+ "",
+ " default String defaultValue() {",
+ " return \"default\";",
+ " }",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testPassesWhenDefaultMethodAnnotatedValueDefault() {
+ helper().addSourceLines(
+ "Test.java",
+ "import org.immutables.value.*;",
+ "public class Test {",
+ " @Value.Immutable",
+ " public interface InterfaceWithValueDefault {",
+ " String value();",
+ "",
+ " @Value.Default",
+ " default String defaultValue() {",
+ " return \"default\";",
+ " }",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testPassesWhenDefaultMethodAnnotatedValueDerived() {
+ helper().addSourceLines(
+ "Test.java",
+ "import org.immutables.value.*;",
+ "public class Test {",
+ " @Value.Immutable",
+ " public interface InterfaceWithValueDefault {",
+ " String value();",
+ "",
+ " @Value.Derived",
+ " default String derivedValue() {",
+ " return value();",
+ " }",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testPassesWhenDefaultMethodAnnotatedValueLazy() {
+ helper().addSourceLines(
+ "Test.java",
+ "import org.immutables.value.*;",
+ "public class Test {",
+ " @Value.Immutable",
+ " public interface InterfaceWithValueDefault {",
+ " String value();",
+ "",
+ " @Value.Lazy",
+ " default String lazyValue() {",
+ " return value();",
+ " }",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testPassesWhenDefaultMethodAnnotatedJsonIgnore() {
+ helper().addSourceLines(
+ "Test.java",
+ "import com.fasterxml.jackson.annotation.JsonIgnore;",
+ "import org.immutables.value.*;",
+ "public class Test {",
+ " @Value.Immutable",
+ " public interface InterfaceWithValueDefault {",
+ " String value();",
+ "",
+ " @JsonIgnore",
+ " default String lazyValue() {",
+ " return value();",
+ " }",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void refactorsMissingDefaultValueAnnotation() {
+ refactoring()
+ .addInputLines(
+ "Test.java",
+ "import org.immutables.value.*;",
+ "import com.palantir.immutables.style.ImmutablesConfigStyle;",
+ "public class Test {",
+ " @Value.Immutable",
+ " @ImmutablesConfigStyle",
+ " public interface InterfaceWithValueDefault {",
+ " String value();",
+ "",
+ " // BUG: Diagnostic contains: "
+ + "@Value.Immutable interface default methods should be annotated with "
+ + "@Value.Default, @Value.Default, @Value.Derived, @Value.Lazy, or @JsonIgnore",
+ " default String defaultValue() {",
+ " return \"default\";",
+ " }",
+ "",
+ " @Value.Derived",
+ " default String derivedValue() {",
+ " return value();",
+ " }",
+ "",
+ " @Value.Lazy",
+ " default String lazyValue() {",
+ " return value();",
+ " }",
+ " }",
+ "}")
+ .addOutputLines(
+ "Test.java",
+ "import org.immutables.value.*;",
+ "import com.palantir.immutables.style.ImmutablesConfigStyle;",
+ "public class Test {",
+ " @Value.Immutable",
+ " @ImmutablesConfigStyle",
+ " public interface InterfaceWithValueDefault {",
+ " String value();",
+ "",
+ " @Value.Default",
+ " default String defaultValue() {",
+ " return \"default\";",
+ " }",
+ "",
+ " @Value.Derived",
+ " default String derivedValue() {",
+ " return value();",
+ " }",
+ "",
+ " @Value.Lazy",
+ " default String lazyValue() {",
+ " return value();",
+ " }",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ private CompilationTestHelper helper() {
+ return CompilationTestHelper.newInstance(ImmutablesInterfaceDefaultValue.class, getClass());
+ }
+
+ private RefactoringValidator refactoring() {
+ return RefactoringValidator.of(ImmutablesInterfaceDefaultValue.class, getClass());
+ }
+}
diff --git a/baseline-error-prone/src/test/java/com/palantir/immutables/style/ImmutablesConfigStyle.java b/baseline-error-prone/src/test/java/com/palantir/immutables/style/ImmutablesConfigStyle.java
new file mode 100644
index 000000000..7444000d2
--- /dev/null
+++ b/baseline-error-prone/src/test/java/com/palantir/immutables/style/ImmutablesConfigStyle.java
@@ -0,0 +1,22 @@
+/*
+ * (c) Copyright 2024 Palantir Technologies Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.palantir.immutables.style;
+
+/**
+ * Placeholder definition for use in tests.
+ */
+public @interface ImmutablesConfigStyle {}
diff --git a/changelog/@unreleased/pr-1761.v2.yml b/changelog/@unreleased/pr-1761.v2.yml
new file mode 100644
index 000000000..add184da3
--- /dev/null
+++ b/changelog/@unreleased/pr-1761.v2.yml
@@ -0,0 +1,8 @@
+type: improvement
+improvement:
+ description: |-
+ Add ImmutablesInterfaceDefaultValue
+
+ @Value.Immutable interface default methods should be annotated @Value.Default
+ links:
+ - https://github.com/palantir/gradle-baseline/pull/1761