clang  3.9.0
Lookup.cpp
Go to the documentation of this file.
1 //===--- Lookup.cpp - Framework for clang refactoring tools ---------------===//
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 // This file defines helper methods for clang tools performing name lookup.
11 //
12 //===----------------------------------------------------------------------===//
13 
15 #include "clang/AST/Decl.h"
16 using namespace clang;
17 using namespace clang::tooling;
18 
20  const DeclContext *DeclB) {
21  while (true) {
22  // Look past non-namespaces on DeclA.
23  while (DeclA && !isa<NamespaceDecl>(DeclA))
24  DeclA = DeclA->getParent();
25 
26  // Look past non-namespaces on DeclB.
27  while (DeclB && !isa<NamespaceDecl>(DeclB))
28  DeclB = DeclB->getParent();
29 
30  // We hit the root, no namespace collision.
31  if (!DeclA || !DeclB)
32  return false;
33 
34  // Literally the same namespace, not a collision.
35  if (DeclA == DeclB)
36  return false;
37 
38  // Now check the names. If they match we have a different namespace with the
39  // same name.
40  if (cast<NamespaceDecl>(DeclA)->getDeclName() ==
41  cast<NamespaceDecl>(DeclB)->getDeclName())
42  return true;
43 
44  DeclA = DeclA->getParent();
45  DeclB = DeclB->getParent();
46  }
47 }
48 
49 static StringRef getBestNamespaceSubstr(const DeclContext *DeclA,
50  StringRef NewName,
51  bool HadLeadingColonColon) {
52  while (true) {
53  while (DeclA && !isa<NamespaceDecl>(DeclA))
54  DeclA = DeclA->getParent();
55 
56  // Fully qualified it is! Leave :: in place if it's there already.
57  if (!DeclA)
58  return HadLeadingColonColon ? NewName : NewName.substr(2);
59 
60  // Otherwise strip off redundant namespace qualifications from the new name.
61  // We use the fully qualified name of the namespace and remove that part
62  // from NewName if it has an identical prefix.
63  std::string NS =
64  "::" + cast<NamespaceDecl>(DeclA)->getQualifiedNameAsString() + "::";
65  if (NewName.startswith(NS))
66  return NewName.substr(NS.size());
67 
68  // No match yet. Strip of a namespace from the end of the chain and try
69  // again. This allows to get optimal qualifications even if the old and new
70  // decl only share common namespaces at a higher level.
71  DeclA = DeclA->getParent();
72  }
73 }
74 
75 /// Check if the name specifier begins with a written "::".
76 static bool isFullyQualified(const NestedNameSpecifier *NNS) {
77  while (NNS) {
79  return true;
80  NNS = NNS->getPrefix();
81  }
82  return false;
83 }
84 
86  const DeclContext *UseContext,
87  const NamedDecl *FromDecl,
88  StringRef ReplacementString) {
89  assert(ReplacementString.startswith("::") &&
90  "Expected fully-qualified name!");
91 
92  // We can do a raw name replacement when we are not inside the namespace for
93  // the original function and it is not in the global namespace. The
94  // assumption is that outside the original namespace we must have a using
95  // statement that makes this work out and that other parts of this refactor
96  // will automatically fix using statements to point to the new function
97  const bool class_name_only = !Use;
98  const bool in_global_namespace =
99  isa<TranslationUnitDecl>(FromDecl->getDeclContext());
100  if (class_name_only && !in_global_namespace &&
101  !isInsideDifferentNamespaceWithSameName(FromDecl->getDeclContext(),
102  UseContext)) {
103  auto Pos = ReplacementString.rfind("::");
104  return Pos != StringRef::npos ? ReplacementString.substr(Pos + 2)
105  : ReplacementString;
106  }
107  // We did not match this because of a using statement, so we will need to
108  // figure out how good a namespace match we have with our destination type.
109  // We work backwards (from most specific possible namespace to least
110  // specific).
111  return getBestNamespaceSubstr(UseContext, ReplacementString,
112  isFullyQualified(Use));
113 }
static bool isFullyQualified(const NestedNameSpecifier *NNS)
Check if the name specifier begins with a written "::".
Definition: Lookup.cpp:76
NestedNameSpecifier * getPrefix() const
Return the prefix of this nested name specifier.
std::string replaceNestedName(const NestedNameSpecifier *Use, const DeclContext *UseContext, const NamedDecl *FromDecl, StringRef ReplacementString)
Emulate a lookup to replace one nested name specifier with another using as few additional namespace ...
Definition: Lookup.cpp:85
static StringRef getBestNamespaceSubstr(const DeclContext *DeclA, StringRef NewName, bool HadLeadingColonColon)
Definition: Lookup.cpp:49
SpecifierKind getKind() const
Determine what kind of nested name specifier is stored.
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition: DeclBase.h:1214
Represents a C++ nested name specifier, such as "\::std::vector<int>::".
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1135
static bool isInsideDifferentNamespaceWithSameName(const DeclContext *DeclA, const DeclContext *DeclB)
Definition: Lookup.cpp:19
NamedDecl - This represents a decl with a name.
Definition: Decl.h:213
The global specifier '::'. There is no stored value.