blob: e479d5916602e409543393b3cdb89ed14434bd4c [file] [log] [blame]
Haojian Wuada28622016-10-17 08:33:59 +00001//===---------- UsingInserter.cpp - clang-tidy ----------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "UsingInserter.h"
11
12#include "ASTUtils.h"
13#include "clang/ASTMatchers/ASTMatchFinder.h"
14#include "clang/ASTMatchers/ASTMatchers.h"
15#include "clang/Lex/Lexer.h"
16
17namespace clang {
18namespace tidy {
19namespace utils {
20
21using namespace ast_matchers;
22
23static StringRef getUnqualifiedName(StringRef QualifiedName) {
24 size_t LastSeparatorPos = QualifiedName.rfind("::");
25 if (LastSeparatorPos == StringRef::npos)
26 return QualifiedName;
27 return QualifiedName.drop_front(LastSeparatorPos + 2);
28}
29
30UsingInserter::UsingInserter(const SourceManager &SourceMgr)
31 : SourceMgr(SourceMgr) {}
32
33Optional<FixItHint> UsingInserter::createUsingDeclaration(
34 ASTContext &Context, const Stmt &Statement, StringRef QualifiedName) {
35 StringRef UnqualifiedName = getUnqualifiedName(QualifiedName);
36 const FunctionDecl *Function = getSurroundingFunction(Context, Statement);
37 if (!Function)
38 return None;
39
40 if (AddedUsing.count(std::make_pair(Function, QualifiedName.str())) != 0)
41 return None;
42
43 SourceLocation InsertLoc = Lexer::getLocForEndOfToken(
Stephen Kelly43465bf2018-08-09 22:42:26 +000044 Function->getBody()->getBeginLoc(), 0, SourceMgr, Context.getLangOpts());
Haojian Wuada28622016-10-17 08:33:59 +000045
46 // Only use using declarations in the main file, not in includes.
47 if (SourceMgr.getFileID(InsertLoc) != SourceMgr.getMainFileID())
48 return None;
49
50 // FIXME: This declaration could be masked. Investigate if
51 // there is a way to avoid using Sema.
52 bool AlreadyHasUsingDecl =
53 !match(stmt(hasAncestor(decl(has(usingDecl(hasAnyUsingShadowDecl(
54 hasTargetDecl(hasName(QualifiedName.str())))))))),
55 Statement, Context)
56 .empty();
57 if (AlreadyHasUsingDecl) {
58 AddedUsing.emplace(NameInFunction(Function, QualifiedName.str()));
59 return None;
60 }
61 // Find conflicting declarations and references.
62 auto ConflictingDecl = namedDecl(hasName(UnqualifiedName));
63 bool HasConflictingDeclaration =
64 !match(findAll(ConflictingDecl), *Function, Context).empty();
65 bool HasConflictingDeclRef =
66 !match(findAll(declRefExpr(to(ConflictingDecl))), *Function, Context)
67 .empty();
68 if (HasConflictingDeclaration || HasConflictingDeclRef)
69 return None;
70
Mandeep Singh Grang7c7ea7d2016-11-08 07:50:19 +000071 std::string Declaration =
72 (llvm::Twine("\nusing ") + QualifiedName + ";").str();
Haojian Wuada28622016-10-17 08:33:59 +000073
74 AddedUsing.emplace(std::make_pair(Function, QualifiedName.str()));
75 return FixItHint::CreateInsertion(InsertLoc, Declaration);
76}
77
78StringRef UsingInserter::getShortName(ASTContext &Context,
79 const Stmt &Statement,
80 StringRef QualifiedName) {
81 const FunctionDecl *Function = getSurroundingFunction(Context, Statement);
82 if (AddedUsing.count(NameInFunction(Function, QualifiedName.str())) != 0)
83 return getUnqualifiedName(QualifiedName);
84 return QualifiedName;
85}
86
87} // namespace utils
88} // namespace tidy
89} // namespace clang