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