mirror of
https://github.com/jlengrand/error-prone-support.git
synced 2026-03-10 08:11:25 +00:00
Compare commits
50 Commits
master
...
benhalasi/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92071c854c | ||
|
|
06028a0729 | ||
|
|
1112cef15c | ||
|
|
7eb5479f98 | ||
|
|
8d3fd072d3 | ||
|
|
0ccea3c3c2 | ||
|
|
d9607bde04 | ||
|
|
6b766891d2 | ||
|
|
a2c92b54dd | ||
|
|
8c4b8c27d2 | ||
|
|
bdb37a553d | ||
|
|
56f58a45b4 | ||
|
|
bf98ce2f28 | ||
|
|
6bd1f577ce | ||
|
|
cd0a54c486 | ||
|
|
4f139830ef | ||
|
|
173b43b0ad | ||
|
|
7ec43faf6a | ||
|
|
46490b83fc | ||
|
|
01c04007d4 | ||
|
|
4b9de605e7 | ||
|
|
4ba51ac275 | ||
|
|
58d21a5ea5 | ||
|
|
92181f3320 | ||
|
|
9b7e5a2da7 | ||
|
|
9476e78fec | ||
|
|
0eb4c8d93b | ||
|
|
1652a24bd2 | ||
|
|
69fe9bea95 | ||
|
|
778e2439ae | ||
|
|
38adfa0507 | ||
|
|
5a7995a598 | ||
|
|
9a9a86cb60 | ||
|
|
d7fc940a99 | ||
|
|
a4dd402172 | ||
|
|
32bd39a4c3 | ||
|
|
4453d9f122 | ||
|
|
253a35fc93 | ||
|
|
b531cd3fc9 | ||
|
|
dec75a841e | ||
|
|
91f11dea71 | ||
|
|
01a31c6585 | ||
|
|
bd08fd30e1 | ||
|
|
c8b7c7cdbf | ||
|
|
305cedd02f | ||
|
|
1bb8b85421 | ||
|
|
78cf52beff | ||
|
|
f61539d266 | ||
|
|
1a6f6ec04c | ||
|
|
f8d6ae147b |
@@ -45,6 +45,11 @@
|
||||
<artifactId>error_prone_test_helpers</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto.value</groupId>
|
||||
<artifactId>auto-value-annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
@@ -68,4 +73,16 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,296 @@
|
||||
package tech.picnic.errorprone.experimental.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.STYLE;
|
||||
import static com.sun.tools.javac.code.Flags.ENUM;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.annotations.Var;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.CompilationUnitTreeMatcher;
|
||||
import com.google.errorprone.fixes.Replacement;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.google.errorprone.util.ErrorProneToken;
|
||||
import com.google.errorprone.util.ErrorProneTokens;
|
||||
import com.sun.source.tree.BlockTree;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.source.tree.Tree.Kind;
|
||||
import com.sun.source.tree.VariableTree;
|
||||
import com.sun.tools.javac.parser.Tokens.TokenKind;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
|
||||
import com.sun.tools.javac.util.Position;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import javax.lang.model.element.Modifier;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags classes with a non-canonical member order.
|
||||
*
|
||||
* <p>Class members should be ordered as follows:
|
||||
*
|
||||
* <ol>
|
||||
* <li>Static fields
|
||||
* <li>Instance fields
|
||||
* <li>Static initializer blocks
|
||||
* <li>Instance initializer blocks
|
||||
* <li>Constructors
|
||||
* <li>Methods
|
||||
* <li>Nested classes, interfaces and enums
|
||||
* </ol>
|
||||
*
|
||||
* @see <a
|
||||
* href="https://checkstyle.sourceforge.io/apidocs/com/puppycrawl/tools/checkstyle/checks/coding/DeclarationOrderCheck.html">Checkstyle's
|
||||
* {@code DeclarationOrderCheck}</a>
|
||||
*/
|
||||
// XXX: Consider introducing support for ordering members in records or annotation definitions.
|
||||
// XXX: Exclude checkstyle from running against (this checker's) test files.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Type members should be defined in a canonical order",
|
||||
link = BUG_PATTERNS_BASE_URL + "TypeMemberOrder",
|
||||
linkType = CUSTOM,
|
||||
severity = WARNING,
|
||||
tags = STYLE)
|
||||
public final class TypeMemberOrder extends BugChecker implements CompilationUnitTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Instantiates a new {@link TypeMemberOrder} instance. */
|
||||
public TypeMemberOrder() {}
|
||||
|
||||
@Override
|
||||
public Description matchCompilationUnit(
|
||||
CompilationUnitTree compilationUnitTree, VisitorState state) {
|
||||
SuggestedFix.Builder suggestedFixes = SuggestedFix.builder();
|
||||
for (Tree tree : compilationUnitTree.getTypeDecls()) {
|
||||
if (!isSuppressed(tree, state) && tree instanceof ClassTree classTree) {
|
||||
suggestedFixes.merge(
|
||||
matchClass(classTree, state, (JCTree.JCCompilationUnit) compilationUnitTree));
|
||||
}
|
||||
}
|
||||
SuggestedFix suggestedFix = suggestedFixes.build();
|
||||
if (suggestedFix.isEmpty()) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
return describeMatch(compilationUnitTree, suggestedFix);
|
||||
}
|
||||
|
||||
private SuggestedFix matchClass(
|
||||
ClassTree tree, VisitorState state, JCTree.JCCompilationUnit compilationUnit) {
|
||||
Kind treeKind = tree.getKind();
|
||||
if (treeKind != Kind.CLASS && treeKind != Kind.INTERFACE && treeKind != Kind.ENUM) {
|
||||
return SuggestedFix.emptyFix();
|
||||
}
|
||||
|
||||
int bodyStartPos = getBodyStartPos(tree, state);
|
||||
if (bodyStartPos == Position.NOPOS) {
|
||||
/*
|
||||
* We can't determine the type body's start position in the source code. This generally means
|
||||
* that (part of) its code was generated. Even if the source code for a subset of its members
|
||||
* is available, dealing with this edge case is not worth the trouble.
|
||||
*/
|
||||
return SuggestedFix.emptyFix();
|
||||
}
|
||||
|
||||
ImmutableList<TypeMember> members = getAllTypeMembers(tree, bodyStartPos, state);
|
||||
boolean topLevelSorted = members.equals(ImmutableList.sortedCopyOf(members));
|
||||
|
||||
if (topLevelSorted) {
|
||||
SuggestedFix.Builder nestedSuggestedFixes = SuggestedFix.builder();
|
||||
for (TypeMember member : members) {
|
||||
if (member.tree() instanceof ClassTree memberClassTree) {
|
||||
SuggestedFix other = matchClass(memberClassTree, state, compilationUnit);
|
||||
nestedSuggestedFixes.merge(other);
|
||||
}
|
||||
}
|
||||
return nestedSuggestedFixes.build();
|
||||
}
|
||||
|
||||
CharSequence source = requireNonNull(state.getSourceCode(), "Source code");
|
||||
ImmutableMap.Builder<TypeMember, String> typeMemberSource = ImmutableMap.builder();
|
||||
|
||||
for (TypeMember member : members) {
|
||||
if (member.tree() instanceof ClassTree memberClassTree) {
|
||||
SuggestedFix suggestedFix = matchClass(memberClassTree, state, compilationUnit);
|
||||
@Var
|
||||
String memberSource =
|
||||
source.subSequence(member.startPosition(), member.endPosition()).toString();
|
||||
// Diff between memberSource and replacement positions.
|
||||
@Var int diff = -member.startPosition();
|
||||
for (Replacement replacement : suggestedFix.getReplacements(compilationUnit.endPositions)) {
|
||||
memberSource =
|
||||
memberSource.subSequence(0, replacement.startPosition() + diff)
|
||||
+ replacement.replaceWith()
|
||||
+ memberSource.subSequence(
|
||||
replacement.endPosition() + diff, memberSource.length());
|
||||
diff +=
|
||||
replacement.replaceWith().length()
|
||||
- (replacement.endPosition() - replacement.startPosition());
|
||||
}
|
||||
typeMemberSource.put(member, memberSource);
|
||||
} else {
|
||||
typeMemberSource.put(
|
||||
member, source.subSequence(member.startPosition(), member.endPosition()).toString());
|
||||
}
|
||||
}
|
||||
|
||||
return sortTypeMembers(members, typeMemberSource.build());
|
||||
}
|
||||
|
||||
/** Returns all members that can be moved or may lay between movable ones. */
|
||||
private ImmutableList<TypeMember> getAllTypeMembers(
|
||||
ClassTree tree, int bodyStartPos, VisitorState state) {
|
||||
ImmutableList.Builder<TypeMember> builder = ImmutableList.builder();
|
||||
@Var int currentStartPos = bodyStartPos;
|
||||
for (Tree member : tree.getMembers()) {
|
||||
if (state.getEndPosition(member) == Position.NOPOS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int treeStartPos = currentStartPos;
|
||||
getMemberTypeOrdinal(member, state)
|
||||
.ifPresent(
|
||||
e ->
|
||||
builder.add(
|
||||
new AutoValue_TypeMemberOrder_TypeMember(
|
||||
member, treeStartPos, state.getEndPosition(member), e)));
|
||||
|
||||
/* XXX: Write explanation about this enum. */
|
||||
currentStartPos = Math.max(currentStartPos, state.getEndPosition(member));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the preferred ordinal of the given member, or empty if it's unmovable for any reason,
|
||||
* including it lacking a preferred ordinal.
|
||||
*/
|
||||
private Optional<Integer> getMemberTypeOrdinal(Tree tree, VisitorState state) {
|
||||
if (isSuppressed(tree, state) || isEnumeratorDefinition(tree)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return switch (tree.getKind()) {
|
||||
case VARIABLE -> Optional.of(isStatic((VariableTree) tree) ? 1 : 2);
|
||||
case BLOCK -> Optional.of(isStatic((BlockTree) tree) ? 3 : 4);
|
||||
case METHOD -> Optional.of(isConstructor((MethodTree) tree) ? 5 : 6);
|
||||
case CLASS, INTERFACE, ENUM -> Optional.of(7);
|
||||
default -> Optional.empty();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start position of the body of the given type, in the case of enums, it returns the
|
||||
* position that follows the enumerated type's enumerations.
|
||||
*/
|
||||
private static int getBodyStartPos(ClassTree tree, VisitorState state) {
|
||||
CharSequence sourceCode = state.getSourceCode();
|
||||
/*
|
||||
* To avoid including the type's preceding annotations, use `getPreferredPosition()` rather than
|
||||
* `ASTHelpers`.
|
||||
*/
|
||||
int typeStart = ((JCTree.JCClassDecl) tree).getPreferredPosition();
|
||||
int typeEnd = state.getEndPosition(tree);
|
||||
if (sourceCode == null || typeStart == Position.NOPOS || typeEnd == Position.NOPOS) {
|
||||
return Position.NOPOS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the source code position of the first token that comes after the first curly left
|
||||
* bracket.
|
||||
*/
|
||||
return ErrorProneTokens.getTokens(
|
||||
sourceCode.subSequence(typeStart, typeEnd).toString(), typeStart, state.context)
|
||||
.stream()
|
||||
.dropWhile(token -> token.kind() != TokenKind.LBRACE)
|
||||
/*
|
||||
* To accommodate enums, skip processing their enumerators. This is needed as Error Prone
|
||||
* has access to the enumerations individually, but not to the whole expression that
|
||||
* declares them, leaving the semicolon trailing the declarations unaccounted for. The
|
||||
* current logic would move this trailing semicolon with the first member after the
|
||||
* enumerations instead of leaving it to close the enumerations' declaration, introducing a
|
||||
* syntax error.
|
||||
*/
|
||||
.dropWhile(token -> tree.getKind() == Kind.ENUM && token.kind() != TokenKind.SEMI)
|
||||
.findFirst()
|
||||
.map(ErrorProneToken::endPos)
|
||||
.orElse(Position.NOPOS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if {@link Tree} is an enum or an enumerator definition, false otherwise.
|
||||
*
|
||||
* @see com.sun.tools.javac.code.Flags#ENUM
|
||||
*/
|
||||
private static boolean isEnumeratorDefinition(Tree tree) {
|
||||
return tree instanceof JCVariableDecl variableDecl && (variableDecl.mods.flags & ENUM) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggests a different way of ordering the given type members.
|
||||
*
|
||||
* @implNote For each member, this method tracks the source code between the end of the definition
|
||||
* of the member that precedes it (or the start of the type body if there is no such member)
|
||||
* and the end of the definition of the member itself. This subsequently enables moving
|
||||
* members around, including any preceding comments and Javadoc. This approach isn't perfect,
|
||||
* and may at times move too much code or documentation around; users will have to manually
|
||||
* resolve this.
|
||||
*/
|
||||
private static SuggestedFix sortTypeMembers(
|
||||
ImmutableList<TypeMember> members, ImmutableMap<TypeMember, String> sourceCode) {
|
||||
return Streams.zip(
|
||||
members.stream(),
|
||||
members.stream().sorted(),
|
||||
(original, replacement) -> {
|
||||
String replacementSource = requireNonNull(sourceCode.get(replacement), "replacement");
|
||||
return original.equals(replacement)
|
||||
? SuggestedFix.emptyFix()
|
||||
: SuggestedFix.replace(
|
||||
original.startPosition(), original.endPosition(), replacementSource);
|
||||
})
|
||||
.reduce(SuggestedFix.builder(), SuggestedFix.Builder::merge, SuggestedFix.Builder::merge)
|
||||
.build();
|
||||
}
|
||||
|
||||
private static boolean isStatic(VariableTree variableTree) {
|
||||
Set<Modifier> modifiers = variableTree.getModifiers().getFlags();
|
||||
return modifiers.contains(Modifier.STATIC);
|
||||
}
|
||||
|
||||
private static boolean isStatic(BlockTree blockTree) {
|
||||
return blockTree.isStatic();
|
||||
}
|
||||
|
||||
private static boolean isConstructor(MethodTree methodTree) {
|
||||
return ASTHelpers.getSymbol(methodTree).isConstructor();
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
abstract static class TypeMember implements Comparable<TypeMember> {
|
||||
abstract Tree tree();
|
||||
|
||||
abstract int startPosition();
|
||||
|
||||
abstract int endPosition();
|
||||
|
||||
abstract int preferredOrdinal();
|
||||
|
||||
@Override
|
||||
public int compareTo(TypeMemberOrder.TypeMember o) {
|
||||
return Integer.compare(preferredOrdinal(), o.preferredOrdinal());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
package tech.picnic.errorprone.experimental.bugpatterns;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class TypeMemberOrderClassTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(TypeMemberOrder.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"class A {",
|
||||
" class InnerClass {}",
|
||||
"",
|
||||
" interface InnerInterface {}",
|
||||
"",
|
||||
" enum InnerEnum {}",
|
||||
"",
|
||||
" int foo() {",
|
||||
" return foo;",
|
||||
" }",
|
||||
"",
|
||||
" A() {}",
|
||||
"",
|
||||
" {",
|
||||
" System.out.println(\"bar\");",
|
||||
" }",
|
||||
"",
|
||||
" static {",
|
||||
" System.out.println(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" private final int bar = 2;",
|
||||
" private static final int foo = 1;",
|
||||
"}")
|
||||
.addSourceLines(
|
||||
"B.java",
|
||||
"class B {",
|
||||
" private static final int foo = 1;",
|
||||
" private final int bar = 2;",
|
||||
"",
|
||||
" static {",
|
||||
" System.out.println(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" {",
|
||||
" System.out.println(\"bar\");",
|
||||
" }",
|
||||
"",
|
||||
" B() {}",
|
||||
"",
|
||||
" int foo() {",
|
||||
" return foo;",
|
||||
" }",
|
||||
"",
|
||||
" class InnerClass {}",
|
||||
"",
|
||||
" interface InnerInterface {}",
|
||||
"",
|
||||
" enum InnerEnum {}",
|
||||
"}")
|
||||
.addSourceLines(
|
||||
"C.java",
|
||||
"class C {",
|
||||
" @SuppressWarnings({\"foo\", \"all\", \"bar\"})",
|
||||
" void unorderedMethod() {}",
|
||||
"",
|
||||
" C() {}",
|
||||
"}")
|
||||
.addSourceLines(
|
||||
"D.java",
|
||||
"class D {",
|
||||
" @SuppressWarnings(\"TypeMemberOrder\")",
|
||||
" void unorderedMethod() {}",
|
||||
"",
|
||||
" D() {}",
|
||||
"}")
|
||||
.addSourceLines(
|
||||
"E.java",
|
||||
"@SuppressWarnings(\"TypeMemberOrder\")",
|
||||
"class E {",
|
||||
" void unorderedMethod() {}",
|
||||
"",
|
||||
" E() {}",
|
||||
"}")
|
||||
.addSourceLines("F.java", "class F {}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(TypeMemberOrder.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
" class Inner {",
|
||||
" int innerFoo() {",
|
||||
" return 1;",
|
||||
" }",
|
||||
"",
|
||||
" private final int innerBar = 2;",
|
||||
" }",
|
||||
"",
|
||||
" int foo() {",
|
||||
" return foo;",
|
||||
" }",
|
||||
"",
|
||||
" A() {}",
|
||||
"",
|
||||
" {",
|
||||
" System.out.println(\"bar\");",
|
||||
" }",
|
||||
"",
|
||||
" static {",
|
||||
" System.out.println(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" private final int bar = 2;",
|
||||
" private static final int foo = 1;",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
" private static final int foo = 1;",
|
||||
"",
|
||||
" private final int bar = 2;",
|
||||
"",
|
||||
" static {",
|
||||
" System.out.println(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" {",
|
||||
" System.out.println(\"bar\");",
|
||||
" }",
|
||||
"",
|
||||
" A() {}",
|
||||
"",
|
||||
" int foo() {",
|
||||
" return foo;",
|
||||
" }",
|
||||
"",
|
||||
" class Inner {",
|
||||
"",
|
||||
" private final int innerBar = 2;",
|
||||
"",
|
||||
" int innerFoo() {",
|
||||
" return 1;",
|
||||
" }",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacementNestedClasses() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(TypeMemberOrder.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
// XXX: Use dedicated helper method to read test files here and below.
|
||||
new BufferedReader(
|
||||
new InputStreamReader(
|
||||
this.getClass()
|
||||
.getClassLoader()
|
||||
.getResourceAsStream(
|
||||
"TypeMemberOrderNestedCompilationUnitTestInput.java"),
|
||||
UTF_8))
|
||||
.lines()
|
||||
.toArray(String[]::new))
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
new BufferedReader(
|
||||
new InputStreamReader(
|
||||
this.getClass()
|
||||
.getClassLoader()
|
||||
.getResourceAsStream(
|
||||
"TypeMemberOrderNestedCompilationUnitTestOutput.java"),
|
||||
UTF_8))
|
||||
.lines()
|
||||
.toArray(String[]::new))
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacementAbstractMethods() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(TypeMemberOrder.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"abstract class A {",
|
||||
" static class InnerClass {}",
|
||||
"",
|
||||
" void foo() {}",
|
||||
"",
|
||||
" abstract void bar();",
|
||||
"",
|
||||
" void baz() {}",
|
||||
"",
|
||||
" A() {}",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"abstract class A {",
|
||||
"",
|
||||
" A() {}",
|
||||
"",
|
||||
" void foo() {}",
|
||||
"",
|
||||
" abstract void bar();",
|
||||
"",
|
||||
" void baz() {}",
|
||||
"",
|
||||
" static class InnerClass {}",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacementUnmovableMembers() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(TypeMemberOrder.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
" @SuppressWarnings(\"TypeMemberOrder\")",
|
||||
" int foo() {",
|
||||
" return foo;",
|
||||
" }",
|
||||
"",
|
||||
" {",
|
||||
" System.out.println(\"bar\");",
|
||||
" }",
|
||||
"",
|
||||
" static {",
|
||||
" System.out.println(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" private final int bar = 2;",
|
||||
"",
|
||||
" @SuppressWarnings(\"TypeMemberOrder\")",
|
||||
" private static final int foo = 1;",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
" @SuppressWarnings(\"TypeMemberOrder\")",
|
||||
" int foo() {",
|
||||
" return foo;",
|
||||
" }",
|
||||
"",
|
||||
" private final int bar = 2;",
|
||||
"",
|
||||
" static {",
|
||||
" System.out.println(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" {",
|
||||
" System.out.println(\"bar\");",
|
||||
" }",
|
||||
"",
|
||||
" @SuppressWarnings(\"TypeMemberOrder\")",
|
||||
" private static final int foo = 1;",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacementHandlesGeneratedDefaultConstructor() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(TypeMemberOrder.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
" int foo() {",
|
||||
" return foo;",
|
||||
" }",
|
||||
"",
|
||||
" {",
|
||||
" System.out.println(\"bar\");",
|
||||
" }",
|
||||
"",
|
||||
" static {",
|
||||
" System.out.println(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" private final int bar = 2;",
|
||||
" private static final int foo = 1;",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
" private static final int foo = 1;",
|
||||
"",
|
||||
" private final int bar = 2;",
|
||||
"",
|
||||
" static {",
|
||||
" System.out.println(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" {",
|
||||
" System.out.println(\"bar\");",
|
||||
" }",
|
||||
"",
|
||||
" int foo() {",
|
||||
" return foo;",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacementDanglingComments() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(TypeMemberOrder.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
" /* empty statement's dangling comment */",
|
||||
" ;",
|
||||
" /**",
|
||||
" * Multiline JavaDoc",
|
||||
" *",
|
||||
" * <p>`foo` method's comment",
|
||||
" */",
|
||||
" int foo() {",
|
||||
" return foo;",
|
||||
" }",
|
||||
"",
|
||||
" // initializer block's comment",
|
||||
" {",
|
||||
" System.out.println(\"bar\");",
|
||||
" }",
|
||||
"",
|
||||
" // static initializer block's comment",
|
||||
" static {",
|
||||
" System.out.println(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" /* `bar` field's dangling comment */",
|
||||
"",
|
||||
" private final int bar = 2;",
|
||||
" // `foo` field's comment",
|
||||
" private static final int foo = 1;",
|
||||
" // trailing comment",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
" // `foo` field's comment",
|
||||
" private static final int foo = 1;",
|
||||
"",
|
||||
" /* `bar` field's dangling comment */",
|
||||
"",
|
||||
" private final int bar = 2;",
|
||||
"",
|
||||
" // static initializer block's comment",
|
||||
" static {",
|
||||
" System.out.println(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" // initializer block's comment",
|
||||
" {",
|
||||
" System.out.println(\"bar\");",
|
||||
" }",
|
||||
" /* empty statement's dangling comment */",
|
||||
" ;",
|
||||
"",
|
||||
" /**",
|
||||
" * Multiline JavaDoc",
|
||||
" *",
|
||||
" * <p>`foo` method's comment",
|
||||
" */",
|
||||
" int foo() {",
|
||||
" return foo;",
|
||||
" }",
|
||||
" // trailing comment",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacementComplexAnnotation() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(TypeMemberOrder.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
"",
|
||||
" @interface AnnotationWithClassReferences {",
|
||||
" Class<?>[] value() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @AnnotationWithClassReferences({Object.class})",
|
||||
" class InnerClassOneValue {",
|
||||
" String bar;",
|
||||
" private static final int foo = 1;",
|
||||
" }",
|
||||
"",
|
||||
" @AnnotationWithClassReferences(value = {Integer.class, String.class})",
|
||||
" class InnerClassTwoValues {",
|
||||
" String bar;",
|
||||
" private static final int foo = 1;",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
"",
|
||||
" @interface AnnotationWithClassReferences {",
|
||||
" Class<?>[] value() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @AnnotationWithClassReferences({Object.class})",
|
||||
" class InnerClassOneValue {",
|
||||
" private static final int foo = 1;",
|
||||
" String bar;",
|
||||
" }",
|
||||
"",
|
||||
" @AnnotationWithClassReferences(value = {Integer.class, String.class})",
|
||||
" class InnerClassTwoValues {",
|
||||
" private static final int foo = 1;",
|
||||
" String bar;",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
package tech.picnic.errorprone.experimental.bugpatterns;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class TypeMemberOrderEnumTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(TypeMemberOrder.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"enum A {",
|
||||
" FOO;",
|
||||
"",
|
||||
" class InnerClass {}",
|
||||
"",
|
||||
" interface InnerInterface {}",
|
||||
"",
|
||||
" enum InnerEnum {}",
|
||||
"",
|
||||
" void qux() {}",
|
||||
"",
|
||||
" A() {}",
|
||||
"",
|
||||
" {",
|
||||
" System.out.println(\"bar\");",
|
||||
" }",
|
||||
"",
|
||||
" static {",
|
||||
" System.out.println(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" final int baz = 2;",
|
||||
" static final int BAR = 1;",
|
||||
"}")
|
||||
.addSourceLines(
|
||||
"B.java",
|
||||
"enum B {",
|
||||
" FOO;",
|
||||
" static final int BAR = 1;",
|
||||
" final int baz = 2;",
|
||||
"",
|
||||
" static {",
|
||||
" System.out.println(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" {",
|
||||
" System.out.println(\"bar\");",
|
||||
" }",
|
||||
"",
|
||||
" B() {}",
|
||||
"",
|
||||
" void qux() {}",
|
||||
"",
|
||||
" class InnerClass {}",
|
||||
"",
|
||||
" interface InnerInterface {}",
|
||||
"",
|
||||
" enum InnerEnum {}",
|
||||
"}")
|
||||
.addSourceLines(
|
||||
"C.java",
|
||||
"enum C {",
|
||||
" FOO;",
|
||||
"",
|
||||
" @SuppressWarnings({\"foo\", \"all\", \"bar\"})",
|
||||
" void bar() {}",
|
||||
"",
|
||||
" C() {}",
|
||||
"}")
|
||||
.addSourceLines(
|
||||
"D.java",
|
||||
"enum D {",
|
||||
" FOO;",
|
||||
"",
|
||||
" @SuppressWarnings({\"TypeMemberOrder\"})",
|
||||
" void bar() {}",
|
||||
"",
|
||||
" D() {}",
|
||||
"}")
|
||||
.addSourceLines("E.java", "enum E {}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(TypeMemberOrder.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"enum A {",
|
||||
" FOO,",
|
||||
" BAR;",
|
||||
"",
|
||||
" class InnerClass {}",
|
||||
"",
|
||||
" interface InnerInterface {}",
|
||||
"",
|
||||
" enum InnerEnum {}",
|
||||
"",
|
||||
" void qux() {}",
|
||||
"",
|
||||
" A() {}",
|
||||
"",
|
||||
" {",
|
||||
" System.out.println(\"bar\");",
|
||||
" }",
|
||||
"",
|
||||
" static {",
|
||||
" System.out.println(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" final int baz = 2;",
|
||||
" static final int BAZ = 1;",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"enum A {",
|
||||
" FOO,",
|
||||
" BAR;",
|
||||
" static final int BAZ = 1;",
|
||||
"",
|
||||
" final int baz = 2;",
|
||||
"",
|
||||
" static {",
|
||||
" System.out.println(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" {",
|
||||
" System.out.println(\"bar\");",
|
||||
" }",
|
||||
"",
|
||||
" A() {}",
|
||||
"",
|
||||
" void qux() {}",
|
||||
"",
|
||||
" class InnerClass {}",
|
||||
"",
|
||||
" interface InnerInterface {}",
|
||||
"",
|
||||
" enum InnerEnum {}",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacementUnmovableMembers() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(TypeMemberOrder.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"enum A {",
|
||||
" FOO;",
|
||||
"",
|
||||
" @SuppressWarnings(\"TypeMemberOrder\")",
|
||||
" class InnerClass {}",
|
||||
"",
|
||||
" interface InnerInterface {}",
|
||||
"",
|
||||
" enum InnerEnum {}",
|
||||
"",
|
||||
" void qux() {}",
|
||||
"",
|
||||
" A() {}",
|
||||
"",
|
||||
" {",
|
||||
" System.out.println(\"bar\");",
|
||||
" }",
|
||||
"",
|
||||
" static {",
|
||||
" System.out.println(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" @SuppressWarnings(\"TypeMemberOrder\")",
|
||||
" final int baz = 2;",
|
||||
"",
|
||||
" static final int BAR = 1;",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"enum A {",
|
||||
" FOO;",
|
||||
"",
|
||||
" @SuppressWarnings(\"TypeMemberOrder\")",
|
||||
" class InnerClass {}",
|
||||
"",
|
||||
" static final int BAR = 1;",
|
||||
"",
|
||||
" static {",
|
||||
" System.out.println(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" {",
|
||||
" System.out.println(\"bar\");",
|
||||
" }",
|
||||
"",
|
||||
" A() {}",
|
||||
"",
|
||||
" void qux() {}",
|
||||
"",
|
||||
" interface InnerInterface {}",
|
||||
"",
|
||||
" @SuppressWarnings(\"TypeMemberOrder\")",
|
||||
" final int baz = 2;",
|
||||
"",
|
||||
" enum InnerEnum {}",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacementHandlesGeneratedDefaultConstructor() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(TypeMemberOrder.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"enum A {",
|
||||
" FOO;",
|
||||
"",
|
||||
" class InnerClass {}",
|
||||
"",
|
||||
" interface InnerInterface {}",
|
||||
"",
|
||||
" enum InnerEnum {}",
|
||||
"",
|
||||
" void qux() {}",
|
||||
"",
|
||||
" {",
|
||||
" System.out.println(\"bar\");",
|
||||
" }",
|
||||
"",
|
||||
" static {",
|
||||
" System.out.println(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" final int baz = 2;",
|
||||
" static final int BAR = 1;",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"enum A {",
|
||||
" FOO;",
|
||||
" static final int BAR = 1;",
|
||||
"",
|
||||
" final int baz = 2;",
|
||||
"",
|
||||
" static {",
|
||||
" System.out.println(\"foo\");",
|
||||
" }",
|
||||
"",
|
||||
" {",
|
||||
" System.out.println(\"bar\");",
|
||||
" }",
|
||||
"",
|
||||
" void qux() {}",
|
||||
"",
|
||||
" class InnerClass {}",
|
||||
"",
|
||||
" interface InnerInterface {}",
|
||||
"",
|
||||
" enum InnerEnum {}",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacementDanglingComments() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(TypeMemberOrder.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"enum A {",
|
||||
" /** FOO's JavaDoc */",
|
||||
" FOO",
|
||||
"/* Dangling comment trailing enumerations. */ ;",
|
||||
"",
|
||||
" /* `quz` method's dangling comment */",
|
||||
" ;",
|
||||
"",
|
||||
" /* `quz` method's comment */",
|
||||
" void qux() {}",
|
||||
"",
|
||||
" // `baz` method's comment",
|
||||
" final int baz = 2;",
|
||||
"",
|
||||
" static final int BAR = 1;",
|
||||
" // trailing comment",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"enum A {",
|
||||
" /** FOO's JavaDoc */",
|
||||
" FOO",
|
||||
"/* Dangling comment trailing enumerations. */ ;",
|
||||
"",
|
||||
" static final int BAR = 1;",
|
||||
"",
|
||||
" // `baz` method's comment",
|
||||
" final int baz = 2;",
|
||||
"",
|
||||
" /* `quz` method's dangling comment */",
|
||||
" ;",
|
||||
"",
|
||||
" /* `quz` method's comment */",
|
||||
" void qux() {}",
|
||||
" // trailing comment",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
package tech.picnic.errorprone.experimental.bugpatterns;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class TypeMemberOrderInterfaceTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(TypeMemberOrder.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"interface A {",
|
||||
" static class InnerClass {}",
|
||||
"",
|
||||
" static interface InnerInterface {}",
|
||||
"",
|
||||
" static enum InnerEnum {}",
|
||||
"",
|
||||
" void bar();",
|
||||
"",
|
||||
" static final int foo = 1;",
|
||||
"}")
|
||||
.addSourceLines(
|
||||
"B.java",
|
||||
"interface B {",
|
||||
" static final int foo = 1;",
|
||||
"",
|
||||
" void bar();",
|
||||
"",
|
||||
" static class InnerClass {}",
|
||||
"",
|
||||
" static interface InnerInterface {}",
|
||||
"",
|
||||
" static enum InnerEnum {}",
|
||||
"}")
|
||||
.addSourceLines(
|
||||
"C.java",
|
||||
"interface C {",
|
||||
" @SuppressWarnings({\"foo\", \"all\", \"bar\"})",
|
||||
" void bar();",
|
||||
"",
|
||||
" static final int foo = 1;",
|
||||
"}")
|
||||
.addSourceLines(
|
||||
"D.java",
|
||||
"interface D {",
|
||||
" @SuppressWarnings(\"TypeMemberOrder\")",
|
||||
" void bar();",
|
||||
"",
|
||||
" static final int foo = 1;",
|
||||
"}")
|
||||
.addSourceLines("E.java", "interface E {}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(TypeMemberOrder.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"interface A {",
|
||||
" static class InnerClass {}",
|
||||
"",
|
||||
" static interface InnerInterface {}",
|
||||
"",
|
||||
" static enum InnerEnum {}",
|
||||
"",
|
||||
" void bar();",
|
||||
"",
|
||||
" static final int foo = 1;",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"interface A {",
|
||||
"",
|
||||
" static final int foo = 1;",
|
||||
"",
|
||||
" void bar();",
|
||||
"",
|
||||
" static class InnerClass {}",
|
||||
"",
|
||||
" static interface InnerInterface {}",
|
||||
"",
|
||||
" static enum InnerEnum {}",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacementDefaultMethods() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(TypeMemberOrder.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"interface A {",
|
||||
" class InnerClass {}",
|
||||
"",
|
||||
" void foo();",
|
||||
"",
|
||||
" default void bar() {}",
|
||||
"",
|
||||
" void baz();",
|
||||
"",
|
||||
" static final int QUX = 1;",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"interface A {",
|
||||
"",
|
||||
" static final int QUX = 1;",
|
||||
"",
|
||||
" void foo();",
|
||||
"",
|
||||
" default void bar() {}",
|
||||
"",
|
||||
" void baz();",
|
||||
"",
|
||||
" class InnerClass {}",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacementUnmovableMembers() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(TypeMemberOrder.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"interface A {",
|
||||
" @SuppressWarnings(\"TypeMemberOrder\")",
|
||||
" static class InnerClass {}",
|
||||
"",
|
||||
" static interface InnerInterface {}",
|
||||
"",
|
||||
" static enum InnerEnum {}",
|
||||
"",
|
||||
" void bar();",
|
||||
"",
|
||||
" @SuppressWarnings(\"TypeMemberOrder\")",
|
||||
" static final int baz = 1;",
|
||||
"",
|
||||
" static final int foo = 1;",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"interface A {",
|
||||
" @SuppressWarnings(\"TypeMemberOrder\")",
|
||||
" static class InnerClass {}",
|
||||
"",
|
||||
" static final int foo = 1;",
|
||||
"",
|
||||
" void bar();",
|
||||
"",
|
||||
" static interface InnerInterface {}",
|
||||
"",
|
||||
" @SuppressWarnings(\"TypeMemberOrder\")",
|
||||
" static final int baz = 1;",
|
||||
"",
|
||||
" static enum InnerEnum {}",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacementDanglingComments() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(TypeMemberOrder.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"interface A {",
|
||||
" // empty statement's dangling comment",
|
||||
" ;",
|
||||
" // `bar` method's comment",
|
||||
" void bar();",
|
||||
"",
|
||||
" // `foo` field's comment",
|
||||
" int foo = 1;",
|
||||
" // trailing comment",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"interface A {",
|
||||
"",
|
||||
" // `foo` field's comment",
|
||||
" int foo = 1;",
|
||||
" // empty statement's dangling comment",
|
||||
" ;",
|
||||
"",
|
||||
" // `bar` method's comment",
|
||||
" void bar();",
|
||||
" // trailing comment",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
class A {
|
||||
class AInner2 {
|
||||
private static final int foo = 1;
|
||||
int bar = 2;
|
||||
|
||||
class AInner2Inner1 {
|
||||
private static final int foo = 1;
|
||||
int bar = 2;
|
||||
}
|
||||
|
||||
class AInner2Inner2 {
|
||||
int bar = 2;
|
||||
private static final int foo = 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int foo = 1;
|
||||
|
||||
class OnlyTopLevelSortedClass {
|
||||
private static final int foo = 1;
|
||||
int bar = 2;
|
||||
|
||||
class UnsortedNestedClass {
|
||||
int bar = 2;
|
||||
private static final int foo = 1;
|
||||
}
|
||||
}
|
||||
|
||||
class AInner1 {
|
||||
class AInner1Inner1 {
|
||||
int bar = 2;
|
||||
private static final int foo = 1;
|
||||
}
|
||||
|
||||
enum DeeplyNestedEnum {
|
||||
/** FOO's JavaDoc */
|
||||
FOO,
|
||||
/* Dangling comment trailing enumerations. */ ;
|
||||
|
||||
/** `quz` method's dangling comment */
|
||||
;
|
||||
|
||||
/** `quz` method's comment */
|
||||
void qux() {}
|
||||
|
||||
// `baz` method's comment
|
||||
final int baz = 2;
|
||||
|
||||
static final int BAR = 1;
|
||||
// trailing comment
|
||||
}
|
||||
|
||||
private static final int foo = 1;
|
||||
|
||||
class AInner1Inner2 {
|
||||
int bar = 2;
|
||||
private static final int foo = 1;
|
||||
}
|
||||
|
||||
int bar = 2;
|
||||
}
|
||||
|
||||
static int baz = 3;
|
||||
private final int bar = 2;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
class A {
|
||||
|
||||
private static final int foo = 1;
|
||||
|
||||
static int baz = 3;
|
||||
private final int bar = 2;
|
||||
|
||||
class AInner2 {
|
||||
private static final int foo = 1;
|
||||
int bar = 2;
|
||||
|
||||
class AInner2Inner1 {
|
||||
private static final int foo = 1;
|
||||
int bar = 2;
|
||||
}
|
||||
|
||||
class AInner2Inner2 {
|
||||
private static final int foo = 1;
|
||||
int bar = 2;
|
||||
}
|
||||
}
|
||||
|
||||
class OnlyTopLevelSortedClass {
|
||||
private static final int foo = 1;
|
||||
int bar = 2;
|
||||
|
||||
class UnsortedNestedClass {
|
||||
private static final int foo = 1;
|
||||
int bar = 2;
|
||||
}
|
||||
}
|
||||
|
||||
class AInner1 {
|
||||
|
||||
private static final int foo = 1;
|
||||
|
||||
int bar = 2;
|
||||
|
||||
class AInner1Inner1 {
|
||||
private static final int foo = 1;
|
||||
int bar = 2;
|
||||
}
|
||||
|
||||
enum DeeplyNestedEnum {
|
||||
/** FOO's JavaDoc */
|
||||
FOO,
|
||||
/* Dangling comment trailing enumerations. */ ;
|
||||
|
||||
static final int BAR = 1;
|
||||
|
||||
// `baz` method's comment
|
||||
final int baz = 2;
|
||||
|
||||
/** `quz` method's dangling comment */
|
||||
;
|
||||
|
||||
/** `quz` method's comment */
|
||||
void qux() {}
|
||||
// trailing comment
|
||||
}
|
||||
|
||||
class AInner1Inner2 {
|
||||
private static final int foo = 1;
|
||||
int bar = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,6 +79,16 @@ public final class MoreASTHelpers {
|
||||
return ASTHelpers.isSameType(ASTHelpers.getType(treeA), ASTHelpers.getType(treeB), state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether a given tree is a generated constructor.
|
||||
*
|
||||
* @param tree The tree of interest.
|
||||
* @return Whether the specified tree is a generated constructor.
|
||||
*/
|
||||
public static boolean isGeneratedConstructor(Tree tree) {
|
||||
return tree instanceof MethodTree methodTree && ASTHelpers.isGeneratedConstructor(methodTree);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the given tree is of type {@link String}.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user