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