Skip to content

Commit b57e0b3

Browse files
committed
Use Clang node USR for decls synthesized for Error enums, and allow requesting the Swift USR.
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 5a92bc5 commit b57e0b3

File tree

11 files changed

+134
-31
lines changed

11 files changed

+134
-31
lines changed

include/swift/AST/TypeCheckRequests.h

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -713,20 +713,45 @@ class RequirementRequest :
713713
bool isCached() const;
714714
};
715715

716+
struct USRGenerationOptions {
717+
/// @brief Whether to emit USRs using the Swift declaration when it is
718+
// synthesized from a Clang based declaration. Useful in cases where Swift
719+
// declarations are synthesized from Clang nodes but the caller actually
720+
// wants the USR of the Swift declaration.
721+
bool distinguishSynthesizedDecls;
722+
723+
friend llvm::hash_code hash_value(const USRGenerationOptions &options) {
724+
return llvm::hash_value(options.distinguishSynthesizedDecls);
725+
}
726+
727+
friend bool operator==(const USRGenerationOptions &lhs,
728+
const USRGenerationOptions &rhs) {
729+
return lhs.distinguishSynthesizedDecls == rhs.distinguishSynthesizedDecls;
730+
}
731+
732+
friend bool operator!=(const USRGenerationOptions &lhs,
733+
const USRGenerationOptions &rhs) {
734+
return !(lhs == rhs);
735+
}
736+
};
737+
738+
void simple_display(llvm::raw_ostream &out,
739+
const USRGenerationOptions &options);
740+
716741
/// Generate the USR for the given declaration.
717-
class USRGenerationRequest :
718-
public SimpleRequest<USRGenerationRequest,
719-
std::string(const ValueDecl*),
720-
RequestFlags::Cached>
721-
{
742+
class USRGenerationRequest
743+
: public SimpleRequest<USRGenerationRequest,
744+
std::string(const ValueDecl *, USRGenerationOptions),
745+
RequestFlags::Cached> {
722746
public:
723747
using SimpleRequest::SimpleRequest;
724748

725749
private:
726750
friend SimpleRequest;
727751

728752
// Evaluation.
729-
std::string evaluate(Evaluator &eval, const ValueDecl *d) const;
753+
std::string evaluate(Evaluator &eval, const ValueDecl *d,
754+
USRGenerationOptions options) const;
730755

731756
public:
732757
// Caching

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,8 @@ SWIFT_REQUEST(TypeChecker, TypeCheckASTNodeAtLocRequest,
366366
Uncached, NoLocationInfo)
367367
SWIFT_REQUEST(TypeChecker, UnderlyingTypeRequest, Type(TypeAliasDecl *),
368368
SeparatelyCached, NoLocationInfo)
369-
SWIFT_REQUEST(TypeChecker, USRGenerationRequest, std::string(const ValueDecl *),
369+
SWIFT_REQUEST(TypeChecker, USRGenerationRequest,
370+
std::string(const ValueDecl *, USRGenerationOptions),
370371
Cached, NoLocationInfo)
371372
SWIFT_REQUEST(TypeChecker, IsABICompatibleOverrideRequest,
372373
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);

lib/AST/USRGeneration.cpp

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,26 @@
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"
23+
#include "swift/ClangImporter/ClangModule.h"
2324
#include "swift/Demangling/Demangler.h"
24-
#include "llvm/ADT/SmallString.h"
25-
#include "llvm/ADT/StringRef.h"
26-
#include "llvm/Support/raw_ostream.h"
2725
#include "clang/AST/ASTContext.h"
2826
#include "clang/AST/Attr.h"
2927
#include "clang/Index/USRGeneration.h"
3028
#include "clang/Lex/PreprocessingRecord.h"
3129
#include "clang/Lex/Preprocessor.h"
30+
#include "llvm/ADT/SmallString.h"
31+
#include "llvm/ADT/StringRef.h"
32+
#include "llvm/Support/raw_ostream.h"
3233

3334
using namespace swift;
3435
using namespace ide;
@@ -170,9 +171,15 @@ static bool shouldUseObjCUSR(const Decl *D) {
170171
return false;
171172
}
172173

174+
void swift::simple_display(llvm::raw_ostream &out,
175+
const USRGenerationOptions &options) {
176+
out << "USRGenerationOptions (distinguishSynthesizedDecls: "
177+
<< options.distinguishSynthesizedDecls << ")";
178+
}
179+
173180
std::string
174-
swift::USRGenerationRequest::evaluate(Evaluator &evaluator,
175-
const ValueDecl *D) const {
181+
swift::USRGenerationRequest::evaluate(Evaluator &evaluator, const ValueDecl *D,
182+
USRGenerationOptions options) const {
176183
if (auto *VD = dyn_cast<VarDecl>(D))
177184
D = VD->getCanonicalVarDecl();
178185

@@ -184,8 +191,10 @@ swift::USRGenerationRequest::evaluate(Evaluator &evaluator,
184191
if (isa<ModuleDecl>(D))
185192
return std::string(); // Ignore.
186193

187-
auto interpretAsClangNode = [](const ValueDecl *D)->ClangNode {
188-
ClangNode ClangN = D->getClangNode();
194+
auto interpretAsClangNode = [&options](const ValueDecl *D) -> ClangNode {
195+
auto &ctx = D->getASTContext();
196+
auto *importer = static_cast<ClangImporter *>(ctx.getClangModuleLoader());
197+
ClangNode ClangN = importer->getEffectiveClangNode(D);
189198
if (auto ClangD = ClangN.getAsDecl()) {
190199
// NSErrorDomain causes the clang enum to be imported like this:
191200
//
@@ -203,12 +212,19 @@ swift::USRGenerationRequest::evaluate(Evaluator &evaluator,
203212
// But we want unique USRs for the above symbols, so use the clang USR
204213
// for the enum cases, and the Swift USR for the vars.
205214
//
215+
if (!options.distinguishSynthesizedDecls) {
216+
return ClangN;
217+
}
206218
if (auto *ClangEnumConst = dyn_cast<clang::EnumConstantDecl>(ClangD)) {
207-
if (auto *ClangEnum = dyn_cast<clang::EnumDecl>(ClangEnumConst->getDeclContext())) {
219+
if (auto *ClangEnum =
220+
dyn_cast<clang::EnumDecl>(ClangEnumConst->getDeclContext())) {
208221
if (ClangEnum->hasAttr<clang::NSErrorDomainAttr>() && isa<VarDecl>(D))
209222
return ClangNode();
210223
}
211224
}
225+
if (D->getAttrs().hasAttribute<ClangImporterSynthesizedTypeAttr>()) {
226+
return ClangNode();
227+
}
212228
}
213229
return ClangN;
214230
};
@@ -292,10 +308,11 @@ bool ide::printModuleUSR(ModuleEntity Mod, raw_ostream &OS) {
292308
}
293309
}
294310

295-
bool ide::printValueDeclUSR(const ValueDecl *D, raw_ostream &OS) {
296-
auto result = evaluateOrDefault(D->getASTContext().evaluator,
297-
USRGenerationRequest { D },
298-
std::string());
311+
bool ide::printValueDeclUSR(const ValueDecl *D, raw_ostream &OS,
312+
bool distinguishSynthesizedDecls) {
313+
auto result = evaluateOrDefault(
314+
D->getASTContext().evaluator,
315+
USRGenerationRequest{D, {distinguishSynthesizedDecls}}, std::string());
299316
if (result.empty())
300317
return true;
301318
OS << result;
@@ -354,9 +371,10 @@ bool ide::printExtensionUSR(const ExtensionDecl *ED, raw_ostream &OS) {
354371
return true;
355372
}
356373

357-
bool ide::printDeclUSR(const Decl *D, raw_ostream &OS) {
374+
bool ide::printDeclUSR(const Decl *D, raw_ostream &OS,
375+
bool distinguishSynthesizedDecls) {
358376
if (auto *VD = dyn_cast<ValueDecl>(D)) {
359-
if (ide::printValueDeclUSR(VD, OS)) {
377+
if (ide::printValueDeclUSR(VD, OS, distinguishSynthesizedDecls)) {
360378
return true;
361379
}
362380
} 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)