11package tech .picnic .errorprone .refaster .test ;
22
33import static com .google .common .base .Preconditions .checkState ;
4+ import static com .google .common .collect .ImmutableList .toImmutableList ;
45import static com .google .common .collect .ImmutableListMultimap .toImmutableListMultimap ;
56import static com .google .common .collect .ImmutableSet .toImmutableSet ;
67import static com .google .common .collect .ImmutableSortedSet .toImmutableSortedSet ;
78import static com .google .errorprone .BugCheckerRefactoringTestHelper .TestMode .TEXT_MATCH ;
89import static com .google .errorprone .BugPattern .SeverityLevel .ERROR ;
10+ import static java .util .Comparator .comparing ;
911import static java .util .Comparator .naturalOrder ;
12+ import static java .util .stream .Collectors .joining ;
1013import static tech .picnic .errorprone .refaster .runner .Refaster .INCLUDED_RULES_PATTERN_FLAG ;
1114
1215import com .google .common .collect .ImmutableList ;
3134import com .google .errorprone .util .ASTHelpers ;
3235import com .sun .source .tree .ClassTree ;
3336import com .sun .source .tree .CompilationUnitTree ;
37+ import com .sun .source .tree .ExpressionTree ;
3438import com .sun .source .tree .LineMap ;
39+ import com .sun .source .tree .MemberSelectTree ;
40+ import com .sun .source .tree .MethodInvocationTree ;
3541import com .sun .source .tree .MethodTree ;
42+ import com .sun .source .tree .ReturnTree ;
3643import com .sun .source .tree .Tree ;
44+ import com .sun .source .tree .Tree .Kind ;
3745import com .sun .source .util .TreeScanner ;
3846import com .sun .tools .javac .tree .EndPosTable ;
3947import com .sun .tools .javac .tree .JCTree .JCCompilationUnit ;
@@ -67,6 +75,8 @@ public final class RefasterRuleCollection extends BugChecker implements Compilat
6775 private static final long serialVersionUID = 1L ;
6876 private static final String RULE_COLLECTION_FLAG = "RefasterRuleCollection:RuleCollection" ;
6977 private static final String TEST_METHOD_NAME_PREFIX = "test" ;
78+ private static final String ELIDED_TYPES_AND_STATIC_IMPORTS_METHOD_NAME =
79+ "elidedTypesAndStaticImports" ;
7080
7181 private final String ruleCollectionUnderTest ;
7282 private final ImmutableSortedSet <String > rulesUnderTest ;
@@ -131,7 +141,10 @@ public static void validate(Class<?> clazz) {
131141
132142 @ Override
133143 public Description matchCompilationUnit (CompilationUnitTree tree , VisitorState state ) {
144+ SuggestedFix .Builder fixBuilder = SuggestedFix .builder ();
145+
134146 reportIncorrectClassName (tree , state );
147+ reportUnSortedElidedTypesAndStaticImports (tree , state , fixBuilder );
135148
136149 List <Description > matches = new ArrayList <>();
137150 delegate .matchCompilationUnit (
@@ -146,7 +159,7 @@ public Description matchCompilationUnit(CompilationUnitTree tree, VisitorState s
146159 reportMissingMatches (tree , indexedMatches , state );
147160 reportUnexpectedMatches (tree , indexedMatches , state );
148161
149- return Description .NO_MATCH ;
162+ return fixBuilder . isEmpty () ? Description .NO_MATCH : describeMatch ( tree , fixBuilder . build ()) ;
150163 }
151164
152165 private void reportIncorrectClassName (CompilationUnitTree tree , VisitorState state ) {
@@ -173,6 +186,68 @@ private void reportIncorrectClassName(CompilationUnitTree tree, VisitorState sta
173186 }
174187 }
175188
189+ private void reportUnSortedElidedTypesAndStaticImports (
190+ CompilationUnitTree compilationUnit , VisitorState state , SuggestedFix .Builder fixBuilder ) {
191+ new TreeScanner <@ Nullable Void , @ Nullable Void >() {
192+ @ Override
193+ public @ Nullable Void visitMethod (MethodTree tree , @ Nullable Void unused ) {
194+ String methodName = tree .getName ().toString ();
195+ if (ELIDED_TYPES_AND_STATIC_IMPORTS_METHOD_NAME .equals (methodName )) {
196+ Optional <ReturnTree > returnTree =
197+ tree .getBody ().getStatements ().stream ()
198+ .filter (statement -> statement .getKind () == Kind .RETURN )
199+ .findFirst ()
200+ .map (ReturnTree .class ::cast );
201+
202+ returnTree
203+ .map (ReturnTree ::getExpression )
204+ .map (MethodInvocationTree .class ::cast )
205+ .ifPresent (
206+ methodInvocationTree -> {
207+ List <? extends ExpressionTree > actualArgumentsOrdering =
208+ methodInvocationTree .getArguments ();
209+
210+ ImmutableList <? extends ExpressionTree > desiredArgumentOrdering =
211+ actualArgumentsOrdering .stream ()
212+ .sorted (
213+ comparing (
214+ arg -> getArgumentName (arg , state ),
215+ String .CASE_INSENSITIVE_ORDER ))
216+ .collect (toImmutableList ());
217+
218+ if (!actualArgumentsOrdering .equals (desiredArgumentOrdering )) {
219+ String suggestion =
220+ desiredArgumentOrdering .stream ()
221+ .map (state ::getSourceForNode )
222+ .collect (
223+ joining (
224+ ", " ,
225+ String .format (
226+ "%s(" ,
227+ state .getSourceForNode (
228+ methodInvocationTree .getMethodSelect ())),
229+ ")" ));
230+
231+ fixBuilder .merge (SuggestedFix .replace (methodInvocationTree , suggestion ));
232+ }
233+ });
234+ }
235+ return super .visitMethod (tree , null );
236+ }
237+ }.scan (compilationUnit , null );
238+ }
239+
240+ private static String getArgumentName (ExpressionTree arg , VisitorState state ) {
241+ switch (arg .getKind ()) {
242+ case MEMBER_SELECT :
243+ return state .getSourceForNode (((MemberSelectTree ) arg ).getExpression ());
244+ case METHOD_INVOCATION :
245+ return state .getSourceForNode (((MethodInvocationTree ) arg ).getMethodSelect ());
246+ default :
247+ return "" ;
248+ }
249+ }
250+
176251 private static ImmutableRangeMap <Integer , String > indexRuleMatches (
177252 List <Description > matches , EndPosTable endPositions ) {
178253 ImmutableRangeMap .Builder <Integer , String > ruleMatches = ImmutableRangeMap .builder ();
@@ -293,7 +368,7 @@ private Optional<String> getRuleUnderTest(MethodTree tree, VisitorState state) {
293368 * Unless this method is `RefasterRuleCollectionTestCase#elidedTypesAndStaticImports`, it's
294369 * misnamed.
295370 */
296- if (!"elidedTypesAndStaticImports" .equals (methodName )) {
371+ if (!ELIDED_TYPES_AND_STATIC_IMPORTS_METHOD_NAME .equals (methodName )) {
297372 state .reportMatch (
298373 describeMatch (
299374 tree ,
0 commit comments