|
25 | 25 | #include "swift/AST/NameLookup.h"
|
26 | 26 | #include "swift/AST/NameLookupRequests.h"
|
27 | 27 | #include "swift/AST/Pattern.h"
|
| 28 | +#include "swift/AST/SemanticAttrs.h" |
28 | 29 | #include "swift/AST/SourceFile.h"
|
29 | 30 | #include "swift/AST/Stmt.h"
|
30 | 31 | #include "swift/AST/TypeCheckRequests.h"
|
@@ -5053,31 +5054,40 @@ static void maybeDiagnoseCallToKeyValueObserveMethod(const Expr *E,
|
5053 | 5054 | auto fn = expr->getCalledValue();
|
5054 | 5055 | if (!fn)
|
5055 | 5056 | return;
|
5056 |
| - if (fn->getModuleContext()->getName() != C.Id_Foundation) |
5057 |
| - return; |
5058 |
| - if (!fn->getName().isCompoundName("observe", |
5059 |
| - {"", "options", "changeHandler"})) |
5060 |
| - return; |
| 5057 | + SmallVector<KeyPathExpr *, 1> keyPathArgs; |
5061 | 5058 | auto *args = expr->getArgs();
|
5062 |
| - auto firstArg = dyn_cast<KeyPathExpr>(args->getExpr(0)); |
5063 |
| - if (!firstArg) |
5064 |
| - return; |
5065 |
| - auto lastComponent = firstArg->getComponents().back(); |
5066 |
| - if (lastComponent.getKind() != KeyPathExpr::Component::Kind::Property) |
5067 |
| - return; |
5068 |
| - auto property = lastComponent.getDeclRef().getDecl(); |
5069 |
| - if (!property) |
5070 |
| - return; |
5071 |
| - auto propertyVar = cast<VarDecl>(property); |
5072 |
| - if (propertyVar->shouldUseObjCDispatch() || |
5073 |
| - (propertyVar->isObjC() && |
5074 |
| - propertyVar->getParsedAccessor(AccessorKind::Set))) |
5075 |
| - return; |
5076 |
| - C.Diags |
| 5059 | + if (fn->getModuleContext()->getName() == C.Id_Foundation && |
| 5060 | + fn->getName().isCompoundName("observe", |
| 5061 | + {"", "options", "changeHandler"})) { |
| 5062 | + if (auto keyPathArg = dyn_cast<KeyPathExpr>(args->getExpr(0))) { |
| 5063 | + keyPathArgs.push_back(keyPathArg); |
| 5064 | + } |
| 5065 | + } else if (fn->getAttrs() |
| 5066 | + .hasSemanticsAttr(semantics::KEYPATH_MUST_BE_VALID_FOR_KVO)) { |
| 5067 | + for (const auto& arg: *args) { |
| 5068 | + if (auto keyPathArg = dyn_cast<KeyPathExpr>(arg.getExpr())) { |
| 5069 | + keyPathArgs.push_back(keyPathArg); |
| 5070 | + } |
| 5071 | + } |
| 5072 | + } |
| 5073 | + for (auto *keyPathArg : keyPathArgs) { |
| 5074 | + auto lastComponent = keyPathArg->getComponents().back(); |
| 5075 | + if (lastComponent.getKind() != KeyPathExpr::Component::Kind::Property) |
| 5076 | + continue; |
| 5077 | + auto property = lastComponent.getDeclRef().getDecl(); |
| 5078 | + if (!property) |
| 5079 | + continue; |
| 5080 | + auto propertyVar = cast<VarDecl>(property); |
| 5081 | + if (propertyVar->shouldUseObjCDispatch() || |
| 5082 | + (propertyVar->isObjC() && |
| 5083 | + propertyVar->getParsedAccessor(AccessorKind::Set))) |
| 5084 | + continue; |
| 5085 | + C.Diags |
5077 | 5086 | .diagnose(expr->getLoc(),
|
5078 | 5087 | diag::observe_keypath_property_not_objc_dynamic,
|
5079 | 5088 | property->getName(), fn->getName())
|
5080 | 5089 | .highlight(lastComponent.getLoc());
|
| 5090 | + } |
5081 | 5091 | }
|
5082 | 5092 |
|
5083 | 5093 | PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
|
|
0 commit comments