Skip to content

Commit 58751f9

Browse files
committed
[clang-format] SortUsingDeclarations support lexicographic order
fix #59930 Differential Revision: https://reviews.llvm.org/D141694
1 parent a5b457b commit 58751f9

File tree

6 files changed

+644
-79
lines changed

6 files changed

+644
-79
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4505,22 +4505,54 @@ the configuration (without a prefix: ``Auto``).
45054505
45064506
.. _SortUsingDeclarations:
45074507

4508-
**SortUsingDeclarations** (``Boolean``) :versionbadge:`clang-format 5` :ref:`<SortUsingDeclarations>`
4509-
If ``true``, clang-format will sort using declarations.
4508+
**SortUsingDeclarations** (``SortUsingDeclarationsOptions``) :versionbadge:`clang-format 5` :ref:`<SortUsingDeclarations>`
4509+
Controls if and how clang-format will sort using declarations.
45104510

4511-
The order of using declarations is defined as follows:
4512-
Split the strings by "::" and discard any initial empty strings. The last
4513-
element of each list is a non-namespace name; all others are namespace
4514-
names. Sort the lists of names lexicographically, where the sort order of
4515-
individual names is that all non-namespace names come before all namespace
4516-
names, and within those groups, names are in case-insensitive
4517-
lexicographic order.
4511+
Possible values:
4512+
4513+
* ``SUD_Never`` (in configuration: ``Never``)
4514+
Using declarations are never sorted.
4515+
4516+
.. code-block:: c++
4517+
4518+
using std::chrono::duration_cast;
4519+
using std::move;
4520+
using boost::regex;
4521+
using boost::regex_constants::icase;
4522+
using std::string;
4523+
4524+
* ``SUD_Lexicographic`` (in configuration: ``Lexicographic``)
4525+
Using declarations are sorted in the order defined as follows:
4526+
Split the strings by "::" and discard any initial empty strings. Sort
4527+
the lists of names lexicographically, and within those groups, names are
4528+
in case-insensitive lexicographic order.
4529+
4530+
.. code-block:: c++
4531+
4532+
using boost::regex;
4533+
using boost::regex_constants::icase;
4534+
using std::chrono::duration_cast;
4535+
using std::move;
4536+
using std::string;
4537+
4538+
* ``SUD_LexicographicNumeric`` (in configuration: ``LexicographicNumeric``)
4539+
Using declarations are sorted in the order defined as follows:
4540+
Split the strings by "::" and discard any initial empty strings. The
4541+
last element of each list is a non-namespace name; all others are
4542+
namespace names. Sort the lists of names lexicographically, where the
4543+
sort order of individual names is that all non-namespace names come
4544+
before all namespace names, and within those groups, names are in
4545+
case-insensitive lexicographic order.
4546+
4547+
.. code-block:: c++
4548+
4549+
using boost::regex;
4550+
using boost::regex_constants::icase;
4551+
using std::move;
4552+
using std::string;
4553+
using std::chrono::duration_cast;
45184554

4519-
.. code-block:: c++
45204555

4521-
false: true:
4522-
using std::cout; vs. using std::cin;
4523-
using std::cin; using std::cout;
45244556

45254557
.. _SpaceAfterCStyleCast:
45264558

