diff options
Diffstat (limited to 'clang-tools-extra/clang-tidy/utils/NamespaceAliaser.cpp')
-rw-r--r-- | clang-tools-extra/clang-tidy/utils/NamespaceAliaser.cpp | 99 |
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 |