xref: /src/contrib/llvm-project/clang/lib/Format/UsingDeclarationsSorter.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1ef915aabSDimitry Andric //===--- UsingDeclarationsSorter.cpp ----------------------------*- C++ -*-===//
2ef915aabSDimitry Andric //
322989816SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
422989816SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
522989816SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ef915aabSDimitry Andric //
7ef915aabSDimitry Andric //===----------------------------------------------------------------------===//
8ef915aabSDimitry Andric ///
9ef915aabSDimitry Andric /// \file
1048675466SDimitry Andric /// This file implements UsingDeclarationsSorter, a TokenAnalyzer that
11ef915aabSDimitry Andric /// sorts consecutive using declarations.
12ef915aabSDimitry Andric ///
13ef915aabSDimitry Andric //===----------------------------------------------------------------------===//
14ef915aabSDimitry Andric 
15ef915aabSDimitry Andric #include "UsingDeclarationsSorter.h"
16e3b55780SDimitry Andric #include "clang/Format/Format.h"
17ef915aabSDimitry Andric #include "llvm/Support/Debug.h"
18ef915aabSDimitry Andric #include "llvm/Support/Regex.h"
19ef915aabSDimitry Andric 
20ef915aabSDimitry Andric #include <algorithm>
21ef915aabSDimitry Andric 
22ef915aabSDimitry Andric #define DEBUG_TYPE "using-declarations-sorter"
23ef915aabSDimitry Andric 
24ef915aabSDimitry Andric namespace clang {
25ef915aabSDimitry Andric namespace format {
26ef915aabSDimitry Andric 
27ef915aabSDimitry Andric namespace {
28ef915aabSDimitry Andric 
29461a67faSDimitry Andric // The order of using declaration is defined as follows:
30461a67faSDimitry Andric // Split the strings by "::" and discard any initial empty strings. The last
31461a67faSDimitry Andric // element of each list is a non-namespace name; all others are namespace
32461a67faSDimitry Andric // names. Sort the lists of names lexicographically, where the sort order of
33461a67faSDimitry Andric // individual names is that all non-namespace names come before all namespace
34461a67faSDimitry Andric // names, and within those groups, names are in case-insensitive lexicographic
35461a67faSDimitry Andric // order.
compareLabelsLexicographicNumeric(StringRef A,StringRef B)36e3b55780SDimitry Andric int compareLabelsLexicographicNumeric(StringRef A, StringRef B) {
37461a67faSDimitry Andric   SmallVector<StringRef, 2> NamesA;
38461a67faSDimitry Andric   A.split(NamesA, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
39461a67faSDimitry Andric   SmallVector<StringRef, 2> NamesB;
40461a67faSDimitry Andric   B.split(NamesB, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
41461a67faSDimitry Andric   size_t SizeA = NamesA.size();
42461a67faSDimitry Andric   size_t SizeB = NamesB.size();
43461a67faSDimitry Andric   for (size_t I = 0, E = std::min(SizeA, SizeB); I < E; ++I) {
44461a67faSDimitry Andric     if (I + 1 == SizeA) {
45461a67faSDimitry Andric       // I is the last index of NamesA and NamesA[I] is a non-namespace name.
46461a67faSDimitry Andric 
47461a67faSDimitry Andric       // Non-namespace names come before all namespace names.
48461a67faSDimitry Andric       if (SizeB > SizeA)
49461a67faSDimitry Andric         return -1;
50461a67faSDimitry Andric 
51461a67faSDimitry Andric       // Two names within a group compare case-insensitively.
52344a3780SDimitry Andric       return NamesA[I].compare_insensitive(NamesB[I]);
53461a67faSDimitry Andric     }
54461a67faSDimitry Andric 
55461a67faSDimitry Andric     // I is the last index of NamesB and NamesB[I] is a non-namespace name.
56461a67faSDimitry Andric     // Non-namespace names come before all namespace names.
57461a67faSDimitry Andric     if (I + 1 == SizeB)
58461a67faSDimitry Andric       return 1;
59461a67faSDimitry Andric 
60461a67faSDimitry Andric     // Two namespaces names within a group compare case-insensitively.
61344a3780SDimitry Andric     int C = NamesA[I].compare_insensitive(NamesB[I]);
62461a67faSDimitry Andric     if (C != 0)
63461a67faSDimitry Andric       return C;
64461a67faSDimitry Andric   }
65461a67faSDimitry Andric   return 0;
66461a67faSDimitry Andric }
67461a67faSDimitry Andric 
compareLabelsLexicographic(StringRef A,StringRef B)68e3b55780SDimitry Andric int compareLabelsLexicographic(StringRef A, StringRef B) {
69e3b55780SDimitry Andric   SmallVector<StringRef, 2> NamesA;
70e3b55780SDimitry Andric   A.split(NamesA, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
71e3b55780SDimitry Andric   SmallVector<StringRef, 2> NamesB;
72e3b55780SDimitry Andric   B.split(NamesB, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
73e3b55780SDimitry Andric   size_t SizeA = NamesA.size();
74e3b55780SDimitry Andric   size_t SizeB = NamesB.size();
75e3b55780SDimitry Andric   for (size_t I = 0, E = std::min(SizeA, SizeB); I < E; ++I) {
76e3b55780SDimitry Andric     // Two namespaces names within a group compare case-insensitively.
77e3b55780SDimitry Andric     int C = NamesA[I].compare_insensitive(NamesB[I]);
78e3b55780SDimitry Andric     if (C != 0)
79e3b55780SDimitry Andric       return C;
80e3b55780SDimitry Andric   }
81e3b55780SDimitry Andric   if (SizeA < SizeB)
82e3b55780SDimitry Andric     return -1;
83e3b55780SDimitry Andric   return SizeA == SizeB ? 0 : 1;
84e3b55780SDimitry Andric }
85e3b55780SDimitry Andric 
compareLabels(StringRef A,StringRef B,FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations)86e3b55780SDimitry Andric int compareLabels(
87e3b55780SDimitry Andric     StringRef A, StringRef B,
88e3b55780SDimitry Andric     FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations) {
89e3b55780SDimitry Andric   if (SortUsingDeclarations == FormatStyle::SUD_LexicographicNumeric)
90e3b55780SDimitry Andric     return compareLabelsLexicographicNumeric(A, B);
91e3b55780SDimitry Andric   return compareLabelsLexicographic(A, B);
92e3b55780SDimitry Andric }
93e3b55780SDimitry Andric 
94ef915aabSDimitry Andric struct UsingDeclaration {
95ef915aabSDimitry Andric   const AnnotatedLine *Line;
96ef915aabSDimitry Andric   std::string Label;
97ef915aabSDimitry Andric 
UsingDeclarationclang::format::__anonfbc22be50111::UsingDeclaration98ef915aabSDimitry Andric   UsingDeclaration(const AnnotatedLine *Line, const std::string &Label)
99ef915aabSDimitry Andric       : Line(Line), Label(Label) {}
100ef915aabSDimitry Andric };
101ef915aabSDimitry Andric 
102ef915aabSDimitry Andric /// Computes the label of a using declaration starting at tthe using token
103ef915aabSDimitry Andric /// \p UsingTok.
104ef915aabSDimitry Andric /// If \p UsingTok doesn't begin a using declaration, returns the empty string.
105ef915aabSDimitry Andric /// Note that this detects specifically using declarations, as in:
106ef915aabSDimitry Andric /// using A::B::C;
107ef915aabSDimitry Andric /// and not type aliases, as in:
108ef915aabSDimitry Andric /// using A = B::C;
109ef915aabSDimitry Andric /// Type aliases are in general not safe to permute.
computeUsingDeclarationLabel(const FormatToken * UsingTok)110ef915aabSDimitry Andric std::string computeUsingDeclarationLabel(const FormatToken *UsingTok) {
111ef915aabSDimitry Andric   assert(UsingTok && UsingTok->is(tok::kw_using) && "Expecting a using token");
112ef915aabSDimitry Andric   std::string Label;
113ef915aabSDimitry Andric   const FormatToken *Tok = UsingTok->Next;
114ef915aabSDimitry Andric   if (Tok && Tok->is(tok::kw_typename)) {
115ef915aabSDimitry Andric     Label.append("typename ");
116ef915aabSDimitry Andric     Tok = Tok->Next;
117ef915aabSDimitry Andric   }
118ef915aabSDimitry Andric   if (Tok && Tok->is(tok::coloncolon)) {
119ef915aabSDimitry Andric     Label.append("::");
120ef915aabSDimitry Andric     Tok = Tok->Next;
121ef915aabSDimitry Andric   }
122ef915aabSDimitry Andric   bool HasIdentifier = false;
123ef915aabSDimitry Andric   while (Tok && Tok->is(tok::identifier)) {
124ef915aabSDimitry Andric     HasIdentifier = true;
125ef915aabSDimitry Andric     Label.append(Tok->TokenText.str());
126ef915aabSDimitry Andric     Tok = Tok->Next;
127ef915aabSDimitry Andric     if (!Tok || Tok->isNot(tok::coloncolon))
128ef915aabSDimitry Andric       break;
129ef915aabSDimitry Andric     Label.append("::");
130ef915aabSDimitry Andric     Tok = Tok->Next;
131ef915aabSDimitry Andric   }
132ef915aabSDimitry Andric   if (HasIdentifier && Tok && Tok->isOneOf(tok::semi, tok::comma))
133ef915aabSDimitry Andric     return Label;
134ef915aabSDimitry Andric   return "";
135ef915aabSDimitry Andric }
136ef915aabSDimitry Andric 
endUsingDeclarationBlock(SmallVectorImpl<UsingDeclaration> * UsingDeclarations,const SourceManager & SourceMgr,tooling::Replacements * Fixes,FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations)137ef915aabSDimitry Andric void endUsingDeclarationBlock(
138ef915aabSDimitry Andric     SmallVectorImpl<UsingDeclaration> *UsingDeclarations,
139e3b55780SDimitry Andric     const SourceManager &SourceMgr, tooling::Replacements *Fixes,
140e3b55780SDimitry Andric     FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations) {
141461a67faSDimitry Andric   bool BlockAffected = false;
142461a67faSDimitry Andric   for (const UsingDeclaration &Declaration : *UsingDeclarations) {
143461a67faSDimitry Andric     if (Declaration.Line->Affected) {
144461a67faSDimitry Andric       BlockAffected = true;
145461a67faSDimitry Andric       break;
146461a67faSDimitry Andric     }
147461a67faSDimitry Andric   }
148461a67faSDimitry Andric   if (!BlockAffected) {
149461a67faSDimitry Andric     UsingDeclarations->clear();
150461a67faSDimitry Andric     return;
151461a67faSDimitry Andric   }
152ef915aabSDimitry Andric   SmallVector<UsingDeclaration, 4> SortedUsingDeclarations(
153ef915aabSDimitry Andric       UsingDeclarations->begin(), UsingDeclarations->end());
154e3b55780SDimitry Andric   auto Comp = [SortUsingDeclarations](const UsingDeclaration &Lhs,
155e3b55780SDimitry Andric                                       const UsingDeclaration &Rhs) -> bool {
156e3b55780SDimitry Andric     return compareLabels(Lhs.Label, Rhs.Label, SortUsingDeclarations) < 0;
157e3b55780SDimitry Andric   };
158e3b55780SDimitry Andric   llvm::stable_sort(SortedUsingDeclarations, Comp);
159461a67faSDimitry Andric   SortedUsingDeclarations.erase(
160461a67faSDimitry Andric       std::unique(SortedUsingDeclarations.begin(),
161461a67faSDimitry Andric                   SortedUsingDeclarations.end(),
162461a67faSDimitry Andric                   [](const UsingDeclaration &a, const UsingDeclaration &b) {
163461a67faSDimitry Andric                     return a.Label == b.Label;
164461a67faSDimitry Andric                   }),
165461a67faSDimitry Andric       SortedUsingDeclarations.end());
166ef915aabSDimitry Andric   for (size_t I = 0, E = UsingDeclarations->size(); I < E; ++I) {
167461a67faSDimitry Andric     if (I >= SortedUsingDeclarations.size()) {
168461a67faSDimitry Andric       // This using declaration has been deduplicated, delete it.
169461a67faSDimitry Andric       auto Begin =
170461a67faSDimitry Andric           (*UsingDeclarations)[I].Line->First->WhitespaceRange.getBegin();
171461a67faSDimitry Andric       auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
172461a67faSDimitry Andric       auto Range = CharSourceRange::getCharRange(Begin, End);
173461a67faSDimitry Andric       auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, ""));
174461a67faSDimitry Andric       if (Err) {
175461a67faSDimitry Andric         llvm::errs() << "Error while sorting using declarations: "
176461a67faSDimitry Andric                      << llvm::toString(std::move(Err)) << "\n";
177461a67faSDimitry Andric       }
178461a67faSDimitry Andric       continue;
179461a67faSDimitry Andric     }
180ef915aabSDimitry Andric     if ((*UsingDeclarations)[I].Line == SortedUsingDeclarations[I].Line)
181ef915aabSDimitry Andric       continue;
182ef915aabSDimitry Andric     auto Begin = (*UsingDeclarations)[I].Line->First->Tok.getLocation();
183ef915aabSDimitry Andric     auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
184ef915aabSDimitry Andric     auto SortedBegin =
185ef915aabSDimitry Andric         SortedUsingDeclarations[I].Line->First->Tok.getLocation();
186ef915aabSDimitry Andric     auto SortedEnd = SortedUsingDeclarations[I].Line->Last->Tok.getEndLoc();
187ef915aabSDimitry Andric     StringRef Text(SourceMgr.getCharacterData(SortedBegin),
188ef915aabSDimitry Andric                    SourceMgr.getCharacterData(SortedEnd) -
189ef915aabSDimitry Andric                        SourceMgr.getCharacterData(SortedBegin));
19048675466SDimitry Andric     LLVM_DEBUG({
191ef915aabSDimitry Andric       StringRef OldText(SourceMgr.getCharacterData(Begin),
192ef915aabSDimitry Andric                         SourceMgr.getCharacterData(End) -
193ef915aabSDimitry Andric                             SourceMgr.getCharacterData(Begin));
194ef915aabSDimitry Andric       llvm::dbgs() << "Replacing '" << OldText << "' with '" << Text << "'\n";
195ef915aabSDimitry Andric     });
196ef915aabSDimitry Andric     auto Range = CharSourceRange::getCharRange(Begin, End);
197ef915aabSDimitry Andric     auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, Text));
198ef915aabSDimitry Andric     if (Err) {
199ef915aabSDimitry Andric       llvm::errs() << "Error while sorting using declarations: "
200ef915aabSDimitry Andric                    << llvm::toString(std::move(Err)) << "\n";
201ef915aabSDimitry Andric     }
202ef915aabSDimitry Andric   }
203ef915aabSDimitry Andric   UsingDeclarations->clear();
204ef915aabSDimitry Andric }
205ef915aabSDimitry Andric 
206ef915aabSDimitry Andric } // namespace
207ef915aabSDimitry Andric 
UsingDeclarationsSorter(const Environment & Env,const FormatStyle & Style)208ef915aabSDimitry Andric UsingDeclarationsSorter::UsingDeclarationsSorter(const Environment &Env,
209ef915aabSDimitry Andric                                                  const FormatStyle &Style)
210ef915aabSDimitry Andric     : TokenAnalyzer(Env, Style) {}
211ef915aabSDimitry Andric 
analyze(TokenAnnotator & Annotator,SmallVectorImpl<AnnotatedLine * > & AnnotatedLines,FormatTokenLexer & Tokens)212461a67faSDimitry Andric std::pair<tooling::Replacements, unsigned> UsingDeclarationsSorter::analyze(
213ef915aabSDimitry Andric     TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
214ef915aabSDimitry Andric     FormatTokenLexer &Tokens) {
215ef915aabSDimitry Andric   const SourceManager &SourceMgr = Env.getSourceManager();
21648675466SDimitry Andric   AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
217ef915aabSDimitry Andric   tooling::Replacements Fixes;
218ef915aabSDimitry Andric   SmallVector<UsingDeclaration, 4> UsingDeclarations;
219ecbca9f5SDimitry Andric   for (const AnnotatedLine *Line : AnnotatedLines) {
220ecbca9f5SDimitry Andric     const auto *FirstTok = Line->First;
221ecbca9f5SDimitry Andric     if (Line->InPPDirective || !Line->startsWith(tok::kw_using) ||
222ecbca9f5SDimitry Andric         FirstTok->Finalized) {
223e3b55780SDimitry Andric       endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
224e3b55780SDimitry Andric                                Style.SortUsingDeclarations);
225ef915aabSDimitry Andric       continue;
226ef915aabSDimitry Andric     }
227e3b55780SDimitry Andric     if (FirstTok->NewlinesBefore > 1) {
228e3b55780SDimitry Andric       endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
229e3b55780SDimitry Andric                                Style.SortUsingDeclarations);
230e3b55780SDimitry Andric     }
231461a67faSDimitry Andric     const auto *UsingTok =
232461a67faSDimitry Andric         FirstTok->is(tok::comment) ? FirstTok->getNextNonComment() : FirstTok;
233461a67faSDimitry Andric     std::string Label = computeUsingDeclarationLabel(UsingTok);
234ef915aabSDimitry Andric     if (Label.empty()) {
235e3b55780SDimitry Andric       endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
236e3b55780SDimitry Andric                                Style.SortUsingDeclarations);
237ef915aabSDimitry Andric       continue;
238ef915aabSDimitry Andric     }
239ecbca9f5SDimitry Andric     UsingDeclarations.push_back(UsingDeclaration(Line, Label));
240ef915aabSDimitry Andric   }
241e3b55780SDimitry Andric   endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
242e3b55780SDimitry Andric                            Style.SortUsingDeclarations);
243461a67faSDimitry Andric   return {Fixes, 0};
244ef915aabSDimitry Andric }
245ef915aabSDimitry Andric 
246ef915aabSDimitry Andric } // namespace format
247ef915aabSDimitry Andric } // namespace clang
248