diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -4505,22 +4505,54 @@ .. _SortUsingDeclarations: -**SortUsingDeclarations** (``Boolean``) :versionbadge:`clang-format 5` :ref:`¶ ` - If ``true``, clang-format will sort using declarations. +**SortUsingDeclarations** (``SortUsingDeclarationsOptions``) :versionbadge:`clang-format 5` :ref:`¶ ` + Controls if and how clang-format will sort using declarations. - The order of using declarations is defined as follows: - Split the strings by "::" and discard any initial empty strings. The last - element of each list is a non-namespace name; all others are namespace - names. Sort the lists of names lexicographically, where the sort order of - individual names is that all non-namespace names come before all namespace - names, and within those groups, names are in case-insensitive - lexicographic order. + Possible values: + + * ``SUD_Never`` (in configuration: ``Never``) + Using declarations are never sorted. + + .. code-block:: c++ + + using std::chrono::duration_cast; + using std::move; + using boost::regex; + using boost::regex_constants::icase; + using std::string; + + * ``SUD_Lexicographic`` (in configuration: ``Lexicographic``) + Using declarations are sorted in the order defined as follows: + Split the strings by "::" and discard any initial empty strings. Sort + the lists of names lexicographically, and within those groups, names are + in case-insensitive lexicographic order. + + .. code-block:: c++ + + using boost::regex; + using boost::regex_constants::icase; + using std::chrono::duration_cast; + using std::move; + using std::string; + + * ``SUD_LexicographicNumeric`` (in configuration: ``LexicographicNumeric``) + Using declarations are sorted in the order defined as follows: + Split the strings by "::" and discard any initial empty strings. The + last element of each list is a non-namespace name; all others are + namespace names. Sort the lists of names lexicographically, where the + sort order of individual names is that all non-namespace names come + before all namespace names, and within those groups, names are in + case-insensitive lexicographic order. + + .. code-block:: c++ + + using boost::regex; + using boost::regex_constants::icase; + using std::move; + using std::string; + using std::chrono::duration_cast; - .. code-block:: c++ - false: true: - using std::cout; vs. using std::cin; - using std::cin; using std::cout; .. _SpaceAfterCStyleCast: diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -3510,22 +3510,49 @@ /// \version 12 SortJavaStaticImportOptions SortJavaStaticImport; - /// If ``true``, clang-format will sort using declarations. - /// - /// The order of using declarations is defined as follows: - /// Split the strings by "::" and discard any initial empty strings. The last - /// element of each list is a non-namespace name; all others are namespace - /// names. Sort the lists of names lexicographically, where the sort order of - /// individual names is that all non-namespace names come before all namespace - /// names, and within those groups, names are in case-insensitive - /// lexicographic order. - /// \code - /// false: true: - /// using std::cout; vs. using std::cin; - /// using std::cin; using std::cout; - /// \endcode + /// Using declaration sorting options. + enum SortUsingDeclarationsOptions : int8_t { + /// Using declarations are never sorted. + /// \code + /// using std::chrono::duration_cast; + /// using std::move; + /// using boost::regex; + /// using boost::regex_constants::icase; + /// using std::string; + /// \endcode + SUD_Never, + /// Using declarations are sorted in the order defined as follows: + /// Split the strings by "::" and discard any initial empty strings. Sort + /// the lists of names lexicographically, and within those groups, names are + /// in case-insensitive lexicographic order. + /// \code + /// using boost::regex; + /// using boost::regex_constants::icase; + /// using std::chrono::duration_cast; + /// using std::move; + /// using std::string; + /// \endcode + SUD_Lexicographic, + /// Using declarations are sorted in the order defined as follows: + /// Split the strings by "::" and discard any initial empty strings. The + /// last element of each list is a non-namespace name; all others are + /// namespace names. Sort the lists of names lexicographically, where the + /// sort order of individual names is that all non-namespace names come + /// before all namespace names, and within those groups, names are in + /// case-insensitive lexicographic order. + /// \code + /// using boost::regex; + /// using boost::regex_constants::icase; + /// using std::move; + /// using std::string; + /// using std::chrono::duration_cast; + /// \endcode + SUD_LexicographicNumeric, + }; + + /// Controls if and how clang-format will sort using declarations. /// \version 5 - bool SortUsingDeclarations; + SortUsingDeclarationsOptions SortUsingDeclarations; /// If ``true``, a space is inserted after C style casts. /// \code diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -606,6 +606,21 @@ } }; +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, + FormatStyle::SortUsingDeclarationsOptions &Value) { + IO.enumCase(Value, "Never", FormatStyle::SUD_Never); + IO.enumCase(Value, "Lexicographic", FormatStyle::SUD_Lexicographic); + IO.enumCase(Value, "LexicographicNumeric", + FormatStyle::SUD_LexicographicNumeric); + + // For backward compatibility. + IO.enumCase(Value, "false", FormatStyle::SUD_Never); + IO.enumCase(Value, "true", FormatStyle::SUD_LexicographicNumeric); + } +}; + template <> struct ScalarEnumerationTraits { static void @@ -1404,7 +1419,7 @@ LLVMStyle.ShortNamespaceLines = 1; LLVMStyle.SortIncludes = FormatStyle::SI_CaseSensitive; LLVMStyle.SortJavaStaticImport = FormatStyle::SJSIO_Before; - LLVMStyle.SortUsingDeclarations = true; + LLVMStyle.SortUsingDeclarations = FormatStyle::SUD_LexicographicNumeric; LLVMStyle.SpaceAfterCStyleCast = false; LLVMStyle.SpaceAfterLogicalNot = false; LLVMStyle.SpaceAfterTemplateKeyword = true; @@ -1772,7 +1787,7 @@ FormatStyle NoStyle = getLLVMStyle(); NoStyle.DisableFormat = true; NoStyle.SortIncludes = FormatStyle::SI_Never; - NoStyle.SortUsingDeclarations = false; + NoStyle.SortUsingDeclarations = FormatStyle::SUD_Never; return NoStyle; } @@ -3480,7 +3495,7 @@ }); } - if (Style.SortUsingDeclarations) { + if (Style.SortUsingDeclarations != FormatStyle::SUD_Never) { Passes.emplace_back([&](const Environment &Env) { return UsingDeclarationsSorter(Env, Expanded).process(); }); diff --git a/clang/lib/Format/UsingDeclarationsSorter.cpp b/clang/lib/Format/UsingDeclarationsSorter.cpp --- a/clang/lib/Format/UsingDeclarationsSorter.cpp +++ b/clang/lib/Format/UsingDeclarationsSorter.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "UsingDeclarationsSorter.h" +#include "clang/Format/Format.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Regex.h" @@ -32,7 +33,7 @@ // individual names is that all non-namespace names come before all namespace // names, and within those groups, names are in case-insensitive lexicographic // order. -int compareLabels(StringRef A, StringRef B) { +int compareLabelsLexicographicNumeric(StringRef A, StringRef B) { SmallVector NamesA; A.split(NamesA, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false); SmallVector NamesB; @@ -64,16 +65,38 @@ return 0; } +int compareLabelsLexicographic(StringRef A, StringRef B) { + SmallVector NamesA; + A.split(NamesA, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false); + SmallVector NamesB; + B.split(NamesB, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false); + size_t SizeA = NamesA.size(); + size_t SizeB = NamesB.size(); + for (size_t I = 0, E = std::min(SizeA, SizeB); I < E; ++I) { + // Two namespaces names within a group compare case-insensitively. + int C = NamesA[I].compare_insensitive(NamesB[I]); + if (C != 0) + return C; + } + if (SizeA < SizeB) + return -1; + return SizeA == SizeB ? 0 : 1; +} + +int compareLabels( + StringRef A, StringRef B, + FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations) { + if (SortUsingDeclarations == FormatStyle::SUD_LexicographicNumeric) + return compareLabelsLexicographicNumeric(A, B); + return compareLabelsLexicographic(A, B); +} + struct UsingDeclaration { const AnnotatedLine *Line; std::string Label; UsingDeclaration(const AnnotatedLine *Line, const std::string &Label) : Line(Line), Label(Label) {} - - bool operator<(const UsingDeclaration &Other) const { - return compareLabels(Label, Other.Label) < 0; - } }; /// Computes the label of a using declaration starting at tthe using token @@ -113,7 +136,8 @@ void endUsingDeclarationBlock( SmallVectorImpl *UsingDeclarations, - const SourceManager &SourceMgr, tooling::Replacements *Fixes) { + const SourceManager &SourceMgr, tooling::Replacements *Fixes, + FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations) { bool BlockAffected = false; for (const UsingDeclaration &Declaration : *UsingDeclarations) { if (Declaration.Line->Affected) { @@ -127,7 +151,11 @@ } SmallVector SortedUsingDeclarations( UsingDeclarations->begin(), UsingDeclarations->end()); - llvm::stable_sort(SortedUsingDeclarations); + auto Comp = [SortUsingDeclarations](const UsingDeclaration &Lhs, + const UsingDeclaration &Rhs) -> bool { + return compareLabels(Lhs.Label, Rhs.Label, SortUsingDeclarations) < 0; + }; + llvm::stable_sort(SortedUsingDeclarations, Comp); SortedUsingDeclarations.erase( std::unique(SortedUsingDeclarations.begin(), SortedUsingDeclarations.end(), @@ -192,21 +220,26 @@ const auto *FirstTok = Line->First; if (Line->InPPDirective || !Line->startsWith(tok::kw_using) || FirstTok->Finalized) { - endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); + endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes, + Style.SortUsingDeclarations); continue; } - if (FirstTok->NewlinesBefore > 1) - endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); + if (FirstTok->NewlinesBefore > 1) { + endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes, + Style.SortUsingDeclarations); + } const auto *UsingTok = FirstTok->is(tok::comment) ? FirstTok->getNextNonComment() : FirstTok; std::string Label = computeUsingDeclarationLabel(UsingTok); if (Label.empty()) { - endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); + endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes, + Style.SortUsingDeclarations); continue; } UsingDeclarations.push_back(UsingDeclaration(Line, Label)); } - endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); + endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes, + Style.SortUsingDeclarations); return {Fixes, 0}; } diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -174,7 +174,6 @@ CHECK_PARSE_BOOL(ReflowComments); CHECK_PARSE_BOOL(RemoveBracesLLVM); CHECK_PARSE_BOOL(RemoveSemicolon); - CHECK_PARSE_BOOL(SortUsingDeclarations); CHECK_PARSE_BOOL(SpacesInParentheses); CHECK_PARSE_BOOL(SpacesInSquareBrackets); CHECK_PARSE_BOOL(SpacesInConditionalStatement); @@ -714,6 +713,19 @@ CHECK_PARSE("SortJavaStaticImport: Before", SortJavaStaticImport, FormatStyle::SJSIO_Before); + Style.SortUsingDeclarations = FormatStyle::SUD_LexicographicNumeric; + CHECK_PARSE("SortUsingDeclarations: Never", SortUsingDeclarations, + FormatStyle::SUD_Never); + CHECK_PARSE("SortUsingDeclarations: Lexicographic", SortUsingDeclarations, + FormatStyle::SUD_Lexicographic); + CHECK_PARSE("SortUsingDeclarations: LexicographicNumeric", + SortUsingDeclarations, FormatStyle::SUD_LexicographicNumeric); + // For backward compatibility: + CHECK_PARSE("SortUsingDeclarations: false", SortUsingDeclarations, + FormatStyle::SUD_Never); + CHECK_PARSE("SortUsingDeclarations: true", SortUsingDeclarations, + FormatStyle::SUD_LexicographicNumeric); + // FIXME: This is required because parsing a configuration simply overwrites // the first N elements of the list instead of resetting it. Style.ForEachMacros.clear(); diff --git a/clang/unittests/Format/UsingDeclarationsSorterTest.cpp b/clang/unittests/Format/UsingDeclarationsSorterTest.cpp --- a/clang/unittests/Format/UsingDeclarationsSorterTest.cpp +++ b/clang/unittests/Format/UsingDeclarationsSorterTest.cpp @@ -41,88 +41,162 @@ }; TEST_F(UsingDeclarationsSorterTest, SwapsTwoConsecutiveUsingDeclarations) { + FormatStyle Style = getLLVMStyle(); + EXPECT_EQ(FormatStyle::SUD_LexicographicNumeric, Style.SortUsingDeclarations); EXPECT_EQ("using a;\n" "using b;", sortUsingDeclarations("using a;\n" - "using b;")); + "using b;", + Style)); EXPECT_EQ("using a;\n" "using aa;", sortUsingDeclarations("using aa;\n" - "using a;")); + "using a;", + Style)); EXPECT_EQ("using a;\n" "using ::a;", sortUsingDeclarations("using a;\n" - "using ::a;")); + "using ::a;", + Style)); EXPECT_EQ("using a::bcd;\n" "using a::cd;", sortUsingDeclarations("using a::cd;\n" - "using a::bcd;")); + "using a::bcd;", + Style)); EXPECT_EQ("using a;\n" "using a::a;", sortUsingDeclarations("using a::a;\n" - "using a;")); + "using a;", + Style)); EXPECT_EQ("using a::ba::aa;\n" "using a::bb::ccc;", sortUsingDeclarations("using a::bb::ccc;\n" - "using a::ba::aa;")); + "using a::ba::aa;", + Style)); EXPECT_EQ("using a;\n" "using typename a;", sortUsingDeclarations("using typename a;\n" - "using a;")); + "using a;", + Style)); EXPECT_EQ("using typename z;\n" "using typenamea;", sortUsingDeclarations("using typenamea;\n" - "using typename z;")); + "using typename z;", + Style)); EXPECT_EQ("using a, b;\n" "using aa;", sortUsingDeclarations("using aa;\n" - "using a, b;")); + "using a, b;", + Style)); + + Style.SortUsingDeclarations = FormatStyle::SUD_Lexicographic; + EXPECT_EQ("using a;\n" + "using b;", + sortUsingDeclarations("using a;\n" + "using b;", + Style)); + EXPECT_EQ("using a;\n" + "using aa;", + sortUsingDeclarations("using aa;\n" + "using a;", + Style)); + EXPECT_EQ("using a;\n" + "using ::a;", + sortUsingDeclarations("using a;\n" + "using ::a;", + Style)); + + EXPECT_EQ("using a::bcd;\n" + "using a::cd;", + sortUsingDeclarations("using a::cd;\n" + "using a::bcd;", + Style)); + + EXPECT_EQ("using a;\n" + "using a::a;", + sortUsingDeclarations("using a::a;\n" + "using a;", + Style)); + + EXPECT_EQ("using a::ba::aa;\n" + "using a::bb::ccc;", + sortUsingDeclarations("using a::bb::ccc;\n" + "using a::ba::aa;", + Style)); + + EXPECT_EQ("using a;\n" + "using typename a;", + sortUsingDeclarations("using typename a;\n" + "using a;", + Style)); + + EXPECT_EQ("using typename z;\n" + "using typenamea;", + sortUsingDeclarations("using typenamea;\n" + "using typename z;", + Style)); + + EXPECT_EQ("using a, b;\n" + "using aa;", + sortUsingDeclarations("using aa;\n" + "using a, b;", + Style)); } TEST_F(UsingDeclarationsSorterTest, UsingDeclarationOrder) { + FormatStyle Style = getLLVMStyle(); + EXPECT_EQ(FormatStyle::SUD_LexicographicNumeric, Style.SortUsingDeclarations); EXPECT_EQ("using A;\n" "using a;", sortUsingDeclarations("using A;\n" - "using a;")); + "using a;", + Style)); EXPECT_EQ("using a;\n" "using A;", sortUsingDeclarations("using a;\n" - "using A;")); + "using A;", + Style)); EXPECT_EQ("using a;\n" "using B;", sortUsingDeclarations("using B;\n" - "using a;")); + "using a;", + Style)); // Ignores leading '::'. EXPECT_EQ("using ::a;\n" "using A;", sortUsingDeclarations("using ::a;\n" - "using A;")); + "using A;", + Style)); EXPECT_EQ("using ::A;\n" "using a;", sortUsingDeclarations("using ::A;\n" - "using a;")); + "using a;", + Style)); // Sorts '_' before 'a' and 'A'. EXPECT_EQ("using _;\n" "using A;", sortUsingDeclarations("using A;\n" - "using _;")); + "using _;", + Style)); EXPECT_EQ("using _;\n" "using a;", sortUsingDeclarations("using a;\n" - "using _;")); + "using _;", + Style)); EXPECT_EQ("using a::_;\n" "using a::a;", sortUsingDeclarations("using a::a;\n" - "using a::_;")); + "using a::_;", + Style)); // Sorts non-namespace names before namespace names at the same level. EXPECT_EQ("using ::testing::_;\n" @@ -136,10 +210,75 @@ "using ::testing::kMax;\n" "using ::testing::_;\n" "using ::testing::apple::Honeycrisp;\n" - "using ::testing::zebra::Stripes;")); + "using ::testing::zebra::Stripes;", + Style)); + + Style.SortUsingDeclarations = FormatStyle::SUD_Lexicographic; + EXPECT_EQ("using A;\n" + "using a;", + sortUsingDeclarations("using A;\n" + "using a;", + Style)); + EXPECT_EQ("using a;\n" + "using A;", + sortUsingDeclarations("using a;\n" + "using A;", + Style)); + EXPECT_EQ("using a;\n" + "using B;", + sortUsingDeclarations("using B;\n" + "using a;", + Style)); + + // Ignores leading '::'. + EXPECT_EQ("using ::a;\n" + "using A;", + sortUsingDeclarations("using ::a;\n" + "using A;", + Style)); + + EXPECT_EQ("using ::A;\n" + "using a;", + sortUsingDeclarations("using ::A;\n" + "using a;", + Style)); + + // Sorts '_' before 'a' and 'A'. + EXPECT_EQ("using _;\n" + "using A;", + sortUsingDeclarations("using A;\n" + "using _;", + Style)); + EXPECT_EQ("using _;\n" + "using a;", + sortUsingDeclarations("using a;\n" + "using _;", + Style)); + EXPECT_EQ("using a::_;\n" + "using a::a;", + sortUsingDeclarations("using a::a;\n" + "using a::_;", + Style)); + + // Sorts non-namespace names before namespace names at the same level. + EXPECT_EQ("using ::testing::_;\n" + "using ::testing::Aardvark;\n" + "using ::testing::apple::Honeycrisp;\n" + "using ::testing::kMax;\n" + "using ::testing::Xylophone;\n" + "using ::testing::zebra::Stripes;", + sortUsingDeclarations("using ::testing::Aardvark;\n" + "using ::testing::Xylophone;\n" + "using ::testing::kMax;\n" + "using ::testing::_;\n" + "using ::testing::apple::Honeycrisp;\n" + "using ::testing::zebra::Stripes;", + Style)); } TEST_F(UsingDeclarationsSorterTest, SortsStably) { + FormatStyle Style = getLLVMStyle(); + EXPECT_EQ(FormatStyle::SUD_LexicographicNumeric, Style.SortUsingDeclarations); EXPECT_EQ("using a;\n" "using A;\n" "using a;\n" @@ -169,10 +308,46 @@ "using B;\n" "using b;\n" "using A;\n" - "using a;")); + "using a;", + Style)); + + Style.SortUsingDeclarations = FormatStyle::SUD_Lexicographic; + EXPECT_EQ("using a;\n" + "using A;\n" + "using a;\n" + "using A;\n" + "using a;\n" + "using A;\n" + "using a;\n" + "using B;\n" + "using b;\n" + "using B;\n" + "using b;\n" + "using B;\n" + "using b;", + sortUsingDeclarations("using a;\n" + "using B;\n" + "using a;\n" + "using b;\n" + "using A;\n" + "using a;\n" + "using b;\n" + "using B;\n" + "using b;\n" + "using A;\n" + "using a;\n" + "using b;\n" + "using b;\n" + "using B;\n" + "using b;\n" + "using A;\n" + "using a;", + Style)); } TEST_F(UsingDeclarationsSorterTest, SortsMultipleTopLevelDeclarations) { + FormatStyle Style = getLLVMStyle(); + EXPECT_EQ(FormatStyle::SUD_LexicographicNumeric, Style.SortUsingDeclarations); EXPECT_EQ("using a;\n" "using b;\n" "using c;\n" @@ -182,7 +357,8 @@ "using b;\n" "using e;\n" "using a;\n" - "using c;")); + "using c;", + Style)); EXPECT_EQ("#include \n" "using std::cin;\n" @@ -193,10 +369,51 @@ "using std::cout;\n" "using ::std::endl;\n" "using std::cin;\n" - "int main();")); + "int main();", + Style)); + + Style.SortUsingDeclarations = FormatStyle::SUD_Lexicographic; + EXPECT_EQ("using a;\n" + "using b;\n" + "using c;\n" + "using d;\n" + "using e;", + sortUsingDeclarations("using d;\n" + "using b;\n" + "using e;\n" + "using a;\n" + "using c;", + Style)); + + EXPECT_EQ("#include \n" + "using std::cin;\n" + "using std::cout;\n" + "using ::std::endl;\n" + "int main();", + sortUsingDeclarations("#include \n" + "using std::cout;\n" + "using ::std::endl;\n" + "using std::cin;\n" + "int main();", + Style)); } TEST_F(UsingDeclarationsSorterTest, BreaksOnEmptyLines) { + FormatStyle Style = getLLVMStyle(); + EXPECT_EQ(FormatStyle::SUD_LexicographicNumeric, Style.SortUsingDeclarations); + EXPECT_EQ("using b;\n" + "using c;\n" + "\n" + "using a;\n" + "using d;", + sortUsingDeclarations("using c;\n" + "using b;\n" + "\n" + "using d;\n" + "using a;", + Style)); + + Style.SortUsingDeclarations = FormatStyle::SUD_Lexicographic; EXPECT_EQ("using b;\n" "using c;\n" "\n" @@ -206,35 +423,68 @@ "using b;\n" "\n" "using d;\n" - "using a;")); + "using a;", + Style)); } TEST_F(UsingDeclarationsSorterTest, BreaksOnUsingNamespace) { + FormatStyle Style = getLLVMStyle(); + EXPECT_EQ(FormatStyle::SUD_LexicographicNumeric, Style.SortUsingDeclarations); + EXPECT_EQ("using b;\n" + "using namespace std;\n" + "using a;", + sortUsingDeclarations("using b;\n" + "using namespace std;\n" + "using a;", + Style)); + + Style.SortUsingDeclarations = FormatStyle::SUD_Lexicographic; EXPECT_EQ("using b;\n" "using namespace std;\n" "using a;", sortUsingDeclarations("using b;\n" "using namespace std;\n" - "using a;")); + "using a;", + Style)); } TEST_F(UsingDeclarationsSorterTest, KeepsUsingDeclarationsInPPDirectives) { + FormatStyle Style = getLLVMStyle(); + EXPECT_EQ(FormatStyle::SUD_LexicographicNumeric, Style.SortUsingDeclarations); EXPECT_EQ("#define A \\\n" "using b;\\\n" "using a;", sortUsingDeclarations("#define A \\\n" "using b;\\\n" - "using a;")); + "using a;", + Style)); + + Style.SortUsingDeclarations = FormatStyle::SUD_Lexicographic; + EXPECT_EQ("#define A \\\n" + "using b;\\\n" + "using a;", + sortUsingDeclarations("#define A \\\n" + "using b;\\\n" + "using a;", + Style)); } TEST_F(UsingDeclarationsSorterTest, KeepsTypeAliases) { auto Code = "struct C { struct B { struct A; }; };\n" "using B = C::B;\n" "using A = B::A;"; - EXPECT_EQ(Code, sortUsingDeclarations(Code)); + + FormatStyle Style = getLLVMStyle(); + EXPECT_EQ(FormatStyle::SUD_LexicographicNumeric, Style.SortUsingDeclarations); + EXPECT_EQ(Code, sortUsingDeclarations(Code, Style)); + + Style.SortUsingDeclarations = FormatStyle::SUD_Lexicographic; + EXPECT_EQ(Code, sortUsingDeclarations(Code, Style)); } TEST_F(UsingDeclarationsSorterTest, MovesTrailingCommentsWithDeclarations) { + FormatStyle Style = getLLVMStyle(); + EXPECT_EQ(FormatStyle::SUD_LexicographicNumeric, Style.SortUsingDeclarations); EXPECT_EQ("using a; // line a1\n" "using b; /* line b1\n" " * line b2\n" @@ -246,10 +496,41 @@ "using b; /* line b1\n" " * line b2\n" " * line b3 */\n" - "using a; // line a1")); + "using a; // line a1", + Style)); + + Style.SortUsingDeclarations = FormatStyle::SUD_Lexicographic; + EXPECT_EQ("using a; // line a1\n" + "using b; /* line b1\n" + " * line b2\n" + " * line b3 */\n" + "using c; // line c1\n" + " // line c2", + sortUsingDeclarations("using c; // line c1\n" + " // line c2\n" + "using b; /* line b1\n" + " * line b2\n" + " * line b3 */\n" + "using a; // line a1", + Style)); } TEST_F(UsingDeclarationsSorterTest, SortsInStructScope) { + FormatStyle Style = getLLVMStyle(); + EXPECT_EQ(FormatStyle::SUD_LexicographicNumeric, Style.SortUsingDeclarations); + EXPECT_EQ("struct pt3 : pt2 {\n" + " using pt2::x;\n" + " using pt2::y;\n" + " float z;\n" + "};", + sortUsingDeclarations("struct pt3 : pt2 {\n" + " using pt2::y;\n" + " using pt2::x;\n" + " float z;\n" + "};", + Style)); + + Style.SortUsingDeclarations = FormatStyle::SUD_Lexicographic; EXPECT_EQ("struct pt3 : pt2 {\n" " using pt2::x;\n" " using pt2::y;\n" @@ -259,19 +540,53 @@ " using pt2::y;\n" " using pt2::x;\n" " float z;\n" - "};")); + "};", + Style)); } TEST_F(UsingDeclarationsSorterTest, KeepsOperators) { + FormatStyle Style = getLLVMStyle(); + EXPECT_EQ(FormatStyle::SUD_LexicographicNumeric, Style.SortUsingDeclarations); EXPECT_EQ("using a::operator();\n" "using a::operator-;\n" "using a::operator+;", sortUsingDeclarations("using a::operator();\n" "using a::operator-;\n" - "using a::operator+;")); + "using a::operator+;", + Style)); + + Style.SortUsingDeclarations = FormatStyle::SUD_Lexicographic; + EXPECT_EQ("using a::operator();\n" + "using a::operator-;\n" + "using a::operator+;", + sortUsingDeclarations("using a::operator();\n" + "using a::operator-;\n" + "using a::operator+;", + Style)); } TEST_F(UsingDeclarationsSorterTest, SortsUsingDeclarationsInsideNamespaces) { + FormatStyle Style = getLLVMStyle(); + EXPECT_EQ(FormatStyle::SUD_LexicographicNumeric, Style.SortUsingDeclarations); + EXPECT_EQ("namespace A {\n" + "struct B;\n" + "struct C;\n" + "}\n" + "namespace X {\n" + "using A::B;\n" + "using A::C;\n" + "}", + sortUsingDeclarations("namespace A {\n" + "struct B;\n" + "struct C;\n" + "}\n" + "namespace X {\n" + "using A::C;\n" + "using A::B;\n" + "}", + Style)); + + Style.SortUsingDeclarations = FormatStyle::SUD_Lexicographic; EXPECT_EQ("namespace A {\n" "struct B;\n" "struct C;\n" @@ -287,10 +602,28 @@ "namespace X {\n" "using A::C;\n" "using A::B;\n" - "}")); + "}", + Style)); } TEST_F(UsingDeclarationsSorterTest, SupportsClangFormatOff) { + FormatStyle Style = getLLVMStyle(); + EXPECT_EQ(FormatStyle::SUD_LexicographicNumeric, Style.SortUsingDeclarations); + EXPECT_EQ("// clang-format off\n" + "using b;\n" + "using a;\n" + "// clang-format on\n" + "using c;\n" + "using d;", + sortUsingDeclarations("// clang-format off\n" + "using b;\n" + "using a;\n" + "// clang-format on\n" + "using d;\n" + "using c;", + Style)); + + Style.SortUsingDeclarations = FormatStyle::SUD_Lexicographic; EXPECT_EQ("// clang-format off\n" "using b;\n" "using a;\n" @@ -302,10 +635,13 @@ "using a;\n" "// clang-format on\n" "using d;\n" - "using c;")); + "using c;", + Style)); } TEST_F(UsingDeclarationsSorterTest, SortsPartialRangeOfUsingDeclarations) { + FormatStyle Style = getLLVMStyle(); + EXPECT_EQ(FormatStyle::SUD_LexicographicNumeric, Style.SortUsingDeclarations); // Sorts the whole block of using declarations surrounding the range. EXPECT_EQ("using a;\n" "using b;\n" @@ -313,7 +649,7 @@ sortUsingDeclarations("using b;\n" "using c;\n" // starts at offset 10 "using a;", - {tooling::Range(10, 15)})); + {tooling::Range(10, 15)}, Style)); EXPECT_EQ("using a;\n" "using b;\n" "using c;\n" @@ -322,7 +658,7 @@ "using c;\n" // starts at offset 10 "using a;\n" "using A = b;", - {tooling::Range(10, 15)})); + {tooling::Range(10, 15)}, Style)); EXPECT_EQ("using d;\n" "using c;\n" @@ -340,18 +676,67 @@ "\n" "using f;\n" "using e;", - {tooling::Range(19, 1)})); + {tooling::Range(19, 1)}, Style)); + + Style.SortUsingDeclarations = FormatStyle::SUD_Lexicographic; + // Sorts the whole block of using declarations surrounding the range. + EXPECT_EQ("using a;\n" + "using b;\n" + "using c;", + sortUsingDeclarations("using b;\n" + "using c;\n" // starts at offset 10 + "using a;", + {tooling::Range(10, 15)}, Style)); + EXPECT_EQ("using a;\n" + "using b;\n" + "using c;\n" + "using A = b;", + sortUsingDeclarations("using b;\n" + "using c;\n" // starts at offset 10 + "using a;\n" + "using A = b;", + {tooling::Range(10, 15)}, Style)); + + EXPECT_EQ("using d;\n" + "using c;\n" + "\n" + "using a;\n" + "using b;\n" + "\n" + "using f;\n" + "using e;", + sortUsingDeclarations("using d;\n" + "using c;\n" + "\n" + "using b;\n" // starts at offset 19 + "using a;\n" + "\n" + "using f;\n" + "using e;", + {tooling::Range(19, 1)}, Style)); } TEST_F(UsingDeclarationsSorterTest, SortsUsingDeclarationsWithLeadingkComments) { + FormatStyle Style = getLLVMStyle(); + EXPECT_EQ(FormatStyle::SUD_LexicographicNumeric, Style.SortUsingDeclarations); EXPECT_EQ("/* comment */ using a;\n" "/* comment */ using b;", sortUsingDeclarations("/* comment */ using b;\n" - "/* comment */ using a;")); + "/* comment */ using a;", + Style)); + + Style.SortUsingDeclarations = FormatStyle::SUD_Lexicographic; + EXPECT_EQ("/* comment */ using a;\n" + "/* comment */ using b;", + sortUsingDeclarations("/* comment */ using b;\n" + "/* comment */ using a;", + Style)); } TEST_F(UsingDeclarationsSorterTest, DeduplicatesUsingDeclarations) { + FormatStyle Style = getLLVMStyle(); + EXPECT_EQ(FormatStyle::SUD_LexicographicNumeric, Style.SortUsingDeclarations); EXPECT_EQ("using a;\n" "using b;\n" "using c;\n" @@ -366,7 +751,68 @@ "\n" "using e;\n" "using a;\n" - "using e;")); + "using e;", + Style)); + + Style.SortUsingDeclarations = FormatStyle::SUD_Lexicographic; + EXPECT_EQ("using a;\n" + "using b;\n" + "using c;\n" + "\n" + "using a;\n" + "using e;", + sortUsingDeclarations("using c;\n" + "using a;\n" + "using b;\n" + "using a;\n" + "using b;\n" + "\n" + "using e;\n" + "using a;\n" + "using e;", + Style)); +} + +TEST_F(UsingDeclarationsSorterTest, + SortsUsingDeclarationsWithDifferentCountsOfScopes) { + FormatStyle Style = getLLVMStyle(); + EXPECT_EQ(FormatStyle::SUD_LexicographicNumeric, Style.SortUsingDeclarations); + EXPECT_EQ("using boost::regex;\n" + "using boost::regex_constants::icase;\n" + "using std::move;\n" + "using std::string;\n" + "using std::chrono::duration_cast;\n" + "using std::chrono::microseconds;\n" + "using std::chrono::seconds;\n" + "using std::chrono::steady_clock;\n", + sortUsingDeclarations("using boost::regex;\n" + "using boost::regex_constants::icase;\n" + "using std::chrono::duration_cast;\n" + "using std::chrono::microseconds;\n" + "using std::chrono::seconds;\n" + "using std::chrono::steady_clock;\n" + "using std::move;\n" + "using std::string;\n", + Style)); + + Style.SortUsingDeclarations = FormatStyle::SUD_Lexicographic; + EXPECT_EQ("using boost::regex;\n" + "using boost::regex_constants::icase;\n" + "using std::chrono::duration_cast;\n" + "using std::chrono::microseconds;\n" + "using std::chrono::seconds;\n" + "using std::chrono::steady_clock;\n" + "using std::move;\n" + "using std::string;\n", + sortUsingDeclarations("using boost::regex;\n" + "using boost::regex_constants::icase;\n" + "using std::move;\n" + "using std::string;\n" + "using std::chrono::duration_cast;\n" + "using std::chrono::microseconds;\n" + "using std::chrono::seconds;\n" + "using std::chrono::steady_clock;\n", + Style)); } } // end namespace