clang/include/clang/Format/Format.h

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3510,22 +3510,49 @@ struct FormatStyle {
35103510
/// \version 12
35113511
SortJavaStaticImportOptions SortJavaStaticImport;
35123512

3513-
/// If ``true``, clang-format will sort using declarations.
3514-
///
3515-
/// The order of using declarations is defined as follows:
3516-
/// Split the strings by "::" and discard any initial empty strings. The last
3517-
/// element of each list is a non-namespace name; all others are namespace
3518-
/// names. Sort the lists of names lexicographically, where the sort order of
3519-
/// individual names is that all non-namespace names come before all namespace
3520-
/// names, and within those groups, names are in case-insensitive
3521-
/// lexicographic order.
3522-
/// \code
3523-
/// false: true:
3524-
/// using std::cout; vs. using std::cin;
3525-
/// using std::cin; using std::cout;
3526-
/// \endcode
3513+
/// Using declaration sorting options.
3514+
enum SortUsingDeclarationsOptions : int8_t {
3515+
/// Using declarations are never sorted.
3516+
/// \code
3517+
/// using std::chrono::duration_cast;
3518+
/// using std::move;
3519+
/// using boost::regex;
3520+
/// using boost::regex_constants::icase;
3521+
/// using std::string;
3522+
/// \endcode
3523+
SUD_Never,
3524+
/// Using declarations are sorted in the order defined as follows:
3525+
/// Split the strings by "::" and discard any initial empty strings. Sort
3526+
/// the lists of names lexicographically, and within those groups, names are
3527+
/// in case-insensitive lexicographic order.
3528+
/// \code
3529+
/// using boost::regex;
3530+
/// using boost::regex_constants::icase;
3531+
/// using std::chrono::duration_cast;
3532+
/// using std::move;
3533+
/// using std::string;
3534+
/// \endcode
3535+
SUD_Lexicographic,
3536+
/// Using declarations are sorted in the order defined as follows:
3537+
/// Split the strings by "::" and discard any initial empty strings. The
3538+
/// last element of each list is a non-namespace name; all others are
3539+
/// namespace names. Sort the lists of names lexicographically, where the
3540+
/// sort order of individual names is that all non-namespace names come
3541+
/// before all namespace names, and within those groups, names are in
3542+
/// case-insensitive lexicographic order.
3543+
/// \code
3544+
/// using boost::regex;
3545+
/// using boost::regex_constants::icase;
3546+
/// using std::move;
3547+
/// using std::string;
3548+
/// using std::chrono::duration_cast;
3549+
/// \endcode
3550+
SUD_LexicographicNumeric,
3551+
};
3552+
3553+
/// Controls if and how clang-format will sort using declarations.
35273554
/// \version 5
3528-
bool SortUsingDeclarations;
3555+
SortUsingDeclarationsOptions SortUsingDeclarations;
35293556

35303557
/// If ``true``, a space is inserted after C style casts.
35313558
/// \code

clang/lib/Format/Format.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,21 @@ struct ScalarEnumerationTraits<FormatStyle::SortJavaStaticImportOptions> {
606606
}
607607
};
608608

609+
template <>
610+
struct ScalarEnumerationTraits<FormatStyle::SortUsingDeclarationsOptions> {
611+
static void enumeration(IO &IO,
612+
FormatStyle::SortUsingDeclarationsOptions &Value) {
613+
IO.enumCase(Value, "Never", FormatStyle::SUD_Never);
614+
IO.enumCase(Value, "Lexicographic", FormatStyle::SUD_Lexicographic);
615+
IO.enumCase(Value, "LexicographicNumeric",
616+
FormatStyle::SUD_LexicographicNumeric);
617+
618+
// For backward compatibility.
619+
IO.enumCase(Value, "false", FormatStyle::SUD_Never);
620+
IO.enumCase(Value, "true", FormatStyle::SUD_LexicographicNumeric);
621+
}
622+
};
623+
609624
template <>
610625
struct ScalarEnumerationTraits<FormatStyle::SpaceAroundPointerQualifiersStyle> {
611626
static void
@@ -1404,7 +1419,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
14041419
LLVMStyle.ShortNamespaceLines = 1;
14051420
LLVMStyle.SortIncludes = FormatStyle::SI_CaseSensitive;
14061421
LLVMStyle.SortJavaStaticImport = FormatStyle::SJSIO_Before;
1407-
LLVMStyle.SortUsingDeclarations = true;
1422+
LLVMStyle.SortUsingDeclarations = FormatStyle::SUD_LexicographicNumeric;
14081423
LLVMStyle.SpaceAfterCStyleCast = false;
14091424
LLVMStyle.SpaceAfterLogicalNot = false;
14101425
LLVMStyle.SpaceAfterTemplateKeyword = true;
@@ -1772,7 +1787,7 @@ FormatStyle getNoStyle() {
17721787
FormatStyle NoStyle = getLLVMStyle();
17731788
NoStyle.DisableFormat = true;
17741789
NoStyle.SortIncludes = FormatStyle::SI_Never;
1775-
NoStyle.SortUsingDeclarations = false;
1790+
NoStyle.SortUsingDeclarations = FormatStyle::SUD_Never;
17761791
return NoStyle;
17771792
}
17781793

@@ -3480,7 +3495,7 @@ reformat(const FormatStyle &Style, StringRef Code,
34803495
});
34813496
}
34823497

