clang-tools  9.0.0svn
UsingInserter.cpp
Go to the documentation of this file.
1 //===---------- UsingInserter.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 
9 #include "UsingInserter.h"
10 
11 #include "ASTUtils.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/ASTMatchers/ASTMatchers.h"
14 #include "clang/Lex/Lexer.h"
15 
16 namespace clang {
17 namespace tidy {
18 namespace utils {
19 
20 using namespace ast_matchers;
21 
22 static StringRef getUnqualifiedName(StringRef QualifiedName) {
23  size_t LastSeparatorPos = QualifiedName.rfind("::");
24  if (LastSeparatorPos == StringRef::npos)
25  return QualifiedName;
26  return QualifiedName.drop_front(LastSeparatorPos + 2);
27 }
28 
29 UsingInserter::UsingInserter(const SourceManager &SourceMgr)
30  : SourceMgr(SourceMgr) {}
31 
33  ASTContext &Context, const Stmt &Statement, StringRef QualifiedName) {
34  StringRef UnqualifiedName = getUnqualifiedName(QualifiedName);
35  const FunctionDecl *Function = getSurroundingFunction(Context, Statement);
36  if (!Function)
37  return None;
38 
39  if (AddedUsing.count(std::make_pair(Function, QualifiedName.str())) != 0)
40  return None;
41 
42  SourceLocation InsertLoc = Lexer::getLocForEndOfToken(
43  Function->getBody()->getBeginLoc(), 0, SourceMgr, Context.getLangOpts());
44 
45  // Only use using declarations in the main file, not in includes.
46  if (SourceMgr.getFileID(InsertLoc) != SourceMgr.getMainFileID())
47  return None;
48 
49  // FIXME: This declaration could be masked. Investigate if
50  // there is a way to avoid using Sema.
51  bool AlreadyHasUsingDecl =
52  !match(stmt(hasAncestor(decl(has(usingDecl(hasAnyUsingShadowDecl(
53  hasTargetDecl(hasName(QualifiedName.str())))))))),
54  Statement, Context)
55  .empty();
56  if (AlreadyHasUsingDecl) {
57  AddedUsing.emplace(NameInFunction(Function, QualifiedName.str()));
58  return None;
59  }
60  // Find conflicting declarations and references.
61  auto ConflictingDecl = namedDecl(hasName(UnqualifiedName));
62  bool HasConflictingDeclaration =
63  !match(findAll(ConflictingDecl), *Function, Context).empty();
64  bool HasConflictingDeclRef =
65  !match(findAll(declRefExpr(to(ConflictingDecl))), *Function, Context)
66  .empty();
67  if (HasConflictingDeclaration || HasConflictingDeclRef)
68  return None;
69 
70  std::string Declaration =
71  (llvm::Twine("\nusing ") + QualifiedName + ";").str();
72 
73  AddedUsing.emplace(std::make_pair(Function, QualifiedName.str()));
74  return FixItHint::CreateInsertion(InsertLoc, Declaration);
75 }
76 
77 StringRef UsingInserter::getShortName(ASTContext &Context,
78  const Stmt &Statement,
79  StringRef QualifiedName) {
80  const FunctionDecl *Function = getSurroundingFunction(Context, Statement);
81  if (AddedUsing.count(NameInFunction(Function, QualifiedName.str())) != 0)
82  return getUnqualifiedName(QualifiedName);
83  return QualifiedName;
84 }
85 
86 } // namespace utils
87 } // namespace tidy
88 } // namespace clang
UsingInserter(const SourceManager &SourceMgr)
static StringRef getUnqualifiedName(StringRef QualifiedName)
const FunctionDecl * getSurroundingFunction(ASTContext &Context, const Stmt &Statement)
Definition: ASTUtils.cpp:20
llvm::Optional< FixItHint > createUsingDeclaration(ASTContext &Context, const Stmt &Statement, llvm::StringRef QualifiedName)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::StringRef getShortName(ASTContext &Context, const Stmt &Statement, llvm::StringRef QualifiedName)