clang-tools  7.0.0svn
UsingInserter.cpp
Go to the documentation of this file.
1 //===---------- 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 
17 namespace clang {
18 namespace tidy {
19 namespace utils {
20 
21 using namespace ast_matchers;
22 
23 static 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 
30 UsingInserter::UsingInserter(const SourceManager &SourceMgr)
31  : SourceMgr(SourceMgr) {}
32 
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(
44  Function->getBody()->getLocStart(), 0, SourceMgr, Context.getLangOpts());
45 
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 
71  std::string Declaration =
72  (llvm::Twine("\nusing ") + QualifiedName + ";").str();
73 
74  AddedUsing.emplace(std::make_pair(Function, QualifiedName.str()));
75  return FixItHint::CreateInsertion(InsertLoc, Declaration);
76 }
77 
78 StringRef 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
UsingInserter(const SourceManager &SourceMgr)
static StringRef getUnqualifiedName(StringRef QualifiedName)
const FunctionDecl * getSurroundingFunction(ASTContext &Context, const Stmt &Statement)
Definition: ASTUtils.cpp:21
llvm::Optional< FixItHint > createUsingDeclaration(ASTContext &Context, const Stmt &Statement, llvm::StringRef QualifiedName)
llvm::StringRef getShortName(ASTContext &Context, const Stmt &Statement, llvm::StringRef QualifiedName)