Skip to content

Commit 2e7add8

Browse files
[clang-format] Add a option for the position of Java static import
Some Java style guides and IDEs group Java static imports after non-static imports. This patch allows clang-format to control the location of static imports. Patch by: @bc-lee Reviewed By: MyDeveloperDay, JakeMerdichAMD Differential Revision: https://reviews.llvm.org/D87201
1 parent a9be2b5 commit 2e7add8

File tree

5 files changed

+144
-12
lines changed

5 files changed

+144
-12
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1964,10 +1964,12 @@ the configuration (without a prefix: ``Auto``).
19641964
**JavaImportGroups** (``std::vector<std::string>``)
19651965
A vector of prefixes ordered by the desired groups for Java imports.
19661966

1967-
Each group is separated by a newline. Static imports will also follow the
1968-
same grouping convention above all non-static imports. One group's prefix
1969-
can be a subset of another - the longest prefix is always matched. Within
1970-
a group, the imports are ordered lexicographically.
1967+
One group's prefix can be a subset of another - the longest prefix is
1968+
always matched. Within a group, the imports are ordered lexicographically.
1969+
Static imports are grouped separately and follow the same group rules.
1970+
By default, static imports are placed before non-static imports,
1971+
but this behavior is changed by another option,
1972+
``SortJavaStaticImport``.
19711973

19721974
In the .clang-format configuration file, this can be configured like
19731975
in the following yaml example. This will result in imports being
@@ -2393,6 +2395,33 @@ the configuration (without a prefix: ``Auto``).
23932395
#include "b.h" vs. #include "a.h"
23942396
#include "a.h" #include "b.h"
23952397

2398+
**SortJavaStaticImport** (``SortJavaStaticImportOptions``)
2399+
When sorting Java imports, by default static imports are placed before
2400+
non-static imports. If ``JavaStaticImportAfterImport`` is ``After``,
2401+
static imports are placed after non-static imports.
2402+
2403+
Possible values:
2404+
2405+
* ``SJSIO_Before`` (in configuration: ``Before``)
2406+
Static imports are placed before non-static imports.
2407+
2408+
.. code-block:: java
2409+
2410+
import static org.example.function1;
2411+
2412+
import org.example.ClassA;
2413+
2414+
* ``SJSIO_After`` (in configuration: ``After``)
2415+
Static imports are placed after non-static imports.
2416+
2417+
.. code-block:: java
2418+
2419+
import org.example.ClassA;
2420+
2421+
import static org.example.function1;
2422+
2423+
2424+
23962425
**SortUsingDeclarations** (``bool``)
23972426
If ``true``, clang-format will sort using declarations.
23982427

