1b03877abSKrasimir Georgiev //===--- UsingDeclarationsSorter.cpp ----------------------------*- C++ -*-===//
2b03877abSKrasimir Georgiev //
3b03877abSKrasimir Georgiev //                     The LLVM Compiler Infrastructure
4b03877abSKrasimir Georgiev //
5b03877abSKrasimir Georgiev // This file is distributed under the University of Illinois Open Source
6b03877abSKrasimir Georgiev // License. See LICENSE.TXT for details.
7b03877abSKrasimir Georgiev //
8b03877abSKrasimir Georgiev //===----------------------------------------------------------------------===//
9b03877abSKrasimir Georgiev ///
10b03877abSKrasimir Georgiev /// \file
11b03877abSKrasimir Georgiev /// \brief This file implements UsingDeclarationsSorter, a TokenAnalyzer that
12b03877abSKrasimir Georgiev /// sorts consecutive using declarations.
13b03877abSKrasimir Georgiev ///
14b03877abSKrasimir Georgiev //===----------------------------------------------------------------------===//
15b03877abSKrasimir Georgiev 
16b03877abSKrasimir Georgiev #include "UsingDeclarationsSorter.h"
17b03877abSKrasimir Georgiev #include "llvm/Support/Debug.h"
18b03877abSKrasimir Georgiev #include "llvm/Support/Regex.h"
19b03877abSKrasimir Georgiev 
20b03877abSKrasimir Georgiev #include <algorithm>
21b03877abSKrasimir Georgiev 
22b03877abSKrasimir Georgiev #define DEBUG_TYPE "using-declarations-sorter"
23b03877abSKrasimir Georgiev 
24b03877abSKrasimir Georgiev namespace clang {
25b03877abSKrasimir Georgiev namespace format {
26b03877abSKrasimir Georgiev 
27b03877abSKrasimir Georgiev namespace {
28b03877abSKrasimir Georgiev 
29818da9bbSKrasimir Georgiev // The order of using declaration is defined as follows:
30818da9bbSKrasimir Georgiev // Split the strings by "::" and discard any initial empty strings. The last
31818da9bbSKrasimir Georgiev // element of each list is a non-namespace name; all others are namespace
32818da9bbSKrasimir Georgiev // names. Sort the lists of names lexicographically, where the sort order of
33818da9bbSKrasimir Georgiev // individual names is that all non-namespace names come before all namespace
34818da9bbSKrasimir Georgiev // names, and within those groups, names are in case-insensitive lexicographic
35818da9bbSKrasimir Georgiev // order.
36818da9bbSKrasimir Georgiev int compareLabels(StringRef A, StringRef B) {
37818da9bbSKrasimir Georgiev   SmallVector<StringRef, 2> NamesA;
38818da9bbSKrasimir Georgiev   A.split(NamesA, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
39818da9bbSKrasimir Georgiev   SmallVector<StringRef, 2> NamesB;
40818da9bbSKrasimir Georgiev   B.split(NamesB, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
41818da9bbSKrasimir Georgiev   size_t SizeA = NamesA.size();
42818da9bbSKrasimir Georgiev   size_t SizeB = NamesB.size();
43818da9bbSKrasimir Georgiev   for (size_t I = 0, E = std::min(SizeA, SizeB); I < E; ++I) {
44818da9bbSKrasimir Georgiev     if (I + 1 == SizeA) {
45818da9bbSKrasimir Georgiev       // I is the last index of NamesA and NamesA[I] is a non-namespace name.
46818da9bbSKrasimir Georgiev 
47818da9bbSKrasimir Georgiev       // Non-namespace names come before all namespace names.
48818da9bbSKrasimir Georgiev       if (SizeB > SizeA)
49818da9bbSKrasimir Georgiev         return -1;
50818da9bbSKrasimir Georgiev 
51818da9bbSKrasimir Georgiev       // Two names within a group compare case-insensitively.
52818da9bbSKrasimir Georgiev       return NamesA[I].compare_lower(NamesB[I]);
53818da9bbSKrasimir Georgiev     }
54818da9bbSKrasimir Georgiev 
55818da9bbSKrasimir Georgiev     // I is the last index of NamesB and NamesB[I] is a non-namespace name.
56818da9bbSKrasimir Georgiev     // Non-namespace names come before all namespace names.
57818da9bbSKrasimir Georgiev     if (I + 1 == SizeB)
58818da9bbSKrasimir Georgiev       return 1;
59818da9bbSKrasimir Georgiev 
60818da9bbSKrasimir Georgiev     // Two namespaces names within a group compare case-insensitively.
61818da9bbSKrasimir Georgiev     int C = NamesA[I].compare_lower(NamesB[I]);
62818da9bbSKrasimir Georgiev     if (C != 0)
63818da9bbSKrasimir Georgiev       return C;
64818da9bbSKrasimir Georgiev   }
65818da9bbSKrasimir Georgiev   return 0;
66818da9bbSKrasimir Georgiev }
67818da9bbSKrasimir Georgiev 
68b03877abSKrasimir Georgiev struct UsingDeclaration {
69b03877abSKrasimir Georgiev   const AnnotatedLine *Line;
70b03877abSKrasimir Georgiev   std::string Label;
71b03877abSKrasimir Georgiev 
72b03877abSKrasimir Georgiev   UsingDeclaration(const AnnotatedLine *Line, const std::string &Label)
73b03877abSKrasimir Georgiev       : Line(Line), Label(Label) {}
74b03877abSKrasimir Georgiev 
75b03877abSKrasimir Georgiev   bool operator<(const UsingDeclaration &Other) const {
76818da9bbSKrasimir Georgiev     return compareLabels(Label, Other.Label) < 0;
77b03877abSKrasimir Georgiev   }
78b03877abSKrasimir Georgiev };
79b03877abSKrasimir Georgiev 
80b03877abSKrasimir Georgiev /// Computes the label of a using declaration starting at tthe using token
81b03877abSKrasimir Georgiev /// \p UsingTok.
82b03877abSKrasimir Georgiev /// If \p UsingTok doesn't begin a using declaration, returns the empty string.
83b03877abSKrasimir Georgiev /// Note that this detects specifically using declarations, as in:
84b03877abSKrasimir Georgiev /// using A::B::C;
85b03877abSKrasimir Georgiev /// and not type aliases, as in:
86b03877abSKrasimir Georgiev /// using A = B::C;
87b03877abSKrasimir Georgiev /// Type aliases are in general not safe to permute.
88b03877abSKrasimir Georgiev std::string computeUsingDeclarationLabel(const FormatToken *UsingTok) {
89b03877abSKrasimir Georgiev   assert(UsingTok && UsingTok->is(tok::kw_using) && "Expecting a using token");
90b03877abSKrasimir Georgiev   std::string Label;
91b03877abSKrasimir Georgiev   const FormatToken *Tok = UsingTok->Next;
92b03877abSKrasimir Georgiev   if (Tok && Tok->is(tok::kw_typename)) {
93b03877abSKrasimir Georgiev     Label.append("typename ");
94b03877abSKrasimir Georgiev     Tok = Tok->Next;
95b03877abSKrasimir Georgiev   }
96b03877abSKrasimir Georgiev   if (Tok && Tok->is(tok::coloncolon)) {
97b03877abSKrasimir Georgiev     Label.append("::");
98b03877abSKrasimir Georgiev     Tok = Tok->Next;
99b03877abSKrasimir Georgiev   }
100b03877abSKrasimir Georgiev   bool HasIdentifier = false;
101b03877abSKrasimir Georgiev   while (Tok && Tok->is(tok::identifier)) {
102b03877abSKrasimir Georgiev     HasIdentifier = true;
103b03877abSKrasimir Georgiev     Label.append(Tok->TokenText.str());
104b03877abSKrasimir Georgiev     Tok = Tok->Next;
105b03877abSKrasimir Georgiev     if (!Tok || Tok->isNot(tok::coloncolon))
106b03877abSKrasimir Georgiev       break;
107b03877abSKrasimir Georgiev     Label.append("::");
108b03877abSKrasimir Georgiev     Tok = Tok->Next;
109b03877abSKrasimir Georgiev   }
110b03877abSKrasimir Georgiev   if (HasIdentifier && Tok && Tok->isOneOf(tok::semi, tok::comma))
111b03877abSKrasimir Georgiev     return Label;
112b03877abSKrasimir Georgiev   return "";
113b03877abSKrasimir Georgiev }
114b03877abSKrasimir Georgiev 
115b03877abSKrasimir Georgiev void endUsingDeclarationBlock(
116b03877abSKrasimir Georgiev     SmallVectorImpl<UsingDeclaration> *UsingDeclarations,
117b03877abSKrasimir Georgiev     const SourceManager &SourceMgr, tooling::Replacements *Fixes) {
1189da65aa8SKrasimir Georgiev   bool BlockAffected = false;
1199da65aa8SKrasimir Georgiev   for (const UsingDeclaration &Declaration : *UsingDeclarations) {
1209da65aa8SKrasimir Georgiev     if (Declaration.Line->Affected) {
1219da65aa8SKrasimir Georgiev       BlockAffected = true;
1229da65aa8SKrasimir Georgiev       break;
1239da65aa8SKrasimir Georgiev     }
1249da65aa8SKrasimir Georgiev   }
1259da65aa8SKrasimir Georgiev   if (!BlockAffected) {
1269da65aa8SKrasimir Georgiev     UsingDeclarations->clear();
1279da65aa8SKrasimir Georgiev     return;
1289da65aa8SKrasimir Georgiev   }
129b03877abSKrasimir Georgiev   SmallVector<UsingDeclaration, 4> SortedUsingDeclarations(
130b03877abSKrasimir Georgiev       UsingDeclarations->begin(), UsingDeclarations->end());
1317fc53367SKrasimir Georgiev   std::stable_sort(SortedUsingDeclarations.begin(),
1327fc53367SKrasimir Georgiev                    SortedUsingDeclarations.end());
133f09c4285SKrasimir Georgiev   SortedUsingDeclarations.erase(
134f09c4285SKrasimir Georgiev       std::unique(SortedUsingDeclarations.begin(),
135f09c4285SKrasimir Georgiev                   SortedUsingDeclarations.end(),
136f09c4285SKrasimir Georgiev                   [](const UsingDeclaration &a, const UsingDeclaration &b) {
137f09c4285SKrasimir Georgiev                     return a.Label == b.Label;
138f09c4285SKrasimir Georgiev                   }),
139f09c4285SKrasimir Georgiev       SortedUsingDeclarations.end());
140b03877abSKrasimir Georgiev   for (size_t I = 0, E = UsingDeclarations->size(); I < E; ++I) {
141f09c4285SKrasimir Georgiev     if (I >= SortedUsingDeclarations.size()) {
142f09c4285SKrasimir Georgiev       // This using declaration has been deduplicated, delete it.
143f09c4285SKrasimir Georgiev       auto Begin =
144f09c4285SKrasimir Georgiev           (*UsingDeclarations)[I].Line->First->WhitespaceRange.getBegin();
145f09c4285SKrasimir Georgiev       auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
146f09c4285SKrasimir Georgiev       auto Range = CharSourceRange::getCharRange(Begin, End);
147f09c4285SKrasimir Georgiev       auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, ""));
148f09c4285SKrasimir Georgiev       if (Err) {
149f09c4285SKrasimir Georgiev         llvm::errs() << "Error while sorting using declarations: "
150f09c4285SKrasimir Georgiev                      << llvm::toString(std::move(Err)) << "\n";
151f09c4285SKrasimir Georgiev       }
152f09c4285SKrasimir Georgiev       continue;
153f09c4285SKrasimir Georgiev     }
154b03877abSKrasimir Georgiev     if ((*UsingDeclarations)[I].Line == SortedUsingDeclarations[I].Line)
155b03877abSKrasimir Georgiev       continue;
156b03877abSKrasimir Georgiev     auto Begin = (*UsingDeclarations)[I].Line->First->Tok.getLocation();
157b03877abSKrasimir Georgiev     auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
158b03877abSKrasimir Georgiev     auto SortedBegin =
159b03877abSKrasimir Georgiev         SortedUsingDeclarations[I].Line->First->Tok.getLocation();
160b03877abSKrasimir Georgiev     auto SortedEnd = SortedUsingDeclarations[I].Line->Last->Tok.getEndLoc();
161b03877abSKrasimir Georgiev     StringRef Text(SourceMgr.getCharacterData(SortedBegin),
162b03877abSKrasimir Georgiev                    SourceMgr.getCharacterData(SortedEnd) -
163b03877abSKrasimir Georgiev                        SourceMgr.getCharacterData(SortedBegin));
164b03877abSKrasimir Georgiev     DEBUG({
165b03877abSKrasimir Georgiev       StringRef OldText(SourceMgr.getCharacterData(Begin),
166b03877abSKrasimir Georgiev                         SourceMgr.getCharacterData(End) -
167b03877abSKrasimir Georgiev                             SourceMgr.getCharacterData(Begin));
168b03877abSKrasimir Georgiev       llvm::dbgs() << "Replacing '" << OldText << "' with '" << Text << "'\n";
169b03877abSKrasimir Georgiev     });
170b03877abSKrasimir Georgiev     auto Range = CharSourceRange::getCharRange(Begin, End);
171b03877abSKrasimir Georgiev     auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, Text));
172b03877abSKrasimir Georgiev     if (Err) {
173b03877abSKrasimir Georgiev       llvm::errs() << "Error while sorting using declarations: "
174b03877abSKrasimir Georgiev                    << llvm::toString(std::move(Err)) << "\n";
175b03877abSKrasimir Georgiev     }
176b03877abSKrasimir Georgiev   }
177b03877abSKrasimir Georgiev   UsingDeclarations->clear();
178b03877abSKrasimir Georgiev }
179b03877abSKrasimir Georgiev 
180b03877abSKrasimir Georgiev } // namespace
181b03877abSKrasimir Georgiev 
182b03877abSKrasimir Georgiev UsingDeclarationsSorter::UsingDeclarationsSorter(const Environment &Env,
183b03877abSKrasimir Georgiev                                                  const FormatStyle &Style)
184b03877abSKrasimir Georgiev     : TokenAnalyzer(Env, Style) {}
185b03877abSKrasimir Georgiev 
1869ad83fe7SKrasimir Georgiev std::pair<tooling::Replacements, unsigned> UsingDeclarationsSorter::analyze(
187b03877abSKrasimir Georgiev     TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
188b03877abSKrasimir Georgiev     FormatTokenLexer &Tokens) {
189b03877abSKrasimir Georgiev   const SourceManager &SourceMgr = Env.getSourceManager();
190*0dddcf78SManuel Klimek   AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
191b03877abSKrasimir Georgiev   tooling::Replacements Fixes;
192b03877abSKrasimir Georgiev   SmallVector<UsingDeclaration, 4> UsingDeclarations;
193b03877abSKrasimir Georgiev   for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) {
194028d815eSDaniel Jasper     const auto *FirstTok = AnnotatedLines[I]->First;
1959da65aa8SKrasimir Georgiev     if (AnnotatedLines[I]->InPPDirective ||
196028d815eSDaniel Jasper         !AnnotatedLines[I]->startsWith(tok::kw_using) || FirstTok->Finalized) {
197b03877abSKrasimir Georgiev       endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
198b03877abSKrasimir Georgiev       continue;
199b03877abSKrasimir Georgiev     }
200028d815eSDaniel Jasper     if (FirstTok->NewlinesBefore > 1)
201b03877abSKrasimir Georgiev       endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
202028d815eSDaniel Jasper     const auto *UsingTok =
203028d815eSDaniel Jasper         FirstTok->is(tok::comment) ? FirstTok->getNextNonComment() : FirstTok;
204028d815eSDaniel Jasper     std::string Label = computeUsingDeclarationLabel(UsingTok);
205b03877abSKrasimir Georgiev     if (Label.empty()) {
206b03877abSKrasimir Georgiev       endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
207b03877abSKrasimir Georgiev       continue;
208b03877abSKrasimir Georgiev     }
209b03877abSKrasimir Georgiev     UsingDeclarations.push_back(UsingDeclaration(AnnotatedLines[I], Label));
210b03877abSKrasimir Georgiev   }
211b03877abSKrasimir Georgiev   endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
2129ad83fe7SKrasimir Georgiev   return {Fixes, 0};
213b03877abSKrasimir Georgiev }
214b03877abSKrasimir Georgiev 
215b03877abSKrasimir Georgiev } // namespace format
216b03877abSKrasimir Georgiev } // namespace clang
217