1 //===---------- UsingInserter.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 "UsingInserter.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/ASTMatchers/ASTMatchers.h"
14 #include "clang/Lex/Lexer.h"
17 namespace clang::tidy::utils
{
19 using namespace ast_matchers
;
21 static StringRef
getUnqualifiedName(StringRef QualifiedName
) {
22 size_t LastSeparatorPos
= QualifiedName
.rfind("::");
23 if (LastSeparatorPos
== StringRef::npos
)
25 return QualifiedName
.drop_front(LastSeparatorPos
+ 2);
28 UsingInserter::UsingInserter(const SourceManager
&SourceMgr
)
29 : SourceMgr(SourceMgr
) {}
31 std::optional
<FixItHint
> UsingInserter::createUsingDeclaration(
32 ASTContext
&Context
, const Stmt
&Statement
, StringRef QualifiedName
) {
33 StringRef UnqualifiedName
= getUnqualifiedName(QualifiedName
);
34 const FunctionDecl
*Function
= getSurroundingFunction(Context
, Statement
);
38 if (AddedUsing
.count(std::make_pair(Function
, QualifiedName
.str())) != 0)
41 SourceLocation InsertLoc
= Lexer::getLocForEndOfToken(
42 Function
->getBody()->getBeginLoc(), 0, SourceMgr
, Context
.getLangOpts());
44 // Only use using declarations in the main file, not in includes.
45 if (SourceMgr
.getFileID(InsertLoc
) != SourceMgr
.getMainFileID())
48 // FIXME: This declaration could be masked. Investigate if
49 // there is a way to avoid using Sema.
50 bool AlreadyHasUsingDecl
=
51 !match(stmt(hasAncestor(decl(has(usingDecl(hasAnyUsingShadowDecl(
52 hasTargetDecl(hasName(QualifiedName
.str())))))))),
55 if (AlreadyHasUsingDecl
) {
56 AddedUsing
.emplace(NameInFunction(Function
, QualifiedName
.str()));
59 // Find conflicting declarations and references.
60 auto ConflictingDecl
= namedDecl(hasName(UnqualifiedName
));
61 bool HasConflictingDeclaration
=
62 !match(findAll(ConflictingDecl
), *Function
, Context
).empty();
63 bool HasConflictingDeclRef
=
64 !match(findAll(declRefExpr(to(ConflictingDecl
))), *Function
, Context
)
66 if (HasConflictingDeclaration
|| HasConflictingDeclRef
)
69 std::string Declaration
=
70 (llvm::Twine("\nusing ") + QualifiedName
+ ";").str();
72 AddedUsing
.emplace(std::make_pair(Function
, QualifiedName
.str()));
73 return FixItHint::CreateInsertion(InsertLoc
, Declaration
);
76 StringRef
UsingInserter::getShortName(ASTContext
&Context
,
77 const Stmt
&Statement
,
78 StringRef QualifiedName
) {
79 const FunctionDecl
*Function
= getSurroundingFunction(Context
, Statement
);
80 if (AddedUsing
.count(NameInFunction(Function
, QualifiedName
.str())) != 0)
81 return getUnqualifiedName(QualifiedName
);
85 } // namespace clang::tidy::utils