]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/Tooling/Core/Lookup.cpp
MFV r330102: ntp 4.2.8p11
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / Tooling / Core / Lookup.cpp
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
14 #include "clang/Tooling/Core/Lookup.h"
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}`.
25 static llvm::SmallVector<const NamespaceDecl *, 4>
26 getAllNamedNamespaces(const DeclContext *Context) {
27   llvm::SmallVector<const NamespaceDecl *, 4> Namespaces;
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
45 usingFromDifferentCanonicalNamespace(const DeclContext *FromContext,
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.
52   llvm::SmallVector<const NamespaceDecl *, 4> FromNamespaces =
53       getAllNamedNamespaces(FromContext);
54   llvm::SmallVector<const NamespaceDecl *, 4> UseNamespaces =
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
117 std::string tooling::replaceNestedName(const NestedNameSpecifier *Use,
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 &&
139       !usingFromDifferentCanonicalNamespace(FromDecl->getDeclContext(),
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 }