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