Skip to content

Commit

Permalink
[Code completion] Teach code completion to use declarations for postf…
Browse files Browse the repository at this point in the history
…ix completions.

Code completion had the ability to use declarations to provide better
code completion results for postfix completions, e.g., calls to
functions/methods, but it wasn't trying to get these declarations from
anywhere. Now, get these declarations from the solution to the
constraint system.

The impetus for this is to use default-argument information from the
declaration rather than the type, but plumbing this information
through also means that we get proper "rethrows" annotations, covered
by <rdar://problem/21010193>, and more specific completions in a
number of other places.

Fixes <rdar://problem/21010193>.
  • Loading branch information
DougGregor committed Jun 16, 2016
1 parent 51f19ea commit e2632c1
Show file tree
Hide file tree
Showing 14 changed files with 299 additions and 89 deletions.
6 changes: 5 additions & 1 deletion include/swift/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,11 @@ class alignas(8) Expr {
/// has an access kind
void propagateLValueAccessKind(AccessKind accessKind,
bool allowOverwrite = false);


/// Retrieves the declaration that is being referenced by this
/// expression, if any.
ConcreteDeclRef getReferencedDecl() const;

/// Determine whether this expression is 'super', possibly converted to
/// a base class.
bool isSuperExpr() const;
Expand Down
10 changes: 6 additions & 4 deletions include/swift/Sema/IDETypeChecking.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,12 @@ namespace swift {

/// \brief Return the type of an expression parsed during code completion, or
/// None on error.
Optional<Type> getTypeOfCompletionContextExpr(ASTContext &Ctx,
DeclContext *DC,
CompletionTypeCheckKind kind,
Expr *&parsedExpr);
Optional<Type> getTypeOfCompletionContextExpr(
ASTContext &Ctx,
DeclContext *DC,
CompletionTypeCheckKind kind,
Expr *&parsedExpr,
ConcreteDeclRef &referencedDecl);

/// Typecheck the sequence expression \p parsedExpr for code completion.
///
Expand Down
139 changes: 139 additions & 0 deletions lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,145 @@ void Expr::propagateLValueAccessKind(AccessKind accessKind,
PropagateAccessKind(allowOverwrite).visit(this, accessKind);
}

ConcreteDeclRef Expr::getReferencedDecl() const {
switch (getKind()) {
// No declaration reference.
#define NO_REFERENCE(Id) case ExprKind::Id: return ConcreteDeclRef()
#define SIMPLE_REFERENCE(Id, Getter) \
case ExprKind::Id: \
return cast<Id##Expr>(this)->Getter()
#define PASS_THROUGH_REFERENCE(Id, GetSubExpr) \
case ExprKind::Id: \
return cast<Id##Expr>(this)->GetSubExpr()->getReferencedDecl()

NO_REFERENCE(Error);
NO_REFERENCE(NilLiteral);
NO_REFERENCE(IntegerLiteral);
NO_REFERENCE(FloatLiteral);
NO_REFERENCE(BooleanLiteral);
NO_REFERENCE(StringLiteral);
NO_REFERENCE(InterpolatedStringLiteral);
NO_REFERENCE(ObjectLiteral);
NO_REFERENCE(MagicIdentifierLiteral);
NO_REFERENCE(DiscardAssignment);

SIMPLE_REFERENCE(DeclRef, getDecl);
SIMPLE_REFERENCE(SuperRef, getSelf);

case ExprKind::Type: {
auto typeRepr = cast<TypeExpr>(this)->getTypeRepr();
if (!typeRepr) return ConcreteDeclRef();
auto ident = dyn_cast<IdentTypeRepr>(typeRepr);
if (!ident) return ConcreteDeclRef();
return ident->getComponentRange().back()->getBoundDecl();
}

SIMPLE_REFERENCE(OtherConstructorDeclRef, getDecl);

PASS_THROUGH_REFERENCE(DotSyntaxBaseIgnored, getRHS);

// FIXME: Return multiple results?
case ExprKind::OverloadedDeclRef:
case ExprKind::OverloadedMemberRef:
return ConcreteDeclRef();

NO_REFERENCE(UnresolvedDeclRef);

SIMPLE_REFERENCE(MemberRef, getMember);
SIMPLE_REFERENCE(DynamicMemberRef, getMember);
SIMPLE_REFERENCE(DynamicSubscript, getMember);

PASS_THROUGH_REFERENCE(UnresolvedSpecialize, getSubExpr);

NO_REFERENCE(UnresolvedMember);
NO_REFERENCE(UnresolvedDot);
NO_REFERENCE(Sequence);
PASS_THROUGH_REFERENCE(Paren, getSubExpr);
PASS_THROUGH_REFERENCE(DotSelf, getSubExpr);
PASS_THROUGH_REFERENCE(Try, getSubExpr);
PASS_THROUGH_REFERENCE(ForceTry, getSubExpr);
PASS_THROUGH_REFERENCE(OptionalTry, getSubExpr);

NO_REFERENCE(Tuple);
NO_REFERENCE(Array);
NO_REFERENCE(Dictionary);

case ExprKind::Subscript: {
auto subscript = cast<SubscriptExpr>(this);
if (subscript->hasDecl()) return subscript->getDecl();
return ConcreteDeclRef();
}

NO_REFERENCE(TupleElement);
NO_REFERENCE(CaptureList);
NO_REFERENCE(Closure);

PASS_THROUGH_REFERENCE(AutoClosure, getSingleExpressionBody);
PASS_THROUGH_REFERENCE(InOut, getSubExpr);

NO_REFERENCE(DynamicType);

PASS_THROUGH_REFERENCE(RebindSelfInConstructor, getSubExpr);

NO_REFERENCE(OpaqueValue);
PASS_THROUGH_REFERENCE(BindOptional, getSubExpr);
PASS_THROUGH_REFERENCE(OptionalEvaluation, getSubExpr);
PASS_THROUGH_REFERENCE(ForceValue, getSubExpr);
PASS_THROUGH_REFERENCE(OpenExistential, getSubExpr);

NO_REFERENCE(Call);
NO_REFERENCE(PrefixUnary);
NO_REFERENCE(PostfixUnary);
NO_REFERENCE(Binary);
NO_REFERENCE(DotSyntaxCall);
NO_REFERENCE(ConstructorRefCall);

PASS_THROUGH_REFERENCE(Load, getSubExpr);
NO_REFERENCE(TupleShuffle);
NO_REFERENCE(UnresolvedTypeConversion);
PASS_THROUGH_REFERENCE(FunctionConversion, getSubExpr);
PASS_THROUGH_REFERENCE(CovariantFunctionConversion, getSubExpr);
PASS_THROUGH_REFERENCE(CovariantReturnConversion, getSubExpr);
PASS_THROUGH_REFERENCE(MetatypeConversion, getSubExpr);
PASS_THROUGH_REFERENCE(CollectionUpcastConversion, getSubExpr);
PASS_THROUGH_REFERENCE(Erasure, getSubExpr);
PASS_THROUGH_REFERENCE(DerivedToBase, getSubExpr);
PASS_THROUGH_REFERENCE(ArchetypeToSuper, getSubExpr);
PASS_THROUGH_REFERENCE(InjectIntoOptional, getSubExpr);
PASS_THROUGH_REFERENCE(ClassMetatypeToObject, getSubExpr);
PASS_THROUGH_REFERENCE(ExistentialMetatypeToObject, getSubExpr);
PASS_THROUGH_REFERENCE(ProtocolMetatypeToObject, getSubExpr);
PASS_THROUGH_REFERENCE(InOutToPointer, getSubExpr);
PASS_THROUGH_REFERENCE(ArrayToPointer, getSubExpr);
PASS_THROUGH_REFERENCE(StringToPointer, getSubExpr);
PASS_THROUGH_REFERENCE(PointerToPointer, getSubExpr);
PASS_THROUGH_REFERENCE(LValueToPointer, getSubExpr);
PASS_THROUGH_REFERENCE(ForeignObjectConversion, getSubExpr);
PASS_THROUGH_REFERENCE(UnevaluatedInstance, getSubExpr);
NO_REFERENCE(Coerce);
NO_REFERENCE(ForcedCheckedCast);
NO_REFERENCE(ConditionalCheckedCast);
NO_REFERENCE(Is);

NO_REFERENCE(Arrow);
NO_REFERENCE(If);
NO_REFERENCE(EnumIsCase);
NO_REFERENCE(Assign);
NO_REFERENCE(DefaultValue);
NO_REFERENCE(CodeCompletion);
NO_REFERENCE(UnresolvedPattern);
NO_REFERENCE(EditorPlaceholder);
NO_REFERENCE(ObjCSelector);
NO_REFERENCE(ObjCKeyPath);

#undef SIMPLE_REFERENCE
#undef NO_REFERENCE
#undef PASS_THROUGH_REFERENCE
}

return ConcreteDeclRef();
}

/// Enumerate each immediate child expression of this node, invoking the
/// specific functor on it. This ignores statements and other non-expression
/// children.
Expand Down
Loading

0 comments on commit e2632c1

Please sign in to comment.