Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into master-next
Browse files Browse the repository at this point in the history
  • Loading branch information
swift-ci committed Jun 16, 2020
2 parents aac020c + 1fd4725 commit 9cb4f90
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 18 deletions.
34 changes: 26 additions & 8 deletions lib/IDE/CodeCompletion.cpp
Expand Up @@ -6172,15 +6172,33 @@ void CodeCompletionCallbacksImpl::doneParsing() {
if (analyzedExpr->getEndLoc() != CodeCompleteTokenExpr->getLoc())
break;

// If the call expression doesn't have a type, infer it from the
// possible callee info.
Type resultTy = analyzedExpr->getType();
if (!resultTy) {
if (ContextInfo.getPossibleCallees().empty())
break;
auto calleeInfo = ContextInfo.getPossibleCallees()[0];
resultTy = calleeInfo.Type->getResult();
analyzedExpr->setType(resultTy);
// If the call expression doesn't have a type, fallback to:
if (!resultTy || resultTy->is<ErrorType>()) {
// 1) Try to type check removing CodeCompletionExpr from the call.
Expr *removedExpr = analyzedExpr;
removeCodeCompletionExpr(CurDeclContext->getASTContext(),
removedExpr);
ConcreteDeclRef referencedDecl;
auto optT = getTypeOfCompletionContextExpr(
CurDeclContext->getASTContext(), CurDeclContext,
CompletionTypeCheckKind::Normal, removedExpr, referencedDecl);
if (optT) {
resultTy = *optT;
analyzedExpr->setType(resultTy);
}
}
if (!resultTy || resultTy->is<ErrorType>()) {
// 2) Infer it from the possible callee info.
if (!ContextInfo.getPossibleCallees().empty()) {
auto calleeInfo = ContextInfo.getPossibleCallees()[0];
resultTy = calleeInfo.Type->getResult();
analyzedExpr->setType(resultTy);
}
}
if (!resultTy || resultTy->is<ErrorType>()) {
// 3) Give up providing postfix completions.
break;
}

auto &SM = CurDeclContext->getASTContext().SourceMgr;
Expand Down
76 changes: 76 additions & 0 deletions lib/IDE/ExprContextAnalysis.cpp
Expand Up @@ -12,6 +12,7 @@

#include "ExprContextAnalysis.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DeclContext.h"
Expand Down Expand Up @@ -181,6 +182,81 @@ Expr *swift::ide::findParsedExpr(const DeclContext *DC,
return finder.get();
}

//===----------------------------------------------------------------------===//
// removeCodeCompletionExpr(ASTContext, Expr)
//===----------------------------------------------------------------------===//

namespace {
// TODO: Implement other expressions?
class CCExprRemover: public ASTWalker, public ExprVisitor<CCExprRemover, Expr *> {
ASTContext &Ctx;

public:
bool Removed = false;

CCExprRemover(ASTContext &Ctx) : Ctx(Ctx) {}

Expr *visitCallExpr(CallExpr *E) {
SourceLoc lParenLoc, rParenLoc;
SmallVector<Identifier, 2> argLabels;
SmallVector<SourceLoc, 2> argLabelLocs;
SmallVector<Expr *, 2> args;
SmallVector<TrailingClosure, 2> trailingClosures;
bool removing = false;

if (auto paren = dyn_cast<ParenExpr>(E->getArg())) {
if (isa<CodeCompletionExpr>(paren->getSubExpr())) {
lParenLoc = paren->getLParenLoc();
rParenLoc = paren->getRParenLoc();
removing = true;
}
} else if (auto tuple = dyn_cast<TupleExpr>(E->getArg())) {
lParenLoc = tuple->getLParenLoc();
rParenLoc = tuple->getRParenLoc();
for (unsigned i = 0, e = tuple->getNumElements(); i != e; ++i) {
if (isa<CodeCompletionExpr>(tuple->getElement(i))) {
removing = true;
continue;
}

if (i < E->getUnlabeledTrailingClosureIndex()) {
// Normal arguments.
argLabels.push_back(E->getArgumentLabels()[i]);
argLabelLocs.push_back(E->getArgumentLabelLocs()[i]);
args.push_back(tuple->getElement(i));
} else {
// Trailing closure arguments.
trailingClosures.emplace_back(E->getArgumentLabels()[i],
E->getArgumentLabelLocs()[i],
tuple->getElement(i));
}
}
}
if (removing) {
Removed = true;
return CallExpr::create(Ctx, E->getFn(), lParenLoc, args, argLabels,
argLabelLocs, rParenLoc, trailingClosures,
E->isImplicit());
}
return E;
}

Expr *visitExpr(Expr *E) {
return E;
}

std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
return {true, visit(E)};
}
};
}

bool swift::ide::removeCodeCompletionExpr(ASTContext &Ctx, Expr *&expr) {
CCExprRemover remover(Ctx);
expr = expr->walk(remover);
return remover.Removed;
}

//===----------------------------------------------------------------------===//
// getReturnTypeFromContext(DeclContext)
//===----------------------------------------------------------------------===//
Expand Down
7 changes: 7 additions & 0 deletions lib/IDE/ExprContextAnalysis.h
Expand Up @@ -34,6 +34,13 @@ void typeCheckContextAt(DeclContext *DC, SourceLoc Loc);
/// exact the same as \p TargetRange. Returns \c nullptr if not found.
Expr *findParsedExpr(const DeclContext *DC, SourceRange TargetRange);

/// Remove \c CodeCompletionExpr from \p expr . Returns \c true if it actually
/// mutated the expression.
///
/// NOTE: Currently, this only removes CodeCompletionExpr at call argument
/// position.
bool removeCodeCompletionExpr(ASTContext &Ctx, Expr *&expr);

/// Returns expected return type of the given decl context.
/// \p DC should be an \c AbstractFunctionDecl or an \c AbstractClosureExpr.
Type getReturnTypeFromContext(const DeclContext *DC);
Expand Down
23 changes: 23 additions & 0 deletions test/IDE/complete_multiple_trailingclosure.swift
Expand Up @@ -13,6 +13,8 @@
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INIT_REQUIRED_NEWLINE_2 | %FileCheck %s -check-prefix=INIT_REQUIRED_NEWLINE_2
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INIT_REQUIRED_SAMELINE_3 | %FileCheck %s -check-prefix=INIT_REQUIRED_SAMELINE_3
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INIT_REQUIRED_NEWLINE_3 | %FileCheck %s -check-prefix=INIT_REQUIRED_NEWLINE_3
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INIT_FALLBACK_1 | %FileCheck %s -check-prefix=INIT_FALLBACK
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=INIT_FALLBACK_2 | %FileCheck %s -check-prefix=INIT_FALLBACK

func globalFunc1(fn1: () -> Int, fn2: () -> String) {}
func testGlobalFunc() {
Expand Down Expand Up @@ -184,3 +186,24 @@ func testOptionalInit() {
// INIT_REQUIRED_NEWLINE_3-NOT: name=fn3
// INIT_REQUIRED_NEWLINE_3: End completions
}

struct MyStruct4<T> {
init(arg1: Int = 0, arg2: () -> T) {}
init(name: String, arg2: () -> String, arg3: () -> T) {}

func testStructMethod() {}
}
func testFallbackPostfix() {
let _ = MyStruct4 {
1
} #^INIT_FALLBACK_1^#
// INIT_FALLBACK: Begin completions, 2 items
// INIT_FALLBACK-DAG: Decl[InstanceMethod]/CurrNominal: .testStructMethod()[#Void#];
// INIT_FALLBACK-DAG: Keyword[self]/CurrNominal: .self[#MyStruct4<Int>#];
// INIT_FALLBACK: End completions
let _ = MyStruct4(name: "test") {
""
} arg3: {
1
} #^INIT_FALLBACK_2^#
}
20 changes: 10 additions & 10 deletions test/IDE/range_info_declattr.swift
Expand Up @@ -23,16 +23,16 @@ class Derived : ObjCBase {
}
}

// RUN: %target-swift-ide-test -range -pos=4:1 -end-pos=9:2 -source-filename %s | %FileCheck %s -check-prefix=CHECK1
// RUN: %target-swift-ide-test -range -pos=5:3 -end-pos=7:4 -source-filename %s | %FileCheck %s -check-prefix=CHECK2
// RUN: %target-swift-ide-test -range -pos=5:25 -end-pos=7:4 -source-filename %s | %FileCheck %s -check-prefix=CHECK3
// RUN: %target-swift-ide-test -range -pos=8:3 -end-pos=8:31 -source-filename %s | %FileCheck %s -check-prefix=CHECK4
// RUN: %target-swift-ide-test -range -pos=13:5 -end-pos=13:32 -source-filename %s | %FileCheck %s -check-prefix=CHECK5
// RUN: %target-swift-ide-test -range -pos=13:16 -end-pos=13:32 -source-filename %s | %FileCheck %s -check-prefix=CHECK6
// RUN: %target-swift-ide-test -range -pos=12:26 -end-pos=14:4 -source-filename %s | %FileCheck %s -check-prefix=CHECK7
// RUN: %target-swift-ide-test -range -pos=17:5 -end-pos=18:21 -source-filename %s | %FileCheck %s -check-prefix=CHECK8
// RUN: %target-swift-ide-test -range -pos=20:5 -end-pos=22:12 -source-filename %s | %FileCheck %s -check-prefix=CHECK9
// RUN: %target-swift-ide-test -range -pos=21:5 -end-pos=22:12 -source-filename %s | %FileCheck %s -check-prefix=CHECK10
// RUN: %target-swift-ide-test -enable-objc-interop -disable-objc-attr-requires-foundation-module -range -pos=4:1 -end-pos=9:2 -source-filename %s | %FileCheck %s -check-prefix=CHECK1
// RUN: %target-swift-ide-test -enable-objc-interop -disable-objc-attr-requires-foundation-module -range -pos=5:3 -end-pos=7:4 -source-filename %s | %FileCheck %s -check-prefix=CHECK2
// RUN: %target-swift-ide-test -enable-objc-interop -disable-objc-attr-requires-foundation-module -range -pos=5:25 -end-pos=7:4 -source-filename %s | %FileCheck %s -check-prefix=CHECK3
// RUN: %target-swift-ide-test -enable-objc-interop -disable-objc-attr-requires-foundation-module -range -pos=8:3 -end-pos=8:31 -source-filename %s | %FileCheck %s -check-prefix=CHECK4
// RUN: %target-swift-ide-test -enable-objc-interop -disable-objc-attr-requires-foundation-module -range -pos=13:5 -end-pos=13:32 -source-filename %s | %FileCheck %s -check-prefix=CHECK5
// RUN: %target-swift-ide-test -enable-objc-interop -disable-objc-attr-requires-foundation-module -range -pos=13:16 -end-pos=13:32 -source-filename %s | %FileCheck %s -check-prefix=CHECK6
// RUN: %target-swift-ide-test -enable-objc-interop -disable-objc-attr-requires-foundation-module -range -pos=12:26 -end-pos=14:4 -source-filename %s | %FileCheck %s -check-prefix=CHECK7
// RUN: %target-swift-ide-test -enable-objc-interop -disable-objc-attr-requires-foundation-module -range -pos=17:5 -end-pos=18:21 -source-filename %s | %FileCheck %s -check-prefix=CHECK8
// RUN: %target-swift-ide-test -enable-objc-interop -disable-objc-attr-requires-foundation-module -range -pos=20:5 -end-pos=22:12 -source-filename %s | %FileCheck %s -check-prefix=CHECK9
// RUN: %target-swift-ide-test -enable-objc-interop -disable-objc-attr-requires-foundation-module -range -pos=21:5 -end-pos=22:12 -source-filename %s | %FileCheck %s -check-prefix=CHECK10

// CHECK1: <Kind>SingleDecl</Kind>
// CHECK1-NEXT: <Content>@objc class ObjCClass : ObjCBase {
Expand Down

0 comments on commit 9cb4f90

Please sign in to comment.