-
Notifications
You must be signed in to change notification settings - Fork 10.6k
Use clang-style USRs for swift decls that are exposed to Objective C #7670
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@swift-ci please smoke test |
lib/AST/Decl.cpp
Outdated
| return true; | ||
| } else if (checkParent) { | ||
| if (auto ctor = dyn_cast<ConstructorDecl>(VD)) { | ||
| // Check if we're overriding an initializer that is visible to obj-c |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this the only case that checks the parent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the logic PrintAsObjC was using to decide whether to include a decl in the generated header – I just moved the function here to make sure USR generation and the header printer use the same logic. I assume 'checkParent' was added specifically for the case of still writing out < minRequiredAccess initializers that override a >= minRequiredAccess initializer.
lib/AST/USRGeneration.cpp
Outdated
|
|
||
| auto Parent = D->getDeclContext()->getInnermostDeclarationDeclContext(); | ||
| if (Parent && (!ShouldUseObjCName(Parent) || // parent should be visible too | ||
| !D->getDeclContext()->isTypeContext() || // no local decls |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation is off.
lib/AST/USRGeneration.cpp
Outdated
|
|
||
| if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) { | ||
| if (isa<EnumElementDecl>(VD)) | ||
| return Parent; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does an EnumElementDecl ever not have a parent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wasn't sure about invalid code, but it doesn't look like it – I'll change it to true ;-)
test/IDE/print_usrs.swift
Outdated
| } | ||
|
|
||
| // CHECK: [[@LINE+1]]:14 c:objc(cs)ObjCClass1(cpy)typeComputed{{$}} | ||
| static var typeComputed: Int { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this actually show up as a class property in ObjC? I would have expected you'd need to say "class" instead of "static" (they're not the same).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does at the moment, yeah:
SWIFT_CLASS_PROPERTY(@Property (nonatomic, class) NSInteger typeComputed;)
- (NSInteger)typeComputed SWIFT_WARN_UNUSED_RESULT;
- (void)setTypeComputed:(NSInteger)newValue;
| /// Returns true if the given value decl D is visible to ObjC of its | ||
| /// own accord (i.e. without considering its context) | ||
| bool isVisibleToObjC(const ValueDecl *VD, Accessibility minRequiredAccess, | ||
| bool checkParent = true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: bool should align with const in the previous line.
lib/AST/Decl.cpp
Outdated
| } else if (checkParent) { | ||
| if (auto ctor = dyn_cast<ConstructorDecl>(VD)) { | ||
| // Check if we're overriding an initializer that is visible to obj-c | ||
| if (auto parent = ctor->getOverriddenDecl()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we care about getSatisfiedProtocolRequirements() here?
lib/AST/USRGeneration.cpp
Outdated
| OS << "@" << ObjCName; | ||
| } else { | ||
| llvm_unreachable("Unexpected value decl"); | ||
| return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: redundant return here
lib/AST/USRGeneration.cpp
Outdated
| OS << clang::index::getUSRSpacePrefix(); | ||
|
|
||
| if (D->getDeclContext()->isTypeContext()) { | ||
| auto *Parent = D->getDeclContext()->getAsNominalTypeOrNominalTypeExtensionContext(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these above two lines can be combined as:
if (auto *Parent = D->getDeclContext()->getAsNominalTypeOrNominalTypeExtensionContext())
lib/AST/USRGeneration.cpp
Outdated
|
|
||
| if (!Ident.empty()) | ||
| return printObjCNameFragment(D, Ident.str(), OS); | ||
| if (Selector) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert(Selector) here. one and only one of Ident and Selector is valid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there no cases (e.g. invalid code) where they'll both come back invalid?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For invalid code, we may get nameless value decls. Can we have an early exist in this function like if (VD->getName().empty) return false like the one in ide::printDeclUSR so that we know what's going on without ignoring the cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realize we do have similar forgiving check in SwiftSourceDocInfo.cpp. The reason there is that we may have preferred names that are non-translatable to ObjC names, for instance, when the argument counts do not match. However, these cases are unlikely to happen here because we don't have preferred names.
lib/AST/Decl.cpp
Outdated
| } | ||
|
|
||
| bool swift::objc_translation:: | ||
| isVisibleToObjC(const ValueDecl *VD, Accessibility minRequiredAccess, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a better place for this than Decl.cpp?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We want the utilities to be inside libAST. Which file do you suggest?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest either moving it to some other file, in lib/IDE/, or making it a method on ValueDecl instead of a top-level function. Just feels weird to see 'swift::objc_translation' in this file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also how about 'isVisibleInBridgingHeader' instead of 'isVisibleToObjC'?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bridging header is the other direction (ObjC code visible in Swift).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's generally preferable for headers to have an associated implementation file, so SwiftNameTranslation.h can have SwiftNameTranslation.cpp for its code, it doesn't have to go to Decl.cpp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like @akyrtzi's suggest the best.
… own file. Also fix code formatting issues and simplify the code in USRGeneration.cpp based on review comments in PR swiftlang#7670.
|
@swift-ci please smoke test |
|
@swift-ci please smoke test |
lib/AST/SwiftNameTranslation.cpp
Outdated
| bool checkParent) { | ||
| if (!(VD->isObjC() || VD->getAttrs().hasAttribute<CDeclAttr>())) | ||
| return false; | ||
| if (VD->getFormalAccess() >= minRequiredAccess) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we check VD->hasAccessibility() before getting it? invalid code usually has this trap.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean hasAccessibility()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right
…hasAccessibility() check.
|
@swift-ci please smoke test |
We have an issue where the Swift symbols that are exported to ObjC via the generated ObjC header that the Swift compiler emits, have different USRs when indexed from swift & clang.
The swift side uses Swift-specific USRs while the clang side uses it’s own ObjC USRs, making these symbols and their references seem as if they are different symbols (e.g. for jump-to-definition, callers, etc).
This patch changes the USR generation for @objc swift symbols to use clang-style USRs, so there is a single USR cross-language.
This is a step towards resolving rdar://problem/16271632, but it doesn't yet 'namespace' the generated clang-style USRs with the swift module name (waiting on some clang changes). This is needed to avoid USR conflicts with symbols from different Swift frameworks.