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