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"
160b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
170b57cec5SDimitry Andric #include "llvm/Support/Regex.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric #include <algorithm>
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric #define DEBUG_TYPE "using-declarations-sorter"
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric namespace clang {
240b57cec5SDimitry Andric namespace format {
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric namespace {
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric // The order of using declaration is defined as follows:
290b57cec5SDimitry Andric // Split the strings by "::" and discard any initial empty strings. The last
300b57cec5SDimitry Andric // element of each list is a non-namespace name; all others are namespace
310b57cec5SDimitry Andric // names. Sort the lists of names lexicographically, where the sort order of
320b57cec5SDimitry Andric // individual names is that all non-namespace names come before all namespace
330b57cec5SDimitry Andric // names, and within those groups, names are in case-insensitive lexicographic
340b57cec5SDimitry Andric // order.
compareLabels(StringRef A,StringRef B)350b57cec5SDimitry Andric int compareLabels(StringRef A, StringRef B) {
360b57cec5SDimitry Andric   SmallVector<StringRef, 2> NamesA;
370b57cec5SDimitry Andric   A.split(NamesA, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
380b57cec5SDimitry Andric   SmallVector<StringRef, 2> NamesB;
390b57cec5SDimitry Andric   B.split(NamesB, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
400b57cec5SDimitry Andric   size_t SizeA = NamesA.size();
410b57cec5SDimitry Andric   size_t SizeB = NamesB.size();
420b57cec5SDimitry Andric   for (size_t I = 0, E = std::min(SizeA, SizeB); I < E; ++I) {
430b57cec5SDimitry Andric     if (I + 1 == SizeA) {
440b57cec5SDimitry Andric       // I is the last index of NamesA and NamesA[I] is a non-namespace name.
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric       // Non-namespace names come before all namespace names.
470b57cec5SDimitry Andric       if (SizeB > SizeA)
480b57cec5SDimitry Andric         return -1;
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric       // Two names within a group compare case-insensitively.
51*5f7ddb14SDimitry Andric       return NamesA[I].compare_insensitive(NamesB[I]);
520b57cec5SDimitry Andric     }
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric     // I is the last index of NamesB and NamesB[I] is a non-namespace name.
550b57cec5SDimitry Andric     // Non-namespace names come before all namespace names.
560b57cec5SDimitry Andric     if (I + 1 == SizeB)
570b57cec5SDimitry Andric       return 1;
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric     // Two namespaces names within a group compare case-insensitively.
60*5f7ddb14SDimitry Andric     int C = NamesA[I].compare_insensitive(NamesB[I]);
610b57cec5SDimitry Andric     if (C != 0)
620b57cec5SDimitry Andric       return C;
630b57cec5SDimitry Andric   }
640b57cec5SDimitry Andric   return 0;
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric struct UsingDeclaration {
680b57cec5SDimitry Andric   const AnnotatedLine *Line;
690b57cec5SDimitry Andric   std::string Label;
700b57cec5SDimitry Andric 
UsingDeclarationclang::format::__anonc1b1ed240111::UsingDeclaration710b57cec5SDimitry Andric   UsingDeclaration(const AnnotatedLine *Line, const std::string &Label)
720b57cec5SDimitry Andric       : Line(Line), Label(Label) {}
730b57cec5SDimitry Andric 
operator <clang::format::__anonc1b1ed240111::UsingDeclaration740b57cec5SDimitry Andric   bool operator<(const UsingDeclaration &Other) const {
750b57cec5SDimitry Andric     return compareLabels(Label, Other.Label) < 0;
760b57cec5SDimitry Andric   }
770b57cec5SDimitry Andric };
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric /// Computes the label of a using declaration starting at tthe using token
800b57cec5SDimitry Andric /// \p UsingTok.
810b57cec5SDimitry Andric /// If \p UsingTok doesn't begin a using declaration, returns the empty string.
820b57cec5SDimitry Andric /// Note that this detects specifically using declarations, as in:
830b57cec5SDimitry Andric /// using A::B::C;
840b57cec5SDimitry Andric /// and not type aliases, as in:
850b57cec5SDimitry Andric /// using A = B::C;
860b57cec5SDimitry Andric /// Type aliases are in general not safe to permute.
computeUsingDeclarationLabel(const FormatToken * UsingTok)870b57cec5SDimitry Andric std::string computeUsingDeclarationLabel(const FormatToken *UsingTok) {
880b57cec5SDimitry Andric   assert(UsingTok && UsingTok->is(tok::kw_using) && "Expecting a using token");
890b57cec5SDimitry Andric   std::string Label;
900b57cec5SDimitry Andric   const FormatToken *Tok = UsingTok->Next;
910b57cec5SDimitry Andric   if (Tok && Tok->is(tok::kw_typename)) {
920b57cec5SDimitry Andric     Label.append("typename ");
930b57cec5SDimitry Andric     Tok = Tok->Next;
940b57cec5SDimitry Andric   }
950b57cec5SDimitry Andric   if (Tok && Tok->is(tok::coloncolon)) {
960b57cec5SDimitry Andric     Label.append("::");
970b57cec5SDimitry Andric     Tok = Tok->Next;
980b57cec5SDimitry Andric   }
990b57cec5SDimitry Andric   bool HasIdentifier = false;
1000b57cec5SDimitry Andric   while (Tok && Tok->is(tok::identifier)) {
1010b57cec5SDimitry Andric     HasIdentifier = true;
1020b57cec5SDimitry Andric     Label.append(Tok->TokenText.str());
1030b57cec5SDimitry Andric     Tok = Tok->Next;
1040b57cec5SDimitry Andric     if (!Tok || Tok->isNot(tok::coloncolon))
1050b57cec5SDimitry Andric       break;
1060b57cec5SDimitry Andric     Label.append("::");
1070b57cec5SDimitry Andric     Tok = Tok->Next;
1080b57cec5SDimitry Andric   }
1090b57cec5SDimitry Andric   if (HasIdentifier && Tok && Tok->isOneOf(tok::semi, tok::comma))
1100b57cec5SDimitry Andric     return Label;
1110b57cec5SDimitry Andric   return "";
1120b57cec5SDimitry Andric }
1130b57cec5SDimitry Andric 
endUsingDeclarationBlock(SmallVectorImpl<UsingDeclaration> * UsingDeclarations,const SourceManager & SourceMgr,tooling::Replacements * Fixes)1140b57cec5SDimitry Andric void endUsingDeclarationBlock(
1150b57cec5SDimitry Andric     SmallVectorImpl<UsingDeclaration> *UsingDeclarations,
1160b57cec5SDimitry Andric     const SourceManager &SourceMgr, tooling::Replacements *Fixes) {
1170b57cec5SDimitry Andric   bool BlockAffected = false;
1180b57cec5SDimitry Andric   for (const UsingDeclaration &Declaration : *UsingDeclarations) {
1190b57cec5SDimitry Andric     if (Declaration.Line->Affected) {
1200b57cec5SDimitry Andric       BlockAffected = true;
1210b57cec5SDimitry Andric       break;
1220b57cec5SDimitry Andric     }
1230b57cec5SDimitry Andric   }
1240b57cec5SDimitry Andric   if (!BlockAffected) {
1250b57cec5SDimitry Andric     UsingDeclarations->clear();
1260b57cec5SDimitry Andric     return;
1270b57cec5SDimitry Andric   }
1280b57cec5SDimitry Andric   SmallVector<UsingDeclaration, 4> SortedUsingDeclarations(
1290b57cec5SDimitry Andric       UsingDeclarations->begin(), UsingDeclarations->end());
1300b57cec5SDimitry Andric   llvm::stable_sort(SortedUsingDeclarations);
1310b57cec5SDimitry Andric   SortedUsingDeclarations.erase(
1320b57cec5SDimitry Andric       std::unique(SortedUsingDeclarations.begin(),
1330b57cec5SDimitry Andric                   SortedUsingDeclarations.end(),
1340b57cec5SDimitry Andric                   [](const UsingDeclaration &a, const UsingDeclaration &b) {
1350b57cec5SDimitry Andric                     return a.Label == b.Label;
1360b57cec5SDimitry Andric                   }),
1370b57cec5SDimitry Andric       SortedUsingDeclarations.end());
1380b57cec5SDimitry Andric   for (size_t I = 0, E = UsingDeclarations->size(); I < E; ++I) {
1390b57cec5SDimitry Andric     if (I >= SortedUsingDeclarations.size()) {
1400b57cec5SDimitry Andric       // This using declaration has been deduplicated, delete it.
1410b57cec5SDimitry Andric       auto Begin =
1420b57cec5SDimitry Andric           (*UsingDeclarations)[I].Line->First->WhitespaceRange.getBegin();
1430b57cec5SDimitry Andric       auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
1440b57cec5SDimitry Andric       auto Range = CharSourceRange::getCharRange(Begin, End);
1450b57cec5SDimitry Andric       auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, ""));
1460b57cec5SDimitry Andric       if (Err) {
1470b57cec5SDimitry Andric         llvm::errs() << "Error while sorting using declarations: "
1480b57cec5SDimitry Andric                      << llvm::toString(std::move(Err)) << "\n";
1490b57cec5SDimitry Andric       }
1500b57cec5SDimitry Andric       continue;
1510b57cec5SDimitry Andric     }
1520b57cec5SDimitry Andric     if ((*UsingDeclarations)[I].Line == SortedUsingDeclarations[I].Line)
1530b57cec5SDimitry Andric       continue;
1540b57cec5SDimitry Andric     auto Begin = (*UsingDeclarations)[I].Line->First->Tok.getLocation();
1550b57cec5SDimitry Andric     auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
1560b57cec5SDimitry Andric     auto SortedBegin =
1570b57cec5SDimitry Andric         SortedUsingDeclarations[I].Line->First->Tok.getLocation();
1580b57cec5SDimitry Andric     auto SortedEnd = SortedUsingDeclarations[I].Line->Last->Tok.getEndLoc();
1590b57cec5SDimitry Andric     StringRef Text(SourceMgr.getCharacterData(SortedBegin),
1600b57cec5SDimitry Andric                    SourceMgr.getCharacterData(SortedEnd) -
1610b57cec5SDimitry Andric                        SourceMgr.getCharacterData(SortedBegin));
1620b57cec5SDimitry Andric     LLVM_DEBUG({
1630b57cec5SDimitry Andric       StringRef OldText(SourceMgr.getCharacterData(Begin),
1640b57cec5SDimitry Andric                         SourceMgr.getCharacterData(End) -
1650b57cec5SDimitry Andric                             SourceMgr.getCharacterData(Begin));
1660b57cec5SDimitry Andric       llvm::dbgs() << "Replacing '" << OldText << "' with '" << Text << "'\n";
1670b57cec5SDimitry Andric     });
1680b57cec5SDimitry Andric     auto Range = CharSourceRange::getCharRange(Begin, End);
1690b57cec5SDimitry Andric     auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, Text));
1700b57cec5SDimitry Andric     if (Err) {
1710b57cec5SDimitry Andric       llvm::errs() << "Error while sorting using declarations: "
1720b57cec5SDimitry Andric                    << llvm::toString(std::move(Err)) << "\n";
1730b57cec5SDimitry Andric     }
1740b57cec5SDimitry Andric   }
1750b57cec5SDimitry Andric   UsingDeclarations->clear();
1760b57cec5SDimitry Andric }
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric } // namespace
1790b57cec5SDimitry Andric 
UsingDeclarationsSorter(const Environment & Env,const FormatStyle & Style)1800b57cec5SDimitry Andric UsingDeclarationsSorter::UsingDeclarationsSorter(const Environment &Env,
1810b57cec5SDimitry Andric                                                  const FormatStyle &Style)
1820b57cec5SDimitry Andric     : TokenAnalyzer(Env, Style) {}
1830b57cec5SDimitry Andric 
analyze(TokenAnnotator & Annotator,SmallVectorImpl<AnnotatedLine * > & AnnotatedLines,FormatTokenLexer & Tokens)1840b57cec5SDimitry Andric std::pair<tooling::Replacements, unsigned> UsingDeclarationsSorter::analyze(
1850b57cec5SDimitry Andric     TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
1860b57cec5SDimitry Andric     FormatTokenLexer &Tokens) {
1870b57cec5SDimitry Andric   const SourceManager &SourceMgr = Env.getSourceManager();
1880b57cec5SDimitry Andric   AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
1890b57cec5SDimitry Andric   tooling::Replacements Fixes;
1900b57cec5SDimitry Andric   SmallVector<UsingDeclaration, 4> UsingDeclarations;
1910b57cec5SDimitry Andric   for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) {
1920b57cec5SDimitry Andric     const auto *FirstTok = AnnotatedLines[I]->First;
1930b57cec5SDimitry Andric     if (AnnotatedLines[I]->InPPDirective ||
1940b57cec5SDimitry Andric         !AnnotatedLines[I]->startsWith(tok::kw_using) || FirstTok->Finalized) {
1950b57cec5SDimitry Andric       endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
1960b57cec5SDimitry Andric       continue;
1970b57cec5SDimitry Andric     }
1980b57cec5SDimitry Andric     if (FirstTok->NewlinesBefore > 1)
1990b57cec5SDimitry Andric       endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
2000b57cec5SDimitry Andric     const auto *UsingTok =
2010b57cec5SDimitry Andric         FirstTok->is(tok::comment) ? FirstTok->getNextNonComment() : FirstTok;
2020b57cec5SDimitry Andric     std::string Label = computeUsingDeclarationLabel(UsingTok);
2030b57cec5SDimitry Andric     if (Label.empty()) {
2040b57cec5SDimitry Andric       endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
2050b57cec5SDimitry Andric       continue;
2060b57cec5SDimitry Andric     }
2070b57cec5SDimitry Andric     UsingDeclarations.push_back(UsingDeclaration(AnnotatedLines[I], Label));
2080b57cec5SDimitry Andric   }
2090b57cec5SDimitry Andric   endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
2100b57cec5SDimitry Andric   return {Fixes, 0};
2110b57cec5SDimitry Andric }
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric } // namespace format
2140b57cec5SDimitry Andric } // namespace clang
215