xref: /llvm-project/clang/lib/Tooling/Refactoring/Lookup.cpp (revision 68f832f56da1af0e5fc77003f640648ec7d901ad)
1a2214757SAlex Richardson //===--- Lookup.cpp - Framework for clang refactoring tools ---------------===//
2a2214757SAlex Richardson //
3a2214757SAlex Richardson // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a2214757SAlex Richardson // See https://llvm.org/LICENSE.txt for license information.
5a2214757SAlex Richardson // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a2214757SAlex Richardson //
7a2214757SAlex Richardson //===----------------------------------------------------------------------===//
8a2214757SAlex Richardson //
9a2214757SAlex Richardson //  This file defines helper methods for clang tools performing name lookup.
10a2214757SAlex Richardson //
11a2214757SAlex Richardson //===----------------------------------------------------------------------===//
12a2214757SAlex Richardson 
13a2214757SAlex Richardson #include "clang/Tooling/Refactoring/Lookup.h"
14a2214757SAlex Richardson #include "clang/AST/ASTContext.h"
15a2214757SAlex Richardson #include "clang/AST/Decl.h"
16a2214757SAlex Richardson #include "clang/AST/DeclCXX.h"
17a2214757SAlex Richardson #include "clang/AST/DeclarationName.h"
18a2214757SAlex Richardson #include "clang/Basic/SourceLocation.h"
19a2214757SAlex Richardson #include "clang/Basic/SourceManager.h"
20a2214757SAlex Richardson #include "llvm/ADT/SmallVector.h"
21a2214757SAlex Richardson using namespace clang;
22a2214757SAlex Richardson using namespace clang::tooling;
23a2214757SAlex Richardson 
24a2214757SAlex Richardson // Gets all namespaces that \p Context is in as a vector (ignoring anonymous
25a2214757SAlex Richardson // namespaces). The inner namespaces come before outer namespaces in the vector.
26a2214757SAlex Richardson // For example, if the context is in the following namespace:
27a2214757SAlex Richardson //    `namespace a { namespace b { namespace c ( ... ) } }`,
28a2214757SAlex Richardson // the vector will be `{c, b, a}`.
29a2214757SAlex Richardson static llvm::SmallVector<const NamespaceDecl *, 4>
getAllNamedNamespaces(const DeclContext * Context)30a2214757SAlex Richardson getAllNamedNamespaces(const DeclContext *Context) {
31a2214757SAlex Richardson   llvm::SmallVector<const NamespaceDecl *, 4> Namespaces;
32a2214757SAlex Richardson   auto GetNextNamedNamespace = [](const DeclContext *Context) {
33a2214757SAlex Richardson     // Look past non-namespaces and anonymous namespaces on FromContext.
34a2214757SAlex Richardson     while (Context && (!isa<NamespaceDecl>(Context) ||
35a2214757SAlex Richardson                        cast<NamespaceDecl>(Context)->isAnonymousNamespace()))
36a2214757SAlex Richardson       Context = Context->getParent();
37a2214757SAlex Richardson     return Context;
38a2214757SAlex Richardson   };
39a2214757SAlex Richardson   for (Context = GetNextNamedNamespace(Context); Context != nullptr;
40a2214757SAlex Richardson        Context = GetNextNamedNamespace(Context->getParent()))
41a2214757SAlex Richardson     Namespaces.push_back(cast<NamespaceDecl>(Context));
42a2214757SAlex Richardson   return Namespaces;
43a2214757SAlex Richardson }
44a2214757SAlex Richardson 
45a2214757SAlex Richardson // Returns true if the context in which the type is used and the context in
46a2214757SAlex Richardson // which the type is declared are the same semantical namespace but different
47a2214757SAlex Richardson // lexical namespaces.
48a2214757SAlex Richardson static bool
usingFromDifferentCanonicalNamespace(const DeclContext * FromContext,const DeclContext * UseContext)49a2214757SAlex Richardson usingFromDifferentCanonicalNamespace(const DeclContext *FromContext,
50a2214757SAlex Richardson                                      const DeclContext *UseContext) {
51a2214757SAlex Richardson   // We can skip anonymous namespace because:
52a2214757SAlex Richardson   // 1. `FromContext` and `UseContext` must be in the same anonymous namespaces
53a2214757SAlex Richardson   // since referencing across anonymous namespaces is not possible.
54a2214757SAlex Richardson   // 2. If `FromContext` and `UseContext` are in the same anonymous namespace,
55a2214757SAlex Richardson   // the function will still return `false` as expected.
56a2214757SAlex Richardson   llvm::SmallVector<const NamespaceDecl *, 4> FromNamespaces =
57a2214757SAlex Richardson       getAllNamedNamespaces(FromContext);
58a2214757SAlex Richardson   llvm::SmallVector<const NamespaceDecl *, 4> UseNamespaces =
59a2214757SAlex Richardson       getAllNamedNamespaces(UseContext);
60a2214757SAlex Richardson   // If `UseContext` has fewer level of nested namespaces, it cannot be in the
61a2214757SAlex Richardson   // same canonical namespace as the `FromContext`.
62a2214757SAlex Richardson   if (UseNamespaces.size() < FromNamespaces.size())
63a2214757SAlex Richardson     return false;
64a2214757SAlex Richardson   unsigned Diff = UseNamespaces.size() - FromNamespaces.size();
65a2214757SAlex Richardson   auto FromIter = FromNamespaces.begin();
66a2214757SAlex Richardson   // Only compare `FromNamespaces` with namespaces in `UseNamespaces` that can
67a2214757SAlex Richardson   // collide, i.e. the top N namespaces where N is the number of namespaces in
68a2214757SAlex Richardson   // `FromNamespaces`.
69a2214757SAlex Richardson   auto UseIter = UseNamespaces.begin() + Diff;
70a2214757SAlex Richardson   for (; FromIter != FromNamespaces.end() && UseIter != UseNamespaces.end();
71a2214757SAlex Richardson        ++FromIter, ++UseIter) {
72a2214757SAlex Richardson     // Literally the same namespace, not a collision.
73a2214757SAlex Richardson     if (*FromIter == *UseIter)
74a2214757SAlex Richardson       return false;
75a2214757SAlex Richardson     // Now check the names. If they match we have a different canonical
76a2214757SAlex Richardson     // namespace with the same name.
77a2214757SAlex Richardson     if (cast<NamespaceDecl>(*FromIter)->getDeclName() ==
78a2214757SAlex Richardson         cast<NamespaceDecl>(*UseIter)->getDeclName())
79a2214757SAlex Richardson       return true;
80a2214757SAlex Richardson   }
81a2214757SAlex Richardson   assert(FromIter == FromNamespaces.end() && UseIter == UseNamespaces.end());
82a2214757SAlex Richardson   return false;
83a2214757SAlex Richardson }
84a2214757SAlex Richardson 
getBestNamespaceSubstr(const DeclContext * DeclA,StringRef NewName,bool HadLeadingColonColon)85a2214757SAlex Richardson static StringRef getBestNamespaceSubstr(const DeclContext *DeclA,
86a2214757SAlex Richardson                                         StringRef NewName,
87a2214757SAlex Richardson                                         bool HadLeadingColonColon) {
88a2214757SAlex Richardson   while (true) {
89a2214757SAlex Richardson     while (DeclA && !isa<NamespaceDecl>(DeclA))
90a2214757SAlex Richardson       DeclA = DeclA->getParent();
91a2214757SAlex Richardson 
92a2214757SAlex Richardson     // Fully qualified it is! Leave :: in place if it's there already.
93a2214757SAlex Richardson     if (!DeclA)
94a2214757SAlex Richardson       return HadLeadingColonColon ? NewName : NewName.substr(2);
95a2214757SAlex Richardson 
96a2214757SAlex Richardson     // Otherwise strip off redundant namespace qualifications from the new name.
97a2214757SAlex Richardson     // We use the fully qualified name of the namespace and remove that part
98a2214757SAlex Richardson     // from NewName if it has an identical prefix.
99a2214757SAlex Richardson     std::string NS =
100a2214757SAlex Richardson         "::" + cast<NamespaceDecl>(DeclA)->getQualifiedNameAsString() + "::";
101*68f832f5SKazu Hirata     if (NewName.consume_front(NS))
102*68f832f5SKazu Hirata       return NewName;
103a2214757SAlex Richardson 
104a2214757SAlex Richardson     // No match yet. Strip of a namespace from the end of the chain and try
105a2214757SAlex Richardson     // again. This allows to get optimal qualifications even if the old and new
106a2214757SAlex Richardson     // decl only share common namespaces at a higher level.
107a2214757SAlex Richardson     DeclA = DeclA->getParent();
108a2214757SAlex Richardson   }
109a2214757SAlex Richardson }
110a2214757SAlex Richardson 
111a2214757SAlex Richardson /// Check if the name specifier begins with a written "::".
isFullyQualified(const NestedNameSpecifier * NNS)112a2214757SAlex Richardson static bool isFullyQualified(const NestedNameSpecifier *NNS) {
113a2214757SAlex Richardson   while (NNS) {
114a2214757SAlex Richardson     if (NNS->getKind() == NestedNameSpecifier::Global)
115a2214757SAlex Richardson       return true;
116a2214757SAlex Richardson     NNS = NNS->getPrefix();
117a2214757SAlex Richardson   }
118a2214757SAlex Richardson   return false;
119a2214757SAlex Richardson }
120a2214757SAlex Richardson 
121a2214757SAlex Richardson // Adds more scope specifier to the spelled name until the spelling is not
122a2214757SAlex Richardson // ambiguous. A spelling is ambiguous if the resolution of the symbol is
123a2214757SAlex Richardson // ambiguous. For example, if QName is "::y::bar", the spelling is "y::bar", and
124a2214757SAlex Richardson // context contains a nested namespace "a::y", then "y::bar" can be resolved to
125a2214757SAlex Richardson // ::a::y::bar in the context, which can cause compile error.
126a2214757SAlex Richardson // FIXME: consider using namespaces.
disambiguateSpellingInScope(StringRef Spelling,StringRef QName,const DeclContext & UseContext,SourceLocation UseLoc)127a2214757SAlex Richardson static std::string disambiguateSpellingInScope(StringRef Spelling,
128a2214757SAlex Richardson                                                StringRef QName,
129a2214757SAlex Richardson                                                const DeclContext &UseContext,
130a2214757SAlex Richardson                                                SourceLocation UseLoc) {
131f3dcc235SKazu Hirata   assert(QName.starts_with("::"));
132f3dcc235SKazu Hirata   assert(QName.ends_with(Spelling));
133f3dcc235SKazu Hirata   if (Spelling.starts_with("::"))
134a2214757SAlex Richardson     return std::string(Spelling);
135a2214757SAlex Richardson 
136a2214757SAlex Richardson   auto UnspelledSpecifier = QName.drop_back(Spelling.size());
137a2214757SAlex Richardson   llvm::SmallVector<llvm::StringRef, 2> UnspelledScopes;
138a2214757SAlex Richardson   UnspelledSpecifier.split(UnspelledScopes, "::", /*MaxSplit=*/-1,
139a2214757SAlex Richardson                            /*KeepEmpty=*/false);
140a2214757SAlex Richardson 
141a2214757SAlex Richardson   llvm::SmallVector<const NamespaceDecl *, 4> EnclosingNamespaces =
142a2214757SAlex Richardson       getAllNamedNamespaces(&UseContext);
143a2214757SAlex Richardson   auto &AST = UseContext.getParentASTContext();
144a2214757SAlex Richardson   StringRef TrimmedQName = QName.substr(2);
145a2214757SAlex Richardson   const auto &SM = UseContext.getParentASTContext().getSourceManager();
146a2214757SAlex Richardson   UseLoc = SM.getSpellingLoc(UseLoc);
147a2214757SAlex Richardson 
148a2214757SAlex Richardson   auto IsAmbiguousSpelling = [&](const llvm::StringRef CurSpelling) {
149f3dcc235SKazu Hirata     if (CurSpelling.starts_with("::"))
150a2214757SAlex Richardson       return false;
151a2214757SAlex Richardson     // Lookup the first component of Spelling in all enclosing namespaces
152a2214757SAlex Richardson     // and check if there is any existing symbols with the same name but in
153a2214757SAlex Richardson     // different scope.
154a2214757SAlex Richardson     StringRef Head = CurSpelling.split("::").first;
155a2214757SAlex Richardson     for (const auto *NS : EnclosingNamespaces) {
156a2214757SAlex Richardson       auto LookupRes = NS->lookup(DeclarationName(&AST.Idents.get(Head)));
157a2214757SAlex Richardson       if (!LookupRes.empty()) {
158a2214757SAlex Richardson         for (const NamedDecl *Res : LookupRes)
159a2214757SAlex Richardson           // If `Res` is not visible in `UseLoc`, we don't consider it
160a2214757SAlex Richardson           // ambiguous. For example, a reference in a header file should not be
161a2214757SAlex Richardson           // affected by a potentially ambiguous name in some file that includes
162a2214757SAlex Richardson           // the header.
163f3dcc235SKazu Hirata           if (!TrimmedQName.starts_with(Res->getQualifiedNameAsString()) &&
164a2214757SAlex Richardson               SM.isBeforeInTranslationUnit(
165a2214757SAlex Richardson                   SM.getSpellingLoc(Res->getLocation()), UseLoc))
166a2214757SAlex Richardson             return true;
167a2214757SAlex Richardson       }
168a2214757SAlex Richardson     }
169a2214757SAlex Richardson     return false;
170a2214757SAlex Richardson   };
171a2214757SAlex Richardson 
172a2214757SAlex Richardson   // Add more qualifiers until the spelling is not ambiguous.
173a2214757SAlex Richardson   std::string Disambiguated = std::string(Spelling);
174a2214757SAlex Richardson   while (IsAmbiguousSpelling(Disambiguated)) {
175a2214757SAlex Richardson     if (UnspelledScopes.empty()) {
176a2214757SAlex Richardson       Disambiguated = "::" + Disambiguated;
177a2214757SAlex Richardson     } else {
178a2214757SAlex Richardson       Disambiguated = (UnspelledScopes.back() + "::" + Disambiguated).str();
179a2214757SAlex Richardson       UnspelledScopes.pop_back();
180a2214757SAlex Richardson     }
181a2214757SAlex Richardson   }
182a2214757SAlex Richardson   return Disambiguated;
183a2214757SAlex Richardson }
184a2214757SAlex Richardson 
replaceNestedName(const NestedNameSpecifier * Use,SourceLocation UseLoc,const DeclContext * UseContext,const NamedDecl * FromDecl,StringRef ReplacementString)185a2214757SAlex Richardson std::string tooling::replaceNestedName(const NestedNameSpecifier *Use,
186a2214757SAlex Richardson                                        SourceLocation UseLoc,
187a2214757SAlex Richardson                                        const DeclContext *UseContext,
188a2214757SAlex Richardson                                        const NamedDecl *FromDecl,
189a2214757SAlex Richardson                                        StringRef ReplacementString) {
190f3dcc235SKazu Hirata   assert(ReplacementString.starts_with("::") &&
191a2214757SAlex Richardson          "Expected fully-qualified name!");
192a2214757SAlex Richardson 
193a2214757SAlex Richardson   // We can do a raw name replacement when we are not inside the namespace for
194a2214757SAlex Richardson   // the original class/function and it is not in the global namespace.  The
195a2214757SAlex Richardson   // assumption is that outside the original namespace we must have a using
196a2214757SAlex Richardson   // statement that makes this work out and that other parts of this refactor
197a2214757SAlex Richardson   // will automatically fix using statements to point to the new class/function.
198a2214757SAlex Richardson   // However, if the `FromDecl` is a class forward declaration, the reference is
199a2214757SAlex Richardson   // still considered as referring to the original definition, so we can't do a
200a2214757SAlex Richardson   // raw name replacement in this case.
201a2214757SAlex Richardson   const bool class_name_only = !Use;
202a2214757SAlex Richardson   const bool in_global_namespace =
203a2214757SAlex Richardson       isa<TranslationUnitDecl>(FromDecl->getDeclContext());
204a2214757SAlex Richardson   const bool is_class_forward_decl =
205a2214757SAlex Richardson       isa<CXXRecordDecl>(FromDecl) &&
206a2214757SAlex Richardson       !cast<CXXRecordDecl>(FromDecl)->isCompleteDefinition();
207a2214757SAlex Richardson   if (class_name_only && !in_global_namespace && !is_class_forward_decl &&
208a2214757SAlex Richardson       !usingFromDifferentCanonicalNamespace(FromDecl->getDeclContext(),
209a2214757SAlex Richardson                                             UseContext)) {
210a2214757SAlex Richardson     auto Pos = ReplacementString.rfind("::");
211a2214757SAlex Richardson     return std::string(Pos != StringRef::npos
212a2214757SAlex Richardson                            ? ReplacementString.substr(Pos + 2)
213a2214757SAlex Richardson                            : ReplacementString);
214a2214757SAlex Richardson   }
215a2214757SAlex Richardson   // We did not match this because of a using statement, so we will need to
216a2214757SAlex Richardson   // figure out how good a namespace match we have with our destination type.
217a2214757SAlex Richardson   // We work backwards (from most specific possible namespace to least
218a2214757SAlex Richardson   // specific).
219a2214757SAlex Richardson   StringRef Suggested = getBestNamespaceSubstr(UseContext, ReplacementString,
220a2214757SAlex Richardson                                                isFullyQualified(Use));
221a2214757SAlex Richardson 
222a2214757SAlex Richardson   return disambiguateSpellingInScope(Suggested, ReplacementString, *UseContext,
223a2214757SAlex Richardson                                      UseLoc);
224a2214757SAlex Richardson }
225