1 //===---------- NamespaceAliaser.cpp - clang-tidy -------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "NamespaceAliaser.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/ASTMatchers/ASTMatchers.h"
14 #include "clang/Lex/Lexer.h"
16 namespace clang::tidy::utils
{
18 using namespace ast_matchers
;
20 NamespaceAliaser::NamespaceAliaser(const SourceManager
&SourceMgr
)
21 : SourceMgr(SourceMgr
) {}
23 AST_MATCHER_P(NamespaceAliasDecl
, hasTargetNamespace
,
24 ast_matchers::internal::Matcher
<NamespaceDecl
>, innerMatcher
) {
25 return innerMatcher
.matches(*Node
.getNamespace(), Finder
, Builder
);
28 std::optional
<FixItHint
>
29 NamespaceAliaser::createAlias(ASTContext
&Context
, const Stmt
&Statement
,
31 const std::vector
<std::string
> &Abbreviations
) {
32 const FunctionDecl
*Function
= getSurroundingFunction(Context
, Statement
);
33 if (!Function
|| !Function
->hasBody())
36 if (AddedAliases
[Function
].count(Namespace
.str()) != 0)
39 // FIXME: Doesn't consider the order of declarations.
40 // If we accidentally pick an alias defined later in the function,
41 // the output won't compile.
42 // FIXME: Also doesn't consider file or class-scope aliases.
44 const auto *ExistingAlias
= selectFirst
<NamedDecl
>(
45 "alias", match(functionDecl(hasBody(compoundStmt(has(declStmt(
46 has(namespaceAliasDecl(hasTargetNamespace(hasName(
47 std::string(Namespace
))))
51 if (ExistingAlias
!= nullptr) {
52 AddedAliases
[Function
][Namespace
.str()] = ExistingAlias
->getName().str();
56 for (const auto &Abbreviation
: Abbreviations
) {
57 DeclarationMatcher ConflictMatcher
= namedDecl(hasName(Abbreviation
));
58 const auto HasConflictingChildren
=
59 !match(findAll(ConflictMatcher
), *Function
, Context
).empty();
60 const auto HasConflictingAncestors
=
61 !match(functionDecl(hasAncestor(decl(has(ConflictMatcher
)))), *Function
,
64 if (HasConflictingAncestors
|| HasConflictingChildren
)
67 std::string Declaration
=
68 (llvm::Twine("\nnamespace ") + Abbreviation
+ " = " + Namespace
+ ";")
71 Lexer::getLocForEndOfToken(Function
->getBody()->getBeginLoc(), 0,
72 SourceMgr
, Context
.getLangOpts());
73 AddedAliases
[Function
][Namespace
.str()] = Abbreviation
;
74 return FixItHint::CreateInsertion(Loc
, Declaration
);
80 std::string
NamespaceAliaser::getNamespaceName(ASTContext
&Context
,
81 const Stmt
&Statement
,
82 StringRef Namespace
) const {
83 const auto *Function
= getSurroundingFunction(Context
, Statement
);
84 auto FunctionAliases
= AddedAliases
.find(Function
);
85 if (FunctionAliases
!= AddedAliases
.end()) {
86 if (FunctionAliases
->second
.count(Namespace
) != 0) {
87 return FunctionAliases
->second
.find(Namespace
)->getValue();
90 return Namespace
.str();
93 } // namespace clang::tidy::utils