clang-tools  8.0.0
ConcatNestedNamespacesCheck.cpp
Go to the documentation of this file.
1 //===--- ConcatNestedNamespacesCheck.cpp - clang-tidy----------------------===//
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 
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include <algorithm>
14 #include <iterator>
15 
16 namespace clang {
17 namespace tidy {
18 namespace modernize {
19 
20 static bool locationsInSameFile(const SourceManager &Sources,
21  SourceLocation Loc1, SourceLocation Loc2) {
22  return Loc1.isFileID() && Loc2.isFileID() &&
23  Sources.getFileID(Loc1) == Sources.getFileID(Loc2);
24 }
25 
26 static bool anonymousOrInlineNamespace(const NamespaceDecl &ND) {
27  return ND.isAnonymousNamespace() || ND.isInlineNamespace();
28 }
29 
30 static bool singleNamedNamespaceChild(const NamespaceDecl &ND) {
31  NamespaceDecl::decl_range Decls = ND.decls();
32  if (std::distance(Decls.begin(), Decls.end()) != 1)
33  return false;
34 
35  const auto *ChildNamespace = dyn_cast<const NamespaceDecl>(*Decls.begin());
36  return ChildNamespace && !anonymousOrInlineNamespace(*ChildNamespace);
37 }
38 
39 static bool alreadyConcatenated(std::size_t NumCandidates,
40  const SourceRange &ReplacementRange,
41  const SourceManager &Sources,
42  const LangOptions &LangOpts) {
43  CharSourceRange TextRange =
44  Lexer::getAsCharRange(ReplacementRange, Sources, LangOpts);
45  StringRef CurrentNamespacesText =
46  Lexer::getSourceText(TextRange, Sources, LangOpts);
47  return CurrentNamespacesText.count(':') == (NumCandidates - 1) * 2;
48 }
49 
50 ConcatNestedNamespacesCheck::NamespaceString
51 ConcatNestedNamespacesCheck::concatNamespaces() {
52  NamespaceString Result("namespace ");
53  Result.append(Namespaces.front()->getName());
54 
55  std::for_each(std::next(Namespaces.begin()), Namespaces.end(),
56  [&Result](const NamespaceDecl *ND) {
57  Result.append("::");
58  Result.append(ND->getName());
59  });
60 
61  return Result;
62 }
63 
65  ast_matchers::MatchFinder *Finder) {
66  if (!getLangOpts().CPlusPlus17)
67  return;
68 
69  Finder->addMatcher(ast_matchers::namespaceDecl().bind("namespace"), this);
70 }
71 
72 void ConcatNestedNamespacesCheck::reportDiagnostic(
73  const SourceRange &FrontReplacement, const SourceRange &BackReplacement) {
74  diag(Namespaces.front()->getBeginLoc(),
75  "nested namespaces can be concatenated", DiagnosticIDs::Warning)
76  << FixItHint::CreateReplacement(FrontReplacement, concatNamespaces())
77  << FixItHint::CreateReplacement(BackReplacement, "}");
78 }
79 
81  const ast_matchers::MatchFinder::MatchResult &Result) {
82  const NamespaceDecl &ND = *Result.Nodes.getNodeAs<NamespaceDecl>("namespace");
83  const SourceManager &Sources = *Result.SourceManager;
84 
85  if (!locationsInSameFile(Sources, ND.getBeginLoc(), ND.getRBraceLoc()))
86  return;
87 
88  if (!Sources.isInMainFile(ND.getBeginLoc()))
89  return;
90 
92  return;
93 
94  Namespaces.push_back(&ND);
95 
97  return;
98 
99  SourceRange FrontReplacement(Namespaces.front()->getBeginLoc(),
100  Namespaces.back()->getLocation());
101  SourceRange BackReplacement(Namespaces.back()->getRBraceLoc(),
102  Namespaces.front()->getRBraceLoc());
103 
104  if (!alreadyConcatenated(Namespaces.size(), FrontReplacement, Sources,
105  getLangOpts()))
106  reportDiagnostic(FrontReplacement, BackReplacement);
107 
108  Namespaces.clear();
109 }
110 
111 } // namespace modernize
112 } // namespace tidy
113 } // namespace clang
LangOptions getLangOpts() const
Returns the language options from the context.
Definition: ClangTidy.h:187
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
static bool alreadyConcatenated(std::size_t NumCandidates, const SourceRange &ReplacementRange, const SourceManager &Sources, const LangOptions &LangOpts)
static bool anonymousOrInlineNamespace(const NamespaceDecl &ND)
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static bool singleNamedNamespaceChild(const NamespaceDecl &ND)
static bool locationsInSameFile(const SourceManager &Sources, SourceLocation Loc1, SourceLocation Loc2)
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check&#39;s name.
Definition: ClangTidy.cpp:438
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.