summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy/utils/NamespaceAliaser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clang-tidy/utils/NamespaceAliaser.cpp')
-rw-r--r--clang-tools-extra/clang-tidy/utils/NamespaceAliaser.cpp99
1 files changed, 99 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/utils/NamespaceAliaser.cpp b/clang-tools-extra/clang-tidy/utils/NamespaceAliaser.cpp
new file mode 100644
index 00000000000..04fdb8cd3cb
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/utils/NamespaceAliaser.cpp
@@ -0,0 +1,99 @@
+//===---------- NamespaceAliaser.cpp - clang-tidy -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NamespaceAliaser.h"
+
+#include "ASTUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+namespace clang {
+namespace tidy {
+namespace utils {
+
+using namespace ast_matchers;
+
+NamespaceAliaser::NamespaceAliaser(const SourceManager &SourceMgr)
+ : SourceMgr(SourceMgr) {}
+
+AST_MATCHER_P(NamespaceAliasDecl, hasTargetNamespace,
+ ast_matchers::internal::Matcher<NamespaceDecl>, innerMatcher) {
+ return innerMatcher.matches(*Node.getNamespace(), Finder, Builder);
+}
+
+Optional<FixItHint>
+NamespaceAliaser::createAlias(ASTContext &Context, const Stmt &Statement,
+ StringRef Namespace,
+ const std::vector<std::string> &Abbreviations) {
+ const FunctionDecl *Function = getSurroundingFunction(Context, Statement);
+ if (!Function || !Function->hasBody())
+ return None;
+
+
+ if (AddedAliases[Function].count(Namespace.str()) != 0)
+ return None;
+
+
+ // FIXME: Doesn't consider the order of declarations.
+ // If we accidentially pick an alias defined later in the function,
+ // the output won't compile.
+ // FIXME: Also doesn't consider file or class-scope aliases.
+
+ const auto *ExistingAlias = selectFirst<NamedDecl>(
+ "alias",
+ match(functionDecl(hasBody(compoundStmt(has(declStmt(
+ has(namespaceAliasDecl(hasTargetNamespace(hasName(Namespace)))
+ .bind("alias"))))))),
+ *Function, Context));
+
+ if (ExistingAlias != nullptr) {
+ AddedAliases[Function][Namespace.str()] = ExistingAlias->getName().str();
+ return None;
+ }
+
+ for (const auto &Abbreviation : Abbreviations) {
+ DeclarationMatcher ConflictMatcher = namedDecl(hasName(Abbreviation));
+ const auto HasConflictingChildren =
+ !match(findAll(ConflictMatcher), *Function, Context).empty();
+ const auto HasConflictingAncestors =
+ !match(functionDecl(hasAncestor(decl(has(ConflictMatcher)))), *Function,
+ Context)
+ .empty();
+ if (HasConflictingAncestors || HasConflictingChildren)
+ continue;
+
+ std::string Declaration =
+ (llvm::Twine("\nnamespace ") + Abbreviation + " = " + Namespace + ";")
+ .str();
+ SourceLocation Loc =
+ Lexer::getLocForEndOfToken(Function->getBody()->getLocStart(), 0,
+ SourceMgr, Context.getLangOpts());
+ AddedAliases[Function][Namespace.str()] = Abbreviation;
+ return FixItHint::CreateInsertion(Loc, Declaration);
+ }
+
+ return None;
+}
+
+std::string NamespaceAliaser::getNamespaceName(ASTContext &Context,
+ const Stmt &Statement,
+ StringRef Namespace) const {
+ const auto *Function = getSurroundingFunction(Context, Statement);
+ auto FunctionAliases = AddedAliases.find(Function);
+ if (FunctionAliases != AddedAliases.end()) {
+ if (FunctionAliases->second.count(Namespace) != 0) {
+ return FunctionAliases->second.find(Namespace)->getValue();
+ }
+ }
+ return Namespace.str();
+}
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
OpenPOWER on IntegriCloud