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> 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 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 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*5f757f3fSDimitry Andric if (NewName.starts_with(NS)) 102e8d8bef9SDimitry Andric return NewName.substr(NS.size()); 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 "::". 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. 127e8d8bef9SDimitry Andric static std::string disambiguateSpellingInScope(StringRef Spelling, 128e8d8bef9SDimitry Andric StringRef QName, 129e8d8bef9SDimitry Andric const DeclContext &UseContext, 130e8d8bef9SDimitry Andric SourceLocation UseLoc) { 131*5f757f3fSDimitry Andric assert(QName.starts_with("::")); 132*5f757f3fSDimitry Andric assert(QName.ends_with(Spelling)); 133*5f757f3fSDimitry 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) { 149*5f757f3fSDimitry 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. 163*5f757f3fSDimitry 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 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) { 190*5f757f3fSDimitry 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