diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index c4933fc4009fd..7ec697732e626 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -106,6 +106,12 @@ class ASTMangler : public Mangler { /// defined in. bool RespectOriginallyDefinedIn = true; + /// Whether to always mangle using the declaration's API, ignoring e.g + /// attached `@abi` attributes. This is necessary for USR mangling since for + /// semantic functionality we're only concerned about the API entity, and need + /// to be able to do name lookups to find the original decl based on the USR. + bool UseAPIMangling = false; + public: class SymbolicReferent { public: @@ -187,17 +193,26 @@ class ASTMangler : public Mangler { HasSymbolQuery, }; - /// lldb overrides the defaulted argument to 'true'. - ASTMangler(const ASTContext &Ctx, bool DWARFMangling = false) : Context(Ctx) { + /// lldb overrides \p DWARFMangling to 'true'. + ASTMangler(const ASTContext &Ctx, bool DWARFMangling = false, + bool UseAPIMangling = false) + : Context(Ctx) { if (DWARFMangling) { - DWARFMangling = true; + this->DWARFMangling = true; RespectOriginallyDefinedIn = false; } + this->UseAPIMangling = UseAPIMangling; Flavor = Ctx.LangOpts.hasFeature(Feature::Embedded) ? ManglingFlavor::Embedded : ManglingFlavor::Default; } + /// Create an ASTMangler suitable for mangling a USR for use in semantic + /// functionality. + static ASTMangler forUSR(const ASTContext &Ctx) { + return ASTMangler(Ctx, /*DWARFMangling*/ true, /*UseAPIMangling*/ true); + } + const ASTContext &getASTContext() { return Context; } void addTypeSubstitution(Type type, GenericSignature sig) { @@ -392,9 +407,8 @@ class ASTMangler : public Mangler { std::string mangleTypeAsContextUSR(const NominalTypeDecl *type); void appendAnyDecl(const ValueDecl *Decl); - std::string mangleAnyDecl(const ValueDecl *Decl, bool prefix, - bool respectOriginallyDefinedIn = false); - std::string mangleDeclAsUSR(const ValueDecl *Decl, StringRef USRPrefix); + std::string mangleAnyDecl(const ValueDecl *decl, bool addPrefix); + std::string mangleDeclWithPrefix(const ValueDecl *decl, StringRef prefix); std::string mangleAccessorEntityAsUSR(AccessorKind kind, const AbstractStorageDecl *decl, @@ -791,6 +805,28 @@ class ASTMangler : public Mangler { const ValueDecl *forDecl); void appendLifetimeDependence(LifetimeDependenceInfo info); + + void gatherExistentialRequirements(SmallVectorImpl &reqs, + ParameterizedProtocolType *PPT) const; + + /// Extracts a list of inverse requirements from a PCT serving as the + /// constraint type of an existential. + void extractExistentialInverseRequirements( + SmallVectorImpl &inverses, + ProtocolCompositionType *PCT) const; + + template + DeclType *getABIDecl(DeclType *D) const { + if (!D || UseAPIMangling) + return nullptr; + + auto abiRole = ABIRoleInfo(D); + if (!abiRole.providesABI()) + return abiRole.getCounterpart(); + return nullptr; + } + + std::optional getABIDecl(SymbolicReferent ref) const; }; } // end namespace Mangle diff --git a/lib/APIDigester/ModuleAnalyzerNodes.cpp b/lib/APIDigester/ModuleAnalyzerNodes.cpp index 59ee7d4ed0f83..fe1699330f754 100644 --- a/lib/APIDigester/ModuleAnalyzerNodes.cpp +++ b/lib/APIDigester/ModuleAnalyzerNodes.cpp @@ -1120,8 +1120,7 @@ static StringRef calculateMangledName(SDKContext &Ctx, ValueDecl *VD) { return Ctx.buffer(attr->Name); } Mangle::ASTMangler NewMangler(VD->getASTContext()); - return Ctx.buffer(NewMangler.mangleAnyDecl(VD, true, - /*bool respectOriginallyDefinedIn*/true)); + return Ctx.buffer(NewMangler.mangleAnyDecl(VD, /*addPrefix*/ true)); } static StringRef calculateLocation(SDKContext &SDKCtx, Decl *D) { diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 22d966edde649..f9a6ed9c7f1a6 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -68,33 +68,22 @@ using namespace swift; using namespace swift::Mangle; -template -static DeclType *getABIDecl(DeclType *D) { - if (!D) - return nullptr; - - auto abiRole = ABIRoleInfo(D); - if (!abiRole.providesABI()) - return abiRole.getCounterpart(); - return nullptr; -} - -static std::optional -getABIDecl(ASTMangler::SymbolicReferent ref) { +std::optional +ASTMangler::getABIDecl(SymbolicReferent ref) const { switch (ref.getKind()) { - case ASTMangler::SymbolicReferent::NominalType: + case SymbolicReferent::NominalType: if (auto abiTypeDecl = getABIDecl(ref.getNominalType())) { - return ASTMangler::SymbolicReferent(abiTypeDecl); + return SymbolicReferent(abiTypeDecl); } break; - case ASTMangler::SymbolicReferent::OpaqueType: + case SymbolicReferent::OpaqueType: if (auto abiTypeDecl = getABIDecl(ref.getOpaqueType())) { - return ASTMangler::SymbolicReferent(abiTypeDecl); + return SymbolicReferent(abiTypeDecl); } break; - case ASTMangler::SymbolicReferent::ExtendedExistentialTypeShape: + case SymbolicReferent::ExtendedExistentialTypeShape: // Do nothing; mangling will use the underlying ABI decls in the end. break; } @@ -969,8 +958,6 @@ std::string ASTMangler::mangleTypeAsContextUSR(const NominalTypeDecl *type) { } std::string ASTMangler::mangleTypeAsUSR(Type Ty) { - DWARFMangling = true; - RespectOriginallyDefinedIn = false; beginMangling(); Ty = getTypeForDWARFMangling(Ty); @@ -1006,33 +993,27 @@ void ASTMangler::appendAnyDecl(const ValueDecl *Decl) { } } -std::string -ASTMangler::mangleAnyDecl(const ValueDecl *Decl, - bool prefix, - bool respectOriginallyDefinedIn) { +std::string ASTMangler::mangleAnyDecl(const ValueDecl *decl, bool addPrefix) { DWARFMangling = true; - RespectOriginallyDefinedIn = respectOriginallyDefinedIn; - if (prefix) { + if (addPrefix) { beginMangling(); } else { beginManglingWithoutPrefix(); } llvm::SaveAndRestore allowUnnamedRAII(AllowNamelessEntities, true); - appendAnyDecl(Decl); + appendAnyDecl(decl); // We have a custom prefix, so finalize() won't verify for us. If we're not // in invalid code (coming from an IDE caller) verify manually. - if (CONDITIONAL_ASSERT_enabled() && !prefix && !Decl->isInvalid()) + if (CONDITIONAL_ASSERT_enabled() && !addPrefix && !decl->isInvalid()) verify(Storage.str(), Flavor); return finalize(); } -std::string ASTMangler::mangleDeclAsUSR(const ValueDecl *Decl, - StringRef USRPrefix) { - llvm::SaveAndRestore respectOriginallyDefinedInRAII( - RespectOriginallyDefinedIn, false); - return (llvm::Twine(USRPrefix) + mangleAnyDecl(Decl, false)).str(); +std::string ASTMangler::mangleDeclWithPrefix(const ValueDecl *decl, + StringRef prefix) { + return (llvm::Twine(prefix) + mangleAnyDecl(decl, /*addPrefix*/ false)).str(); } std::string ASTMangler::mangleAccessorEntityAsUSR(AccessorKind kind, @@ -1040,8 +1021,6 @@ std::string ASTMangler::mangleAccessorEntityAsUSR(AccessorKind kind, StringRef USRPrefix, bool isStatic) { beginManglingWithoutPrefix(); - llvm::SaveAndRestore respectOriginallyDefinedInRAII( - RespectOriginallyDefinedIn, false); llvm::SaveAndRestore allowUnnamedRAII(AllowNamelessEntities, true); Buffer << USRPrefix; appendAccessorEntity(getCodeForAccessorKind(kind), decl, isStatic); @@ -5329,8 +5308,8 @@ std::string ASTMangler::mangleAttachedMacroExpansion( return finalize(); } -static void gatherExistentialRequirements(SmallVectorImpl &reqs, - ParameterizedProtocolType *PPT) { +void ASTMangler::gatherExistentialRequirements( + SmallVectorImpl &reqs, ParameterizedProtocolType *PPT) const { auto protoTy = PPT->getBaseType(); ASSERT(!getABIDecl(protoTy->getDecl()) && "need to figure out behavior"); PPT->getRequirements(protoTy->getDecl()->getSelfInterfaceType(), reqs); @@ -5338,9 +5317,9 @@ static void gatherExistentialRequirements(SmallVectorImpl &reqs, /// Extracts a list of inverse requirements from a PCT serving as the constraint /// type of an existential. -static void extractExistentialInverseRequirements( - SmallVectorImpl &inverses, - ProtocolCompositionType *PCT) { +void ASTMangler::extractExistentialInverseRequirements( + SmallVectorImpl &inverses, + ProtocolCompositionType *PCT) const { if (!PCT->hasInverse()) return; diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 3f72179aeb292..823bb95cf66a9 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -1348,9 +1348,9 @@ void PrintAST::printAttributes(const Decl *D) { if (Options.PrintSyntheticSILGenName && !D->getAttrs().hasAttribute()) { if (canPrintSyntheticSILGenName(D)) { - auto mangledName = Mangle::ASTMangler(D->getASTContext()) - .mangleAnyDecl(cast(D), /*prefix=*/true, - /*respectOriginallyDefinedIn=*/true); + auto mangledName = + Mangle::ASTMangler(D->getASTContext()) + .mangleAnyDecl(cast(D), /*addPrefix*/ true); Printer.printAttrName("@_silgen_name"); Printer << "("; Printer.printEscapedStringLiteral(mangledName); diff --git a/lib/AST/USRGeneration.cpp b/lib/AST/USRGeneration.cpp index fd25bc3db6909..c108778f2fc3b 100644 --- a/lib/AST/USRGeneration.cpp +++ b/lib/AST/USRGeneration.cpp @@ -40,7 +40,8 @@ static inline StringRef getUSRSpacePrefix() { bool ide::printTypeUSR(Type Ty, raw_ostream &OS) { assert(!Ty->hasArchetype() && "cannot have contextless archetypes mangled."); Ty = Ty->getCanonicalType()->getRValueType(); - Mangle::ASTMangler Mangler(Ty->getASTContext()); + using namespace Mangle; + ASTMangler Mangler = ASTMangler::forUSR(Ty->getASTContext()); OS << Mangler.mangleTypeAsUSR(Ty); return false; } @@ -245,8 +246,9 @@ swift::SwiftUSRGenerationRequest::evaluate(Evaluator &evaluator, if (declIFaceTy.findIf([](Type t) -> bool { return t->is(); })) return std::string(); - Mangle::ASTMangler NewMangler(D->getASTContext()); - return NewMangler.mangleDeclAsUSR(D, getUSRSpacePrefix()); + using namespace Mangle; + ASTMangler NewMangler = ASTMangler::forUSR(D->getASTContext()); + return NewMangler.mangleDeclWithPrefix(D, getUSRSpacePrefix()); } std::string @@ -375,7 +377,8 @@ bool ide::printAccessorUSR(const AbstractStorageDecl *D, AccessorKind AccKind, return printObjCUSRForAccessor(SD, AccKind, OS); } - Mangle::ASTMangler NewMangler(D->getASTContext()); + using namespace Mangle; + ASTMangler NewMangler = ASTMangler::forUSR(D->getASTContext()); std::string Mangled = NewMangler.mangleAccessorEntityAsUSR(AccKind, SD, getUSRSpacePrefix(), SD->isStatic()); diff --git a/lib/ClangImporter/SwiftDeclSynthesizer.cpp b/lib/ClangImporter/SwiftDeclSynthesizer.cpp index b38901c56848c..9a17906955a30 100644 --- a/lib/ClangImporter/SwiftDeclSynthesizer.cpp +++ b/lib/ClangImporter/SwiftDeclSynthesizer.cpp @@ -998,7 +998,7 @@ getAccessorDeclarationName(clang::ASTContext &Ctx, NominalTypeDecl *structDecl, std::string id; llvm::raw_string_ostream IdStream(id); Mangle::ASTMangler mangler(structDecl->getASTContext()); - IdStream << "$" << mangler.mangleDeclAsUSR(structDecl, "") << "$" + IdStream << "$" << mangler.mangleDeclWithPrefix(structDecl, "") << "$" << fieldDecl->getName() << "$" << suffix; return clang::DeclarationName(&Ctx.Idents.get(IdStream.str())); diff --git a/lib/PrintAsClang/ModuleContentsWriter.cpp b/lib/PrintAsClang/ModuleContentsWriter.cpp index 59d223ccf4817..8f62d8f8e33b2 100644 --- a/lib/PrintAsClang/ModuleContentsWriter.cpp +++ b/lib/PrintAsClang/ModuleContentsWriter.cpp @@ -155,8 +155,7 @@ static std::string getMangledNameString(const Decl *D) { if (!VD) return std::string(); Mangle::ASTMangler mangler(VD->getASTContext()); - return mangler.mangleAnyDecl(VD, /*prefix=*/true, - /*respectOriginallyDefinedIn=*/true); + return mangler.mangleAnyDecl(VD, /*addPrefix*/ true); } static std::string getTypeString(const ValueDecl *VD) { diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp index e08c44ec0cd0f..2d97af4cbe53d 100644 --- a/lib/Serialization/ModuleFile.cpp +++ b/lib/Serialization/ModuleFile.cpp @@ -753,7 +753,7 @@ void ModuleFile::loadDerivativeFunctionConfigurations( return; auto &ctx = originalAFD->getASTContext(); Mangle::ASTMangler Mangler(ctx); - auto mangledName = Mangler.mangleDeclAsUSR(originalAFD, ""); + auto mangledName = Mangler.mangleDeclWithPrefix(originalAFD, ""); auto configs = Core->DerivativeFunctionConfigurations->find(mangledName); if (configs == Core->DerivativeFunctionConfigurations->end()) return; diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 0e128fe200be7..d14e737151598 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -6897,14 +6897,15 @@ static void recordDerivativeFunctionConfig( auto &ctx = AFD->getASTContext(); Mangle::ASTMangler Mangler(AFD->getASTContext()); for (auto *attr : AFD->getAttrs().getAttributes()) { - auto mangledName = ctx.getIdentifier(Mangler.mangleDeclAsUSR(AFD, "")); + auto mangledName = ctx.getIdentifier(Mangler.mangleDeclWithPrefix(AFD, "")); derivativeConfigs[mangledName].insert( {ctx.getIdentifier(attr->getParameterIndices()->getString()), attr->getDerivativeGenericSignature()}); } for (auto *attr : AFD->getAttrs().getAttributes()) { auto *origAFD = attr->getOriginalFunction(ctx); - auto mangledName = ctx.getIdentifier(Mangler.mangleDeclAsUSR(origAFD, "")); + auto mangledName = + ctx.getIdentifier(Mangler.mangleDeclWithPrefix(origAFD, "")); derivativeConfigs[mangledName].insert( {ctx.getIdentifier(attr->getParameterIndices()->getString()), AFD->getGenericSignature()}); diff --git a/test/Index/index_abi_attr.swift b/test/Index/index_abi_attr.swift new file mode 100644 index 0000000000000..791bed5878ba1 --- /dev/null +++ b/test/Index/index_abi_attr.swift @@ -0,0 +1,6 @@ +// RUN: %target-swift-ide-test -print-indexed-symbols -include-locals -source-filename %s | %FileCheck %s + +// Make sure we use the API decl for mangling the USR. +@abi(func bar()) +public func foo() {} +// CHECK: [[@LINE-1]]:13 | function/Swift | foo() | s:14swift_ide_test3fooyyF | Def | rel: 0 diff --git a/test/SourceKit/DocSupport/doc_abi.swift b/test/SourceKit/DocSupport/doc_abi.swift new file mode 100644 index 0000000000000..a9bc52186f49b --- /dev/null +++ b/test/SourceKit/DocSupport/doc_abi.swift @@ -0,0 +1,44 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t +// RUN: %target-swift-frontend -emit-module -module-name Mod %t/mod.swift -o %t/Mod.swiftmodule +// RUN: %sourcekitd-test -req=doc-info -print-raw-response -module Mod -- -I %t -target %target-triple > %t/output.response +// RUN: %diff -u %t/expected.response %t/output.response + +// Make sure we don't crash here, we should exclude the @abi decl from the +// list of entities. + +//--- mod.swift +@abi(func bar()) +public func foo() {} + +//--- expected.response +{ + key.annotations: [ + { + key.kind: source.lang.swift.syntaxtype.attribute.builtin, + key.offset: 0, + key.length: 16 + }, + { + key.kind: source.lang.swift.syntaxtype.keyword, + key.offset: 17, + key.length: 4 + }, + { + key.kind: source.lang.swift.syntaxtype.identifier, + key.offset: 22, + key.length: 3 + } + ], + key.entities: [ + { + key.kind: source.lang.swift.decl.function.free, + key.name: "foo()", + key.usr: "s:3Mod3fooyyF", + key.offset: 0, + key.length: 27, + key.fully_annotated_decl: "@abi(func bar()) func foo()" + } + ], + key.sourcetext: "@abi(func bar())\nfunc foo()\n\n" +} diff --git a/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp b/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp index 211f88ff38bf1..e946bb4b7b857 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp @@ -186,10 +186,22 @@ class AnnotatingPrinter : public StreamPrinter { TopEntities.push_back(std::move(Entity)); } + bool shouldIgnoreDecl(const Decl *D) { + // Parameters are handled specially in addParameters(). + if (isa(D)) + return true; + + // We only care about API for documentation purposes. + if (!ABIRoleInfo(D).providesAPI()) + return true; + + return false; + } + void printDeclPre(const Decl *D, std::optional Bracket) override { - if (isa(D)) - return; // Parameters are handled specially in addParameters(). + if (shouldIgnoreDecl(D)) + return; if (!shouldContinuePre(D, Bracket)) return; unsigned StartOffset = OS.tell(); @@ -212,18 +224,14 @@ class AnnotatingPrinter : public StreamPrinter { void printDeclPost(const Decl *D, std::optional Bracket) override { - if (isa(D)) - return; // Parameters are handled specially in addParameters(). + if (shouldIgnoreDecl(D)) + return; if (!shouldContinuePost(D, Bracket)) return; assert(!EntitiesStack.empty()); TextEntity Entity = std::move(EntitiesStack.back()); EntitiesStack.pop_back(); - // We only care about API for documentation purposes. - if (!ABIRoleInfo(D).providesAPI()) - return; - unsigned EndOffset = OS.tell(); Entity.Range.Length = EndOffset - Entity.Range.Offset; if (EntitiesStack.empty()) { diff --git a/validation-test/IDE/crashers/ASTMangler-appendEntity-1c86dd.swift b/validation-test/IDE/crashers_fixed/ASTMangler-appendEntity-1c86dd.swift similarity index 62% rename from validation-test/IDE/crashers/ASTMangler-appendEntity-1c86dd.swift rename to validation-test/IDE/crashers_fixed/ASTMangler-appendEntity-1c86dd.swift index edbedf789db26..e71983cab011c 100644 --- a/validation-test/IDE/crashers/ASTMangler-appendEntity-1c86dd.swift +++ b/validation-test/IDE/crashers_fixed/ASTMangler-appendEntity-1c86dd.swift @@ -1,4 +1,4 @@ // {"kind":"complete","original":"070481b6","signature":"swift::Mangle::ASTMangler::appendEntity(swift::ValueDecl const*)","signatureAssert":"Assertion failed: (!isa(decl)), function appendEntity"} -// RUN: not --crash %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s +// RUN: %target-swift-ide-test -code-completion -batch-code-completion -skip-filecheck -code-completion-diagnostics -source-filename %s @abi( init () ) func a #^^#()