clang  5.0.0
UsingDeclarationsSorter.cpp
Go to the documentation of this file.
1 //===--- UsingDeclarationsSorter.cpp ----------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief This file implements UsingDeclarationsSorter, a TokenAnalyzer that
12 /// sorts consecutive using declarations.
13 ///
14 //===----------------------------------------------------------------------===//
15 
17 #include "llvm/Support/Debug.h"
18 #include "llvm/Support/Regex.h"
19 
20 #include <algorithm>
21 
22 #define DEBUG_TYPE "using-declarations-sorter"
23 
24 namespace clang {
25 namespace format {
26 
27 namespace {
28 
29 struct UsingDeclaration {
30  const AnnotatedLine *Line;
31  std::string Label;
32 
33  UsingDeclaration(const AnnotatedLine *Line, const std::string &Label)
34  : Line(Line), Label(Label) {}
35 
36  bool operator<(const UsingDeclaration &Other) const {
37  return Label < Other.Label;
38  }
39 };
40 
41 /// Computes the label of a using declaration starting at tthe using token
42 /// \p UsingTok.
43 /// If \p UsingTok doesn't begin a using declaration, returns the empty string.
44 /// Note that this detects specifically using declarations, as in:
45 /// using A::B::C;
46 /// and not type aliases, as in:
47 /// using A = B::C;
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");
51  std::string Label;
52  const FormatToken *Tok = UsingTok->Next;
53  if (Tok && Tok->is(tok::kw_typename)) {
54  Label.append("typename ");
55  Tok = Tok->Next;
56  }
57  if (Tok && Tok->is(tok::coloncolon)) {
58  Label.append("::");
59  Tok = Tok->Next;
60  }
61  bool HasIdentifier = false;
62  while (Tok && Tok->is(tok::identifier)) {
63  HasIdentifier = true;
64  Label.append(Tok->TokenText.str());
65  Tok = Tok->Next;
66  if (!Tok || Tok->isNot(tok::coloncolon))
67  break;
68  Label.append("::");
69  Tok = Tok->Next;
70  }
71  if (HasIdentifier && Tok && Tok->isOneOf(tok::semi, tok::comma))
72  return Label;
73  return "";
74 }
75 
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)
84  continue;
85  auto Begin = (*UsingDeclarations)[I].Line->First->Tok.getLocation();
86  auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
87  auto SortedBegin =
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));
93  DEBUG({
94  StringRef OldText(SourceMgr.getCharacterData(Begin),
95  SourceMgr.getCharacterData(End) -
96  SourceMgr.getCharacterData(Begin));
97  llvm::dbgs() << "Replacing '" << OldText << "' with '" << Text << "'\n";
98  });
100  auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, Text));
101  if (Err) {
102  llvm::errs() << "Error while sorting using declarations: "
103  << llvm::toString(std::move(Err)) << "\n";
104  }
105  }
106  UsingDeclarations->clear();
107 }
108 
109 } // namespace
110 
112  const FormatStyle &Style)
113  : TokenAnalyzer(Env, Style) {}
114 
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);
128  continue;
129  }
130  if (AnnotatedLines[I]->First->NewlinesBefore > 1)
131  endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
132  std::string Label = computeUsingDeclarationLabel(AnnotatedLines[I]->First);
133  if (Label.empty()) {
134  endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
135  continue;
136  }
137  UsingDeclarations.push_back(UsingDeclaration(AnnotatedLines[I], Label));
138  }
139  endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
140  return Fixes;
141 }
142 
143 } // namespace format
144 } // namespace clang
UsingDeclarationsSorter(const Environment &Env, const FormatStyle &Style)
Maintains a set of replacements that are conflict-free.
Definition: Replacement.h:205
AffectedRangeManager AffectedRangeMgr
Definition: TokenAnalyzer.h:95
const Environment & Env
Definition: TokenAnalyzer.h:93
detail::InMemoryDirectory::const_iterator I
const SmallVectorImpl< AnnotatedLine * > & AnnotatedLines
const SmallVectorImpl< AnnotatedLine * >::const_iterator End
bool computeAffectedLines(SmallVectorImpl< AnnotatedLine * >::iterator I, SmallVectorImpl< AnnotatedLine * >::iterator E)
Determines extra information about the tokens comprising an UnwrappedLine.
std::string Label
const AnnotatedLine * Line
SourceLocation Begin
static CharSourceRange getCharRange(SourceRange R)
ArrayRef< FormatToken * > Tokens
tooling::Replacements analyze(TokenAnnotator &Annotator, SmallVectorImpl< AnnotatedLine * > &AnnotatedLines, FormatTokenLexer &Tokens) override
The FormatStyle is used to configure the formatting to follow specific guidelines.
Definition: Format.h:46
const SourceManager & getSourceManager() const
Definition: TokenAnalyzer.h:60
bool operator<(const JsModuleReference &LHS, const JsModuleReference &RHS)
detail::InMemoryDirectory::const_iterator E
SourceMgr(SourceMgr)
std::string toString(const til::SExpr *E)
const Expr * Replacement
Definition: AttributeList.h:59
StringRef Text
Definition: Format.cpp:1302
This file declares UsingDeclarationsSorter, a TokenAnalyzer that sorts consecutive using declarations...
This class handles loading and caching of source files into memory.