From 6f1417135b00ce179b0f41975e5a8cc43aa1f611 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 23 Oct 2025 09:11:17 +0100 Subject: [PATCH 1/7] [SourceKit] Fix handling of `@abi` in `AnnotatingPrinter` Make sure we avoid adding these to the entity stack entirely, which avoids hitting the assertion that a top-level entity isn't encountered with a non-empty stack. --- test/SourceKit/DocSupport/doc_abi.swift | 44 +++++++++++++++++++ .../lib/SwiftLang/SwiftDocSupport.cpp | 24 ++++++---- 2 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 test/SourceKit/DocSupport/doc_abi.swift diff --git a/test/SourceKit/DocSupport/doc_abi.swift b/test/SourceKit/DocSupport/doc_abi.swift new file mode 100644 index 0000000000000..cbfb0ebd5eb45 --- /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:3Mod3baryyF", + 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()) { From 401eafa9f1e708dc62fe88346b7ae3fa36e5ea88 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 23 Oct 2025 09:11:17 +0100 Subject: [PATCH 2/7] [AST] NFC: Move `getABIDecl` onto `ASTMangler` --- include/swift/AST/ASTMangler.h | 22 +++++++++++++++++++++ lib/AST/ASTMangler.cpp | 35 ++++++++++++---------------------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index c4933fc4009fd..19416fa134e6c 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -791,6 +791,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) + 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/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 22d966edde649..566ea7c8e77ca 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; } @@ -5329,8 +5318,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 +5327,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; From 28e0010dd6a65f3c01a00c9a11e8b652360732f5 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 23 Oct 2025 09:11:17 +0100 Subject: [PATCH 3/7] [AST] Fix setting of `DWARFMangling` in ASTMangler Turns out this constructor was never actually setting this bit. `mangleTypeForDebugger` also sets this to `true`, so it doesn't seem like this caused issues in practice, but let's actually set it. This parameter seems like it could be removed at this point, but I'll leave that for a follow-up. --- include/swift/AST/ASTMangler.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index 19416fa134e6c..a6c877e15a0f7 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -187,10 +187,10 @@ class ASTMangler : public Mangler { HasSymbolQuery, }; - /// lldb overrides the defaulted argument to 'true'. + /// lldb overrides \p DWARFMangling to 'true'. ASTMangler(const ASTContext &Ctx, bool DWARFMangling = false) : Context(Ctx) { if (DWARFMangling) { - DWARFMangling = true; + this->DWARFMangling = true; RespectOriginallyDefinedIn = false; } Flavor = Ctx.LangOpts.hasFeature(Feature::Embedded) From b607ec7a2fa7c405941cb86f450ab3fa74ef835c Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 23 Oct 2025 09:11:17 +0100 Subject: [PATCH 4/7] [AST] Introduce `ASTMangler::forUSR` Rather than setting the USR-specific bits for each USR entrypoint into the mangler just expose a convenience constructor for USR generation that sets them. --- include/swift/AST/ASTMangler.h | 6 ++++++ lib/AST/ASTMangler.cpp | 6 ------ lib/AST/USRGeneration.cpp | 9 ++++++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index a6c877e15a0f7..ed944365fc92c 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -198,6 +198,12 @@ class ASTMangler : public Mangler { : 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); + } + const ASTContext &getASTContext() { return Context; } void addTypeSubstitution(Type type, GenericSignature sig) { diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 566ea7c8e77ca..380c9db1a53a0 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -958,8 +958,6 @@ std::string ASTMangler::mangleTypeAsContextUSR(const NominalTypeDecl *type) { } std::string ASTMangler::mangleTypeAsUSR(Type Ty) { - DWARFMangling = true; - RespectOriginallyDefinedIn = false; beginMangling(); Ty = getTypeForDWARFMangling(Ty); @@ -1019,8 +1017,6 @@ ASTMangler::mangleAnyDecl(const ValueDecl *Decl, std::string ASTMangler::mangleDeclAsUSR(const ValueDecl *Decl, StringRef USRPrefix) { - llvm::SaveAndRestore respectOriginallyDefinedInRAII( - RespectOriginallyDefinedIn, false); return (llvm::Twine(USRPrefix) + mangleAnyDecl(Decl, false)).str(); } @@ -1029,8 +1025,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); diff --git a/lib/AST/USRGeneration.cpp b/lib/AST/USRGeneration.cpp index fd25bc3db6909..9724670b49aa0 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,7 +246,8 @@ swift::SwiftUSRGenerationRequest::evaluate(Evaluator &evaluator, if (declIFaceTy.findIf([](Type t) -> bool { return t->is(); })) return std::string(); - Mangle::ASTMangler NewMangler(D->getASTContext()); + using namespace Mangle; + ASTMangler NewMangler = ASTMangler::forUSR(D->getASTContext()); return NewMangler.mangleDeclAsUSR(D, getUSRSpacePrefix()); } @@ -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()); From a1e1656ed562d9f5ab6c6e02255eb821bfbeb0a7 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 23 Oct 2025 09:11:17 +0100 Subject: [PATCH 5/7] [AST] Remove `respectOriginallyDefinedIn` parameter from `mangleAnyDecl` This was always set to `true` except for USR mangling, where we already have it set to `false` for IDE USRs. The other clients were: - AutoDiff, which is just using the resulting string as a dictionary key, so don't seem to have any preference. - The ClangImporter, which always overrides `@_originallyDefinedIn` anyway. --- include/swift/AST/ASTMangler.h | 3 +-- lib/APIDigester/ModuleAnalyzerNodes.cpp | 3 +-- lib/AST/ASTMangler.cpp | 15 ++++++--------- lib/AST/ASTPrinter.cpp | 6 +++--- lib/PrintAsClang/ModuleContentsWriter.cpp | 3 +-- 5 files changed, 12 insertions(+), 18 deletions(-) diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index ed944365fc92c..c8eac3c027b8f 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -398,8 +398,7 @@ 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 mangleAnyDecl(const ValueDecl *decl, bool addPrefix); std::string mangleDeclAsUSR(const ValueDecl *Decl, StringRef USRPrefix); std::string mangleAccessorEntityAsUSR(AccessorKind kind, 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 380c9db1a53a0..8e4f8497e6446 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -993,31 +993,28 @@ 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) { - return (llvm::Twine(USRPrefix) + mangleAnyDecl(Decl, false)).str(); + return (llvm::Twine(USRPrefix) + mangleAnyDecl(Decl, /*addPrefix*/ false)) + .str(); } std::string ASTMangler::mangleAccessorEntityAsUSR(AccessorKind kind, 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/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) { From 169096c233f4eb85231c70fced3505855ee181d6 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 23 Oct 2025 09:11:17 +0100 Subject: [PATCH 6/7] [AST] Rename `mangleDeclAsUSR` -> `mangleDeclWithPrefix` This is used by other things that don't necessarily want an IDE USR. --- include/swift/AST/ASTMangler.h | 2 +- lib/AST/ASTMangler.cpp | 7 +++---- lib/AST/USRGeneration.cpp | 2 +- lib/ClangImporter/SwiftDeclSynthesizer.cpp | 2 +- lib/Serialization/ModuleFile.cpp | 2 +- lib/Serialization/Serialization.cpp | 5 +++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index c8eac3c027b8f..c5f90a5ce020b 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -399,7 +399,7 @@ class ASTMangler : public Mangler { void appendAnyDecl(const ValueDecl *Decl); std::string mangleAnyDecl(const ValueDecl *decl, bool addPrefix); - std::string mangleDeclAsUSR(const ValueDecl *Decl, StringRef USRPrefix); + std::string mangleDeclWithPrefix(const ValueDecl *decl, StringRef prefix); std::string mangleAccessorEntityAsUSR(AccessorKind kind, const AbstractStorageDecl *decl, diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 8e4f8497e6446..f9a6ed9c7f1a6 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -1011,10 +1011,9 @@ std::string ASTMangler::mangleAnyDecl(const ValueDecl *decl, bool addPrefix) { return finalize(); } -std::string ASTMangler::mangleDeclAsUSR(const ValueDecl *Decl, - StringRef USRPrefix) { - return (llvm::Twine(USRPrefix) + mangleAnyDecl(Decl, /*addPrefix*/ 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, diff --git a/lib/AST/USRGeneration.cpp b/lib/AST/USRGeneration.cpp index 9724670b49aa0..c108778f2fc3b 100644 --- a/lib/AST/USRGeneration.cpp +++ b/lib/AST/USRGeneration.cpp @@ -248,7 +248,7 @@ swift::SwiftUSRGenerationRequest::evaluate(Evaluator &evaluator, using namespace Mangle; ASTMangler NewMangler = ASTMangler::forUSR(D->getASTContext()); - return NewMangler.mangleDeclAsUSR(D, getUSRSpacePrefix()); + return NewMangler.mangleDeclWithPrefix(D, getUSRSpacePrefix()); } std::string 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/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()}); From c7e9809480bd87e842f07b69788df908eaed97ba Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Thu, 23 Oct 2025 09:11:17 +0100 Subject: [PATCH 7/7] [IDE] Mangle USRs using API decls rather than ABI decls For semantic functionality the API decl is the more useful thing to mangle, and redeclaration checking ensures we can't end up with conflicts. This ensures we're able to perform a name lookup for the decl based on its USR without having to maintain a separate lookup table for ABI names. --- include/swift/AST/ASTMangler.h | 15 ++++++++++++--- test/Index/index_abi_attr.swift | 6 ++++++ test/SourceKit/DocSupport/doc_abi.swift | 2 +- .../ASTMangler-appendEntity-1c86dd.swift | 2 +- 4 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 test/Index/index_abi_attr.swift rename validation-test/IDE/{crashers => crashers_fixed}/ASTMangler-appendEntity-1c86dd.swift (62%) diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index c5f90a5ce020b..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: @@ -188,11 +194,14 @@ class ASTMangler : public Mangler { }; /// lldb overrides \p DWARFMangling to 'true'. - ASTMangler(const ASTContext &Ctx, bool DWARFMangling = false) : Context(Ctx) { + ASTMangler(const ASTContext &Ctx, bool DWARFMangling = false, + bool UseAPIMangling = false) + : Context(Ctx) { if (DWARFMangling) { this->DWARFMangling = true; RespectOriginallyDefinedIn = false; } + this->UseAPIMangling = UseAPIMangling; Flavor = Ctx.LangOpts.hasFeature(Feature::Embedded) ? ManglingFlavor::Embedded : ManglingFlavor::Default; @@ -201,7 +210,7 @@ class ASTMangler : public Mangler { /// Create an ASTMangler suitable for mangling a USR for use in semantic /// functionality. static ASTMangler forUSR(const ASTContext &Ctx) { - return ASTMangler(Ctx, /*DWARFMangling*/ true); + return ASTMangler(Ctx, /*DWARFMangling*/ true, /*UseAPIMangling*/ true); } const ASTContext &getASTContext() { return Context; } @@ -808,7 +817,7 @@ class ASTMangler : public Mangler { template DeclType *getABIDecl(DeclType *D) const { - if (!D) + if (!D || UseAPIMangling) return nullptr; auto abiRole = ABIRoleInfo(D); 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 index cbfb0ebd5eb45..a9bc52186f49b 100644 --- a/test/SourceKit/DocSupport/doc_abi.swift +++ b/test/SourceKit/DocSupport/doc_abi.swift @@ -34,7 +34,7 @@ public func foo() {} { key.kind: source.lang.swift.decl.function.free, key.name: "foo()", - key.usr: "s:3Mod3baryyF", + key.usr: "s:3Mod3fooyyF", key.offset: 0, key.length: 27, key.fully_annotated_decl: "@abi(func bar()) func foo()" 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 #^^#()