[SourceKit] Add whether a property is dynamic

Properties can also be specified in a protocol/overridden by subclasses,
so they should also be classed as "dynamic" in these cases.

Removed receiver USRs when *not* dynamic, since it's not used for
anything in that case and should be equivalent to the container anyway.

Resolves rdar://92882348.
This commit is contained in:
Ben Barham
2022-05-09 11:18:22 -07:00
parent 78f937f405
commit 8889daedce
17 changed files with 438 additions and 232 deletions

View File

@@ -166,9 +166,9 @@ struct ResolvedCursorInfo {
Type ContainerType;
Stmt *TrailingStmt = nullptr;
Expr *TrailingExpr = nullptr;
/// If this is a call, whether it is "dynamic", see ide::isDynamicCall.
/// It this is a ref, whether it is "dynamic". See \c ide::isDynamicRef.
bool IsDynamic = false;
/// If this is a call, the types of the base (multiple in the case of
/// If this is a dynamic ref, the types of the base (multiple in the case of
/// protocol composition).
SmallVector<NominalTypeDecl *, 1> ReceiverTypes;
@@ -615,11 +615,22 @@ bool isBeingCalled(ArrayRef<Expr*> ExprStack);
/// stack in eg. the case of a `DotSyntaxCallExpr`).
Expr *getBase(ArrayRef<Expr *> ExprStack);
/// Assuming that we have a call, returns whether or not it is "dynamic" based
/// on its base expression and decl of the callee. Note that this is not
/// Swift's "dynamic" modifier (`ValueDecl::isDynamic`), but rathar "can call a
/// function in a conformance/subclass".
bool isDynamicCall(Expr *Base, ValueDecl *D);
/// Returns whether or not \p D could be overridden, eg. it's a member of a
/// protocol, a non-final method in a class, etc.
bool isDeclOverridable(ValueDecl *D);
/// Given a reference to a member \p D and its \p Base expression, return
/// whether that declaration could be dynamic, ie. may resolve to some other
/// declaration. Note that while the decl itself itself may be overridable, a
/// reference to it is not necessarily "dynamic". Furthermore, is *not* the
/// `dynamic` keyword.
///
/// A simple example is `SomeType.classMethod()`. `classMethod`
/// is itself overridable, but that particular reference to it *has* to be the
/// one in `SomeType`. Contrast that to `type(of: foo).classMethod()` where
/// `classMethod` could be any `classMethod` up or down the hierarchy from the
/// type of the \p Base expression.
bool isDynamicRef(Expr *Base, ValueDecl *D);
/// Adds the resolved nominal types of \p Base to \p Types.
void getReceiverType(Expr *Base,