Skip to content

Commit 2c8e337

Browse files
authored
Merge pull request #80074 from dylansturg/objc_enum_refs
The Error enum synthesized declarations, e.g. the struct and its static accessors, should generally appear to be identical to the underlying Clang definitions. There are some specific use cases where the synthesized declarations are necessary though. I've added an option for USR generation to override the Clang node and emit the USR of the synthesized Swift declaration. This is used by SwiftDocSupport so that the USRs of the synthesized declarations are emitted. Fixes 79912
1 parent ea225d5 commit 2c8e337

File tree

13 files changed

+138
-32
lines changed

13 files changed

+138
-32
lines changed

include/swift/AST/ClangModuleLoader.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class SourceLocation;
3333
namespace swift {
3434

3535
class ClangInheritanceInfo;
36+
class ClangNode;
3637
class ConcreteDeclRef;
3738
class Decl;
3839
class FuncDecl;
@@ -321,6 +322,10 @@ class ClangModuleLoader : public ModuleLoader {
321322
getTypeDefForCXXCFOptionsDefinition(const clang::Decl *candidateDecl) = 0;
322323

323324
virtual SourceLoc importSourceLocation(clang::SourceLocation loc) = 0;
325+
326+
/// Just like Decl::getClangNode() except we look through to the 'Code'
327+
/// enum of an error wrapper struct.
328+
virtual ClangNode getEffectiveClangNode(const Decl *decl) const = 0;
324329
};
325330

326331
/// Describes a C++ template instantiation error.

include/swift/AST/TypeCheckRequests.h

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -735,20 +735,45 @@ class RequirementRequest :
735735
bool isCached() const;
736736
};
737737