clang/include/clang/Format/Format.h

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,10 +1618,12 @@ struct FormatStyle {
16181618

16191619
/// A vector of prefixes ordered by the desired groups for Java imports.
16201620
///
1621-
/// Each group is separated by a newline. Static imports will also follow the
1622-
/// same grouping convention above all non-static imports. One group's prefix
1623-
/// can be a subset of another - the longest prefix is always matched. Within
1624-
/// a group, the imports are ordered lexicographically.
1621+
/// One group's prefix can be a subset of another - the longest prefix is
1622+
/// always matched. Within a group, the imports are ordered lexicographically.
1623+
/// Static imports are grouped separately and follow the same group rules.
1624+
/// By default, static imports are placed before non-static imports,
1625+
/// but this behavior is changed by another option,
1626+
/// ``SortJavaStaticImport``.
16251627
///
16261628
/// In the .clang-format configuration file, this can be configured like
16271629
/// in the following yaml example. This will result in imports being
@@ -2016,6 +2018,29 @@ struct FormatStyle {
20162018
/// \endcode
20172019
bool SortIncludes;
20182020

2021+
/// Position for Java Static imports.
2022+
enum SortJavaStaticImportOptions {
2023+
/// Static imports are placed before non-static imports.
2024+
/// \code{.java}
2025+
/// import static org.example.function1;
2026+
///
2027+
/// import org.example.ClassA;
2028+
/// \endcode
2029+
SJSIO_Before,
2030+
/// Static imports are placed after non-static imports.
2031+
/// \code{.java}
2032+
/// import org.example.ClassA;
2033+
///
2034+
/// import static org.example.function1;
2035+
/// \endcode
2036+
SJSIO_After,
2037+
};
2038+
2039+
/// When sorting Java imports, by default static imports are placed before
2040+
/// non-static imports. If ``JavaStaticImportAfterImport`` is ``After``,
2041+
/// static imports are placed after non-static imports.
2042+
SortJavaStaticImportOptions SortJavaStaticImport;
2043+
20192044
/// If ``true``, clang-format will sort using declarations.
20202045
///
20212046
/// The order of using declarations is defined as follows:
@@ -2435,6 +2460,7 @@ struct FormatStyle {
24352460
R.PenaltyBreakTemplateDeclaration &&
24362461
PointerAlignment == R.PointerAlignment &&
24372462
RawStringFormats == R.RawStringFormats &&
2463+
SortJavaStaticImport == R.SortJavaStaticImport &&
24382464
SpaceAfterCStyleCast == R.SpaceAfterCStyleCast &&
24392465
SpaceAfterLogicalNot == R.SpaceAfterLogicalNot &&
24402466
SpaceAfterTemplateKeyword == R.SpaceAfterTemplateKeyword &&

clang/lib/Format/Format.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,15 @@ struct ScalarEnumerationTraits<FormatStyle::BitFieldColonSpacingStyle> {
377377
}
378378
};
379379

380+
template <>
381+
struct ScalarEnumerationTraits<FormatStyle::SortJavaStaticImportOptions> {
382+
static void enumeration(IO &IO,
383+
FormatStyle::SortJavaStaticImportOptions &Value) {
384+
IO.enumCase(Value, "Before", FormatStyle::SJSIO_Before);
385+
IO.enumCase(Value, "After", FormatStyle::SJSIO_After);
386+
}
387+
};
388+
380389
template <> struct MappingTraits<FormatStyle> {
381390
static void mapping(IO &IO, FormatStyle &Style) {
382391
// When reading, read the language first, we need it for getPredefinedStyle.
@@ -574,6 +583,7 @@ template <> struct MappingTraits<FormatStyle> {
574583
IO.mapOptional("RawStringFormats", Style.RawStringFormats);
575584
IO.mapOptional("ReflowComments", Style.ReflowComments);
576585
IO.mapOptional("SortIncludes", Style.SortIncludes);
586+
IO.mapOptional("SortJavaStaticImport", Style.SortJavaStaticImport);
577587
IO.mapOptional("SortUsingDeclarations", Style.SortUsingDeclarations);
578588
IO.mapOptional("SpaceAfterCStyleCast", Style.SpaceAfterCStyleCast);
579589
IO.mapOptional("SpaceAfterLogicalNot", Style.SpaceAfterLogicalNot);
@@ -947,6 +957,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
947957

948958
LLVMStyle.DisableFormat = false;
949959
LLVMStyle.SortIncludes = true;
960+
LLVMStyle.SortJavaStaticImport = FormatStyle::SJSIO_Before;
950961
LLVMStyle.SortUsingDeclarations = true;
951962
LLVMStyle.StatementMacros.push_back("Q_UNUSED");
952963
LLVMStyle.StatementMacros.push_back("QT_REQUIRE_VERSION");
@@ -2312,12 +2323,16 @@ static void sortJavaImports(const FormatStyle &Style,
23122323
JavaImportGroups.push_back(
23132324
findJavaImportGroup(Style, Imports[i].Identifier));
23142325
}
2326+
bool StaticImportAfterNormalImport =
2327+
Style.SortJavaStaticImport == FormatStyle::SJSIO_After;
23152328
llvm::sort(Indices, [&](unsigned LHSI, unsigned RHSI) {
23162329
// Negating IsStatic to push static imports above non-static imports.
2317-
return std::make_tuple(!Imports[LHSI].IsStatic, JavaImportGroups[LHSI],
2318-
Imports[LHSI].Identifier) <
2319-
std::make_tuple(!Imports[RHSI].IsStatic, JavaImportGroups[RHSI],
2320-
Imports[RHSI].Identifier);
2330+
return std::make_tuple(!Imports[LHSI].IsStatic ^
2331+
StaticImportAfterNormalImport,
2332+
JavaImportGroups[LHSI], Imports[LHSI].Identifier) <
2333+
std::make_tuple(!Imports[RHSI].IsStatic ^
2334+
StaticImportAfterNormalImport,
2335+
JavaImportGroups[RHSI], Imports[RHSI].Identifier);
23212336
});
23222337

23232338
// Deduplicate imports.

clang/unittests/Format/FormatTest.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14328,6 +14328,12 @@ TEST_F(FormatTest, ParsesConfiguration) {
1432814328
CHECK_PARSE("BitFieldColonSpacing: After", BitFieldColonSpacing,
1432914329
FormatStyle::BFCS_After);
1433014330

14331+
Style.SortJavaStaticImport = FormatStyle::SJSIO_Before;
14332+
CHECK_PARSE("SortJavaStaticImport: After", SortJavaStaticImport,
14333+
FormatStyle::SJSIO_After);
14334+
CHECK_PARSE("SortJavaStaticImport: Before", SortJavaStaticImport,
14335+
FormatStyle::SJSIO_Before);
14336+
1433114337
// FIXME: This is required because parsing a configuration simply overwrites
1433214338
// the first N elements of the list instead of resetting it.
1433314339
Style.ForEachMacros.clear();

clang/unittests/Format/SortImportsTestJava.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,62 @@ TEST_F(SortImportsTestJava, FormatPariallyOnShouldNotReorder) {
250250
"import org.c;\n"));
251251
}
252252

253+
TEST_F(SortImportsTestJava, SortJavaStaticImport) {
254+
FmtStyle.SortJavaStaticImport = FormatStyle::SJSIO_Before;
255+
EXPECT_EQ("import static com.test.a;\n"
256+
"\n"
257+
"import static org.a;\n"
258+
"\n"
259+
"import static com.a;\n"
260+
"\n"
261+
"import com.test.b;\n"
262+
"\n"
263+
"import org.b;\n"
264+
"\n"
265+
"import com.b;\n",
266+
sort("import static com.test.a;\n"
267+
"import static org.a;\n"
268+
"import static com.a;\n"
269+
"import com.test.b;\n"
270+
"import org.b;\n"
271+
"import com.b;\n"));
272+
273+
FmtStyle.SortJavaStaticImport = FormatStyle::SJSIO_After;
274+
EXPECT_EQ("import com.test.b;\n"
275+
"import com.test.c;\n"
276+
"\n"
277+
"import org.b;\n"
278+
"\n"
279+
"import com.b;\n"
280+
"\n"
281+
"import static com.test.a;\n"
282+
"\n"
283+
"import static org.a;\n"
284+
"\n"
285+
"import static com.a;\n",
286+
sort("import static com.test.a;\n"
287+
"import static org.a;\n"
288+
"import static com.a;\n"
289+
"import com.test.b;\n"
290+
"import org.b;\n"
291+
"import com.b;\n"
292+
"import com.test.c;\n"));
293+
}
294+
295+
TEST_F(SortImportsTestJava, SortJavaStaticImportAsGroup) {
296+
FmtStyle.SortJavaStaticImport = FormatStyle::SJSIO_After;
297+
298+
EXPECT_EQ("import com.test.a;\n"
299+
"import com.test.b;\n"
300+
"\n"
301+
"import static org.a;\n"
302+
"import static org.b;\n",
303+
sort("import com.test.a;\n"
304+
"import static org.a;\n"
305+
"import com.test.b;\n"
306+
"import static org.b;\n"));
307+
}
308+
253309
TEST_F(SortImportsTestJava, DeduplicateImports) {
254310
EXPECT_EQ("import org.a;\n", sort("import org.a;\n"
255311
"import org.a;\n"));

0 commit comments

Comments
 (0)