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