From 1c6082674943b72b0f4a46c1c4c4212924ab9884 Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Fri, 12 Aug 2022 06:44:24 -0700 Subject: [PATCH 01/22] `typeAnnotations()` removes line breaks between type annotations and types --- .../spotless/java/TypeAnnotationsStep.java | 450 ++++++++++++++++++ .../gradle/spotless/JavaExtension.java | 6 + .../TypeAnnotationsInCommentsInput.test | 31 ++ .../TypeAnnotationsInCommentsOutput.test | 25 + .../TypeAnnotationsTestInput.test | 68 +++ .../TypeAnnotationsTestOutput.test | 43 ++ .../java/TypeAnnotationsStepTest.java | 57 +++ 7 files changed, 680 insertions(+) create mode 100644 lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java create mode 100644 testlib/src/main/resources/java/typeannotations/TypeAnnotationsInCommentsInput.test create mode 100644 testlib/src/main/resources/java/typeannotations/TypeAnnotationsInCommentsOutput.test create mode 100644 testlib/src/main/resources/java/typeannotations/TypeAnnotationsTestInput.test create mode 100644 testlib/src/main/resources/java/typeannotations/TypeAnnotationsTestOutput.test create mode 100644 testlib/src/test/java/com/diffplug/spotless/java/TypeAnnotationsStepTest.java diff --git a/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java b/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java new file mode 100644 index 0000000000..d2fdc7cd1b --- /dev/null +++ b/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java @@ -0,0 +1,450 @@ +/* + * Copyright 2022 DiffPlug + * + * 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.diffplug.spotless.java; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.diffplug.spotless.FormatterFunc; +import com.diffplug.spotless.FormatterStep; + +/** + * Some formatters put every annotation on its own line + * -- even type annotations, which should be on the same line as the type they qualify. + * This class corrects the formatting. + * This is useful as a postprocessing step after a Java formatter that is not cognizant of type annotations. + */ +public final class TypeAnnotationsStep { + private TypeAnnotationsStep() {} + + static final String NAME = "No line break between type annotation and type"; + + public static FormatterStep create() { + return FormatterStep.create(NAME, new State(), State::toFormatter); + } + + // TODO: Enable users to specify more type annotations in `typeAnnotations` in build.gradle. + // TODO: Read from a local .type-annotations file. + private static final class State implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * These are type annotations, which should NOT go on their own line. + * A type annotation's {@code @Target} annotation contains {@code TYPE_USE}. + */ + private static final Set typeAnnotations = new HashSet<>( + Arrays.asList( + // Type annotations from the Checker Framework. + "A", + "ACCBottom", + "Acceleration", + "ACCTop", + "AinferBottom", + "AlwaysSafe", + "Angle", + "AnnoWithStringArg", + "Area", + "ArrayLen", + "ArrayLenRange", + "ArrayWithoutPackage", + "AwtAlphaCompositingRule", + "AwtColorSpace", + "AwtCursorType", + "AwtFlowLayout", + "B", + "BinaryName", + "BinaryNameInUnnamedPackage", + "BinaryNameOrPrimitiveType", + "BinaryNameWithoutPackage", + "BoolVal", + "Bottom", + "BottomQualifier", + "BottomThis", + "BottomVal", + "C", + "CalledMethods", + "CalledMethodsBottom", + "CalledMethodsPredicate", + "CalledMethodsTop", + "CanonicalName", + "CanonicalNameAndBinaryName", + "CanonicalNameOrEmpty", + "CanonicalNameOrPrimitiveType", + "CCBottom", + "CCTop", + "cd", + "ClassBound", + "ClassGetName", + "ClassGetSimpleName", + "ClassVal", + "ClassValBottom", + "CompilerMessageKey", + "CompilerMessageKeyBottom", + "Constant", + "Critical", + "Current", + "D", + "DefaultType", + "degrees", + "Det", + "DotSeparatedIdentifiers", + "DotSeparatedIdentifiersOrPrimitiveType", + "DoubleVal", + "E", + "Encrypted", + "EnhancedRegex", + "EnumVal", + "Even", + "F", + "FBCBottom", + "FEBottom", + "FEBot", + "Fenum", + "FenumBottom", + "FenumTop", + "FETop", + "FieldDescriptor", + "FieldDescriptorForPrimitive", + "FieldDescriptorForPrimitiveOrArrayInUnnamedPackage", + "FieldDescriptorWithoutPackage", + "FlowExp", + "Force", + "Format", + "FormatBottom", + "FqBinaryName", + "Frequency", + "FullyQualifiedName", + "g", + "GTENegativeOne", + "GuardedBy", + "GuardedByBottom", + "GuardedByUnknown", + "GuardSatisfied", + "h", + "H1Bot", + "H1Invalid", + "H1Poly", + "H1S1", + "H1S2", + "H1Top", + "H2Bot", + "H2Poly", + "H2S1", + "H2S2", + "H2Top", + "Hz", + "I18nFormat", + "I18nFormatBottom", + "I18nFormatFor", + "I18nInvalidFormat", + "I18nUnknownFormat", + "Identifier", + "IdentifierOrArray", + "IdentifierOrPrimitiveType", + "ImplicitAnno", + "IndexFor", + "IndexOrHigh", + "IndexOrLow", + "Initialized", + "InitializedFields", + "InitializedFieldsBottom", + "InitializedFieldsPredicate", + "InternalForm", + "Interned", + "InternedDistinct", + "IntRange", + "IntVal", + "InvalidFormat", + "K", + "KeyFor", + "KeyForBottom", + "KeyForType", + "kg", + "kHz", + "km", + "km2", + "km3", + "kmPERh", + "kN", + "LbTop", + "LB_TOP", + "LeakedToResult", + "Length", + "LengthOf", + "LessThan", + "LessThanBottom", + "LessThanUnknown", + "LocalizableKey", + "LocalizableKeyBottom", + "Localized", + "LowerBoundBottom", + "LowerBoundUnknown", + "LTEqLengthOf", + "LTLengthOf", + "LTOMLengthOf", + "Luminance", + "m", + "m2", + "m3", + "Mass", + "MatchesRegex", + "MaybeAliased", + "MaybeDerivedFromConstant", + "MaybePresent", + "MaybeThis", + "MethodDescriptor", + "MethodVal", + "MethodValBottom", + "min", + "MinLen", + "mm", + "mm2", + "mm3", + "mol", + "MonotonicNonNull", + "MonotonicNonNullType", + "MonotonicOdd", + "mPERs", + "mPERs2", + "MustCall", + "MustCallAlias", + "MustCallUnknown", + "N", + "NegativeIndexFor", + "NewObject", + "NonConstant", + "NonDet", + "NonLeaked", + "NonNegative", + "NonNull", + "NonNullType", + "NonRaw", + "NotCalledMethods", + "NotNull", + "NotQualifier", + "NTDBottom", + "NTDMiddle", + "NTDSide", + "NTDTop", + "Nullable", + "NullableType", + "Odd", + "OptionalBottom", + "OrderNonDet", + "Parent", + "PatternA", + "PatternAB", + "PatternAC", + "PatternB", + "PatternBC", + "PatternBottomFull", + "PatternBottomPartial", + "PatternC", + "PatternUnknown", + "Poly", + "PolyAll", + "PolyConstant", + "PolyDet", + "PolyEncrypted", + "PolyFenum", + "PolyIndex", + "PolyInitializedFields", + "PolyInterned", + "PolyKeyFor", + "PolyLength", + "PolyLowerBound", + "PolyMustCall", + "PolyNull", + "PolyNullType", + "PolyPresent", + "PolyRaw", + "PolyReflection", + "PolyRegex", + "PolySameLen", + "PolySignature", + "PolySigned", + "PolyTainted", + "PolyTestAccumulation", + "PolyTypeDeclDefault", + "PolyUI", + "PolyUnit", + "PolyUpperBound", + "PolyValue", + "PolyVariableNameDefault", + "Positive", + "Present", + "PrimitiveType", + "PropertyKey", + "PropertyKeyBottom", + "PurityUnqualified", + "Qualifier", + "radians", + "Raw", + "ReflectBottom", + "Regex", + "RegexBottom", + "RegexNNGroups", + "ReportUnqualified", + "s", + "SameLen", + "SameLenBottom", + "SameLenUnknown", + "SearchIndexBottom", + "SearchIndexFor", + "SearchIndexUnknown", + "Sibling1", + "Sibling2", + "SiblingWithFields", + "SignatureBottom", + "Signed", + "SignednessBottom", + "SignednessGlb", + "SignedPositive", + "SignedPositiveFromUnsigned", + "Speed", + "StringVal", + "SubQual", + "Substance", + "SubstringIndexBottom", + "SubstringIndexFor", + "SubstringIndexUnknown", + "SuperQual", + "SwingBoxOrientation", + "SwingCompassDirection", + "SwingElementOrientation", + "SwingHorizontalOrientation", + "SwingSplitPaneOrientation", + "SwingTextOrientation", + "SwingTitleJustification", + "SwingTitlePosition", + "SwingVerticalOrientation", + "t", + "Tainted", + "Temperature", + "TestAccumulation", + "TestAccumulationBottom", + "TestAccumulationPredicate", + "This", + "Time", + "Top", + "TypeDeclDefaultBottom", + "TypeDeclDefaultMiddle", + "TypeDeclDefaultTop", + "UbTop", + "UB_TOP", + "UI", + "UnderInitialization", + "Unique", + "UnitsBottom", + "UnknownClass", + "UnknownCompilerMessageKey", + "UnknownFormat", + "UnknownInitialization", + "UnknownInterned", + "UnknownKeyFor", + "UnknownLocalizableKey", + "UnknownLocalized", + "UnknownMethod", + "UnknownPropertyKey", + "UnknownRegex", + "UnknownSignedness", + "UnknownThis", + "UnknownUnits", + "UnknownVal", + "Unsigned", + "Untainted", + "UpperBoundBottom", + "UpperBoundLiteral", + "UpperBoundUnknown", + "Value", + "VariableNameDefaultBottom", + "VariableNameDefaultMiddle", + "VariableNameDefaultTop", + "Volume", + "WholeProgramInferenceBottom" + // Add type annotations from other tools here. + + )); + + // group 1 is the basename of the annotation. + private static final String annoNoArgRegex = "@(?:[A-Za-z_][A-Za-z0-9_.]*\\.)?([A-Za-z_][A-Za-z0-9_]*)"; + private static final Pattern annoNoArgPattern = Pattern.compile(annoNoArgRegex); + // 3 non-empty cases: () (".*") (.*) + private static final String annoArgRegex = "(?:\\(\\)|\\(\"[^\"]*\"\\)|\\([^\")][^)]*\\))?"; + // group 1 is the basename of the annotation. + private static final String annoRegex = annoNoArgRegex + annoArgRegex; + private static final String trailingAnnoRegex = annoRegex + "$"; + private static final Pattern trailingAnnoPattern = Pattern.compile(trailingAnnoRegex); + + // Heuristic: matches if the line might be within a //, /*, or Javadoc comment. + private static final Pattern withinCommentPattern = Pattern.compile("//|/\\*(?!.*/*/)|^[ \t]*\\*[ \t]"); + // Don't move an annotation to the start of a comment line. + private static final Pattern startsWithCommentPattern = Pattern.compile("^[ \t]*(//|/\\*$|/\\*|void\\b)"); + + State() {} + + FormatterFunc toFormatter() { + return unixStr -> fixupTypeAnnotations(unixStr); + } + + /** + * Removes line break between type annotations and the following type. + * + * @param the text of a Java file + * @return corrected text of the Java file + */ + String fixupTypeAnnotations(String unixStr) { + // Each element of `lines` ends with a newline. + String[] lines = unixStr.split("((?<=\n))"); + for (int i = 0; i < lines.length - 1; i++) { + String line = lines[i]; + if (endsWithTypeAnnotation(line)) { + String nextLine = lines[i + 1]; + if (startsWithCommentPattern.matcher(nextLine).find()) { + continue; + } + lines[i] = ""; + lines[i + 1] = line.stripTrailing() + " " + nextLine.stripLeading(); + } + } + return String.join("", lines); + } + + /** + * Returns true if the line ends with a type annotation. We need to fix such formatting. + */ + boolean endsWithTypeAnnotation(String unixLine) { + // Remove trailing newline. + String line = unixLine.stripTrailing(); + Matcher m = trailingAnnoPattern.matcher(line); + if (!m.find()) { + return false; + } + String preceding = line.substring(0, m.start()); + String basename = m.group(1); + + if (withinCommentPattern.matcher(preceding).find()) { + return false; + } + + return typeAnnotations.contains(basename); + } + } +} diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java index 479d2ffd12..d882ac472b 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java @@ -36,6 +36,7 @@ import com.diffplug.spotless.java.ImportOrderStep; import com.diffplug.spotless.java.PalantirJavaFormatStep; import com.diffplug.spotless.java.RemoveUnusedImportsStep; +import com.diffplug.spotless.java.TypeAnnotationsStep; public class JavaExtension extends FormatExtension implements HasBuiltinDelimiterForLicense { static final String NAME = "java"; @@ -231,6 +232,11 @@ public void configFile(Object... configFiles) { } + /** Removes newlines between type annotations and types. */ + public void typeAnnotations() { + addStep(TypeAnnotationsStep.create()); + } + /** If the user hasn't specified the files yet, we'll assume he/she means all of the java files. */ @Override protected void setupTask(SpotlessTask task) { diff --git a/testlib/src/main/resources/java/typeannotations/TypeAnnotationsInCommentsInput.test b/testlib/src/main/resources/java/typeannotations/TypeAnnotationsInCommentsInput.test new file mode 100644 index 0000000000..d49799c0c3 --- /dev/null +++ b/testlib/src/main/resources/java/typeannotations/TypeAnnotationsInCommentsInput.test @@ -0,0 +1,31 @@ +class TypeAnnotationsInComments { + + // Here is a comment relating to the annotation @Nullable + @Interned + String m1() {} + + // Here is another comment relating to the annotation @Nullable + String m2() {} + + /** + * Here is a misformatted type annotation within a Javadoc comment. + * + * @Nullable + * String s; + */ + + @Nullable + @Interned + String m3(/* Don't get confused by other comments on the line with the type */) {} + + @Nullable + @Interned + String m3() {} // Still not confused + + /* + code snippets in regular comments do get re-formatted + + @Nullable + String s; + */ +} diff --git a/testlib/src/main/resources/java/typeannotations/TypeAnnotationsInCommentsOutput.test b/testlib/src/main/resources/java/typeannotations/TypeAnnotationsInCommentsOutput.test new file mode 100644 index 0000000000..491ce5b2aa --- /dev/null +++ b/testlib/src/main/resources/java/typeannotations/TypeAnnotationsInCommentsOutput.test @@ -0,0 +1,25 @@ +class TypeAnnotationsInComments { + + // Here is a comment relating to the annotation @Nullable + @Interned String m1() {} + + // Here is another comment relating to the annotation @Nullable + String m2() {} + + /** + * Here is a misformatted type annotation within a Javadoc comment. + * + * @Nullable + * String s; + */ + + @Nullable @Interned String m3(/* Don't get confused by other comments on the line with the type */) {} + + @Nullable @Interned String m3() {} // Still not confused + + /* + code snippets in regular comments do get re-formatted + + @Nullable String s; + */ +} diff --git a/testlib/src/main/resources/java/typeannotations/TypeAnnotationsTestInput.test b/testlib/src/main/resources/java/typeannotations/TypeAnnotationsTestInput.test new file mode 100644 index 0000000000..8a870a34cc --- /dev/null +++ b/testlib/src/main/resources/java/typeannotations/TypeAnnotationsTestInput.test @@ -0,0 +1,68 @@ +class TypeAnnotationsTest { + + public @Nullable + String s0 = null; + + @Deprecated + public @Nullable + String m0() {} + + @Nullable + String s1 = null; + + @Deprecated + @Nullable + String m1() {} + + @Nullable + @Deprecated + String m2() {} + + @Nullable + @Regex(2) + @Interned + String s2 = null; + + @Deprecated + @Nullable + @Regex(2) + @Interned + String m3() {} + + @Nullable + @Deprecated + @Regex(2) + @Interned + String m4() {} + + @Nullable + // a comment + @Regex(2) + @Interned + String s3 = null; + + @Nullable // a comment + @Regex(2) + @Interned + String s4 = null; + + @Nullable + @Regex(2) + @Interned + // a comment + String s5 = null; + + @Deprecated + // a comment + @Nullable + @Regex(2) + @Interned + String m5() {} + + @Deprecated + @Nullable + // a comment + @Regex(2) + @Interned + String m6() {} +} diff --git a/testlib/src/main/resources/java/typeannotations/TypeAnnotationsTestOutput.test b/testlib/src/main/resources/java/typeannotations/TypeAnnotationsTestOutput.test new file mode 100644 index 0000000000..81fd049609 --- /dev/null +++ b/testlib/src/main/resources/java/typeannotations/TypeAnnotationsTestOutput.test @@ -0,0 +1,43 @@ +class TypeAnnotationsTest { + + public @Nullable String s0 = null; + + @Deprecated + public @Nullable String m0() {} + + @Nullable String s1 = null; + + @Deprecated + @Nullable String m1() {} + + @Nullable @Deprecated + String m2() {} + + @Nullable @Regex(2) @Interned String s2 = null; + + @Deprecated + @Nullable @Regex(2) @Interned String m3() {} + + @Nullable @Deprecated + @Regex(2) @Interned String m4() {} + + @Nullable + // a comment + @Regex(2) @Interned String s3 = null; + + @Nullable // a comment + @Regex(2) @Interned String s4 = null; + + @Nullable @Regex(2) @Interned + // a comment + String s5 = null; + + @Deprecated + // a comment + @Nullable @Regex(2) @Interned String m5() {} + + @Deprecated + @Nullable + // a comment + @Regex(2) @Interned String m6() {} +} diff --git a/testlib/src/test/java/com/diffplug/spotless/java/TypeAnnotationsStepTest.java b/testlib/src/test/java/com/diffplug/spotless/java/TypeAnnotationsStepTest.java new file mode 100644 index 0000000000..3724cac09f --- /dev/null +++ b/testlib/src/test/java/com/diffplug/spotless/java/TypeAnnotationsStepTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2022 DiffPlug + * + * 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.diffplug.spotless.java; + +import org.junit.jupiter.api.Test; + +import com.diffplug.spotless.FormatterStep; +import com.diffplug.spotless.ResourceHarness; +import com.diffplug.spotless.SerializableEqualityTester; + +class TypeAnnotationsStepTest extends ResourceHarness { + @Test + void typeAnnotations() throws Throwable { + FormatterStep step = TypeAnnotationsStep.create(); + assertOnResources(step, "java/typeannotations/TypeAnnotationsTestInput.test", "java/typeannotations/TypeAnnotationsTestOutput.test"); + } + + @Test + void typeAnnotationsInComments() throws Throwable { + FormatterStep step = TypeAnnotationsStep.create(); + assertOnResources(step, "java/typeannotations/TypeAnnotationsInCommentsInput.test", "java/typeannotations/TypeAnnotationsInCommentsOutput.test"); + } + + @Test + void doesntThrowIfTypeAnnotationsIsntSerializable() { + TypeAnnotationsStep.create(); + } + + @Test + void equality() throws Exception { + new SerializableEqualityTester() { + @Override + protected void setupTest(API api) { + api.areDifferentThan(); + } + + @Override + protected FormatterStep create() { + return TypeAnnotationsStep.create(); + } + }.testEquals(); + } + +} From 105eb878c91586fce323b2d6cb023b92bcd4cb94 Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Fri, 12 Aug 2022 06:50:36 -0700 Subject: [PATCH 02/22] Add changelog entry --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 751749585f..2b293772ee 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,8 @@ This document is intended for Spotless developers. We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] +### Added +* `typeAnnotations()` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formattng step, such as `googleJavaFormat()`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) ## [2.28.1] - 2022-08-10 ### Fixed From 6d76fc97f30320748a6e10cca7a052d6638b6529 Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Fri, 12 Aug 2022 06:52:13 -0700 Subject: [PATCH 03/22] Changelog in `plugin-gradle`, too --- plugin-gradle/CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 3cf249b893..ec0dd4e951 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `3.27.0`). ## [Unreleased] +### Added +* `typeAnnotations()` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formattng step, such as `googleJavaFormat()`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) ## [6.9.1] - 2022-08-10 ### Fixed From 0c5d1b65b2ec344cd06f310a716a7ad03bd71fc7 Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Sat, 13 Aug 2022 08:55:20 -0700 Subject: [PATCH 04/22] Don't use Java 11 APIs --- .../java/com/diffplug/spotless/java/TypeAnnotationsStep.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java b/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java index d2fdc7cd1b..dd0b86eeb4 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java @@ -421,7 +421,7 @@ String fixupTypeAnnotations(String unixStr) { continue; } lines[i] = ""; - lines[i + 1] = line.stripTrailing() + " " + nextLine.stripLeading(); + lines[i + 1] = line.replaceAll("\\s+$", "") + " " + nextLine.replaceAll("^\\s+", ""); } } return String.join("", lines); @@ -432,7 +432,7 @@ String fixupTypeAnnotations(String unixStr) { */ boolean endsWithTypeAnnotation(String unixLine) { // Remove trailing newline. - String line = unixLine.stripTrailing(); + String line = unixLine.replaceAll("\\s+$", ""); Matcher m = trailingAnnoPattern.matcher(line); if (!m.find()) { return false; From 42edcb1c094732c6efb52bc57bb61cc10bb17f88 Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Thu, 25 Aug 2022 09:28:16 -0700 Subject: [PATCH 05/22] Add documentation in `README.md` --- plugin-gradle/README.md | 42 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index bb71d8ab5b..aee7d43eef 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -60,7 +60,7 @@ Spotless supports all of Gradle's built-in performance features (incremental bui - [**Quickstart**](#quickstart) - [Requirements](#requirements) - **Languages** - - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [clang-format](#clang-format), [prettier](#prettier), [palantir-java-format](#palantir-java-format)) + - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [clang-format](#clang-format), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [type annotations](#Type annotations)) - [Groovy](#groovy) ([eclipse groovy](#eclipse-groovy)) - [Kotlin](#kotlin) ([ktfmt](#ktfmt), [ktlint](#ktlint), [diktat](#diktat), [prettier](#prettier)) - [Scala](#scala) ([scalafmt](#scalafmt)) @@ -117,6 +117,8 @@ spotless { // apply a specific flavor of google-java-format googleJavaFormat('1.8').aosp().reflowLongStrings() + // fix formatting of type annotations + typeAnnotations() // make sure every file has the following copyright header. // optionally, Spotless can set copyright years by digging // through git history (see "license" section below) @@ -162,6 +164,8 @@ spotless { prettier() // has its own section below clangFormat() // has its own section below + typeAnnotations() // has its own section below + licenseHeader '/* (C) $YEAR */' // or licenseHeaderFile } } @@ -188,6 +192,8 @@ spotless { // and/or reflow long strings (requires at least 1.8) // and/or use custom group artifact (you probably don't need this) googleJavaFormat('1.8').aosp().reflowLongStrings().groupArtifact('com.google.googlejavaformat:google-java-format') + // optional: fix formatting of type annotations + typeAnnotations() ``` **⚠️ Note on using Google Java Format with Java 16+** @@ -214,6 +220,8 @@ spotless { palantirJavaFormat() // optional: you can specify a specific version palantirJavaFormat('2.9.0') + // optional: fix formatting of type annotations + typeAnnotations() ``` **⚠️ Note on using Palantir Java Format with Java 16+** @@ -244,6 +252,38 @@ spotless { ``` +### Type annotations + +Type annotations should be on the same line as the type that they qualify. + +```java + @Override + @Deprecated + @Nullable @Interned String s; +``` + +However, some tools format them incorrectly, like this: + +```java + @Override + @Deprecated + @Nullable + @Interned + String s; +``` + +To fix the incorrect formatting, add the `typeAnnotations()` rule after a Java formatter. For example: + +```gradle +spotless { + java { + googleJavaFormat() + typeAnnotations() + } +} +``` + + ## Groovy From 4ad48a95a02261c34a5aa74c225d95289a3ecd56 Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Thu, 25 Aug 2022 09:31:52 -0700 Subject: [PATCH 06/22] Fix indentation --- .../diffplug/spotless/java/TypeAnnotationsStep.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java b/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java index dd0b86eeb4..673807a08e 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java @@ -405,10 +405,10 @@ FormatterFunc toFormatter() { } /** - * Removes line break between type annotations and the following type. - * - * @param the text of a Java file - * @return corrected text of the Java file + * Removes line break between type annotations and the following type. + * + * @param the text of a Java file + * @return corrected text of the Java file */ String fixupTypeAnnotations(String unixStr) { // Each element of `lines` ends with a newline. @@ -428,7 +428,8 @@ String fixupTypeAnnotations(String unixStr) { } /** - * Returns true if the line ends with a type annotation. We need to fix such formatting. + * Returns true if the line ends with a type annotation. + * TypeAnnotationStep fixes such formatting. */ boolean endsWithTypeAnnotation(String unixLine) { // Remove trailing newline. From e886d24500cf32fff6a417f1dc08bf93b6e15c0b Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Thu, 25 Aug 2022 10:17:40 -0700 Subject: [PATCH 07/22] The Checker Framework supports most known type annotations. --- .../java/com/diffplug/spotless/java/TypeAnnotationsStep.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java b/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java index 673807a08e..2a46f0f40c 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java @@ -51,7 +51,9 @@ private static final class State implements Serializable { */ private static final Set typeAnnotations = new HashSet<>( Arrays.asList( - // Type annotations from the Checker Framework. + // Type annotations from the Checker Framework and all the tools it + // supports, including FindBugs, JetBrains (IntelliJ), Eclipse, NetBeans, + // Spring, JML, Android, etc. "A", "ACCBottom", "Acceleration", From 8666f98590976ccffb2e81fabbd3a348eed4066d Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Thu, 25 Aug 2022 11:23:38 -0700 Subject: [PATCH 08/22] Add line to table --- README.md | 2 ++ gradle/spotless.gradle | 1 + plugin-gradle/README.md | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f95ea7a7ca..7680062a6c 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ lib('java.ImportOrderStep') +'{{yes}} | {{yes}} lib('java.PalantirJavaFormatStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |', lib('java.RemoveUnusedImportsStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |', extra('java.EclipseJdtFormatterStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |', +lib('java.TypeAnnotationsStep') +'{{yes}} | {{no}} | {{no}} | {{no}} |', lib('json.gson.GsonStep') +'{{yes}} | {{no}} | {{no}} | {{no}} |', lib('json.JsonSimpleStep') +'{{yes}} | {{no}} | {{no}} | {{no}} |', lib('kotlin.KtLintStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |', @@ -104,6 +105,7 @@ extra('wtp.EclipseWtpFormatterStep') +'{{yes}} | {{yes}} | [`java.PalantirJavaFormatStep`](lib/src/main/java/com/diffplug/spotless/java/PalantirJavaFormatStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | | [`java.RemoveUnusedImportsStep`](lib/src/main/java/com/diffplug/spotless/java/RemoveUnusedImportsStep.java) | :+1: | :+1: | :+1: | :white_large_square: | | [`java.EclipseJdtFormatterStep`](lib-extra/src/main/java/com/diffplug/spotless/extra/java/EclipseJdtFormatterStep.java) | :+1: | :+1: | :+1: | :white_large_square: | +| [`java.TypeAnnotationsStep`](lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | | [`json.gson.GsonStep`](lib/src/main/java/com/diffplug/spotless/json/gson/GsonStep.java) | :+1: | :white_large_square: | :white_large_square: | :white_large_square: | | [`json.JsonSimpleStep`](lib/src/main/java/com/diffplug/spotless/json/JsonSimpleStep.java) | :+1: | :white_large_square: | :white_large_square: | :white_large_square: | | [`kotlin.KtLintStep`](lib/src/main/java/com/diffplug/spotless/kotlin/KtLintStep.java) | :+1: | :+1: | :+1: | :white_large_square: | diff --git a/gradle/spotless.gradle b/gradle/spotless.gradle index 96037b21a3..8ab9516bcc 100644 --- a/gradle/spotless.gradle +++ b/gradle/spotless.gradle @@ -22,6 +22,7 @@ spotless { eclipse().configFile rootProject.file('gradle/spotless.eclipseformat.xml') trimTrailingWhitespace() removeUnusedImports() + // TODO: typeAnnotations() custom 'noInternalDeps', noInternalDepsClosure } } diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index c96e8a1157..35133d4570 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -60,7 +60,7 @@ Spotless supports all of Gradle's built-in performance features (incremental bui - [**Quickstart**](#quickstart) - [Requirements](#requirements) - **Languages** - - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [clang-format](#clang-format), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [type annotations](#Type annotations)) + - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [clang-format](#clang-format), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [type annotations](#type-annotations)) - [Groovy](#groovy) ([eclipse groovy](#eclipse-groovy)) - [Kotlin](#kotlin) ([ktfmt](#ktfmt), [ktlint](#ktlint), [diktat](#diktat), [prettier](#prettier)) - [Scala](#scala) ([scalafmt](#scalafmt)) From 68e421770140f29b2c083ee478447bd1e7932358 Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Thu, 25 Aug 2022 11:44:54 -0700 Subject: [PATCH 09/22] Tweak comment --- plugin-gradle/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 35133d4570..894d8747bf 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -164,7 +164,7 @@ spotless { prettier() // has its own section below clangFormat() // has its own section below - typeAnnotations() // has its own section below + typeAnnotations() // fixes formatting of type annotations, see below licenseHeader '/* (C) $YEAR */' // or licenseHeaderFile } From e69ab4b0266c39f89f61d0c19dd2e5afe98835b3 Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Thu, 25 Aug 2022 11:52:07 -0700 Subject: [PATCH 10/22] Add Maven support --- README.md | 2 +- plugin-maven/CHANGES.md | 2 ++ plugin-maven/README.md | 33 +++++++++++++++++-- .../diffplug/spotless/maven/java/Java.java | 4 +++ .../spotless/maven/java/TypeAnnotations.java | 29 ++++++++++++++++ .../maven/java/TypeAnnotationsStepTest.java | 33 +++++++++++++++++++ 6 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 plugin-maven/src/main/java/com/diffplug/spotless/maven/java/TypeAnnotations.java create mode 100644 plugin-maven/src/test/java/com/diffplug/spotless/maven/java/TypeAnnotationsStepTest.java diff --git a/README.md b/README.md index 7680062a6c..049e8728fa 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ lib('java.ImportOrderStep') +'{{yes}} | {{yes}} lib('java.PalantirJavaFormatStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |', lib('java.RemoveUnusedImportsStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |', extra('java.EclipseJdtFormatterStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |', -lib('java.TypeAnnotationsStep') +'{{yes}} | {{no}} | {{no}} | {{no}} |', +lib('java.TypeAnnotationsStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |', lib('json.gson.GsonStep') +'{{yes}} | {{no}} | {{no}} | {{no}} |', lib('json.JsonSimpleStep') +'{{yes}} | {{no}} | {{no}} | {{no}} |', lib('kotlin.KtLintStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |', diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 3b6986c5db..c5c322ff55 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] +### Added +* `typeAnnotations` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formattng step, such as `googleJavaFormat`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) ## [2.25.0] - 2022-08-23 ### Added diff --git a/plugin-maven/README.md b/plugin-maven/README.md index f59d00d47a..eaee799db7 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -24,7 +24,7 @@ output = [ output = prefixDelimiterReplace(input, 'https://{{org}}.github.io/{{name}}/javadoc/spotless-plugin-maven/', '/', versionLast) --> -Spotless is a general-purpose formatting plugin. It is completely à la carte, but also includes powerful "batteries-included" if you opt-in. Plugin requires a version of Maven higher or equal to 3.1.0. +Spotless is a general-purpose formatting plugin used by [4,000 projects on GitHub (August 2020)](https://github.com/search?l=gradle&q=spotless&type=Code). It is completely à la carte, but also includes powerful "batteries-included" if you opt-in. Plugin requires a version of Maven higher or equal to 3.1.0. To people who use your build, it looks like this: @@ -47,7 +47,7 @@ user@machine repo % mvn spotless:check - [Requirements](#requirements) - [Binding to maven phase](#binding-to-maven-phase) - **Languages** - - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [prettier](#prettier), [palantir-java-format](#palantir-java-format)) + - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [type annotations](#type-annotations)) - [Groovy](#groovy) ([eclipse groovy](#eclipse-groovy)) - [Kotlin](#kotlin) ([ktfmt](#ktfmt), [ktlint](#ktlint), [diktat](#diktat), [prettier](#prettier)) - [Scala](#scala) ([scalafmt](#scalafmt)) @@ -191,6 +191,8 @@ any other maven phase (i.e. compile) then it can be configured as below; + + /* (C)$YEAR */ @@ -255,6 +257,33 @@ This is a workaround to a [pending issue](https://github.com/diffplug/spotless/i ``` +### Type annotations + +Type annotations should be on the same line as the type that they qualify. + +```java + @Override + @Deprecated + @Nullable @Interned String s; +``` + +However, some tools format them incorrectly, like this: + +```java + @Override + @Deprecated + @Nullable + @Interned + String s; +``` + +To fix the incorrect formatting, add the `typeAnnotations()` rule after a Java formatter. For example: + +```XML + + +``` + ## Groovy [code](https://github.com/diffplug/spotless/blob/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/groovy/Groovy.java). [available steps](https://github.com/diffplug/spotless/tree/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/groovy). diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java index 819179ebba..66b6b8b1c7 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java @@ -61,4 +61,8 @@ public void addPalantirJavaFormat(PalantirJavaFormat palantirJavaFormat) { public void addRemoveUnusedImports(RemoveUnusedImports removeUnusedImports) { addStepFactory(removeUnusedImports); } + + public void addTypeAnnotations(TypeAnnotations typeAnnotations) { + addStepFactory(typeAnnotations); + } } diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/TypeAnnotations.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/TypeAnnotations.java new file mode 100644 index 0000000000..8a555c6c72 --- /dev/null +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/TypeAnnotations.java @@ -0,0 +1,29 @@ +/* + * Copyright 2022 DiffPlug + * + * 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.diffplug.spotless.maven.java; + +import com.diffplug.spotless.FormatterStep; +import com.diffplug.spotless.java.TypeAnnotationsStep; +import com.diffplug.spotless.maven.FormatterStepConfig; +import com.diffplug.spotless.maven.FormatterStepFactory; + +public class TypeAnnotations implements FormatterStepFactory { + + @Override + public FormatterStep newFormatterStep(FormatterStepConfig config) { + return TypeAnnotationsStep.create(); + } +} diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/TypeAnnotationsStepTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/TypeAnnotationsStepTest.java new file mode 100644 index 0000000000..9ceebafb5e --- /dev/null +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/TypeAnnotationsStepTest.java @@ -0,0 +1,33 @@ +/* + * Copyright 2022 DiffPlug + * + * 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.diffplug.spotless.maven.java; + +import org.junit.jupiter.api.Test; + +import com.diffplug.spotless.maven.MavenIntegrationHarness; + +class TypeAnnotationsStepTest extends MavenIntegrationHarness { + + @Test + void testRemoveUnusedInports() throws Exception { + writePomWithJavaSteps(""); + + String path = "src/main/java/test.java"; + setFile(path).toResource("java/typeannotations/TypeAnnotationsTestInput.test"); + mavenRunner().withArguments("spotless:apply").runNoError(); + assertFile(path).sameAsResource("java/typeannotations/TypeAnnotationsTestOutput.test"); + } +} From 61da1b2357656f31e23e04ccdf20803ff6ad649c Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Thu, 25 Aug 2022 12:02:38 -0700 Subject: [PATCH 11/22] Fix test name --- .../diffplug/spotless/maven/java/TypeAnnotationsStepTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/TypeAnnotationsStepTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/TypeAnnotationsStepTest.java index 9ceebafb5e..c2281bf8fd 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/TypeAnnotationsStepTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/TypeAnnotationsStepTest.java @@ -22,7 +22,7 @@ class TypeAnnotationsStepTest extends MavenIntegrationHarness { @Test - void testRemoveUnusedInports() throws Exception { + void testTypeAnnotations() throws Exception { writePomWithJavaSteps(""); String path = "src/main/java/test.java"; From 9553e60bc2ed8dc32a5e96a58fbf25ca6d07e69c Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Thu, 25 Aug 2022 12:02:47 -0700 Subject: [PATCH 12/22] Define "type annotation" --- .../java/com/diffplug/spotless/java/TypeAnnotationsStep.java | 4 ++++ plugin-gradle/README.md | 2 ++ plugin-maven/README.md | 2 ++ 3 files changed, 8 insertions(+) diff --git a/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java b/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java index 2a46f0f40c..36a988aa23 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java @@ -30,6 +30,9 @@ * -- even type annotations, which should be on the same line as the type they qualify. * This class corrects the formatting. * This is useful as a postprocessing step after a Java formatter that is not cognizant of type annotations. + + *

+ * Note: A type annotation is an annotation that is meta-annotated with {@code @Target({ElementType.TYPE_USE})}. */ public final class TypeAnnotationsStep { private TypeAnnotationsStep() {} @@ -54,6 +57,7 @@ private static final class State implements Serializable { // Type annotations from the Checker Framework and all the tools it // supports, including FindBugs, JetBrains (IntelliJ), Eclipse, NetBeans, // Spring, JML, Android, etc. + // A type annotation is an annotation that is meta-annotated with @Target({ElementType.TYPE_USE}). "A", "ACCBottom", "Acceleration", diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 894d8747bf..71ccaf939c 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -262,6 +262,8 @@ Type annotations should be on the same line as the type that they qualify. @Nullable @Interned String s; ``` +(A type annotation is an annotation that is meta-annotated with `@Target({ElementType.TYPE_USE})`.) + However, some tools format them incorrectly, like this: ```java diff --git a/plugin-maven/README.md b/plugin-maven/README.md index eaee799db7..9968bc3217 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -267,6 +267,8 @@ Type annotations should be on the same line as the type that they qualify. @Nullable @Interned String s; ``` +(A type annotation is an annotation that is meta-annotated with `@Target({ElementType.TYPE_USE})`.) + However, some tools format them incorrectly, like this: ```java From d7cd9fdaebc278b7605a65b174d1cffd19b1df0c Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Thu, 25 Aug 2022 12:17:15 -0700 Subject: [PATCH 13/22] No reordering --- plugin-gradle/README.md | 2 ++ plugin-maven/README.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 71ccaf939c..3bb5ad4b9a 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -285,6 +285,8 @@ spotless { } ``` +This does not re-order annotations, it just removes incorrect newlines. + diff --git a/plugin-maven/README.md b/plugin-maven/README.md index 9968bc3217..449e6f617f 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -286,6 +286,8 @@ To fix the incorrect formatting, add the `typeAnnotations()` rule after a Java f ``` +This does not re-order annotations, it just removes incorrect newlines. + ## Groovy [code](https://github.com/diffplug/spotless/blob/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/groovy/Groovy.java). [available steps](https://github.com/diffplug/spotless/tree/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/groovy). From d8f047ee2d20fb6394aff5bb2847a3917f819147 Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Thu, 25 Aug 2022 12:17:37 -0700 Subject: [PATCH 14/22] Whitespace --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 049e8728fa..94e093ce4f 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ extra('wtp.EclipseWtpFormatterStep') +'{{yes}} | {{yes}} | [`java.PalantirJavaFormatStep`](lib/src/main/java/com/diffplug/spotless/java/PalantirJavaFormatStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | | [`java.RemoveUnusedImportsStep`](lib/src/main/java/com/diffplug/spotless/java/RemoveUnusedImportsStep.java) | :+1: | :+1: | :+1: | :white_large_square: | | [`java.EclipseJdtFormatterStep`](lib-extra/src/main/java/com/diffplug/spotless/extra/java/EclipseJdtFormatterStep.java) | :+1: | :+1: | :+1: | :white_large_square: | -| [`java.TypeAnnotationsStep`](lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | +| [`java.TypeAnnotationsStep`](lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | | [`json.gson.GsonStep`](lib/src/main/java/com/diffplug/spotless/json/gson/GsonStep.java) | :+1: | :white_large_square: | :white_large_square: | :white_large_square: | | [`json.JsonSimpleStep`](lib/src/main/java/com/diffplug/spotless/json/JsonSimpleStep.java) | :+1: | :white_large_square: | :white_large_square: | :white_large_square: | | [`kotlin.KtLintStep`](lib/src/main/java/com/diffplug/spotless/kotlin/KtLintStep.java) | :+1: | :+1: | :+1: | :white_large_square: | From 437636b3c49430ad8cf692f029ca6e11197ffea2 Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Thu, 25 Aug 2022 14:10:36 -0700 Subject: [PATCH 15/22] List of type annotations is hard-coded --- CHANGES.md | 2 +- plugin-gradle/CHANGES.md | 2 +- plugin-gradle/README.md | 7 +++++-- plugin-maven/CHANGES.md | 2 +- plugin-maven/README.md | 8 ++++++-- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index cc2296c166..613df41623 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,7 +11,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added -* `typeAnnotations()` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formattng step, such as `googleJavaFormat()`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) +* `typeAnnotations()` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formatting step, such as `googleJavaFormat()`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) ## [2.29.0] - 2022-08-23 ### Added diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 2c3f483356..bd12048a49 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -4,7 +4,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added -* `typeAnnotations()` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formattng step, such as `googleJavaFormat()`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) +* `typeAnnotations()` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formatting step, such as `googleJavaFormat()`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) ## [6.10.0] - 2022-08-23 ### Added diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 3bb5ad4b9a..121917b7c9 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -262,8 +262,6 @@ Type annotations should be on the same line as the type that they qualify. @Nullable @Interned String s; ``` -(A type annotation is an annotation that is meta-annotated with `@Target({ElementType.TYPE_USE})`.) - However, some tools format them incorrectly, like this: ```java @@ -287,6 +285,11 @@ spotless { This does not re-order annotations, it just removes incorrect newlines. +A type annotation is an annotation that is meta-annotated with `@Target({ElementType.TYPE_USE})`. +Because Spotless cannot necessarily examine the annotation definition, it uses a hard-coded +list of well-known type annotations. You can make a pull request to add new ones. +In the future there will be mechanisms to add/remove annotations from the list. + diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index c5c322ff55..33e3bc7774 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -4,7 +4,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added -* `typeAnnotations` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formattng step, such as `googleJavaFormat`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) +* `typeAnnotations` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formatting step, such as `googleJavaFormat`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) ## [2.25.0] - 2022-08-23 ### Added diff --git a/plugin-maven/README.md b/plugin-maven/README.md index 449e6f617f..42372387be 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -267,8 +267,6 @@ Type annotations should be on the same line as the type that they qualify. @Nullable @Interned String s; ``` -(A type annotation is an annotation that is meta-annotated with `@Target({ElementType.TYPE_USE})`.) - However, some tools format them incorrectly, like this: ```java @@ -288,6 +286,12 @@ To fix the incorrect formatting, add the `typeAnnotations()` rule after a Java f This does not re-order annotations, it just removes incorrect newlines. +A type annotation is an annotation that is meta-annotated with `@Target({ElementType.TYPE_USE})`. +Because Spotless cannot necessarily examine the annotation definition, it uses a hard-coded +list of well-known type annotations. You can make a pull request to add new ones. +In the future there will be mechanisms to add/remove annotations from the list. + + ## Groovy [code](https://github.com/diffplug/spotless/blob/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/groovy/Groovy.java). [available steps](https://github.com/diffplug/spotless/tree/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/groovy). From d8b8a863872b7132dbae03b7d18a0cffcfbc5946 Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Sun, 28 Aug 2022 11:09:25 -1000 Subject: [PATCH 16/22] Support `addTypeAnnotation()` and `removeTypeAnnotation()` --- .github/dependabot.yml | 10 - CHANGES.md | 2 +- README.md | 4 +- gradle.properties | 2 +- gradle/spotless.gradle | 2 +- .../spotless/java/FormatAnnotationsStep.java | 471 ++++++++++++++++++ .../spotless/java/TypeAnnotationsStep.java | 457 ----------------- plugin-gradle/CHANGES.md | 2 +- plugin-gradle/README.md | 32 +- .../gradle/spotless/FormatExtension.java | 1 + .../gradle/spotless/JavaExtension.java | 37 +- plugin-maven/CHANGES.md | 2 +- plugin-maven/README.md | 6 +- ...nnotations.java => FormatAnnotations.java} | 9 +- .../diffplug/spotless/maven/java/Java.java | 4 +- ...st.java => FormatAnnotationsStepTest.java} | 10 +- renovate.json | 6 + .../FormatAnnotationsAddRemoveInput.test | 11 + .../FormatAnnotationsAddRemoveOutput.test | 9 + .../FormatAnnotationsInCommentsInput.test} | 2 +- .../FormatAnnotationsInCommentsOutput.test} | 2 +- .../FormatAnnotationsTestInput.test} | 11 +- .../FormatAnnotationsTestOutput.test} | 10 +- ...st.java => FormatAnnotationsStepTest.java} | 28 +- 24 files changed, 613 insertions(+), 517 deletions(-) delete mode 100644 .github/dependabot.yml create mode 100644 lib/src/main/java/com/diffplug/spotless/java/FormatAnnotationsStep.java delete mode 100644 lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java rename plugin-maven/src/main/java/com/diffplug/spotless/maven/java/{TypeAnnotations.java => FormatAnnotations.java} (75%) rename plugin-maven/src/test/java/com/diffplug/spotless/maven/java/{TypeAnnotationsStepTest.java => FormatAnnotationsStepTest.java} (71%) create mode 100644 renovate.json create mode 100644 testlib/src/main/resources/java/formatannotations/FormatAnnotationsAddRemoveInput.test create mode 100644 testlib/src/main/resources/java/formatannotations/FormatAnnotationsAddRemoveOutput.test rename testlib/src/main/resources/java/{typeannotations/TypeAnnotationsInCommentsInput.test => formatannotations/FormatAnnotationsInCommentsInput.test} (94%) rename testlib/src/main/resources/java/{typeannotations/TypeAnnotationsInCommentsOutput.test => formatannotations/FormatAnnotationsInCommentsOutput.test} (93%) rename testlib/src/main/resources/java/{typeannotations/TypeAnnotationsTestInput.test => formatannotations/FormatAnnotationsTestInput.test} (87%) rename testlib/src/main/resources/java/{typeannotations/TypeAnnotationsTestOutput.test => formatannotations/FormatAnnotationsTestOutput.test} (87%) rename testlib/src/test/java/com/diffplug/spotless/java/{TypeAnnotationsStepTest.java => FormatAnnotationsStepTest.java} (50%) diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 10ef831183..0000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,10 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "gradle" - directory: "/" - schedule: - interval: "weekly" - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" diff --git a/CHANGES.md b/CHANGES.md index 613df41623..cec949f59d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,7 +11,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added -* `typeAnnotations()` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formatting step, such as `googleJavaFormat()`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) +* `formatAnnotations()` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formatting step, such as `googleJavaFormat()`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) ## [2.29.0] - 2022-08-23 ### Added diff --git a/README.md b/README.md index 94e093ce4f..fb1a3670e6 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ lib('java.ImportOrderStep') +'{{yes}} | {{yes}} lib('java.PalantirJavaFormatStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |', lib('java.RemoveUnusedImportsStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |', extra('java.EclipseJdtFormatterStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |', -lib('java.TypeAnnotationsStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |', +lib('java.FormatAnnotationsStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |', lib('json.gson.GsonStep') +'{{yes}} | {{no}} | {{no}} | {{no}} |', lib('json.JsonSimpleStep') +'{{yes}} | {{no}} | {{no}} | {{no}} |', lib('kotlin.KtLintStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |', @@ -105,7 +105,7 @@ extra('wtp.EclipseWtpFormatterStep') +'{{yes}} | {{yes}} | [`java.PalantirJavaFormatStep`](lib/src/main/java/com/diffplug/spotless/java/PalantirJavaFormatStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | | [`java.RemoveUnusedImportsStep`](lib/src/main/java/com/diffplug/spotless/java/RemoveUnusedImportsStep.java) | :+1: | :+1: | :+1: | :white_large_square: | | [`java.EclipseJdtFormatterStep`](lib-extra/src/main/java/com/diffplug/spotless/extra/java/EclipseJdtFormatterStep.java) | :+1: | :+1: | :+1: | :white_large_square: | -| [`java.TypeAnnotationsStep`](lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | +| [`java.FormatAnnotationsStep`](lib/src/main/java/com/diffplug/spotless/java/FormatAnnotationsStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: | | [`json.gson.GsonStep`](lib/src/main/java/com/diffplug/spotless/json/gson/GsonStep.java) | :+1: | :white_large_square: | :white_large_square: | :white_large_square: | | [`json.JsonSimpleStep`](lib/src/main/java/com/diffplug/spotless/json/JsonSimpleStep.java) | :+1: | :white_large_square: | :white_large_square: | :white_large_square: | | [`kotlin.KtLintStep`](lib/src/main/java/com/diffplug/spotless/kotlin/KtLintStep.java) | :+1: | :+1: | :+1: | :white_large_square: | diff --git a/gradle.properties b/gradle.properties index 032beae95c..918ff28ab3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -33,5 +33,5 @@ VER_MOCKITO=3.3.3 # Used for Maven Plugin VER_MAVEN_API=3.0 VER_ECLIPSE_AETHER=0.9.0.M2 -VER_MUSTACHE=0.9.6 +VER_MUSTACHE=0.9.10 VER_PLEXUS_RESOURCES=1.2.0 diff --git a/gradle/spotless.gradle b/gradle/spotless.gradle index 8ab9516bcc..677630ac69 100644 --- a/gradle/spotless.gradle +++ b/gradle/spotless.gradle @@ -22,7 +22,7 @@ spotless { eclipse().configFile rootProject.file('gradle/spotless.eclipseformat.xml') trimTrailingWhitespace() removeUnusedImports() - // TODO: typeAnnotations() + // TODO: formatAnnotations() custom 'noInternalDeps', noInternalDepsClosure } } diff --git a/lib/src/main/java/com/diffplug/spotless/java/FormatAnnotationsStep.java b/lib/src/main/java/com/diffplug/spotless/java/FormatAnnotationsStep.java new file mode 100644 index 0000000000..28691ccf91 --- /dev/null +++ b/lib/src/main/java/com/diffplug/spotless/java/FormatAnnotationsStep.java @@ -0,0 +1,471 @@ +/* + * Copyright 2022 DiffPlug + * + * 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.diffplug.spotless.java; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.diffplug.spotless.FormatterFunc; +import com.diffplug.spotless.FormatterStep; + +/** + * Some formatters put every annotation on its own line + * -- even type annotations, which should be on the same line as the type they qualify. + * This class corrects the formatting. + * This is useful as a postprocessing step after a Java formatter that is not cognizant of type annotations. + + *

+ * Note: A type annotation is an annotation that is meta-annotated with {@code @Target({ElementType.TYPE_USE})}. + */ +public final class FormatAnnotationsStep { + + /** + * Simple names of type annotations. + * A type annotation is an annotation that is meta-annotated with @Target({ElementType.TYPE_USE}). + * A type annotation should be formatted on the same line as the type it qualifies. + */ + private static final List defaultTypeAnnotations = + // Use simple names because Spotless has no access to the + // fully-qualified names or the definitions of the type qualifiers. + Arrays.asList( + // Type annotations from the Checker Framework and all + // the tools it supports: FindBugs, JetBrains (IntelliJ), + // Eclipse, NetBeans, Spring, JML, Android, etc. + "A", + "ACCBottom", + "Acceleration", + "ACCTop", + "AinferBottom", + "AlwaysSafe", + "Angle", + "AnnoWithStringArg", + "Area", + "ArrayLen", + "ArrayLenRange", + "ArrayWithoutPackage", + "AwtAlphaCompositingRule", + "AwtColorSpace", + "AwtCursorType", + "AwtFlowLayout", + "B", + "BinaryName", + "BinaryNameInUnnamedPackage", + "BinaryNameOrPrimitiveType", + "BinaryNameWithoutPackage", + "BoolVal", + "Bottom", + "BottomQualifier", + "BottomThis", + "BottomVal", + "C", + "CalledMethods", + "CalledMethodsBottom", + "CalledMethodsPredicate", + "CalledMethodsTop", + "CanonicalName", + "CanonicalNameAndBinaryName", + "CanonicalNameOrEmpty", + "CanonicalNameOrPrimitiveType", + "CCBottom", + "CCTop", + "cd", + "ClassBound", + "ClassGetName", + "ClassGetSimpleName", + "ClassVal", + "ClassValBottom", + "CompilerMessageKey", + "CompilerMessageKeyBottom", + "Constant", + "Critical", + "Current", + "D", + "DefaultType", + "degrees", + "Det", + "DotSeparatedIdentifiers", + "DotSeparatedIdentifiersOrPrimitiveType", + "DoubleVal", + "E", + "Encrypted", + "EnhancedRegex", + "EnumVal", + "Even", + "F", + "FBCBottom", + "FEBottom", + "FEBot", + "Fenum", + "FenumBottom", + "FenumTop", + "FETop", + "FieldDescriptor", + "FieldDescriptorForPrimitive", + "FieldDescriptorForPrimitiveOrArrayInUnnamedPackage", + "FieldDescriptorWithoutPackage", + "FlowExp", + "Force", + "Format", + "FormatBottom", + "FqBinaryName", + "Frequency", + "FullyQualifiedName", + "g", + "GTENegativeOne", + "GuardedBy", + "GuardedByBottom", + "GuardedByUnknown", + "GuardSatisfied", + "h", + "H1Bot", + "H1Invalid", + "H1Poly", + "H1S1", + "H1S2", + "H1Top", + "H2Bot", + "H2Poly", + "H2S1", + "H2S2", + "H2Top", + "Hz", + "I18nFormat", + "I18nFormatBottom", + "I18nFormatFor", + "I18nInvalidFormat", + "I18nUnknownFormat", + "Identifier", + "IdentifierOrArray", + "IdentifierOrPrimitiveType", + "ImplicitAnno", + "IndexFor", + "IndexOrHigh", + "IndexOrLow", + "Initialized", + "InitializedFields", + "InitializedFieldsBottom", + "InitializedFieldsPredicate", + "InternalForm", + "Interned", + "InternedDistinct", + "IntRange", + "IntVal", + "InvalidFormat", + "K", + "KeyFor", + "KeyForBottom", + "KeyForType", + "kg", + "kHz", + "km", + "km2", + "km3", + "kmPERh", + "kN", + "LbTop", + "LB_TOP", + "LeakedToResult", + "Length", + "LengthOf", + "LessThan", + "LessThanBottom", + "LessThanUnknown", + "LocalizableKey", + "LocalizableKeyBottom", + "Localized", + "LowerBoundBottom", + "LowerBoundUnknown", + "LTEqLengthOf", + "LTLengthOf", + "LTOMLengthOf", + "Luminance", + "m", + "m2", + "m3", + "Mass", + "MatchesRegex", + "MaybeAliased", + "MaybeDerivedFromConstant", + "MaybePresent", + "MaybeThis", + "MethodDescriptor", + "MethodVal", + "MethodValBottom", + "min", + "MinLen", + "mm", + "mm2", + "mm3", + "mol", + "MonotonicNonNull", + "MonotonicNonNullType", + "MonotonicOdd", + "mPERs", + "mPERs2", + "MustCall", + "MustCallAlias", + "MustCallUnknown", + "N", + "NegativeIndexFor", + "NewObject", + "NonConstant", + "NonDet", + "NonLeaked", + "NonNegative", + "NonNull", + "NonNullType", + "NonRaw", + "NotCalledMethods", + "NotNull", + "NotQualifier", + "NTDBottom", + "NTDMiddle", + "NTDSide", + "NTDTop", + "Nullable", + "NullableType", + "Odd", + "OptionalBottom", + "OrderNonDet", + "Parent", + "PatternA", + "PatternAB", + "PatternAC", + "PatternB", + "PatternBC", + "PatternBottomFull", + "PatternBottomPartial", + "PatternC", + "PatternUnknown", + "Poly", + "PolyAll", + "PolyConstant", + "PolyDet", + "PolyEncrypted", + "PolyFenum", + "PolyIndex", + "PolyInitializedFields", + "PolyInterned", + "PolyKeyFor", + "PolyLength", + "PolyLowerBound", + "PolyMustCall", + "PolyNull", + "PolyNullType", + "PolyPresent", + "PolyRaw", + "PolyReflection", + "PolyRegex", + "PolySameLen", + "PolySignature", + "PolySigned", + "PolyTainted", + "PolyTestAccumulation", + "PolyTypeDeclDefault", + "PolyUI", + "PolyUnit", + "PolyUpperBound", + "PolyValue", + "PolyVariableNameDefault", + "Positive", + "Present", + "PrimitiveType", + "PropertyKey", + "PropertyKeyBottom", + "PurityUnqualified", + "Qualifier", + "radians", + "Raw", + "ReflectBottom", + "Regex", + "RegexBottom", + "RegexNNGroups", + "ReportUnqualified", + "s", + "SameLen", + "SameLenBottom", + "SameLenUnknown", + "SearchIndexBottom", + "SearchIndexFor", + "SearchIndexUnknown", + "Sibling1", + "Sibling2", + "SiblingWithFields", + "SignatureBottom", + "Signed", + "SignednessBottom", + "SignednessGlb", + "SignedPositive", + "SignedPositiveFromUnsigned", + "Speed", + "StringVal", + "SubQual", + "Substance", + "SubstringIndexBottom", + "SubstringIndexFor", + "SubstringIndexUnknown", + "SuperQual", + "SwingBoxOrientation", + "SwingCompassDirection", + "SwingElementOrientation", + "SwingHorizontalOrientation", + "SwingSplitPaneOrientation", + "SwingTextOrientation", + "SwingTitleJustification", + "SwingTitlePosition", + "SwingVerticalOrientation", + "t", + "Tainted", + "Temperature", + "TestAccumulation", + "TestAccumulationBottom", + "TestAccumulationPredicate", + "This", + "Time", + "Top", + "TypeDeclDefaultBottom", + "TypeDeclDefaultMiddle", + "TypeDeclDefaultTop", + "UbTop", + "UB_TOP", + "UI", + "UnderInitialization", + "Unique", + "UnitsBottom", + "UnknownClass", + "UnknownCompilerMessageKey", + "UnknownFormat", + "UnknownInitialization", + "UnknownInterned", + "UnknownKeyFor", + "UnknownLocalizableKey", + "UnknownLocalized", + "UnknownMethod", + "UnknownPropertyKey", + "UnknownRegex", + "UnknownSignedness", + "UnknownThis", + "UnknownUnits", + "UnknownVal", + "Unsigned", + "Untainted", + "UpperBoundBottom", + "UpperBoundLiteral", + "UpperBoundUnknown", + "Value", + "VariableNameDefaultBottom", + "VariableNameDefaultMiddle", + "VariableNameDefaultTop", + "Volume", + "WholeProgramInferenceBottom" + // TODO: Add type annotations from other tools here. + + ); + + static final String NAME = "No line break between type annotation and type"; + + public static FormatterStep create() { + return create(Collections.emptyList(), Collections.emptyList()); + } + + public static FormatterStep create(List addedTypeAnnotations, List removedTypeAnnotations) { + return FormatterStep.create(NAME, new State(addedTypeAnnotations, removedTypeAnnotations), State::toFormatter); + } + + private FormatAnnotationsStep() {} + + // TODO: Enable users to specify more type annotations in `formatAnnotations` in build.gradle. + // TODO: Read from a local .type-annotations file. + private static final class State implements Serializable { + private static final long serialVersionUID = 1L; + + private final Set typeAnnotations = new HashSet<>(defaultTypeAnnotations); + + // group 1 is the basename of the annotation. + private static final String annoNoArgRegex = "@(?:[A-Za-z_][A-Za-z0-9_.]*\\.)?([A-Za-z_][A-Za-z0-9_]*)"; + private static final Pattern annoNoArgPattern = Pattern.compile(annoNoArgRegex); + // 3 non-empty cases: () (".*") (.*) + private static final String annoArgRegex = "(?:\\(\\)|\\(\"[^\"]*\"\\)|\\([^\")][^)]*\\))?"; + // group 1 is the basename of the annotation. + private static final String annoRegex = annoNoArgRegex + annoArgRegex; + private static final String trailingAnnoRegex = annoRegex + "$"; + private static final Pattern trailingAnnoPattern = Pattern.compile(trailingAnnoRegex); + + // Heuristic: matches if the line might be within a //, /*, or Javadoc comment. + private static final Pattern withinCommentPattern = Pattern.compile("//|/\\*(?!.*/*/)|^[ \t]*\\*[ \t]"); + // Don't move an annotation to the start of a comment line. + private static final Pattern startsWithCommentPattern = Pattern.compile("^[ \t]*(//|/\\*$|/\\*|void\\b)"); + + State(List addedTypeAnnotations, List removedTypeAnnotations) { + typeAnnotations.addAll(addedTypeAnnotations); + typeAnnotations.removeAll(removedTypeAnnotations); + } + + FormatterFunc toFormatter() { + return unixStr -> fixupFormatAnnotations(unixStr); + } + + /** + * Removes line break between type annotations and the following type. + * + * @param the text of a Java file + * @return corrected text of the Java file + */ + String fixupFormatAnnotations(String unixStr) { + // Each element of `lines` ends with a newline. + String[] lines = unixStr.split("((?<=\n))"); + for (int i = 0; i < lines.length - 1; i++) { + String line = lines[i]; + if (endsWithTypeAnnotation(line)) { + String nextLine = lines[i + 1]; + if (startsWithCommentPattern.matcher(nextLine).find()) { + continue; + } + lines[i] = ""; + lines[i + 1] = line.replaceAll("\\s+$", "") + " " + nextLine.replaceAll("^\\s+", ""); + } + } + return String.join("", lines); + } + + /** + * Returns true if the line ends with a type annotation. + * FormatAnnotationsStep fixes such formatting. + */ + boolean endsWithTypeAnnotation(String unixLine) { + // Remove trailing newline. + String line = unixLine.replaceAll("\\s+$", ""); + Matcher m = trailingAnnoPattern.matcher(line); + if (!m.find()) { + return false; + } + String preceding = line.substring(0, m.start()); + String basename = m.group(1); + + if (withinCommentPattern.matcher(preceding).find()) { + return false; + } + + return typeAnnotations.contains(basename); + } + } +} diff --git a/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java b/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java deleted file mode 100644 index 36a988aa23..0000000000 --- a/lib/src/main/java/com/diffplug/spotless/java/TypeAnnotationsStep.java +++ /dev/null @@ -1,457 +0,0 @@ -/* - * Copyright 2022 DiffPlug - * - * 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.diffplug.spotless.java; - -import java.io.Serializable; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.diffplug.spotless.FormatterFunc; -import com.diffplug.spotless.FormatterStep; - -/** - * Some formatters put every annotation on its own line - * -- even type annotations, which should be on the same line as the type they qualify. - * This class corrects the formatting. - * This is useful as a postprocessing step after a Java formatter that is not cognizant of type annotations. - - *

- * Note: A type annotation is an annotation that is meta-annotated with {@code @Target({ElementType.TYPE_USE})}. - */ -public final class TypeAnnotationsStep { - private TypeAnnotationsStep() {} - - static final String NAME = "No line break between type annotation and type"; - - public static FormatterStep create() { - return FormatterStep.create(NAME, new State(), State::toFormatter); - } - - // TODO: Enable users to specify more type annotations in `typeAnnotations` in build.gradle. - // TODO: Read from a local .type-annotations file. - private static final class State implements Serializable { - private static final long serialVersionUID = 1L; - - /** - * These are type annotations, which should NOT go on their own line. - * A type annotation's {@code @Target} annotation contains {@code TYPE_USE}. - */ - private static final Set typeAnnotations = new HashSet<>( - Arrays.asList( - // Type annotations from the Checker Framework and all the tools it - // supports, including FindBugs, JetBrains (IntelliJ), Eclipse, NetBeans, - // Spring, JML, Android, etc. - // A type annotation is an annotation that is meta-annotated with @Target({ElementType.TYPE_USE}). - "A", - "ACCBottom", - "Acceleration", - "ACCTop", - "AinferBottom", - "AlwaysSafe", - "Angle", - "AnnoWithStringArg", - "Area", - "ArrayLen", - "ArrayLenRange", - "ArrayWithoutPackage", - "AwtAlphaCompositingRule", - "AwtColorSpace", - "AwtCursorType", - "AwtFlowLayout", - "B", - "BinaryName", - "BinaryNameInUnnamedPackage", - "BinaryNameOrPrimitiveType", - "BinaryNameWithoutPackage", - "BoolVal", - "Bottom", - "BottomQualifier", - "BottomThis", - "BottomVal", - "C", - "CalledMethods", - "CalledMethodsBottom", - "CalledMethodsPredicate", - "CalledMethodsTop", - "CanonicalName", - "CanonicalNameAndBinaryName", - "CanonicalNameOrEmpty", - "CanonicalNameOrPrimitiveType", - "CCBottom", - "CCTop", - "cd", - "ClassBound", - "ClassGetName", - "ClassGetSimpleName", - "ClassVal", - "ClassValBottom", - "CompilerMessageKey", - "CompilerMessageKeyBottom", - "Constant", - "Critical", - "Current", - "D", - "DefaultType", - "degrees", - "Det", - "DotSeparatedIdentifiers", - "DotSeparatedIdentifiersOrPrimitiveType", - "DoubleVal", - "E", - "Encrypted", - "EnhancedRegex", - "EnumVal", - "Even", - "F", - "FBCBottom", - "FEBottom", - "FEBot", - "Fenum", - "FenumBottom", - "FenumTop", - "FETop", - "FieldDescriptor", - "FieldDescriptorForPrimitive", - "FieldDescriptorForPrimitiveOrArrayInUnnamedPackage", - "FieldDescriptorWithoutPackage", - "FlowExp", - "Force", - "Format", - "FormatBottom", - "FqBinaryName", - "Frequency", - "FullyQualifiedName", - "g", - "GTENegativeOne", - "GuardedBy", - "GuardedByBottom", - "GuardedByUnknown", - "GuardSatisfied", - "h", - "H1Bot", - "H1Invalid", - "H1Poly", - "H1S1", - "H1S2", - "H1Top", - "H2Bot", - "H2Poly", - "H2S1", - "H2S2", - "H2Top", - "Hz", - "I18nFormat", - "I18nFormatBottom", - "I18nFormatFor", - "I18nInvalidFormat", - "I18nUnknownFormat", - "Identifier", - "IdentifierOrArray", - "IdentifierOrPrimitiveType", - "ImplicitAnno", - "IndexFor", - "IndexOrHigh", - "IndexOrLow", - "Initialized", - "InitializedFields", - "InitializedFieldsBottom", - "InitializedFieldsPredicate", - "InternalForm", - "Interned", - "InternedDistinct", - "IntRange", - "IntVal", - "InvalidFormat", - "K", - "KeyFor", - "KeyForBottom", - "KeyForType", - "kg", - "kHz", - "km", - "km2", - "km3", - "kmPERh", - "kN", - "LbTop", - "LB_TOP", - "LeakedToResult", - "Length", - "LengthOf", - "LessThan", - "LessThanBottom", - "LessThanUnknown", - "LocalizableKey", - "LocalizableKeyBottom", - "Localized", - "LowerBoundBottom", - "LowerBoundUnknown", - "LTEqLengthOf", - "LTLengthOf", - "LTOMLengthOf", - "Luminance", - "m", - "m2", - "m3", - "Mass", - "MatchesRegex", - "MaybeAliased", - "MaybeDerivedFromConstant", - "MaybePresent", - "MaybeThis", - "MethodDescriptor", - "MethodVal", - "MethodValBottom", - "min", - "MinLen", - "mm", - "mm2", - "mm3", - "mol", - "MonotonicNonNull", - "MonotonicNonNullType", - "MonotonicOdd", - "mPERs", - "mPERs2", - "MustCall", - "MustCallAlias", - "MustCallUnknown", - "N", - "NegativeIndexFor", - "NewObject", - "NonConstant", - "NonDet", - "NonLeaked", - "NonNegative", - "NonNull", - "NonNullType", - "NonRaw", - "NotCalledMethods", - "NotNull", - "NotQualifier", - "NTDBottom", - "NTDMiddle", - "NTDSide", - "NTDTop", - "Nullable", - "NullableType", - "Odd", - "OptionalBottom", - "OrderNonDet", - "Parent", - "PatternA", - "PatternAB", - "PatternAC", - "PatternB", - "PatternBC", - "PatternBottomFull", - "PatternBottomPartial", - "PatternC", - "PatternUnknown", - "Poly", - "PolyAll", - "PolyConstant", - "PolyDet", - "PolyEncrypted", - "PolyFenum", - "PolyIndex", - "PolyInitializedFields", - "PolyInterned", - "PolyKeyFor", - "PolyLength", - "PolyLowerBound", - "PolyMustCall", - "PolyNull", - "PolyNullType", - "PolyPresent", - "PolyRaw", - "PolyReflection", - "PolyRegex", - "PolySameLen", - "PolySignature", - "PolySigned", - "PolyTainted", - "PolyTestAccumulation", - "PolyTypeDeclDefault", - "PolyUI", - "PolyUnit", - "PolyUpperBound", - "PolyValue", - "PolyVariableNameDefault", - "Positive", - "Present", - "PrimitiveType", - "PropertyKey", - "PropertyKeyBottom", - "PurityUnqualified", - "Qualifier", - "radians", - "Raw", - "ReflectBottom", - "Regex", - "RegexBottom", - "RegexNNGroups", - "ReportUnqualified", - "s", - "SameLen", - "SameLenBottom", - "SameLenUnknown", - "SearchIndexBottom", - "SearchIndexFor", - "SearchIndexUnknown", - "Sibling1", - "Sibling2", - "SiblingWithFields", - "SignatureBottom", - "Signed", - "SignednessBottom", - "SignednessGlb", - "SignedPositive", - "SignedPositiveFromUnsigned", - "Speed", - "StringVal", - "SubQual", - "Substance", - "SubstringIndexBottom", - "SubstringIndexFor", - "SubstringIndexUnknown", - "SuperQual", - "SwingBoxOrientation", - "SwingCompassDirection", - "SwingElementOrientation", - "SwingHorizontalOrientation", - "SwingSplitPaneOrientation", - "SwingTextOrientation", - "SwingTitleJustification", - "SwingTitlePosition", - "SwingVerticalOrientation", - "t", - "Tainted", - "Temperature", - "TestAccumulation", - "TestAccumulationBottom", - "TestAccumulationPredicate", - "This", - "Time", - "Top", - "TypeDeclDefaultBottom", - "TypeDeclDefaultMiddle", - "TypeDeclDefaultTop", - "UbTop", - "UB_TOP", - "UI", - "UnderInitialization", - "Unique", - "UnitsBottom", - "UnknownClass", - "UnknownCompilerMessageKey", - "UnknownFormat", - "UnknownInitialization", - "UnknownInterned", - "UnknownKeyFor", - "UnknownLocalizableKey", - "UnknownLocalized", - "UnknownMethod", - "UnknownPropertyKey", - "UnknownRegex", - "UnknownSignedness", - "UnknownThis", - "UnknownUnits", - "UnknownVal", - "Unsigned", - "Untainted", - "UpperBoundBottom", - "UpperBoundLiteral", - "UpperBoundUnknown", - "Value", - "VariableNameDefaultBottom", - "VariableNameDefaultMiddle", - "VariableNameDefaultTop", - "Volume", - "WholeProgramInferenceBottom" - // Add type annotations from other tools here. - - )); - - // group 1 is the basename of the annotation. - private static final String annoNoArgRegex = "@(?:[A-Za-z_][A-Za-z0-9_.]*\\.)?([A-Za-z_][A-Za-z0-9_]*)"; - private static final Pattern annoNoArgPattern = Pattern.compile(annoNoArgRegex); - // 3 non-empty cases: () (".*") (.*) - private static final String annoArgRegex = "(?:\\(\\)|\\(\"[^\"]*\"\\)|\\([^\")][^)]*\\))?"; - // group 1 is the basename of the annotation. - private static final String annoRegex = annoNoArgRegex + annoArgRegex; - private static final String trailingAnnoRegex = annoRegex + "$"; - private static final Pattern trailingAnnoPattern = Pattern.compile(trailingAnnoRegex); - - // Heuristic: matches if the line might be within a //, /*, or Javadoc comment. - private static final Pattern withinCommentPattern = Pattern.compile("//|/\\*(?!.*/*/)|^[ \t]*\\*[ \t]"); - // Don't move an annotation to the start of a comment line. - private static final Pattern startsWithCommentPattern = Pattern.compile("^[ \t]*(//|/\\*$|/\\*|void\\b)"); - - State() {} - - FormatterFunc toFormatter() { - return unixStr -> fixupTypeAnnotations(unixStr); - } - - /** - * Removes line break between type annotations and the following type. - * - * @param the text of a Java file - * @return corrected text of the Java file - */ - String fixupTypeAnnotations(String unixStr) { - // Each element of `lines` ends with a newline. - String[] lines = unixStr.split("((?<=\n))"); - for (int i = 0; i < lines.length - 1; i++) { - String line = lines[i]; - if (endsWithTypeAnnotation(line)) { - String nextLine = lines[i + 1]; - if (startsWithCommentPattern.matcher(nextLine).find()) { - continue; - } - lines[i] = ""; - lines[i + 1] = line.replaceAll("\\s+$", "") + " " + nextLine.replaceAll("^\\s+", ""); - } - } - return String.join("", lines); - } - - /** - * Returns true if the line ends with a type annotation. - * TypeAnnotationStep fixes such formatting. - */ - boolean endsWithTypeAnnotation(String unixLine) { - // Remove trailing newline. - String line = unixLine.replaceAll("\\s+$", ""); - Matcher m = trailingAnnoPattern.matcher(line); - if (!m.find()) { - return false; - } - String preceding = line.substring(0, m.start()); - String basename = m.group(1); - - if (withinCommentPattern.matcher(preceding).find()) { - return false; - } - - return typeAnnotations.contains(basename); - } - } -} diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index bd12048a49..513f36346d 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -4,7 +4,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added -* `typeAnnotations()` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formatting step, such as `googleJavaFormat()`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) +* `formatAnnotations()` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formatting step, such as `googleJavaFormat()`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) ## [6.10.0] - 2022-08-23 ### Added diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 121917b7c9..c1a41c2ef0 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -118,7 +118,7 @@ spotless { // apply a specific flavor of google-java-format googleJavaFormat('1.8').aosp().reflowLongStrings() // fix formatting of type annotations - typeAnnotations() + formatAnnotations() // make sure every file has the following copyright header. // optionally, Spotless can set copyright years by digging // through git history (see "license" section below) @@ -159,12 +159,13 @@ spotless { removeUnusedImports() - googleJavaFormat() // has its own section below - eclipse() // has its own section below - prettier() // has its own section below - clangFormat() // has its own section below + // Choose one of these formatters. + googleJavaFormat() // has its own section below + eclipse() // has its own section below + prettier() // has its own section below + clangFormat() // has its own section below - typeAnnotations() // fixes formatting of type annotations, see below + formatAnnotations() // fixes formatting of type annotations, see below licenseHeader '/* (C) $YEAR */' // or licenseHeaderFile } @@ -193,7 +194,7 @@ spotless { // and/or use custom group artifact (you probably don't need this) googleJavaFormat('1.8').aosp().reflowLongStrings().groupArtifact('com.google.googlejavaformat:google-java-format') // optional: fix formatting of type annotations - typeAnnotations() + formatAnnotations() ``` **⚠️ Note on using Google Java Format with Java 16+** @@ -221,7 +222,7 @@ spotless { // optional: you can specify a specific version palantirJavaFormat('2.9.0') // optional: fix formatting of type annotations - typeAnnotations() + formatAnnotations() ``` **⚠️ Note on using Palantir Java Format with Java 16+** @@ -272,13 +273,13 @@ However, some tools format them incorrectly, like this: String s; ``` -To fix the incorrect formatting, add the `typeAnnotations()` rule after a Java formatter. For example: +To fix the incorrect formatting, add the `formatAnnotations()` rule after a Java formatter. For example: ```gradle spotless { java { googleJavaFormat() - typeAnnotations() + formatAnnotations() } } ``` @@ -286,9 +287,14 @@ spotless { This does not re-order annotations, it just removes incorrect newlines. A type annotation is an annotation that is meta-annotated with `@Target({ElementType.TYPE_USE})`. -Because Spotless cannot necessarily examine the annotation definition, it uses a hard-coded -list of well-known type annotations. You can make a pull request to add new ones. -In the future there will be mechanisms to add/remove annotations from the list. +Spotless has a default list of well-known type annotations. +You can use `addTypeAnnotation()` and `removeTypeAnnotation()` to override its defaults: + +```gradle + formatAnnotations().addTypeAnnotation("Empty").addTypeAnnotation("NonEmpty").removeTypeAnnotation("Localized") +``` + +You can make a pull request to add new annotations to Spotless's default list. diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java index 94ae136429..de0313eab4 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java @@ -691,6 +691,7 @@ public void withinBlocks(String name, String open, String close, Action diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java index d882ac472b..1329ce1ad9 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java @@ -18,6 +18,8 @@ import static com.diffplug.gradle.spotless.PluginGradlePreconditions.requireElementsNonNull; import java.io.File; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import javax.inject.Inject; @@ -32,11 +34,11 @@ import com.diffplug.spotless.extra.EclipseBasedStepBuilder; import com.diffplug.spotless.extra.java.EclipseJdtFormatterStep; import com.diffplug.spotless.generic.LicenseHeaderStep; +import com.diffplug.spotless.java.FormatAnnotationsStep; import com.diffplug.spotless.java.GoogleJavaFormatStep; import com.diffplug.spotless.java.ImportOrderStep; import com.diffplug.spotless.java.PalantirJavaFormatStep; import com.diffplug.spotless.java.RemoveUnusedImportsStep; -import com.diffplug.spotless.java.TypeAnnotationsStep; public class JavaExtension extends FormatExtension implements HasBuiltinDelimiterForLicense { static final String NAME = "java"; @@ -233,8 +235,37 @@ public void configFile(Object... configFiles) { } /** Removes newlines between type annotations and types. */ - public void typeAnnotations() { - addStep(TypeAnnotationsStep.create()); + public FormatAnnotationsConfig formatAnnotations() { + return new FormatAnnotationsConfig(); + } + + public class FormatAnnotationsConfig { + final List addedTypeAnnotations = new ArrayList<>(); + final List removedTypeAnnotations = new ArrayList<>(); + + FormatAnnotationsConfig() { + addStep(createStep()); + } + + public FormatAnnotationsConfig addTypeAnnotation(String simpleName) { + Objects.requireNonNull(simpleName); + addedTypeAnnotations.add(simpleName); + replaceStep(createStep()); + return this; + } + + public FormatAnnotationsConfig removeTypeAnnotation(String simpleName) { + Objects.requireNonNull(simpleName); + removedTypeAnnotations.add(simpleName); + replaceStep(createStep()); + return this; + } + + private FormatterStep createStep() { + return FormatAnnotationsStep.create( + addedTypeAnnotations, + removedTypeAnnotations); + } } /** If the user hasn't specified the files yet, we'll assume he/she means all of the java files. */ diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 33e3bc7774..30842b1b06 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -4,7 +4,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added -* `typeAnnotations` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formatting step, such as `googleJavaFormat`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) +* `formatAnnotations` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formatting step, such as `googleJavaFormat`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) ## [2.25.0] - 2022-08-23 ### Added diff --git a/plugin-maven/README.md b/plugin-maven/README.md index 42372387be..b7e93f41ca 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -191,7 +191,7 @@ any other maven phase (i.e. compile) then it can be configured as below; - + /* (C)$YEAR */ @@ -277,11 +277,11 @@ However, some tools format them incorrectly, like this: String s; ``` -To fix the incorrect formatting, add the `typeAnnotations()` rule after a Java formatter. For example: +To fix the incorrect formatting, add the `formatAnnotations()` rule after a Java formatter. For example: ```XML - + ``` This does not re-order annotations, it just removes incorrect newlines. diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/TypeAnnotations.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/FormatAnnotations.java similarity index 75% rename from plugin-maven/src/main/java/com/diffplug/spotless/maven/java/TypeAnnotations.java rename to plugin-maven/src/main/java/com/diffplug/spotless/maven/java/FormatAnnotations.java index 8a555c6c72..5ce820921a 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/TypeAnnotations.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/FormatAnnotations.java @@ -15,15 +15,18 @@ */ package com.diffplug.spotless.maven.java; +import java.util.Collections; + import com.diffplug.spotless.FormatterStep; -import com.diffplug.spotless.java.TypeAnnotationsStep; +import com.diffplug.spotless.java.FormatAnnotationsStep; import com.diffplug.spotless.maven.FormatterStepConfig; import com.diffplug.spotless.maven.FormatterStepFactory; -public class TypeAnnotations implements FormatterStepFactory { +public class FormatAnnotations implements FormatterStepFactory { @Override public FormatterStep newFormatterStep(FormatterStepConfig config) { - return TypeAnnotationsStep.create(); + // TODO: Permit customization in Maven. + return FormatAnnotationsStep.create(Collections.emptyList(), Collections.emptyList()); } } diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java index 66b6b8b1c7..4bd018d53c 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Java.java @@ -62,7 +62,7 @@ public void addRemoveUnusedImports(RemoveUnusedImports removeUnusedImports) { addStepFactory(removeUnusedImports); } - public void addTypeAnnotations(TypeAnnotations typeAnnotations) { - addStepFactory(typeAnnotations); + public void addFormatAnnotations(FormatAnnotations formatAnnotations) { + addStepFactory(formatAnnotations); } } diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/TypeAnnotationsStepTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/FormatAnnotationsStepTest.java similarity index 71% rename from plugin-maven/src/test/java/com/diffplug/spotless/maven/java/TypeAnnotationsStepTest.java rename to plugin-maven/src/test/java/com/diffplug/spotless/maven/java/FormatAnnotationsStepTest.java index c2281bf8fd..8560b73fd4 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/TypeAnnotationsStepTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/java/FormatAnnotationsStepTest.java @@ -19,15 +19,15 @@ import com.diffplug.spotless.maven.MavenIntegrationHarness; -class TypeAnnotationsStepTest extends MavenIntegrationHarness { +class FormatAnnotationsStepTest extends MavenIntegrationHarness { @Test - void testTypeAnnotations() throws Exception { - writePomWithJavaSteps(""); + void testFormatAnnotations() throws Exception { + writePomWithJavaSteps(""); String path = "src/main/java/test.java"; - setFile(path).toResource("java/typeannotations/TypeAnnotationsTestInput.test"); + setFile(path).toResource("java/formatannotations/FormatAnnotationsTestInput.test"); mavenRunner().withArguments("spotless:apply").runNoError(); - assertFile(path).sameAsResource("java/typeannotations/TypeAnnotationsTestOutput.test"); + assertFile(path).sameAsResource("java/formatannotations/FormatAnnotationsTestOutput.test"); } } diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000000..7bd954555f --- /dev/null +++ b/renovate.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:base" + ] +} diff --git a/testlib/src/main/resources/java/formatannotations/FormatAnnotationsAddRemoveInput.test b/testlib/src/main/resources/java/formatannotations/FormatAnnotationsAddRemoveInput.test new file mode 100644 index 0000000000..e822a8cc41 --- /dev/null +++ b/testlib/src/main/resources/java/formatannotations/FormatAnnotationsAddRemoveInput.test @@ -0,0 +1,11 @@ +class FormatAnnotationsAddRemove { + + @Empty + String e; + + @NonEmpty + String ne; + + @Localized + String localized; +} diff --git a/testlib/src/main/resources/java/formatannotations/FormatAnnotationsAddRemoveOutput.test b/testlib/src/main/resources/java/formatannotations/FormatAnnotationsAddRemoveOutput.test new file mode 100644 index 0000000000..355528bd88 --- /dev/null +++ b/testlib/src/main/resources/java/formatannotations/FormatAnnotationsAddRemoveOutput.test @@ -0,0 +1,9 @@ +class FormatAnnotationsAddRemove { + + @Empty String e; + + @NonEmpty String ne; + + @Localized + String localized; +} diff --git a/testlib/src/main/resources/java/typeannotations/TypeAnnotationsInCommentsInput.test b/testlib/src/main/resources/java/formatannotations/FormatAnnotationsInCommentsInput.test similarity index 94% rename from testlib/src/main/resources/java/typeannotations/TypeAnnotationsInCommentsInput.test rename to testlib/src/main/resources/java/formatannotations/FormatAnnotationsInCommentsInput.test index d49799c0c3..1095de0fd6 100644 --- a/testlib/src/main/resources/java/typeannotations/TypeAnnotationsInCommentsInput.test +++ b/testlib/src/main/resources/java/formatannotations/FormatAnnotationsInCommentsInput.test @@ -1,4 +1,4 @@ -class TypeAnnotationsInComments { +class FormatAnnotationsInComments { // Here is a comment relating to the annotation @Nullable @Interned diff --git a/testlib/src/main/resources/java/typeannotations/TypeAnnotationsInCommentsOutput.test b/testlib/src/main/resources/java/formatannotations/FormatAnnotationsInCommentsOutput.test similarity index 93% rename from testlib/src/main/resources/java/typeannotations/TypeAnnotationsInCommentsOutput.test rename to testlib/src/main/resources/java/formatannotations/FormatAnnotationsInCommentsOutput.test index 491ce5b2aa..91a352347b 100644 --- a/testlib/src/main/resources/java/typeannotations/TypeAnnotationsInCommentsOutput.test +++ b/testlib/src/main/resources/java/formatannotations/FormatAnnotationsInCommentsOutput.test @@ -1,4 +1,4 @@ -class TypeAnnotationsInComments { +class FormatAnnotationsInComments { // Here is a comment relating to the annotation @Nullable @Interned String m1() {} diff --git a/testlib/src/main/resources/java/typeannotations/TypeAnnotationsTestInput.test b/testlib/src/main/resources/java/formatannotations/FormatAnnotationsTestInput.test similarity index 87% rename from testlib/src/main/resources/java/typeannotations/TypeAnnotationsTestInput.test rename to testlib/src/main/resources/java/formatannotations/FormatAnnotationsTestInput.test index 8a870a34cc..fb711451d1 100644 --- a/testlib/src/main/resources/java/typeannotations/TypeAnnotationsTestInput.test +++ b/testlib/src/main/resources/java/formatannotations/FormatAnnotationsTestInput.test @@ -1,4 +1,4 @@ -class TypeAnnotationsTest { +class FormatAnnotationsTest { public @Nullable String s0 = null; @@ -65,4 +65,13 @@ class TypeAnnotationsTest { @Regex(2) @Interned String m6() {} + + @Empty + String e; + + @NonEmpty + String ne; + + @Localized + String localized; } diff --git a/testlib/src/main/resources/java/typeannotations/TypeAnnotationsTestOutput.test b/testlib/src/main/resources/java/formatannotations/FormatAnnotationsTestOutput.test similarity index 87% rename from testlib/src/main/resources/java/typeannotations/TypeAnnotationsTestOutput.test rename to testlib/src/main/resources/java/formatannotations/FormatAnnotationsTestOutput.test index 81fd049609..ca37e66d86 100644 --- a/testlib/src/main/resources/java/typeannotations/TypeAnnotationsTestOutput.test +++ b/testlib/src/main/resources/java/formatannotations/FormatAnnotationsTestOutput.test @@ -1,4 +1,4 @@ -class TypeAnnotationsTest { +class FormatAnnotationsTest { public @Nullable String s0 = null; @@ -40,4 +40,12 @@ class TypeAnnotationsTest { @Nullable // a comment @Regex(2) @Interned String m6() {} + + @Empty + String e; + + @NonEmpty + String ne; + + @Localized String localized; } diff --git a/testlib/src/test/java/com/diffplug/spotless/java/TypeAnnotationsStepTest.java b/testlib/src/test/java/com/diffplug/spotless/java/FormatAnnotationsStepTest.java similarity index 50% rename from testlib/src/test/java/com/diffplug/spotless/java/TypeAnnotationsStepTest.java rename to testlib/src/test/java/com/diffplug/spotless/java/FormatAnnotationsStepTest.java index 3724cac09f..84d347e490 100644 --- a/testlib/src/test/java/com/diffplug/spotless/java/TypeAnnotationsStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/java/FormatAnnotationsStepTest.java @@ -15,28 +15,36 @@ */ package com.diffplug.spotless.java; +import java.util.Arrays; + import org.junit.jupiter.api.Test; import com.diffplug.spotless.FormatterStep; import com.diffplug.spotless.ResourceHarness; import com.diffplug.spotless.SerializableEqualityTester; -class TypeAnnotationsStepTest extends ResourceHarness { +class FormatAnnotationsStepTest extends ResourceHarness { + @Test + void formatAnnotations() throws Throwable { + FormatterStep step = FormatAnnotationsStep.create(); + assertOnResources(step, "java/formatannotations/FormatAnnotationsTestInput.test", "java/formatannotations/FormatAnnotationsTestOutput.test"); + } + @Test - void typeAnnotations() throws Throwable { - FormatterStep step = TypeAnnotationsStep.create(); - assertOnResources(step, "java/typeannotations/TypeAnnotationsTestInput.test", "java/typeannotations/TypeAnnotationsTestOutput.test"); + void formatAnnotationsInComments() throws Throwable { + FormatterStep step = FormatAnnotationsStep.create(); + assertOnResources(step, "java/formatannotations/FormatAnnotationsInCommentsInput.test", "java/formatannotations/FormatAnnotationsInCommentsOutput.test"); } @Test - void typeAnnotationsInComments() throws Throwable { - FormatterStep step = TypeAnnotationsStep.create(); - assertOnResources(step, "java/typeannotations/TypeAnnotationsInCommentsInput.test", "java/typeannotations/TypeAnnotationsInCommentsOutput.test"); + void formatAnnotationsAddRemove() throws Throwable { + FormatterStep step = FormatAnnotationsStep.create(Arrays.asList("Empty", "NonEmpty"), Arrays.asList("Localized")); + assertOnResources(step, "java/formatannotations/FormatAnnotationsAddRemoveInput.test", "java/formatannotations/FormatAnnotationsAddRemoveOutput.test"); } @Test - void doesntThrowIfTypeAnnotationsIsntSerializable() { - TypeAnnotationsStep.create(); + void doesntThrowIfFormatAnnotationsIsntSerializable() { + FormatAnnotationsStep.create(); } @Test @@ -49,7 +57,7 @@ protected void setupTest(API api) { @Override protected FormatterStep create() { - return TypeAnnotationsStep.create(); + return FormatAnnotationsStep.create(); } }.testEquals(); } From 263da38e4ef5ef33b2f5ea45b43d972ffdc78abd Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Sun, 28 Aug 2022 14:21:43 -0700 Subject: [PATCH 17/22] Tweaks --- .../diffplug/spotless/java/FormatAnnotationsStep.java | 9 ++++++--- .../java/com/diffplug/gradle/spotless/JavaExtension.java | 2 ++ plugin-maven/README.md | 1 + .../diffplug/spotless/maven/java/FormatAnnotations.java | 2 +- .../FormatAnnotationsInCommentsInput.test | 4 ++-- .../FormatAnnotationsInCommentsOutput.test | 4 ++-- 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/java/FormatAnnotationsStep.java b/lib/src/main/java/com/diffplug/spotless/java/FormatAnnotationsStep.java index 28691ccf91..1345182acf 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/FormatAnnotationsStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/FormatAnnotationsStep.java @@ -393,7 +393,6 @@ public static FormatterStep create(List addedTypeAnnotations, List addedTypeAnnotations, List removedTypeAnnotations) { typeAnnotations.addAll(addedTypeAnnotations); typeAnnotations.removeAll(removedTypeAnnotations); } FormatterFunc toFormatter() { - return unixStr -> fixupFormatAnnotations(unixStr); + return unixStr -> fixupTypeAnnotations(unixStr); } /** @@ -430,7 +433,7 @@ FormatterFunc toFormatter() { * @param the text of a Java file * @return corrected text of the Java file */ - String fixupFormatAnnotations(String unixStr) { + String fixupTypeAnnotations(String unixStr) { // Each element of `lines` ends with a newline. String[] lines = unixStr.split("((?<=\n))"); for (int i = 0; i < lines.length - 1; i++) { diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java index 1329ce1ad9..25e464b0da 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java @@ -240,7 +240,9 @@ public FormatAnnotationsConfig formatAnnotations() { } public class FormatAnnotationsConfig { + /** Annotations in addition to those in the default list. */ final List addedTypeAnnotations = new ArrayList<>(); + /** Annotations that the user doesn't want treated as type annotations. */ final List removedTypeAnnotations = new ArrayList<>(); FormatAnnotationsConfig() { diff --git a/plugin-maven/README.md b/plugin-maven/README.md index b7e93f41ca..3a112cd3b1 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -290,6 +290,7 @@ A type annotation is an annotation that is meta-annotated with `@Target({Element Because Spotless cannot necessarily examine the annotation definition, it uses a hard-coded list of well-known type annotations. You can make a pull request to add new ones. In the future there will be mechanisms to add/remove annotations from the list. +These mechanisms already exist for the Gradle plugin. ## Groovy diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/FormatAnnotations.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/FormatAnnotations.java index 5ce820921a..ac60af0a62 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/FormatAnnotations.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/FormatAnnotations.java @@ -26,7 +26,7 @@ public class FormatAnnotations implements FormatterStepFactory { @Override public FormatterStep newFormatterStep(FormatterStepConfig config) { - // TODO: Permit customization in Maven. + // TODO: Permit customization in Maven build files. return FormatAnnotationsStep.create(Collections.emptyList(), Collections.emptyList()); } } diff --git a/testlib/src/main/resources/java/formatannotations/FormatAnnotationsInCommentsInput.test b/testlib/src/main/resources/java/formatannotations/FormatAnnotationsInCommentsInput.test index 1095de0fd6..a744b072a1 100644 --- a/testlib/src/main/resources/java/formatannotations/FormatAnnotationsInCommentsInput.test +++ b/testlib/src/main/resources/java/formatannotations/FormatAnnotationsInCommentsInput.test @@ -1,10 +1,10 @@ class FormatAnnotationsInComments { - // Here is a comment relating to the annotation @Nullable + // Here is a comment @Interned String m1() {} - // Here is another comment relating to the annotation @Nullable + // Here is another comment String m2() {} /** diff --git a/testlib/src/main/resources/java/formatannotations/FormatAnnotationsInCommentsOutput.test b/testlib/src/main/resources/java/formatannotations/FormatAnnotationsInCommentsOutput.test index 91a352347b..be65af24be 100644 --- a/testlib/src/main/resources/java/formatannotations/FormatAnnotationsInCommentsOutput.test +++ b/testlib/src/main/resources/java/formatannotations/FormatAnnotationsInCommentsOutput.test @@ -1,9 +1,9 @@ class FormatAnnotationsInComments { - // Here is a comment relating to the annotation @Nullable + // Here is a comment @Interned String m1() {} - // Here is another comment relating to the annotation @Nullable + // Here is another comment String m2() {} /** From 04040622bed59ebcd87a32a2b1f56a9917587c00 Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Sun, 28 Aug 2022 14:23:32 -0700 Subject: [PATCH 18/22] Tabify --- .../com/diffplug/spotless/java/FormatAnnotationsStep.java | 8 ++++---- .../java/com/diffplug/gradle/spotless/JavaExtension.java | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/java/FormatAnnotationsStep.java b/lib/src/main/java/com/diffplug/spotless/java/FormatAnnotationsStep.java index 1345182acf..2d01e305a0 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/FormatAnnotationsStep.java +++ b/lib/src/main/java/com/diffplug/spotless/java/FormatAnnotationsStep.java @@ -414,10 +414,10 @@ private static final class State implements Serializable { // Don't move an annotation to the start of a comment line. private static final Pattern startsWithCommentPattern = Pattern.compile("^[ \t]*(//|/\\*$|/\\*|void\\b)"); - /** - * @param addedTypeAnnotations simple names to add to Spotless's default list - * @param removedTypeAnnotations simple names to remove from Spotless's default list - */ + /** + * @param addedTypeAnnotations simple names to add to Spotless's default list + * @param removedTypeAnnotations simple names to remove from Spotless's default list + */ State(List addedTypeAnnotations, List removedTypeAnnotations) { typeAnnotations.addAll(addedTypeAnnotations); typeAnnotations.removeAll(removedTypeAnnotations); diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java index 25e464b0da..3976c154aa 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java @@ -240,9 +240,9 @@ public FormatAnnotationsConfig formatAnnotations() { } public class FormatAnnotationsConfig { - /** Annotations in addition to those in the default list. */ + /** Annotations in addition to those in the default list. */ final List addedTypeAnnotations = new ArrayList<>(); - /** Annotations that the user doesn't want treated as type annotations. */ + /** Annotations that the user doesn't want treated as type annotations. */ final List removedTypeAnnotations = new ArrayList<>(); FormatAnnotationsConfig() { From ef219c09a1d3a9119d393c9cd383892086aef83a Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Tue, 13 Sep 2022 17:10:27 -0700 Subject: [PATCH 19/22] Remove workarounds to #834 because they are no longer needed thanks to #1224 and #1228. --- plugin-gradle/README.md | 30 ------------------------------ plugin-maven/README.md | 22 ---------------------- 2 files changed, 52 deletions(-) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index c1a41c2ef0..dc49c21a88 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -197,21 +197,6 @@ spotless { formatAnnotations() ``` -**⚠️ Note on using Google Java Format with Java 16+** - -Using Java 16+ with Google Java Format 1.10.0 [requires additional flags](https://github.com/google/google-java-format/releases/tag/v1.10.0) to the running JDK. -These Flags can be provided using the `gradle.properties` file (See [documentation](https://docs.gradle.org/current/userguide/build_environment.html)). - -For example the following file under `gradle.properties` will run gradle with the required flags: -``` -org.gradle.jvmargs=--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ - --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \ - --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \ - --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \ - --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED -``` -This is a workaround to a [pending issue](https://github.com/diffplug/spotless/issues/834). - ### palantir-java-format [homepage](https://github.com/palantir/palantir-java-format). [changelog](https://github.com/palantir/palantir-java-format/releases). @@ -225,21 +210,6 @@ spotless { formatAnnotations() ``` -**⚠️ Note on using Palantir Java Format with Java 16+** - -Using Java 16+ with Palantir Java Format [requires additional flags](https://github.com/google/google-java-format/releases/tag/v1.10.0) on the running JDK. -These Flags can be provided using the `gradle.properties` file (See [documentation](https://docs.gradle.org/current/userguide/build_environment.html)). - -For example the following file under `gradle.properties` will run gradle with the required flags: -``` -org.gradle.jvmargs=--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ - --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \ - --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \ - --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \ - --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED -``` -This is a workaround to a [pending issue](https://github.com/diffplug/spotless/issues/834). - ### eclipse jdt [homepage](https://www.eclipse.org/downloads/packages/). [compatible versions](https://github.com/diffplug/spotless/tree/main/lib-extra/src/main/resources/com/diffplug/spotless/extra/eclipse_jdt_formatter). See [here](../ECLIPSE_SCREENSHOTS.md) for screenshots that demonstrate how to get and install the config file mentioned below. diff --git a/plugin-maven/README.md b/plugin-maven/README.md index 3a112cd3b1..93175b9ed8 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -214,17 +214,6 @@ any other maven phase (i.e. compile) then it can be configured as below; ``` -**⚠️ Note on using Google Java Format with Java 16+** - -Using Java 16+ with Google Java Format 1.10.0 [requires additional flags](https://github.com/google/google-java-format/releases/tag/v1.10.0) to the running JDK. -These Flags can be provided using `MAVEN_OPTS` environment variable or using the `./mvn/jvm.config` file (See [documentation](https://maven.apache.org/configure.html#mvn-jvm-config-file)). - -For example the following file under `.mvn/jvm.config` will run maven with the required flags: -``` ---add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED -``` -This is a workaround to a [pending issue](https://github.com/diffplug/spotless/issues/834). - ### palantir-java-format [homepage](https://github.com/palantir/palantir-java-format). [changelog](https://github.com/palantir/palantir-java-format/releases). [code](https://github.com/diffplug/spotless/blob/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/PalantirJavaFormat.java). @@ -235,17 +224,6 @@ This is a workaround to a [pending issue](https://github.com/diffplug/spotless/i ``` -**⚠️ Note on using Palantir Java Format with Java 16+** - -Using Java 16+ with Palantir Java Format [requires additional flags](https://github.com/google/google-java-format/releases/tag/v1.10.0) on the running JDK. -These Flags can be provided using `MAVEN_OPTS` environment variable or using the `./mvn/jvm.config` file (See [documentation](https://maven.apache.org/configure.html#mvn-jvm-config-file)). - -For example the following file under `.mvn/jvm.config` will run maven with the required flags: -``` ---add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED -``` -This is a workaround to a [pending issue](https://github.com/diffplug/spotless/issues/834). - ### eclipse jdt [homepage](https://www.eclipse.org/downloads/packages/). [compatible versions](https://github.com/diffplug/spotless/tree/main/lib-extra/src/main/resources/com/diffplug/spotless/extra/eclipse_jdt_formatter). [code](https://github.com/diffplug/spotless/blob/main/plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Eclipse.java). See [here](../ECLIPSE_SCREENSHOTS.md) for screenshots that demonstrate how to get and install the config file mentioned below. From 61d362bf03f7e8e47d5fccf8602ddef253c9a314 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Tue, 13 Sep 2022 17:14:06 -0700 Subject: [PATCH 20/22] Keep the step-specific sections specific to their section. --- plugin-gradle/README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index dc49c21a88..f5b7bbf1cc 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -193,8 +193,6 @@ spotless { // and/or reflow long strings (requires at least 1.8) // and/or use custom group artifact (you probably don't need this) googleJavaFormat('1.8').aosp().reflowLongStrings().groupArtifact('com.google.googlejavaformat:google-java-format') - // optional: fix formatting of type annotations - formatAnnotations() ``` ### palantir-java-format @@ -206,8 +204,6 @@ spotless { palantirJavaFormat() // optional: you can specify a specific version palantirJavaFormat('2.9.0') - // optional: fix formatting of type annotations - formatAnnotations() ``` ### eclipse jdt From 7a434ce732b50927a5690bb9b3e822407a462fa1 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Tue, 13 Sep 2022 17:15:51 -0700 Subject: [PATCH 21/22] Fix TOC entry to match the new formatAnnotations name. --- plugin-gradle/README.md | 4 ++-- plugin-maven/README.md | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index f5b7bbf1cc..a6d05daa9d 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -60,7 +60,7 @@ Spotless supports all of Gradle's built-in performance features (incremental bui - [**Quickstart**](#quickstart) - [Requirements](#requirements) - **Languages** - - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [clang-format](#clang-format), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [type annotations](#type-annotations)) + - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [clang-format](#clang-format), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [formatAnnotations](#formatAnnotations)) - [Groovy](#groovy) ([eclipse groovy](#eclipse-groovy)) - [Kotlin](#kotlin) ([ktfmt](#ktfmt), [ktlint](#ktlint), [diktat](#diktat), [prettier](#prettier)) - [Scala](#scala) ([scalafmt](#scalafmt)) @@ -219,7 +219,7 @@ spotless { ``` -### Type annotations +### formatAnnotations Type annotations should be on the same line as the type that they qualify. diff --git a/plugin-maven/README.md b/plugin-maven/README.md index 93175b9ed8..d80773f3f1 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -47,7 +47,7 @@ user@machine repo % mvn spotless:check - [Requirements](#requirements) - [Binding to maven phase](#binding-to-maven-phase) - **Languages** - - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [type annotations](#type-annotations)) + - [Java](#java) ([google-java-format](#google-java-format), [eclipse jdt](#eclipse-jdt), [prettier](#prettier), [palantir-java-format](#palantir-java-format), [formatAnnotations](#formatAnnotations)) - [Groovy](#groovy) ([eclipse groovy](#eclipse-groovy)) - [Kotlin](#kotlin) ([ktfmt](#ktfmt), [ktlint](#ktlint), [diktat](#diktat), [prettier](#prettier)) - [Scala](#scala) ([scalafmt](#scalafmt)) @@ -235,7 +235,7 @@ any other maven phase (i.e. compile) then it can be configured as below; ``` -### Type annotations +### formatAnnotations Type annotations should be on the same line as the type that they qualify. @@ -255,7 +255,7 @@ However, some tools format them incorrectly, like this: String s; ``` -To fix the incorrect formatting, add the `formatAnnotations()` rule after a Java formatter. For example: +To fix the incorrect formatting, add the `formatAnnotations` rule after a Java formatter. For example: ```XML From 78cd2ef7448260c6640b8acc3ac158ed73b7f50c Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Tue, 13 Sep 2022 17:17:16 -0700 Subject: [PATCH 22/22] Minor tweak to changelog. --- CHANGES.md | 2 +- plugin-gradle/CHANGES.md | 2 +- plugin-maven/CHANGES.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index cec949f59d..f61bebaa50 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,7 +11,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added -* `formatAnnotations()` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formatting step, such as `googleJavaFormat()`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) +* `formatAnnotations()` step to correct formatting of Java type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formatting step, such as `googleJavaFormat()`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) ## [2.29.0] - 2022-08-23 ### Added diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 0efb87334d..5003de1aba 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -4,7 +4,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added -* `formatAnnotations()` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formatting step, such as `googleJavaFormat()`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) +* `formatAnnotations()` step to correct formatting of Java type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formatting step, such as `googleJavaFormat()`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) ## [6.10.0] - 2022-08-23 ### Added diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 30842b1b06..fd371233f2 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -4,7 +4,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] ### Added -* `formatAnnotations` step to correct formatting of type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formatting step, such as `googleJavaFormat`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) +* `formatAnnotations` step to correct formatting of Java type annotations. It puts type annotations on the same line as the type that they qualify. Run it after a Java formatting step, such as `googleJavaFormat`. ([#1275](https://github.com/diffplug/spotless/pull/1275)) ## [2.25.0] - 2022-08-23 ### Added