clang  6.0.0svn
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 #include "clang/AST/DeclCXX.h"
17 using namespace clang;
18 using namespace clang::tooling;
19 
20 // Gets all namespaces that \p Context is in as a vector (ignoring anonymous
21 // namespaces). The inner namespaces come before outer namespaces in the vector.
22 // For example, if the context is in the following namespace:
23 // `namespace a { namespace b { namespace c ( ... ) } }`,
24 // the vector will be `{c, b, a}`.
28  auto GetNextNamedNamespace = [](const DeclContext *Context) {
29  // Look past non-namespaces and anonymous namespaces on FromContext.
30  while (Context && (!isa<NamespaceDecl>(Context) ||
31  cast<NamespaceDecl>(Context)->isAnonymousNamespace()))
32  Context = Context->getParent();
33  return Context;
34  };
35  for (Context = GetNextNamedNamespace(Context); Context != nullptr;
36  Context = GetNextNamedNamespace(Context->getParent()))
37  Namespaces.push_back(cast<NamespaceDecl>(Context));
38  return Namespaces;
39 }
40 
41 // Returns true if the context in which the type is used and the context in
42 // which the type is declared are the same semantical namespace but different
43 // lexical namespaces.
44 static bool
46  const DeclContext *UseContext) {
47  // We can skip anonymous namespace because:
48  // 1. `FromContext` and `UseContext` must be in the same anonymous namespaces
49  // since referencing across anonymous namespaces is not possible.
50  // 2. If `FromContext` and `UseContext` are in the same anonymous namespace,
51  // the function will still return `false` as expected.
53  getAllNamedNamespaces(FromContext);
55  getAllNamedNamespaces(UseContext);
56  // If `UseContext` has fewer level of nested namespaces, it cannot be in the
57  // same canonical namespace as the `FromContext`.
58  if (UseNamespaces.size() < FromNamespaces.size())
59  return false;
60  unsigned Diff = UseNamespaces.size() - FromNamespaces.size();
61  auto FromIter = FromNamespaces.begin();
62  // Only compare `FromNamespaces` with namespaces in `UseNamespaces` that can
63  // collide, i.e. the top N namespaces where N is the number of namespaces in
64  // `FromNamespaces`.
65  auto UseIter = UseNamespaces.begin() + Diff;
66  for (; FromIter != FromNamespaces.end() && UseIter != UseNamespaces.end();
67  ++FromIter, ++UseIter) {
68  // Literally the same namespace, not a collision.
69  if (*FromIter == *UseIter)
70  return false;
71  // Now check the names. If they match we have a different canonical
72  // namespace with the same name.
73  if (cast<NamespaceDecl>(*FromIter)->getDeclName() ==
74  cast<NamespaceDecl>(*UseIter)->getDeclName())
75  return true;
76  }
77  assert(FromIter == FromNamespaces.end() && UseIter == UseNamespaces.end());
78  return false;
79 }
80 
81 static StringRef getBestNamespaceSubstr(const DeclContext *DeclA,
82  StringRef NewName,
83  bool HadLeadingColonColon) {
84  while (true) {
85  while (DeclA && !isa<NamespaceDecl>(DeclA))
86  DeclA = DeclA->getParent();
87 
88  // Fully qualified it is! Leave :: in place if it's there already.
89  if (!DeclA)
90  return HadLeadingColonColon ? NewName : NewName.substr(2);
91 
92  // Otherwise strip off redundant namespace qualifications from the new name.
93  // We use the fully qualified name of the namespace and remove that part
94  // from NewName if it has an identical prefix.
95  std::string NS =
96  "::" + cast<NamespaceDecl>(DeclA)->getQualifiedNameAsString() + "::";
97  if (NewName.startswith(NS))
98  return NewName.substr(NS.size());
99 
100  // No match yet. Strip of a namespace from the end of the chain and try
101  // again. This allows to get optimal qualifications even if the old and new
102  // decl only share common namespaces at a higher level.
103  DeclA = DeclA->getParent();
104  }
105 }
106 
107 /// Check if the name specifier begins with a written "::".
108 static bool isFullyQualified(const NestedNameSpecifier *NNS) {
109  while (NNS) {
110  if (NNS->getKind() == NestedNameSpecifier::Global)
111  return true;
112  NNS = NNS->getPrefix();
113  }
114  return false;
115 }
116 
118  const DeclContext *UseContext,
119  const NamedDecl *FromDecl,
120  StringRef ReplacementString) {
121  assert(ReplacementString.startswith("::") &&
122  "Expected fully-qualified name!");
123 
124  // We can do a raw name replacement when we are not inside the namespace for
125  // the original class/function and it is not in the global namespace. The
126  // assumption is that outside the original namespace we must have a using
127  // statement that makes this work out and that other parts of this refactor
128  // will automatically fix using statements to point to the new class/function.
129  // However, if the `FromDecl` is a class forward declaration, the reference is
130  // still considered as referring to the original definition, so we can't do a
131  // raw name replacement in this case.
132  const bool class_name_only = !Use;
133  const bool in_global_namespace =
134  isa<TranslationUnitDecl>(FromDecl->getDeclContext());
135  const bool is_class_forward_decl =
136  isa<CXXRecordDecl>(FromDecl) &&
137  !cast<CXXRecordDecl>(FromDecl)->isCompleteDefinition();
138  if (class_name_only && !in_global_namespace && !is_class_forward_decl &&
140  UseContext)) {
141  auto Pos = ReplacementString.rfind("::");
142  return Pos != StringRef::npos ? ReplacementString.substr(Pos + 2)
143  : ReplacementString;
144  }
145  // We did not match this because of a using statement, so we will need to
146  // figure out how good a namespace match we have with our destination type.
147  // We work backwards (from most specific possible namespace to least
148  // specific).
149  return getBestNamespaceSubstr(UseContext, ReplacementString,
150  isFullyQualified(Use));
151 }
NestedNameSpecifier * getPrefix() const
Return the prefix of this nested name specifier.
static bool isFullyQualified(const NestedNameSpecifier *NNS)
Check if the name specifier begins with a written "::".
Definition: Lookup.cpp:108
SpecifierKind getKind() const
Determine what kind of nested name specifier is stored.
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:117
static StringRef getBestNamespaceSubstr(const DeclContext *DeclA, StringRef NewName, bool HadLeadingColonColon)
Definition: Lookup.cpp:81
DeclContext * getDeclContext()
Definition: DeclBase.h:425
static llvm::SmallVector< const NamespaceDecl *, 4 > getAllNamedNamespaces(const DeclContext *Context)
Definition: Lookup.cpp:26
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition: DeclBase.h:1331
const NamedDecl * FromDecl
Represents a C++ nested name specifier, such as "\::std::vector<int>::".
Dataflow Directional Tag Classes.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1252
static bool usingFromDifferentCanonicalNamespace(const DeclContext *FromContext, const DeclContext *UseContext)
Definition: Lookup.cpp:45
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
NamedDecl - This represents a decl with a name.
Definition: Decl.h:245
The global specifier &#39;::&#39;. There is no stored value.