-
Notifications
You must be signed in to change notification settings - Fork 745
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add AndroidImportOrganizer to support Android import formatting
Supports both android-static-first and android-static-last as the Android Code Style does not specify how static imports should be ordered relative to non-static imports. Refactors the ImportOrganizer interface and existing implementations to provide a better abstraction of an import and the results of organizing the imports. Added tests for BasicImportOrganizer to ensure that behavior did not change. RELNOTES: Updated options so order can be selected using: -XepPatchImportOrder:android-static-first -XepPatchImportOrder:android-static-last ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=155603065
1 parent
bb3c426
commit ea720d4
Showing
11 changed files
with
701 additions
and
89 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
139 changes: 139 additions & 0 deletions
139
check_api/src/main/java/com/google/errorprone/apply/AndroidImportOrganizer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/* | ||
* Copyright 2017 Google Inc. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.google.errorprone.apply; | ||
|
||
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet; | ||
|
||
import com.google.common.collect.ImmutableList; | ||
import com.google.common.collect.ImmutableSet; | ||
import com.google.common.collect.ImmutableSortedSet; | ||
import com.google.common.collect.Ordering; | ||
import java.util.Comparator; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.TreeMap; | ||
import java.util.stream.Collectors; | ||
|
||
/** | ||
* Organizes imports based on Android Code Style | ||
* | ||
* <p>As the style rules do not specify where static imports are placed this supports first or last. | ||
* | ||
* <p>The imports are partitioned into groups in two steps, each step sub-partitions all groups from | ||
* the previous step. The steps are: | ||
* | ||
* <ol> | ||
* <li>Split into static and non-static, the static imports come before or after the non static | ||
* imports depending on the {@link StaticOrder} specified. | ||
* <li>The groups are then partitioned based on a prefix of the type, the groups are ordered by | ||
* prefix as follows: | ||
* <ol> | ||
* <li>{@code android.} | ||
* <li>{@code com.android.} | ||
* <li>A group for each root package, in alphabetical order. | ||
* <li>{@code java.} | ||
* <li>{@code javax.} | ||
* </ol> | ||
* </ol> | ||
* | ||
* <p>Each group is separate from the previous/next groups with a blank line. | ||
*/ | ||
class AndroidImportOrganizer implements ImportOrganizer { | ||
|
||
private static final String ANDROID = "android"; | ||
|
||
private static final String COM_ANDROID = "com.android"; | ||
|
||
private static final String JAVA = "java"; | ||
|
||
private static final String JAVAX = "javax"; | ||
|
||
private static final ImmutableSet<String> SPECIAL_ROOTS = | ||
ImmutableSet.of(ANDROID, COM_ANDROID, JAVA, JAVAX); | ||
|
||
private final StaticOrder order; | ||
|
||
AndroidImportOrganizer(StaticOrder order) { | ||
this.order = order; | ||
} | ||
|
||
@Override | ||
public OrganizedImports organizeImports(List<Import> imports) { | ||
OrganizedImports organized = new OrganizedImports(); | ||
|
||
// Group into static and non-static. | ||
Map<Boolean, List<Import>> partionedByStatic = | ||
imports.stream().collect(Collectors.partitioningBy(Import::isStatic)); | ||
|
||
for (Boolean key : order.groupOrder()) { | ||
organizePartition(organized, partionedByStatic.get(key)); | ||
} | ||
|
||
return organized; | ||
} | ||
|
||
private void organizePartition(OrganizedImports organized, List<Import> imports) { | ||
|
||
Map<String, ImmutableSortedSet<Import>> groupedByRoot = | ||
imports | ||
.stream() | ||
.collect( | ||
Collectors.groupingBy( | ||
// Group by root package. | ||
AndroidImportOrganizer::rootPackage, | ||
// Ensure that the results are sorted. | ||
TreeMap::new, | ||
// Each group is a set sorted by type. | ||
toImmutableSortedSet(Comparator.comparing(Import::getType)))); | ||
|
||
// Get the third party roots by removing the roots that are handled specially and sorting. | ||
Set<String> thirdParty = | ||
groupedByRoot | ||
.keySet() | ||
.stream() | ||
.filter(r -> !SPECIAL_ROOTS.contains(r)) | ||
.collect(toImmutableSortedSet(Ordering.natural())); | ||
|
||
// Construct a list of the possible roots in the correct order. | ||
List<String> roots = | ||
ImmutableList.<String>builder() | ||
.add(ANDROID) | ||
.add(COM_ANDROID) | ||
.addAll(thirdParty) | ||
.add(JAVA) | ||
.add(JAVAX) | ||
.build(); | ||
|
||
organized.addGroups(groupedByRoot, roots); | ||
} | ||
|
||
private static String rootPackage(Import anImport) { | ||
String type = anImport.getType(); | ||
|
||
if (type.startsWith("com.android.")) { | ||
return "com.android"; | ||
} | ||
|
||
int index = type.indexOf('.'); | ||
if (index == -1) { | ||
// Treat the default package as if it has an empty root. | ||
return ""; | ||
} else { | ||
return type.substring(0, index); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
43 changes: 43 additions & 0 deletions
43
check_api/src/main/java/com/google/errorprone/apply/StaticOrder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/* | ||
* Copyright 2017 Google Inc. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.google.errorprone.apply; | ||
|
||
import com.google.common.collect.ImmutableList; | ||
|
||
/** The different ways to order static imports. */ | ||
enum StaticOrder { | ||
/** | ||
* Sorts import statements so that all static imports come before all non-static imports and | ||
* otherwise sorted alphabetically. | ||
*/ | ||
STATIC_FIRST(ImmutableList.of(Boolean.TRUE, Boolean.FALSE)), | ||
|
||
/** | ||
* Sorts import statements so that all static imports come after all non-static imports and | ||
* otherwise sorted alphabetically. | ||
*/ | ||
STATIC_LAST(ImmutableList.of(Boolean.FALSE, Boolean.TRUE)); | ||
|
||
private final Iterable<Boolean> groupOrder; | ||
|
||
StaticOrder(Iterable<Boolean> groupOrder) { | ||
this.groupOrder = groupOrder; | ||
} | ||
|
||
public Iterable<Boolean> groupOrder() { | ||
return groupOrder; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
113 changes: 113 additions & 0 deletions
113
check_api/src/test/java/com/google/errorprone/apply/AndroidImportOrganizerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
/* | ||
* Copyright 2017 Google Inc. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.google.errorprone.apply; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
|
||
import com.google.common.collect.ImmutableList; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.junit.runners.JUnit4; | ||
|
||
/** Unit tests for {@link AndroidImportOrganizer} */ | ||
@RunWith(JUnit4.class) | ||
public class AndroidImportOrganizerTest { | ||
|
||
private static final List<ImportOrganizer.Import> IMPORTS = | ||
ImmutableList.of( | ||
"import com.android.blah", | ||
"import android.foo", | ||
"import java.ping", | ||
"import javax.pong", | ||
"import unknown.fred", | ||
"import unknown.barney", | ||
"import net.wilma", | ||
"import static com.android.blah.blah", | ||
"import static android.foo.bar", | ||
"import static java.ping.pong", | ||
"import static javax.pong.ping", | ||
"import static unknown.fred.flintstone", | ||
"import static net.wilma.flintstone") | ||
.stream() | ||
.map(ImportOrganizer.Import::importOf) | ||
.collect(Collectors.toList()); | ||
|
||
@Test | ||
public void testStaticFirstOrdering() { | ||
AndroidImportOrganizer organizer = new AndroidImportOrganizer(StaticOrder.STATIC_FIRST); | ||
ImportOrganizer.OrganizedImports organized = organizer.organizeImports(IMPORTS); | ||
assertEquals( | ||
"import static android.foo.bar;\n" | ||
+ "\n" | ||
+ "import static com.android.blah.blah;\n" | ||
+ "\n" | ||
+ "import static net.wilma.flintstone;\n" | ||
+ "\n" | ||
+ "import static unknown.fred.flintstone;\n" | ||
+ "\n" | ||
+ "import static java.ping.pong;\n" | ||
+ "\n" | ||
+ "import static javax.pong.ping;\n" | ||
+ "\n" | ||
+ "import android.foo;\n" | ||
+ "\n" | ||
+ "import com.android.blah;\n" | ||
+ "\n" | ||
+ "import net.wilma;\n" | ||
+ "\n" | ||
+ "import unknown.barney;\n" | ||
+ "import unknown.fred;\n" | ||
+ "\n" | ||
+ "import java.ping;\n" | ||
+ "\n" | ||
+ "import javax.pong;\n", | ||
organized.asImportBlock()); | ||
} | ||
|
||
@Test | ||
public void testStaticLastOrdering() { | ||
AndroidImportOrganizer organizer = new AndroidImportOrganizer(StaticOrder.STATIC_LAST); | ||
ImportOrganizer.OrganizedImports organized = organizer.organizeImports(IMPORTS); | ||
assertEquals( | ||
"import android.foo;\n" | ||
+ "\n" | ||
+ "import com.android.blah;\n" | ||
+ "\n" | ||
+ "import net.wilma;\n" | ||
+ "\n" | ||
+ "import unknown.barney;\n" | ||
+ "import unknown.fred;\n" | ||
+ "\n" | ||
+ "import java.ping;\n" | ||
+ "\n" | ||
+ "import javax.pong;\n" | ||
+ "\n" | ||
+ "import static android.foo.bar;\n" | ||
+ "\n" | ||
+ "import static com.android.blah.blah;\n" | ||
+ "\n" | ||
+ "import static net.wilma.flintstone;\n" | ||
+ "\n" | ||
+ "import static unknown.fred.flintstone;\n" | ||
+ "\n" | ||
+ "import static java.ping.pong;\n" | ||
+ "\n" | ||
+ "import static javax.pong.ping;\n", | ||
organized.asImportBlock()); | ||
} | ||
} |
93 changes: 93 additions & 0 deletions
93
check_api/src/test/java/com/google/errorprone/apply/BasicImportOrganizerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
/* | ||
* Copyright 2017 Google Inc. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.google.errorprone.apply; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
|
||
import com.google.common.collect.ImmutableList; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.junit.runners.JUnit4; | ||
|
||
/** Unit tests for {@link BasicImportOrganizer} */ | ||
@RunWith(JUnit4.class) | ||
public class BasicImportOrganizerTest { | ||
|
||
private static final List<ImportOrganizer.Import> IMPORTS = | ||
ImmutableList.of( | ||
"import com.android.blah", | ||
"import android.foo", | ||
"import java.ping", | ||
"import javax.pong", | ||
"import unknown.fred", | ||
"import unknown.barney", | ||
"import net.wilma", | ||
"import static com.android.blah.blah", | ||
"import static android.foo.bar", | ||
"import static java.ping.pong", | ||
"import static javax.pong.ping", | ||
"import static unknown.fred.flintstone", | ||
"import static net.wilma.flintstone") | ||
.stream() | ||
.map(ImportOrganizer.Import::importOf) | ||
.collect(Collectors.toList()); | ||
|
||
@Test | ||
public void testStaticFirstOrdering() { | ||
BasicImportOrganizer organizer = new BasicImportOrganizer(StaticOrder.STATIC_FIRST); | ||
ImportOrganizer.OrganizedImports organized = organizer.organizeImports(IMPORTS); | ||
assertEquals( | ||
"import static android.foo.bar;\n" | ||
+ "import static com.android.blah.blah;\n" | ||
+ "import static java.ping.pong;\n" | ||
+ "import static javax.pong.ping;\n" | ||
+ "import static net.wilma.flintstone;\n" | ||
+ "import static unknown.fred.flintstone;\n" | ||
+ "\n" | ||
+ "import android.foo;\n" | ||
+ "import com.android.blah;\n" | ||
+ "import java.ping;\n" | ||
+ "import javax.pong;\n" | ||
+ "import net.wilma;\n" | ||
+ "import unknown.barney;\n" | ||
+ "import unknown.fred;\n", | ||
organized.asImportBlock()); | ||
} | ||
|
||
@Test | ||
public void testStaticLastOrdering() { | ||
BasicImportOrganizer organizer = new BasicImportOrganizer(StaticOrder.STATIC_LAST); | ||
ImportOrganizer.OrganizedImports organized = organizer.organizeImports(IMPORTS); | ||
assertEquals( | ||
"import android.foo;\n" | ||
+ "import com.android.blah;\n" | ||
+ "import java.ping;\n" | ||
+ "import javax.pong;\n" | ||
+ "import net.wilma;\n" | ||
+ "import unknown.barney;\n" | ||
+ "import unknown.fred;\n" | ||
+ "\n" | ||
+ "import static android.foo.bar;\n" | ||
+ "import static com.android.blah.blah;\n" | ||
+ "import static java.ping.pong;\n" | ||
+ "import static javax.pong.ping;\n" | ||
+ "import static net.wilma.flintstone;\n" | ||
+ "import static unknown.fred.flintstone;\n", | ||
organized.asImportBlock()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
check_api/src/test/java/com/google/errorprone/apply/OrganizedImportsTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/* | ||
* Copyright 2017 Google Inc. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.google.errorprone.apply; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
|
||
import com.google.common.collect.ImmutableSortedSet; | ||
import com.google.errorprone.apply.ImportOrganizer.Import; | ||
import java.util.Comparator; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.TreeMap; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.junit.runners.JUnit4; | ||
|
||
/** */ | ||
@RunWith(JUnit4.class) | ||
public class OrganizedImportsTest { | ||
|
||
private static final Comparator<Import> IMPORT_COMPARATOR = | ||
Comparator.comparing(Import::isStatic).thenComparing(Import::getType); | ||
|
||
@Test | ||
public void emptyList() { | ||
ImportOrganizer.OrganizedImports organizedImports = new ImportOrganizer.OrganizedImports(); | ||
assertEquals("", organizedImports.asImportBlock()); | ||
} | ||
|
||
private ImmutableSortedSet<Import> buildSortedImportSet(Import... element) { | ||
return ImmutableSortedSet.orderedBy(IMPORT_COMPARATOR).add(element).build(); | ||
} | ||
|
||
@Test | ||
public void singleGroup() { | ||
Map<String, Set<Import>> groups = new TreeMap<>(); | ||
groups.put("first", buildSortedImportSet(Import.importOf("import first"))); | ||
ImportOrganizer.OrganizedImports organizedImports = | ||
new ImportOrganizer.OrganizedImports().addGroups(groups, groups.keySet()); | ||
assertEquals("import first;\n", organizedImports.asImportBlock()); | ||
} | ||
|
||
@Test | ||
public void multipleGroups() { | ||
Map<String, Set<Import>> groups = new TreeMap<>(); | ||
groups.put("first", buildSortedImportSet(Import.importOf("import first"))); | ||
groups.put("second", buildSortedImportSet(Import.importOf("import second"))); | ||
ImportOrganizer.OrganizedImports organizedImports = | ||
new ImportOrganizer.OrganizedImports().addGroups(groups, groups.keySet()); | ||
assertEquals("import first;\n\nimport second;\n", organizedImports.asImportBlock()); | ||
} | ||
|
||
@Test | ||
public void importCount() { | ||
Map<String, Set<Import>> groups = new TreeMap<>(); | ||
groups.put("first", buildSortedImportSet(Import.importOf("import first"))); | ||
groups.put("second", buildSortedImportSet(Import.importOf("import second"))); | ||
ImportOrganizer.OrganizedImports organizedImports = | ||
new ImportOrganizer.OrganizedImports().addGroups(groups, groups.keySet()); | ||
assertEquals(2, organizedImports.getImportCount()); | ||
} | ||
} |