blob: 04fdb8cd3cbacf3b8a0b87e1dc969f89c3f2be34 [file] [log] [blame]
Haojian Wuada28622016-10-17 08:33:59 +00001//===---------- NamespaceAliaser.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
10#include "NamespaceAliaser.h"
11
12#include "ASTUtils.h"
13#include "clang/ASTMatchers/ASTMatchFinder.h"
14#include "clang/ASTMatchers/ASTMatchers.h"
15#include "clang/Lex/Lexer.h"
16namespace clang {
17namespace tidy {
18namespace utils {
19
20using namespace ast_matchers;
21
22NamespaceAliaser::NamespaceAliaser(const SourceManager &SourceMgr)
23 : SourceMgr(SourceMgr) {}
24
25AST_MATCHER_P(NamespaceAliasDecl, hasTargetNamespace,
26 ast_matchers::internal::Matcher<NamespaceDecl>, innerMatcher) {
27 return innerMatcher.matches(*Node.getNamespace(), Finder, Builder);
28}
29
30Optional<FixItHint>
31NamespaceAliaser::createAlias(ASTContext &Context, const Stmt &Statement,
32 StringRef Namespace,
33 const std::vector<std::string> &Abbreviations) {
34 const FunctionDecl *Function = getSurroundingFunction(Context, Statement);
35 if (!Function || !Function->hasBody())
36 return None;
37
38
39 if (AddedAliases[Function].count(Namespace.str()) != 0)
40 return None;
41
42
43 // FIXME: Doesn't consider the order of declarations.
44 // If we accidentially pick an alias defined later in the function,
45 // the output won't compile.
46 // FIXME: Also doesn't consider file or class-scope aliases.
47
48 const auto *ExistingAlias = selectFirst<NamedDecl>(
49 "alias",
50 match(functionDecl(hasBody(compoundStmt(has(declStmt(
51 has(namespaceAliasDecl(hasTargetNamespace(hasName(Namespace)))
52 .bind("alias"))))))),
53 *Function, Context));
54
55 if (ExistingAlias != nullptr) {
56 AddedAliases[Function][Namespace.str()] = ExistingAlias->getName().str();
57 return None;
58 }
59
60 for (const auto &Abbreviation : Abbreviations) {
61 DeclarationMatcher ConflictMatcher = namedDecl(hasName(Abbreviation));
62 const auto HasConflictingChildren =
63 !match(findAll(ConflictMatcher), *Function, Context).empty();
64 const auto HasConflictingAncestors =
65 !match(functionDecl(hasAncestor(decl(has(ConflictMatcher)))), *Function,
66 Context)
67 .empty();
68 if (HasConflictingAncestors || HasConflictingChildren)
69 continue;
70
71 std::string Declaration =
72 (llvm::Twine("\nnamespace ") + Abbreviation + " = " + Namespace + ";")
73 .str();
74 SourceLocation Loc =
75 Lexer::getLocForEndOfToken(Function->getBody()->getLocStart(), 0,
76 SourceMgr, Context.getLangOpts());
77 AddedAliases[Function][Namespace.str()] = Abbreviation;
78 return FixItHint::CreateInsertion(Loc, Declaration);
79 }
80
81 return None;
82}
83
84std::string NamespaceAliaser::getNamespaceName(ASTContext &Context,
85 const Stmt &Statement,
86 StringRef Namespace) const {
87 const auto *Function = getSurroundingFunction(Context, Statement);
88 auto FunctionAliases = AddedAliases.find(Function);
89 if (FunctionAliases != AddedAliases.end()) {
90 if (FunctionAliases->second.count(Namespace) != 0) {
91 return FunctionAliases->second.find(Namespace)->getValue();
92 }
93 }
94 return Namespace.str();
95}
96
97} // namespace utils
98} // namespace tidy
99} // namespace clang