//===--- USRGeneration.cpp - Routines for USR generation ------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "swift/AST/ASTContext.h" #include "swift/AST/Module.h" #include "swift/AST/USRGeneration.h" #include "swift/AST/ASTMangler.h" #include "swift/AST/SwiftNameTranslation.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/raw_ostream.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/Index/USRGeneration.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" using namespace swift; using namespace ide; static inline StringRef getUSRSpacePrefix() { return "s:"; } bool ide::printTypeUSR(Type Ty, raw_ostream &OS) { assert(!Ty->hasArchetype() && "cannot have contextless archetypes mangled."); Mangle::ASTMangler Mangler; OS << Mangler.mangleTypeForDebugger(Ty->getRValueType(), nullptr, nullptr); return false; } bool ide::printDeclTypeUSR(const ValueDecl *D, raw_ostream &OS) { Mangle::ASTMangler Mangler; std::string MangledName = Mangler.mangleDeclType(D); OS << MangledName; return false; } static bool printObjCUSRFragment(const ValueDecl *D, StringRef ObjCName, const ExtensionDecl *ExtContextD, raw_ostream &OS) { if (!D) return true; // The Swift module name that the decl originated from. If the decl is // originating from ObjC code (ObjC module or the bridging header) then this // will be empty. StringRef ModuleName; if (!D->hasClangNode()) ModuleName = D->getModuleContext()->getNameStr(); if (isa(D)) { StringRef extContextName; if (ExtContextD) { extContextName = ExtContextD->getModuleContext()->getNameStr(); } clang::index::generateUSRForObjCClass(ObjCName, OS, ModuleName, extContextName); } else if (isa(D)) { clang::index::generateUSRForObjCProtocol(ObjCName, OS, ModuleName); } else if (isa(D)) { clang::index::generateUSRForObjCProperty(ObjCName, D->isStatic(), OS); } else if (isa(D)) { // init() is a class member in Swift, but an instance method in ObjC. clang::index::generateUSRForObjCMethod(ObjCName, /*IsInstanceMethod=*/true, OS); } else if (isa(D)) { clang::index::generateUSRForObjCMethod(ObjCName, D->isInstanceMember(), OS); } else if (isa(D)) { clang::index::generateUSRForGlobalEnum(ObjCName, OS, ModuleName); } else if (isa(D)) { clang::index::generateUSRForEnumConstant(ObjCName, OS); } else { llvm_unreachable("Unexpected value decl"); } return false; } static bool printObjCUSRContext(const Decl *D, raw_ostream &OS) { OS << clang::index::getUSRSpacePrefix(); auto *DC = D->getDeclContext(); if (auto *Parent = DC->getAsNominalTypeOrNominalTypeExtensionContext()) { auto *extContextD = dyn_cast(DC); auto ObjCName = objc_translation::getObjCNameForSwiftDecl(Parent); if (printObjCUSRFragment(Parent, ObjCName.first.str(), extContextD, OS)) return true; } return false; } static bool printObjCUSRForAccessor(const AbstractStorageDecl *ASD, AccessorKind Kind, raw_ostream &OS) { if (printObjCUSRContext(ASD, OS)) return true; ObjCSelector Selector; switch (Kind) { case swift::AccessorKind::IsGetter: Selector = ASD->getObjCGetterSelector(); break; case swift::AccessorKind::IsSetter: Selector = ASD->getObjCSetterSelector(); break; default: llvm_unreachable("invalid accessor kind"); } assert(Selector); llvm::SmallString<128> Buf; clang::index::generateUSRForObjCMethod(Selector.getString(Buf), ASD->isInstanceMember(), OS); return false; } static bool printObjCUSR(const ValueDecl *D, raw_ostream &OS) { if (printObjCUSRContext(D, OS)) return true; auto *extContextD = dyn_cast(D->getDeclContext()); auto ObjCName = objc_translation::getObjCNameForSwiftDecl(D); if (!ObjCName.first.empty()) return printObjCUSRFragment(D, ObjCName.first.str(), extContextD, OS); assert(ObjCName.second); llvm::SmallString<128> Buf; return printObjCUSRFragment(D, ObjCName.second.getString(Buf), extContextD, OS); } static bool shouldUseObjCUSR(const Decl *D) { // Only the subscript getter/setter are visible to ObjC rather than the // subscript itself if (isa(D)) return false; auto Parent = D->getDeclContext()->getInnermostDeclarationDeclContext(); if (Parent && (!shouldUseObjCUSR(Parent) || // parent should be visible too !D->getDeclContext()->isTypeContext() || // no local decls isa(D))) // nested types aren't supported return false; if (const ValueDecl *VD = dyn_cast(D)) { if (auto *PD = dyn_cast(D)) if (auto known = PD->getKnownProtocolKind()) if (known == KnownProtocolKind::AnyObject) return false; if (isa(VD)) return true; return objc_translation::isVisibleToObjC(VD, Accessibility::Internal); } if (const ExtensionDecl *ED = dyn_cast(D)) { if (auto ExtendedType = ED->getExtendedType()) { auto baseClass = ExtendedType->getClassOrBoundGenericClass(); return baseClass && shouldUseObjCUSR(baseClass) && !baseClass->isForeign(); } } return false; } bool ide::printDeclUSR(const ValueDecl *D, raw_ostream &OS) { if (!D->hasName() && !isa(D) && (!isa(D) || cast(D)->getAccessorKind() == AccessorKind::NotAccessor)) return true; // Ignore. if (D->getModuleContext()->isBuiltinModule()) return true; // Ignore. if (isa(D)) return true; // Ignore. auto interpretAsClangNode = [](const ValueDecl *D)->ClangNode { ClangNode ClangN = D->getClangNode(); if (auto ClangD = ClangN.getAsDecl()) { // NSErrorDomain causes the clang enum to be imported like this: // // struct MyError { // enum Code : Int32 { // case errFirst // case errSecond // } // static var errFirst: MyError.Code { get } // static var errSecond: MyError.Code { get } // } // // The clang enum constants are associated with both the static vars and // the enum cases. // But we want unique USRs for the above symbols, so use the clang USR // for the enum cases, and the Swift USR for the vars. // if (auto *ClangEnumConst = dyn_cast(ClangD)) { if (auto *ClangEnum = dyn_cast(ClangEnumConst->getDeclContext())) { if (ClangEnum->hasAttr() && isa(D)) return ClangNode(); } } } return ClangN; }; if (ClangNode ClangN = interpretAsClangNode(D)) { llvm::SmallString<128> Buf; if (auto ClangD = ClangN.getAsDecl()) { bool Ignore = clang::index::generateUSRForDecl(ClangD, Buf); if (!Ignore) OS << Buf.str(); return Ignore; } auto &Importer = *D->getASTContext().getClangModuleLoader(); auto ClangMacroInfo = ClangN.getAsMacro(); bool Ignore = clang::index::generateUSRForMacro(D->getNameStr(), ClangMacroInfo->getDefinitionLoc(), Importer.getClangASTContext().getSourceManager(), Buf); if (!Ignore) OS << Buf.str(); return Ignore; } if (shouldUseObjCUSR(D)) { return printObjCUSR(D, OS); } if (!D->hasInterfaceType()) return true; // Invalid code. if (D->getInterfaceType().findIf([](Type t) -> bool { return t->is(); })) return true; Mangle::ASTMangler NewMangler; std::string Mangled = NewMangler.mangleDeclAsUSR(D, getUSRSpacePrefix()); OS << Mangled; return false; } bool ide::printAccessorUSR(const AbstractStorageDecl *D, AccessorKind AccKind, llvm::raw_ostream &OS) { // AccKind should always be either IsGetter or IsSetter here, based // on whether a reference is a mutating or non-mutating use. USRs // aren't supposed to reflect implementation differences like stored // vs. addressed vs. observing. // // On the other side, the implementation indexer should be // registering the getter/setter USRs independently of how they're // actually implemented. So a stored variable should still have // getter/setter USRs (pointing to the variable declaration), and an // addressed variable should have its "getter" point at the // addressor. AbstractStorageDecl *SD = const_cast(D); if (shouldUseObjCUSR(SD)) { return printObjCUSRForAccessor(SD, AccKind, OS); } Mangle::ASTMangler NewMangler; std::string Mangled = NewMangler.mangleAccessorEntityAsUSR(AccKind, AddressorKind::NotAddressor, SD, getUSRSpacePrefix()); OS << Mangled; return false; } bool ide::printExtensionUSR(const ExtensionDecl *ED, raw_ostream &OS) { if (ED->getExtendedType().isNull()) return true; // We make up a unique usr for each extension by combining a prefix // and the USR of the first value member of the extension. for (auto D : ED->getMembers()) { if (auto VD = dyn_cast(D)) { OS << getUSRSpacePrefix() << "e:"; return printDeclUSR(VD, OS); } } if (ED->getExtendedType() && ED->getExtendedType()->getAnyNominal()) { OS << getUSRSpacePrefix() << "e:"; printDeclUSR(ED->getExtendedType()->getAnyNominal(), OS); } else { return true; } for (auto Inherit : ED->getInherited()) { if (auto T = Inherit.getType()) { if (T->getAnyNominal()) return printDeclUSR(T->getAnyNominal(), OS); } } return true; }