xref: /freebsd-src/contrib/llvm-project/clang/lib/Format/UsingDeclarationsSorter.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
10b57cec5SDimitry Andric //===--- UsingDeclarationsSorter.cpp ----------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// This file implements UsingDeclarationsSorter, a TokenAnalyzer that
110b57cec5SDimitry Andric /// sorts consecutive using declarations.
120b57cec5SDimitry Andric ///
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "UsingDeclarationsSorter.h"
16*bdd1243dSDimitry Andric #include "clang/Format/Format.h"
170b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
180b57cec5SDimitry Andric #include "llvm/Support/Regex.h"
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric #include <algorithm>
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric #define DEBUG_TYPE "using-declarations-sorter"
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric namespace clang {
250b57cec5SDimitry Andric namespace format {
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric namespace {
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric // The order of using declaration is defined as follows:
300b57cec5SDimitry Andric // Split the strings by "::" and discard any initial empty strings. The last
310b57cec5SDimitry Andric // element of each list is a non-namespace name; all others are namespace
320b57cec5SDimitry Andric // names. Sort the lists of names lexicographically, where the sort order of
330b57cec5SDimitry Andric // individual names is that all non-namespace names come before all namespace
340b57cec5SDimitry Andric // names, and within those groups, names are in case-insensitive lexicographic
350b57cec5SDimitry Andric // order.
compareLabelsLexicographicNumeric(StringRef A,StringRef B)36*bdd1243dSDimitry Andric int compareLabelsLexicographicNumeric(StringRef A, StringRef B) {
370b57cec5SDimitry Andric   SmallVector<StringRef, 2> NamesA;
380b57cec5SDimitry Andric   A.split(NamesA, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
390b57cec5SDimitry Andric   SmallVector<StringRef, 2> NamesB;
400b57cec5SDimitry Andric   B.split(NamesB, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
410b57cec5SDimitry Andric   size_t SizeA = NamesA.size();
420b57cec5SDimitry Andric   size_t SizeB = NamesB.size();
430b57cec5SDimitry Andric   for (size_t I = 0, E = std::min(SizeA, SizeB); I < E; ++I) {
440b57cec5SDimitry Andric     if (I + 1 == SizeA) {
450b57cec5SDimitry Andric       // I is the last index of NamesA and NamesA[I] is a non-namespace name.
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric       // Non-namespace names come before all namespace names.
480b57cec5SDimitry Andric       if (SizeB > SizeA)
490b57cec5SDimitry Andric         return -1;
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric       // Two names within a group compare case-insensitively.
52fe6060f1SDimitry Andric       return NamesA[I].compare_insensitive(NamesB[I]);
530b57cec5SDimitry Andric     }
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric     // I is the last index of NamesB and NamesB[I] is a non-namespace name.
560b57cec5SDimitry Andric     // Non-namespace names come before all namespace names.
570b57cec5SDimitry Andric     if (I + 1 == SizeB)
580b57cec5SDimitry Andric       return 1;
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric     // Two namespaces names within a group compare case-insensitively.
61fe6060f1SDimitry Andric     int C = NamesA[I].compare_insensitive(NamesB[I]);
620b57cec5SDimitry Andric     if (C != 0)
630b57cec5SDimitry Andric       return C;
640b57cec5SDimitry Andric   }
650b57cec5SDimitry Andric   return 0;
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric 
compareLabelsLexicographic(StringRef A,StringRef B)68*bdd1243dSDimitry Andric int compareLabelsLexicographic(StringRef A, StringRef B) {
69*bdd1243dSDimitry Andric   SmallVector<StringRef, 2> NamesA;
70*bdd1243dSDimitry Andric   A.split(NamesA, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
71*bdd1243dSDimitry Andric   SmallVector<StringRef, 2> NamesB;
72*bdd1243dSDimitry Andric   B.split(NamesB, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
73*bdd1243dSDimitry Andric   size_t SizeA = NamesA.size();
74*bdd1243dSDimitry Andric   size_t SizeB = NamesB.size();
75*bdd1243dSDimitry Andric   for (size_t I = 0, E = std::min(SizeA, SizeB); I < E; ++I) {
76*bdd1243dSDimitry Andric     // Two namespaces names within a group compare case-insensitively.
77*bdd1243dSDimitry Andric     int C = NamesA[I].compare_insensitive(NamesB[I]);
78*bdd1243dSDimitry Andric     if (C != 0)
79*bdd1243dSDimitry Andric       return C;
80*bdd1243dSDimitry Andric   }
81*bdd1243dSDimitry Andric   if (SizeA < SizeB)
82*bdd1243dSDimitry Andric     return -1;
83*bdd1243dSDimitry Andric   return SizeA == SizeB ? 0 : 1;
84*bdd1243dSDimitry Andric }
85*bdd1243dSDimitry Andric 
compareLabels(StringRef A,StringRef B,FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations)86*bdd1243dSDimitry Andric int compareLabels(
87*bdd1243dSDimitry Andric     StringRef A, StringRef B,
88*bdd1243dSDimitry Andric     FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations) {
89*bdd1243dSDimitry Andric   if (SortUsingDeclarations == FormatStyle::SUD_LexicographicNumeric)
90*bdd1243dSDimitry Andric     return compareLabelsLexicographicNumeric(A, B);
91*bdd1243dSDimitry Andric   return compareLabelsLexicographic(A, B);
92*bdd1243dSDimitry Andric }
93*bdd1243dSDimitry Andric 
940b57cec5SDimitry Andric struct UsingDeclaration {
950b57cec5SDimitry Andric   const AnnotatedLine *Line;
960b57cec5SDimitry Andric   std::string Label;
970b57cec5SDimitry Andric 
UsingDeclarationclang::format::__anon5801d5820111::UsingDeclaration980b57cec5SDimitry Andric   UsingDeclaration(const AnnotatedLine *Line, const std::string &Label)
990b57cec5SDimitry Andric       : Line(Line), Label(Label) {}
1000b57cec5SDimitry Andric };
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric /// Computes the label of a using declaration starting at tthe using token
1030b57cec5SDimitry Andric /// \p UsingTok.
1040b57cec5SDimitry Andric /// If \p UsingTok doesn't begin a using declaration, returns the empty string.
1050b57cec5SDimitry Andric /// Note that this detects specifically using declarations, as in:
1060b57cec5SDimitry Andric /// using A::B::C;
1070b57cec5SDimitry Andric /// and not type aliases, as in:
1080b57cec5SDimitry Andric /// using A = B::C;
1090b57cec5SDimitry Andric /// Type aliases are in general not safe to permute.
computeUsingDeclarationLabel(const FormatToken * UsingTok)1100b57cec5SDimitry Andric std::string computeUsingDeclarationLabel(const FormatToken *UsingTok) {
1110b57cec5SDimitry Andric   assert(UsingTok && UsingTok->is(tok::kw_using) && "Expecting a using token");
1120b57cec5SDimitry Andric   std::string Label;
1130b57cec5SDimitry Andric   const FormatToken *Tok = UsingTok->Next;
1140b57cec5SDimitry Andric   if (Tok && Tok->is(tok::kw_typename)) {
1150b57cec5SDimitry Andric     Label.append("typename ");
1160b57cec5SDimitry Andric     Tok = Tok->Next;
1170b57cec5SDimitry Andric   }
1180b57cec5SDimitry Andric   if (Tok && Tok->is(tok::coloncolon)) {
1190b57cec5SDimitry Andric     Label.append("::");
1200b57cec5SDimitry Andric     Tok = Tok->Next;
1210b57cec5SDimitry Andric   }
1220b57cec5SDimitry Andric   bool HasIdentifier = false;
1230b57cec5SDimitry Andric   while (Tok && Tok->is(tok::identifier)) {
1240b57cec5SDimitry Andric     HasIdentifier = true;
1250b57cec5SDimitry Andric     Label.append(Tok->TokenText.str());
1260b57cec5SDimitry Andric     Tok = Tok->Next;
1270b57cec5SDimitry Andric     if (!Tok || Tok->isNot(tok::coloncolon))
1280b57cec5SDimitry Andric       break;
1290b57cec5SDimitry Andric     Label.append("::");
1300b57cec5SDimitry Andric     Tok = Tok->Next;
1310b57cec5SDimitry Andric   }
1320b57cec5SDimitry Andric   if (HasIdentifier && Tok && Tok->isOneOf(tok::semi, tok::comma))
1330b57cec5SDimitry Andric     return Label;
1340b57cec5SDimitry Andric   return "";
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric 
endUsingDeclarationBlock(SmallVectorImpl<UsingDeclaration> * UsingDeclarations,const SourceManager & SourceMgr,tooling::Replacements * Fixes,FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations)1370b57cec5SDimitry Andric void endUsingDeclarationBlock(
1380b57cec5SDimitry Andric     SmallVectorImpl<UsingDeclaration> *UsingDeclarations,
139*bdd1243dSDimitry Andric     const SourceManager &SourceMgr, tooling::Replacements *Fixes,
140*bdd1243dSDimitry Andric     FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations) {
1410b57cec5SDimitry Andric   bool BlockAffected = false;
1420b57cec5SDimitry Andric   for (const UsingDeclaration &Declaration : *UsingDeclarations) {
1430b57cec5SDimitry Andric     if (Declaration.Line->Affected) {
1440b57cec5SDimitry Andric       BlockAffected = true;
1450b57cec5SDimitry Andric       break;
1460b57cec5SDimitry Andric     }
1470b57cec5SDimitry Andric   }
1480b57cec5SDimitry Andric   if (!BlockAffected) {
1490b57cec5SDimitry Andric     UsingDeclarations->clear();
1500b57cec5SDimitry Andric     return;
1510b57cec5SDimitry Andric   }
1520b57cec5SDimitry Andric   SmallVector<UsingDeclaration, 4> SortedUsingDeclarations(
1530b57cec5SDimitry Andric       UsingDeclarations->begin(), UsingDeclarations->end());
154*bdd1243dSDimitry Andric   auto Comp = [SortUsingDeclarations](const UsingDeclaration &Lhs,
155*bdd1243dSDimitry Andric                                       const UsingDeclaration &Rhs) -> bool {
156*bdd1243dSDimitry Andric     return compareLabels(Lhs.Label, Rhs.Label, SortUsingDeclarations) < 0;
157*bdd1243dSDimitry Andric   };
158*bdd1243dSDimitry Andric   llvm::stable_sort(SortedUsingDeclarations, Comp);
1590b57cec5SDimitry Andric   SortedUsingDeclarations.erase(
1600b57cec5SDimitry Andric       std::unique(SortedUsingDeclarations.begin(),
1610b57cec5SDimitry Andric                   SortedUsingDeclarations.end(),
1620b57cec5SDimitry Andric                   [](const UsingDeclaration &a, const UsingDeclaration &b) {
1630b57cec5SDimitry Andric                     return a.Label == b.Label;
1640b57cec5SDimitry Andric                   }),
1650b57cec5SDimitry Andric       SortedUsingDeclarations.end());
1660b57cec5SDimitry Andric   for (size_t I = 0, E = UsingDeclarations->size(); I < E; ++I) {
1670b57cec5SDimitry Andric     if (I >= SortedUsingDeclarations.size()) {
1680b57cec5SDimitry Andric       // This using declaration has been deduplicated, delete it.
1690b57cec5SDimitry Andric       auto Begin =
1700b57cec5SDimitry Andric           (*UsingDeclarations)[I].Line->First->WhitespaceRange.getBegin();
1710b57cec5SDimitry Andric       auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
1720b57cec5SDimitry Andric       auto Range = CharSourceRange::getCharRange(Begin, End);
1730b57cec5SDimitry Andric       auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, ""));
1740b57cec5SDimitry Andric       if (Err) {
1750b57cec5SDimitry Andric         llvm::errs() << "Error while sorting using declarations: "
1760b57cec5SDimitry Andric                      << llvm::toString(std::move(Err)) << "\n";
1770b57cec5SDimitry Andric       }
1780b57cec5SDimitry Andric       continue;
1790b57cec5SDimitry Andric     }
1800b57cec5SDimitry Andric     if ((*UsingDeclarations)[I].Line == SortedUsingDeclarations[I].Line)
1810b57cec5SDimitry Andric       continue;
1820b57cec5SDimitry Andric     auto Begin = (*UsingDeclarations)[I].Line->First->Tok.getLocation();
1830b57cec5SDimitry Andric     auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
1840b57cec5SDimitry Andric     auto SortedBegin =
1850b57cec5SDimitry Andric         SortedUsingDeclarations[I].Line->First->Tok.getLocation();
1860b57cec5SDimitry Andric     auto SortedEnd = SortedUsingDeclarations[I].Line->Last->Tok.getEndLoc();
1870b57cec5SDimitry Andric     StringRef Text(SourceMgr.getCharacterData(SortedBegin),
1880b57cec5SDimitry Andric                    SourceMgr.getCharacterData(SortedEnd) -
1890b57cec5SDimitry Andric                        SourceMgr.getCharacterData(SortedBegin));
1900b57cec5SDimitry Andric     LLVM_DEBUG({
1910b57cec5SDimitry Andric       StringRef OldText(SourceMgr.getCharacterData(Begin),
1920b57cec5SDimitry Andric                         SourceMgr.getCharacterData(End) -
1930b57cec5SDimitry Andric                             SourceMgr.getCharacterData(Begin));
1940b57cec5SDimitry Andric       llvm::dbgs() << "Replacing '" << OldText << "' with '" << Text << "'\n";
1950b57cec5SDimitry Andric     });
1960b57cec5SDimitry Andric     auto Range = CharSourceRange::getCharRange(Begin, End);
1970b57cec5SDimitry Andric     auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, Text));
1980b57cec5SDimitry Andric     if (Err) {
1990b57cec5SDimitry Andric       llvm::errs() << "Error while sorting using declarations: "
2000b57cec5SDimitry Andric                    << llvm::toString(std::move(Err)) << "\n";
2010b57cec5SDimitry Andric     }
2020b57cec5SDimitry Andric   }
2030b57cec5SDimitry Andric   UsingDeclarations->clear();
2040b57cec5SDimitry Andric }
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric } // namespace
2070b57cec5SDimitry Andric 
UsingDeclarationsSorter(const Environment & Env,const FormatStyle & Style)2080b57cec5SDimitry Andric UsingDeclarationsSorter::UsingDeclarationsSorter(const Environment &Env,
2090b57cec5SDimitry Andric                                                  const FormatStyle &Style)
2100b57cec5SDimitry Andric     : TokenAnalyzer(Env, Style) {}
2110b57cec5SDimitry Andric 
analyze(TokenAnnotator & Annotator,SmallVectorImpl<AnnotatedLine * > & AnnotatedLines,FormatTokenLexer & Tokens)2120b57cec5SDimitry Andric std::pair<tooling::Replacements, unsigned> UsingDeclarationsSorter::analyze(
2130b57cec5SDimitry Andric     TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
2140b57cec5SDimitry Andric     FormatTokenLexer &Tokens) {
2150b57cec5SDimitry Andric   const SourceManager &SourceMgr = Env.getSourceManager();
2160b57cec5SDimitry Andric   AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
2170b57cec5SDimitry Andric   tooling::Replacements Fixes;
2180b57cec5SDimitry Andric   SmallVector<UsingDeclaration, 4> UsingDeclarations;
2191fd87a68SDimitry Andric   for (const AnnotatedLine *Line : AnnotatedLines) {
2201fd87a68SDimitry Andric     const auto *FirstTok = Line->First;
2211fd87a68SDimitry Andric     if (Line->InPPDirective || !Line->startsWith(tok::kw_using) ||
2221fd87a68SDimitry Andric         FirstTok->Finalized) {
223*bdd1243dSDimitry Andric       endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
224*bdd1243dSDimitry Andric                                Style.SortUsingDeclarations);
2250b57cec5SDimitry Andric       continue;
2260b57cec5SDimitry Andric     }
227*bdd1243dSDimitry Andric     if (FirstTok->NewlinesBefore > 1) {
228*bdd1243dSDimitry Andric       endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
229*bdd1243dSDimitry Andric                                Style.SortUsingDeclarations);
230*bdd1243dSDimitry Andric     }
2310b57cec5SDimitry Andric     const auto *UsingTok =
2320b57cec5SDimitry Andric         FirstTok->is(tok::comment) ? FirstTok->getNextNonComment() : FirstTok;
2330b57cec5SDimitry Andric     std::string Label = computeUsingDeclarationLabel(UsingTok);
2340b57cec5SDimitry Andric     if (Label.empty()) {
235*bdd1243dSDimitry Andric       endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
236*bdd1243dSDimitry Andric                                Style.SortUsingDeclarations);
2370b57cec5SDimitry Andric       continue;
2380b57cec5SDimitry Andric     }
2391fd87a68SDimitry Andric     UsingDeclarations.push_back(UsingDeclaration(Line, Label));
2400b57cec5SDimitry Andric   }
241*bdd1243dSDimitry Andric   endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
242*bdd1243dSDimitry Andric                            Style.SortUsingDeclarations);
2430b57cec5SDimitry Andric   return {Fixes, 0};
2440b57cec5SDimitry Andric }
2450b57cec5SDimitry Andric 
2460b57cec5SDimitry Andric } // namespace format
2470b57cec5SDimitry Andric } // namespace clang
248