3483-
if (Style.SortUsingDeclarations) {
3498+
if (Style.SortUsingDeclarations != FormatStyle::SUD_Never) {
34843499
Passes.emplace_back([&](const Environment &Env) {
34853500
return UsingDeclarationsSorter(Env, Expanded).process();
34863501
});

clang/lib/Format/UsingDeclarationsSorter.cpp

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//===----------------------------------------------------------------------===//
1414

1515
#include "UsingDeclarationsSorter.h"
16+
#include "clang/Format/Format.h"
1617
#include "llvm/Support/Debug.h"
1718
#include "llvm/Support/Regex.h"
1819

@@ -32,7 +33,7 @@ namespace {
3233
// individual names is that all non-namespace names come before all namespace
3334
// names, and within those groups, names are in case-insensitive lexicographic
3435
// order.
35-
int compareLabels(StringRef A, StringRef B) {
36+
int compareLabelsLexicographicNumeric(StringRef A, StringRef B) {
3637
SmallVector<StringRef, 2> NamesA;
3738
A.split(NamesA, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
3839
SmallVector<StringRef, 2> NamesB;
@@ -64,16 +65,38 @@ int compareLabels(StringRef A, StringRef B) {
6465
return 0;
6566
}
6667

68+
int compareLabelsLexicographic(StringRef A, StringRef B) {
69+
SmallVector<StringRef, 2> NamesA;
70+
A.split(NamesA, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
71+
SmallVector<StringRef, 2> NamesB;
72+
B.split(NamesB, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
73+
size_t SizeA = NamesA.size();
74+
size_t SizeB = NamesB.size();
75+
for (size_t I = 0, E = std::min(SizeA, SizeB); I < E; ++I) {
76+
// Two namespaces names within a group compare case-insensitively.
77+
int C = NamesA[I].compare_insensitive(NamesB[I]);
78+
if (C != 0)
79+
return C;
80+
}
81+
if (SizeA < SizeB)
82+
return -1;
83+
return SizeA == SizeB ? 0 : 1;
84+
}
85+
86+
int compareLabels(
87+
StringRef A, StringRef B,
88+
FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations) {
89+
if (SortUsingDeclarations == FormatStyle::SUD_LexicographicNumeric)
90+
return compareLabelsLexicographicNumeric(A, B);
91+
return compareLabelsLexicographic(A, B);
92+
}
93+
6794
struct UsingDeclaration {
6895
const AnnotatedLine *Line;
6996
std::string Label;
7097

7198
UsingDeclaration(const AnnotatedLine *Line, const std::string &Label)
7299
: Line(Line), Label(Label) {}
73-
74-
bool operator<(const UsingDeclaration &Other) const {
75-
return compareLabels(Label, Other.Label) < 0;
76-
}
77100
};
78101

79102
/// Computes the label of a using declaration starting at tthe using token
@@ -113,7 +136,8 @@ std::string computeUsingDeclarationLabel(const FormatToken *UsingTok) {
113136

114137
void endUsingDeclarationBlock(
115138
SmallVectorImpl<UsingDeclaration> *UsingDeclarations,
116-
const SourceManager &SourceMgr, tooling::Replacements *Fixes) {
139+
const SourceManager &SourceMgr, tooling::Replacements *Fixes,
140+
FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations) {
117141
bool BlockAffected = false;
118142
for (const UsingDeclaration &Declaration : *UsingDeclarations) {
119143
if (Declaration.Line->Affected) {
@@ -127,7 +151,11 @@ void endUsingDeclarationBlock(
127151
}
128152
SmallVector<UsingDeclaration, 4> SortedUsingDeclarations(
129153
UsingDeclarations->begin(), UsingDeclarations->end());
130-
llvm::stable_sort(SortedUsingDeclarations);
154+
auto Comp = [SortUsingDeclarations](const UsingDeclaration &Lhs,
155+
const UsingDeclaration &Rhs) -> bool {
156+
return compareLabels(Lhs.Label, Rhs.Label, SortUsingDeclarations) < 0;
157+
};
158+
llvm::stable_sort(SortedUsingDeclarations, Comp);
131159
SortedUsingDeclarations.erase(
132160
std::unique(SortedUsingDeclarations.begin(),
133161
SortedUsingDeclarations.end(),
@@ -192,21 +220,26 @@ std::pair<tooling::Replacements, unsigned> UsingDeclarationsSorter::analyze(
192220
const auto *FirstTok = Line->First;
193221
if (Line->InPPDirective || !Line->startsWith(tok::kw_using) ||
194222
FirstTok->Finalized) {
195-
endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
223+
endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
224+
Style.SortUsingDeclarations);
196225
continue;
197226
}
198-
if (FirstTok->NewlinesBefore > 1)
199-
endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
227+
if (FirstTok->NewlinesBefore > 1) {
228+
endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
229+
Style.SortUsingDeclarations);
230+
}
200231
const auto *UsingTok =
201232
FirstTok->is(tok::comment) ? FirstTok->getNextNonComment() : FirstTok;
202233
std::string Label = computeUsingDeclarationLabel(UsingTok);
203234
if (Label.empty()) {
204-
endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
235+
endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
236+
Style.SortUsingDeclarations);
205237
continue;
206238
}
207239
UsingDeclarations.push_back(UsingDeclaration(Line, Label));
208240
}
209-
endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
241+
endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
242+
Style.SortUsingDeclarations);
210243
return {Fixes, 0};
211244
}
212245

clang/unittests/Format/ConfigParseTest.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
174174
CHECK_PARSE_BOOL(ReflowComments);
175175
CHECK_PARSE_BOOL(RemoveBracesLLVM);
176176
CHECK_PARSE_BOOL(RemoveSemicolon);
177-
CHECK_PARSE_BOOL(SortUsingDeclarations);
178177
CHECK_PARSE_BOOL(SpacesInParentheses);
179178
CHECK_PARSE_BOOL(SpacesInSquareBrackets);
180179
CHECK_PARSE_BOOL(SpacesInConditionalStatement);
@@ -714,6 +713,19 @@ TEST(ConfigParseTest, ParsesConfiguration) {
714713
CHECK_PARSE("SortJavaStaticImport: Before", SortJavaStaticImport,
715714
FormatStyle::SJSIO_Before);
716715

716+
Style.SortUsingDeclarations = FormatStyle::SUD_LexicographicNumeric;
717+
CHECK_PARSE("SortUsingDeclarations: Never", SortUsingDeclarations,
718+
FormatStyle::SUD_Never);
719+
CHECK_PARSE("SortUsingDeclarations: Lexicographic", SortUsingDeclarations,
720+
FormatStyle::SUD_Lexicographic);
721+
CHECK_PARSE("SortUsingDeclarations: LexicographicNumeric",
722+
SortUsingDeclarations, FormatStyle::SUD_LexicographicNumeric);
723+
// For backward compatibility:
724+
CHECK_PARSE("SortUsingDeclarations: false", SortUsingDeclarations,
725+
FormatStyle::SUD_Never);
726+
CHECK_PARSE("SortUsingDeclarations: true", SortUsingDeclarations,
727+
FormatStyle::SUD_LexicographicNumeric);
728+
717729
// FIXME: This is required because parsing a configuration simply overwrites
718730
// the first N elements of the list instead of resetting it.
719731
Style.ForEachMacros.clear();

0 commit comments

Comments
 (0)