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