1 //===--- UsingDeclarationsSorter.cpp ----------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// \brief This file implements UsingDeclarationsSorter, a TokenAnalyzer that
12 /// sorts consecutive using declarations.
14 //===----------------------------------------------------------------------===//
16 #include "UsingDeclarationsSorter.h"
17 #include "llvm/Support/Debug.h"
18 #include "llvm/Support/Regex.h"
22 #define DEBUG_TYPE "using-declarations-sorter"
29 struct UsingDeclaration {
30 const AnnotatedLine *Line;
33 UsingDeclaration(const AnnotatedLine *Line, const std::string &Label)
34 : Line(Line), Label(Label) {}
36 bool operator<(const UsingDeclaration &Other) const {
37 return Label < Other.Label;
41 /// Computes the label of a using declaration starting at tthe using token
43 /// If \p UsingTok doesn't begin a using declaration, returns the empty string.
44 /// Note that this detects specifically using declarations, as in:
46 /// and not type aliases, as in:
48 /// Type aliases are in general not safe to permute.
49 std::string computeUsingDeclarationLabel(const FormatToken *UsingTok) {
50 assert(UsingTok && UsingTok->is(tok::kw_using) && "Expecting a using token");
52 const FormatToken *Tok = UsingTok->Next;
53 if (Tok && Tok->is(tok::kw_typename)) {
54 Label.append("typename ");
57 if (Tok && Tok->is(tok::coloncolon)) {
61 bool HasIdentifier = false;
62 while (Tok && Tok->is(tok::identifier)) {
64 Label.append(Tok->TokenText.str());
66 if (!Tok || Tok->isNot(tok::coloncolon))
71 if (HasIdentifier && Tok && Tok->isOneOf(tok::semi, tok::comma))
76 void endUsingDeclarationBlock(
77 SmallVectorImpl<UsingDeclaration> *UsingDeclarations,
78 const SourceManager &SourceMgr, tooling::Replacements *Fixes) {
79 SmallVector<UsingDeclaration, 4> SortedUsingDeclarations(
80 UsingDeclarations->begin(), UsingDeclarations->end());
81 std::sort(SortedUsingDeclarations.begin(), SortedUsingDeclarations.end());
82 for (size_t I = 0, E = UsingDeclarations->size(); I < E; ++I) {
83 if ((*UsingDeclarations)[I].Line == SortedUsingDeclarations[I].Line)
85 auto Begin = (*UsingDeclarations)[I].Line->First->Tok.getLocation();
86 auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
88 SortedUsingDeclarations[I].Line->First->Tok.getLocation();
89 auto SortedEnd = SortedUsingDeclarations[I].Line->Last->Tok.getEndLoc();
90 StringRef Text(SourceMgr.getCharacterData(SortedBegin),
91 SourceMgr.getCharacterData(SortedEnd) -
92 SourceMgr.getCharacterData(SortedBegin));
94 StringRef OldText(SourceMgr.getCharacterData(Begin),
95 SourceMgr.getCharacterData(End) -
96 SourceMgr.getCharacterData(Begin));
97 llvm::dbgs() << "Replacing '" << OldText << "' with '" << Text << "'\n";
99 auto Range = CharSourceRange::getCharRange(Begin, End);
100 auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, Text));
102 llvm::errs() << "Error while sorting using declarations: "
103 << llvm::toString(std::move(Err)) << "\n";
106 UsingDeclarations->clear();
111 UsingDeclarationsSorter::UsingDeclarationsSorter(const Environment &Env,
112 const FormatStyle &Style)
113 : TokenAnalyzer(Env, Style) {}
115 tooling::Replacements UsingDeclarationsSorter::analyze(
116 TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
117 FormatTokenLexer &Tokens) {
118 const SourceManager &SourceMgr = Env.getSourceManager();
119 AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
120 AnnotatedLines.end());
121 tooling::Replacements Fixes;
122 SmallVector<UsingDeclaration, 4> UsingDeclarations;
123 for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) {
124 if (!AnnotatedLines[I]->Affected || AnnotatedLines[I]->InPPDirective ||
125 !AnnotatedLines[I]->startsWith(tok::kw_using) ||
126 AnnotatedLines[I]->First->Finalized) {
127 endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
130 if (AnnotatedLines[I]->First->NewlinesBefore > 1)
131 endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
132 std::string Label = computeUsingDeclarationLabel(AnnotatedLines[I]->First);
134 endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
137 UsingDeclarations.push_back(UsingDeclaration(AnnotatedLines[I], Label));
139 endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
143 } // namespace format