NamespaceAliaser.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. //===---------- NamespaceAliaser.cpp - clang-tidy -------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "NamespaceAliaser.h"
  9. #include "ASTUtils.h"
  10. #include "clang/ASTMatchers/ASTMatchFinder.h"
  11. #include "clang/ASTMatchers/ASTMatchers.h"
  12. #include "clang/Lex/Lexer.h"
  13. #include <optional>
  14. namespace clang::tidy::utils {
  15. using namespace ast_matchers;
  16. NamespaceAliaser::NamespaceAliaser(const SourceManager &SourceMgr)
  17. : SourceMgr(SourceMgr) {}
  18. AST_MATCHER_P(NamespaceAliasDecl, hasTargetNamespace,
  19. ast_matchers::internal::Matcher<NamespaceDecl>, innerMatcher) {
  20. return innerMatcher.matches(*Node.getNamespace(), Finder, Builder);
  21. }
  22. std::optional<FixItHint>
  23. NamespaceAliaser::createAlias(ASTContext &Context, const Stmt &Statement,
  24. StringRef Namespace,
  25. const std::vector<std::string> &Abbreviations) {
  26. const FunctionDecl *Function = getSurroundingFunction(Context, Statement);
  27. if (!Function || !Function->hasBody())
  28. return std::nullopt;
  29. if (AddedAliases[Function].count(Namespace.str()) != 0)
  30. return std::nullopt;
  31. // FIXME: Doesn't consider the order of declarations.
  32. // If we accidentally pick an alias defined later in the function,
  33. // the output won't compile.
  34. // FIXME: Also doesn't consider file or class-scope aliases.
  35. const auto *ExistingAlias = selectFirst<NamedDecl>(
  36. "alias", match(functionDecl(hasBody(compoundStmt(has(declStmt(
  37. has(namespaceAliasDecl(hasTargetNamespace(hasName(
  38. std::string(Namespace))))
  39. .bind("alias"))))))),
  40. *Function, Context));
  41. if (ExistingAlias != nullptr) {
  42. AddedAliases[Function][Namespace.str()] = ExistingAlias->getName().str();
  43. return std::nullopt;
  44. }
  45. for (const auto &Abbreviation : Abbreviations) {
  46. DeclarationMatcher ConflictMatcher = namedDecl(hasName(Abbreviation));
  47. const auto HasConflictingChildren =
  48. !match(findAll(ConflictMatcher), *Function, Context).empty();
  49. const auto HasConflictingAncestors =
  50. !match(functionDecl(hasAncestor(decl(has(ConflictMatcher)))), *Function,
  51. Context)
  52. .empty();
  53. if (HasConflictingAncestors || HasConflictingChildren)
  54. continue;
  55. std::string Declaration =
  56. (llvm::Twine("\nnamespace ") + Abbreviation + " = " + Namespace + ";")
  57. .str();
  58. SourceLocation Loc =
  59. Lexer::getLocForEndOfToken(Function->getBody()->getBeginLoc(), 0,
  60. SourceMgr, Context.getLangOpts());
  61. AddedAliases[Function][Namespace.str()] = Abbreviation;
  62. return FixItHint::CreateInsertion(Loc, Declaration);
  63. }
  64. return std::nullopt;
  65. }
  66. std::string NamespaceAliaser::getNamespaceName(ASTContext &Context,
  67. const Stmt &Statement,
  68. StringRef Namespace) const {
  69. const auto *Function = getSurroundingFunction(Context, Statement);
  70. auto FunctionAliases = AddedAliases.find(Function);
  71. if (FunctionAliases != AddedAliases.end()) {
  72. if (FunctionAliases->second.count(Namespace) != 0) {
  73. return FunctionAliases->second.find(Namespace)->getValue();
  74. }
  75. }
  76. return Namespace.str();
  77. }
  78. } // namespace clang::tidy::utils