738+
struct USRGenerationOptions {
739+
/// @brief Whether to emit USRs using the Swift declaration when it is
740+
/// synthesized from a Clang based declaration. Useful in cases where Swift
741+
/// declarations are synthesized from Clang nodes but the caller actually
742+
/// wants the USR of the Swift declaration.
743+
bool distinguishSynthesizedDecls;
744+
745+
friend llvm::hash_code hash_value(const USRGenerationOptions &options) {
746+
return llvm::hash_value(options.distinguishSynthesizedDecls);
747+
}
748+
749+
friend bool operator==(const USRGenerationOptions &lhs,
750+
const USRGenerationOptions &rhs) {
751+
return lhs.distinguishSynthesizedDecls == rhs.distinguishSynthesizedDecls;
752+
}
753+
754+
friend bool operator!=(const USRGenerationOptions &lhs,
755+
const USRGenerationOptions &rhs) {
756+
return !(lhs == rhs);
757+
}
758+
};
759+
760+
void simple_display(llvm::raw_ostream &out,
761+
const USRGenerationOptions &options);
762+
738763
/// Generate the USR for the given declaration.
739-
class USRGenerationRequest :
740-
public SimpleRequest<USRGenerationRequest,
741-
std::string(const ValueDecl*),
742-
RequestFlags::Cached>
743-
{
764+
class USRGenerationRequest
765+
: public SimpleRequest<USRGenerationRequest,
766+
std::string(const ValueDecl *, USRGenerationOptions),
767+
RequestFlags::Cached> {
744768
public:
745769
using SimpleRequest::SimpleRequest;
746770

747771
private:
748772
friend SimpleRequest;
749773

750774
// Evaluation.
751-
std::string evaluate(Evaluator &eval, const ValueDecl *d) const;
775+
std::string evaluate(Evaluator &eval, const ValueDecl *d,
776+
USRGenerationOptions options) const;
752777

753778
public:
754779
// Caching

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,8 @@ SWIFT_REQUEST(TypeChecker, TypeCheckASTNodeAtLocRequest,
364364
Uncached, NoLocationInfo)
365365
SWIFT_REQUEST(TypeChecker, UnderlyingTypeRequest, Type(TypeAliasDecl *),
366366
SeparatelyCached, NoLocationInfo)
367-
SWIFT_REQUEST(TypeChecker, USRGenerationRequest, std::string(const ValueDecl *),
367+
SWIFT_REQUEST(TypeChecker, USRGenerationRequest,
368+
std::string(const ValueDecl *, USRGenerationOptions),
368369
Cached, NoLocationInfo)
369370
SWIFT_REQUEST(TypeChecker, IsABICompatibleOverrideRequest,
370371
bool(ValueDecl *), Cached, NoLocationInfo)

include/swift/AST/USRGeneration.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,11 @@ bool printTypeUSR(Type Ty, raw_ostream &OS);
4343
bool printDeclTypeUSR(const ValueDecl *D, raw_ostream &OS);
4444

4545
/// Prints out the USR for the given ValueDecl.
46+
/// @param distinguishSynthesizedDecls Whether to use the USR of the
47+
/// synthesized declaration instead of the USR of the underlying Clang USR.
4648
/// \returns true if it failed, false on success.
47-
bool printValueDeclUSR(const ValueDecl *D, raw_ostream &OS);
49+
bool printValueDeclUSR(const ValueDecl *D, raw_ostream &OS,
50+
bool distinguishSynthesizedDecls = false);
4851

4952
/// Prints out the USR for the given ModuleEntity.
5053
/// In case module aliasing is used, it prints the real module name. For example,
@@ -64,8 +67,11 @@ bool printAccessorUSR(const AbstractStorageDecl *D, AccessorKind AccKind,
6467
bool printExtensionUSR(const ExtensionDecl *ED, raw_ostream &OS);
6568

6669
/// Prints out the USR for the given Decl.
70+
/// @param distinguishSynthesizedDecls Whether to use the USR of the
71+
/// synthesized declaration instead of the USR of the underlying Clang USR.
6772
/// \returns true if it failed, false on success.
68-
bool printDeclUSR(const Decl *D, raw_ostream &OS);
73+
bool printDeclUSR(const Decl *D, raw_ostream &OS,
74+
bool distinguishSynthesizedDecls = false);
6975

7076
/// Demangle a mangle-name-based USR to a human readable name.
7177
std::string demangleUSR(StringRef mangled);

include/swift/ClangImporter/ClangImporter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ class ClangImporter final : public ClangModuleLoader {
330330

331331
/// Just like Decl::getClangNode() except we look through to the 'Code'
332332
/// enum of an error wrapper struct.
333-
ClangNode getEffectiveClangNode(const Decl *decl) const;
333+
ClangNode getEffectiveClangNode(const Decl *decl) const override;
334334

335335
/// Look for textually included declarations from the bridging header.
336336
///

lib/AST/USRGeneration.cpp

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,25 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#include "swift/AST/USRGeneration.h"
1314
#include "swift/AST/ASTContext.h"
15+
#include "swift/AST/ASTMangler.h"
1416
#include "swift/AST/ClangModuleLoader.h"
1517
#include "swift/AST/GenericParamList.h"
1618
#include "swift/AST/Module.h"
17-
#include "swift/AST/USRGeneration.h"
18-
#include "swift/AST/ASTMangler.h"
1919
#include "swift/AST/SwiftNameTranslation.h"
2020
#include "swift/AST/TypeCheckRequests.h"
2121
#include "swift/AST/USRGeneration.h"
2222
#include "swift/Basic/Assertions.h"
2323
#include "swift/Demangling/Demangler.h"
24-
#include "llvm/ADT/SmallString.h"
25-
#include "llvm/ADT/StringRef.h"
26-
#include "llvm/Support/raw_ostream.h"
2724
#include "clang/AST/ASTContext.h"
2825
#include "clang/AST/Attr.h"
2926
#include "clang/Index/USRGeneration.h"
3027
#include "clang/Lex/PreprocessingRecord.h"
3128
#include "clang/Lex/Preprocessor.h"
29+
#include "llvm/ADT/SmallString.h"
30+
#include "llvm/ADT/StringRef.h"
31+
#include "llvm/Support/raw_ostream.h"
3232

3333
using namespace swift;
3434
using namespace ide;
@@ -170,9 +170,15 @@ static bool shouldUseObjCUSR(const Decl *D) {
170170
return false;
171171
}
172172

173+
void swift::simple_display(llvm::raw_ostream &out,
174+
const USRGenerationOptions &options) {
175+
out << "USRGenerationOptions (distinguishSynthesizedDecls: "
176+
<< options.distinguishSynthesizedDecls << ")";
177+
}
178+
173179
std::string
174-
swift::USRGenerationRequest::evaluate(Evaluator &evaluator,
175-
const ValueDecl *D) const {
180+
swift::USRGenerationRequest::evaluate(Evaluator &evaluator, const ValueDecl *D,
181+
USRGenerationOptions options) const {
176182
if (auto *VD = dyn_cast<VarDecl>(D))
177183
D = VD->getCanonicalVarDecl();
178184

@@ -184,8 +190,9 @@ swift::USRGenerationRequest::evaluate(Evaluator &evaluator,
184190
if (isa<ModuleDecl>(D))
185191
return std::string(); // Ignore.
186192

187-
auto interpretAsClangNode = [](const ValueDecl *D)->ClangNode {
188-
ClangNode ClangN = D->getClangNode();
193+
auto interpretAsClangNode = [&options](const ValueDecl *D) -> ClangNode {
194+
auto *importer = D->getASTContext().getClangModuleLoader();
195+
ClangNode ClangN = importer->getEffectiveClangNode(D);
189196
if (auto ClangD = ClangN.getAsDecl()) {
190197
// NSErrorDomain causes the clang enum to be imported like this:
191198
//
@@ -203,12 +210,19 @@ swift::USRGenerationRequest::evaluate(Evaluator &evaluator,
203210
// But we want unique USRs for the above symbols, so use the clang USR
204211
// for the enum cases, and the Swift USR for the vars.
205212
//
213+
if (!options.distinguishSynthesizedDecls) {
214+
return ClangN;
215+
}
206216
if (auto *ClangEnumConst = dyn_cast<clang::EnumConstantDecl>(ClangD)) {
207-
if (auto *ClangEnum = dyn_cast<clang::EnumDecl>(ClangEnumConst->getDeclContext())) {
217+
if (auto *ClangEnum =
218+
dyn_cast<clang::EnumDecl>(ClangEnumConst->getDeclContext())) {
208219
if (ClangEnum->hasAttr<clang::NSErrorDomainAttr>() && isa<VarDecl>(D))
209220
return ClangNode();
210221
}
211222
}
223+
if (D->getAttrs().hasAttribute<ClangImporterSynthesizedTypeAttr>()) {
224+
return ClangNode();
225+
}
212226
}
213227
return ClangN;
214228
};
@@ -292,10 +306,11 @@ bool ide::printModuleUSR(ModuleEntity Mod, raw_ostream &OS) {
292306
}
293307
}
294308

295-
bool ide::printValueDeclUSR(const ValueDecl *D, raw_ostream &OS) {
296-
auto result = evaluateOrDefault(D->getASTContext().evaluator,
297-
USRGenerationRequest { D },
298-
std::string());
309+
bool ide::printValueDeclUSR(const ValueDecl *D, raw_ostream &OS,
310+
bool distinguishSynthesizedDecls) {
311+
auto result = evaluateOrDefault(
312+
D->getASTContext().evaluator,
313+
USRGenerationRequest{D, {distinguishSynthesizedDecls}}, std::string());
299314
if (result.empty())
300315
return true;
301316
OS << result;
@@ -354,9 +369,10 @@ bool ide::printExtensionUSR(const ExtensionDecl *ED, raw_ostream &OS) {
354369
return true;
355370
}
356371

357-
bool ide::printDeclUSR(const Decl *D, raw_ostream &OS) {
372+
bool ide::printDeclUSR(const Decl *D, raw_ostream &OS,
373+
bool distinguishSynthesizedDecls) {
358374
if (auto *VD = dyn_cast<ValueDecl>(D)) {
359-
if (ide::printValueDeclUSR(VD, OS)) {
375+
if (ide::printValueDeclUSR(VD, OS, distinguishSynthesizedDecls)) {
360376
return true;
361377
}
362378
} else if (auto *ED = dyn_cast<ExtensionDecl>(D)) {

lib/PrintAsClang/ClangSyntaxPrinter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ void ClangSyntaxPrinter::printSymbolUSRAttribute(const ValueDecl *D) const {
472472
return;
473473
}
474474
auto result = evaluateOrDefault(D->getASTContext().evaluator,
475-
USRGenerationRequest{D}, std::string());
475+
USRGenerationRequest{D, {}}, std::string());
476476
if (result.empty())
477477
return;
478478
os << " SWIFT_SYMBOL(\"" << result << "\")";

lib/SymbolGraphGen/Symbol.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -852,7 +852,7 @@ void Symbol::printPath(llvm::raw_ostream &OS) const {
852852

853853
void Symbol::getUSR(SmallVectorImpl<char> &USR) const {
854854
llvm::raw_svector_ostream OS(USR);
855-
ide::printDeclUSR(D, OS);
855+
ide::printDeclUSR(D, OS, /*distinguishSynthesizedDecls*/ true);
856856
if (SynthesizedBaseTypeDecl) {
857857
OS << "::SYNTHESIZED::";
858858
ide::printDeclUSR(SynthesizedBaseTypeDecl, OS);

test/Index/index_imported_objc.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@
2121
@property int categoryAddedProperty;
2222
@end
2323
24+
extern NSErrorDomain const TestErrorDomain;
25+
26+
typedef NS_ERROR_ENUM(TestErrorDomain, TestError){
27+
TestErrorFoo = 0,
28+
TestErrorBar = 1,
29+
};
30+
31+
typedef NS_ENUM(NSInteger, ErrCategory) {
32+
ErrCategoryA = 0,
33+
ErrCategoryB = 1,
34+
};
35+
2436
//--- module.modulemap
2537
module objc_decls {
2638
header "objc_decls.h"
@@ -48,3 +60,34 @@ class SubObjCClass: ObjCClass {
4860
// CHECK-NEXT: RelOver | instance-method/Swift | protocolAddedMethod() | c:objc(pl)MemberAdding(im)protocolAddedMethod
4961
// CHECK-NEXT: RelChild | class/Swift | SubObjCClass | c:@M@swift_ide_test@objc(cs)SubObjCClass
5062
}
63+
func testEnumIndex() {
64+
let _: TestError.Code = .bar
65+
// CHECK: [[@LINE-1]]:10 | struct/Swift | TestError | c:@E@TestError | Ref | rel: 0
66+
// CHECK: [[@LINE-2]]:20 | enum/Swift | Code | c:@E@TestError | Ref,RelCont | rel: 1
67+
// CHECK: [[@LINE-3]]:28 | enumerator/Swift | bar | c:@E@TestError@TestErrorBar | Ref,RelCont | rel: 1
68+
let e = TestError.foo
69+
// CHECK: [[@LINE-1]]:11 | struct/Swift | TestError | c:@E@TestError | Ref,RelCont | rel: 1
70+
// CHECK: [[@LINE-2]]:21 | static-property/Swift | foo | c:@E@TestError@TestErrorFoo | Ref,Read,RelCont | rel: 1
71+
switch e {
72+
case TestError.foo: break
73+
// CHECK: [[@LINE-1]]:10 | struct/Swift | TestError | c:@E@TestError | Ref,RelCont | rel: 1
74+
// CHECK: [[@LINE-2]]:20 | static-property/Swift | foo | c:@E@TestError@TestErrorFoo | Ref,Read,RelCont | rel: 1
75+
case .bar: break
76+
// CHECK: [[@LINE-1]]:11 | enumerator/Swift | bar | c:@E@TestError@TestErrorBar | Ref,RelCont | rel: 1
77+
default: break
78+
}
79+
let _ = ErrCategory.B
80+
// CHECK: [[@LINE-1]]:11 | enum/Swift | ErrCategory | c:@E@ErrCategory | Ref,RelCont | rel: 1
81+
// CHECK: [[@LINE-2]]:23 | enumerator/Swift | B | c:@E@ErrCategory@ErrCategoryB | Ref,RelCont | rel: 1
82+
let c: ErrCategory = .A
83+
// CHECK: [[@LINE-1]]:10 | enum/Swift | ErrCategory | c:@E@ErrCategory | Ref,RelCont | rel: 1
84+
// CHECK: [[@LINE-2]]:25 | enumerator/Swift | A | c:@E@ErrCategory@ErrCategoryA | Ref,RelCont | rel: 1
85+
switch c {
86+
case ErrCategory.A: break
87+
// CHECK: [[@LINE-1]]:22 | enumerator/Swift | A | c:@E@ErrCategory@ErrCategoryA | Ref,RelCont | rel: 1
88+
// CHECK: [[@LINE-2]]:10 | enum/Swift | ErrCategory | c:@E@ErrCategory | Ref,RelCont | rel: 1
89+
// CHECK: [[@LINE-3]]:22 | enum/Swift | ErrCategory | c:@E@ErrCategory | Ref,RelCont | rel: 1
90+
case .B: break
91+
// CHECK: [[@LINE-1]]:11 | enumerator/Swift | B | c:@E@ErrCategory@ErrCategoryB | Ref,RelCont | rel: 1
92+
}
93+
}

test/SymbolGraph/ClangImporter/ErrorEnum.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818
// but it should be hidden for a similar reason
1919
// CHECK-NOT: "precise": "s:SYsSHRzSH8RawValueSYRpzrlE4hash4intoys6HasherVz_tF::SYNTHESIZED::c:@E@MyErrorCode"
2020

21+
// MyError
22+
// CHECK-DAG: "precise": "s:SC11MyErrorCodeLeV"
23+
24+
// MyError.errFirst
25+
// CHECK-DAG: "precise": "s:SC11MyErrorCodeLeV8errFirstSoAAVvpZ"
26+
2127
// MyErrorCode.Code
2228
// CHECK-DAG: "precise": "c:@E@MyErrorCode"
2329

tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ static bool initDocEntityInfo(const Decl *D,
431431
SwiftLangSupport::printDisplayName(VD, NameOS);
432432
{
433433
llvm::raw_svector_ostream OS(Info.USR);
434-
SwiftLangSupport::printUSR(VD, OS);
434+
SwiftLangSupport::printUSR(VD, OS, /*distinguishSynthesizedDecls*/ true);
435435
if (SynthesizedTarget) {
436436
OS << SwiftLangSupport::SynthesizedUSRSeparator;
437437
SwiftLangSupport::printUSR(SynthesizedTargetNTD, OS);

tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -898,8 +898,9 @@ bool SwiftLangSupport::printDisplayName(const swift::ValueDecl *D,
898898
return false;
899899
}
900900

901-
bool SwiftLangSupport::printUSR(const ValueDecl *D, llvm::raw_ostream &OS) {
902-
return ide::printValueDeclUSR(D, OS);
901+
bool SwiftLangSupport::printUSR(const ValueDecl *D, llvm::raw_ostream &OS,
902+
bool distinguishSynthesizedDecls) {
903+
return ide::printValueDeclUSR(D, OS, distinguishSynthesizedDecls);
903904
}
904905

905906
bool SwiftLangSupport::printDeclTypeUSR(const ValueDecl *D, llvm::raw_ostream &OS) {

tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,8 +456,11 @@ class SwiftLangSupport : public LangSupport {
456456
static bool printDisplayName(const swift::ValueDecl *D, llvm::raw_ostream &OS);
457457

458458
/// Generate a USR for a Decl, including the prefix.
459+
/// @param distinguishSynthesizedDecls Whether to use the USR of the
460+
/// synthesized declaration instead of the USR of the underlying Clang USR.
459461
/// \returns true if the results should be ignored, false otherwise.
460-
static bool printUSR(const swift::ValueDecl *D, llvm::raw_ostream &OS);
462+
static bool printUSR(const swift::ValueDecl *D, llvm::raw_ostream &OS,
463+
bool distinguishSynthesizedDecls = false);
461464

462465
/// Generate a USR for the Type of a given decl.
463466
/// \returns true if the results should be ignored, false otherwise.

0 commit comments

Comments
 (0)