mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[RangeInfo] Add a field in ResolvedRangeInfo to indicate whether the range throws uncatched errors. rdar://30586209 (#7574)
This commit is contained in:
@@ -235,6 +235,7 @@ struct ResolvedRangeInfo {
|
||||
Type Ty;
|
||||
StringRef Content;
|
||||
bool HasSingleEntry;
|
||||
bool ThrowingUnhandledError;
|
||||
OrphanKind Orphan;
|
||||
|
||||
// The topmost ast nodes contained in the given range.
|
||||
@@ -244,20 +245,20 @@ struct ResolvedRangeInfo {
|
||||
DeclContext* RangeContext;
|
||||
ResolvedRangeInfo(RangeKind Kind, Type Ty, StringRef Content,
|
||||
DeclContext* RangeContext,
|
||||
bool HasSingleEntry,
|
||||
OrphanKind Orphan,
|
||||
ArrayRef<ASTNode> ContainedNodes,
|
||||
bool HasSingleEntry, bool ThrowingUnhandledError,
|
||||
OrphanKind Orphan, ArrayRef<ASTNode> ContainedNodes,
|
||||
ArrayRef<DeclaredDecl> DeclaredDecls,
|
||||
ArrayRef<ReferencedDecl> ReferencedDecls): Kind(Kind),
|
||||
Ty(Ty), Content(Content), HasSingleEntry(HasSingleEntry),
|
||||
Orphan(Orphan),
|
||||
ContainedNodes(ContainedNodes),
|
||||
ThrowingUnhandledError(ThrowingUnhandledError),
|
||||
Orphan(Orphan), ContainedNodes(ContainedNodes),
|
||||
DeclaredDecls(DeclaredDecls),
|
||||
ReferencedDecls(ReferencedDecls),
|
||||
RangeContext(RangeContext) {}
|
||||
ResolvedRangeInfo() :
|
||||
ResolvedRangeInfo(RangeKind::Invalid, Type(), StringRef(), nullptr,
|
||||
/*Single entry*/true, OrphanKind::None, {}, {}, {}) {}
|
||||
/*Single entry*/true, /*unhandled error*/false,
|
||||
OrphanKind::None, {}, {}, {}) {}
|
||||
void print(llvm::raw_ostream &OS);
|
||||
};
|
||||
|
||||
|
||||
@@ -217,6 +217,10 @@ void ResolvedRangeInfo::print(llvm::raw_ostream &OS) {
|
||||
OS << "<Entry>Multi</Entry>\n";
|
||||
}
|
||||
|
||||
if (ThrowingUnhandledError) {
|
||||
OS << "<Error>Throwing</Error>\n";
|
||||
}
|
||||
|
||||
if (Orphan != OrphanKind::None) {
|
||||
OS << "<Orphan>";
|
||||
switch (Orphan) {
|
||||
@@ -260,6 +264,43 @@ bool ReferencedDecl::operator==(const ReferencedDecl& Other) {
|
||||
return VD == Other.VD && Ty.getPointer() == Other.Ty.getPointer();
|
||||
}
|
||||
|
||||
static bool hasUnhandledError(ArrayRef<ASTNode> Nodes) {
|
||||
class ThrowingEntityAnalyzer : public SourceEntityWalker {
|
||||
bool Throwing;
|
||||
public:
|
||||
ThrowingEntityAnalyzer(): Throwing(false) {}
|
||||
bool walkToStmtPre(Stmt *S) override {
|
||||
if (auto DCS = dyn_cast<DoCatchStmt>(S)) {
|
||||
if (DCS->isSyntacticallyExhaustive())
|
||||
return false;
|
||||
Throwing = true;
|
||||
} else if (auto TS = dyn_cast<ThrowStmt>(S)) {
|
||||
Throwing = true;
|
||||
}
|
||||
return !Throwing;
|
||||
}
|
||||
bool walkToExprPre(Expr *E) override {
|
||||
if (auto TE = dyn_cast<TryExpr>(E)) {
|
||||
Throwing = true;
|
||||
}
|
||||
return !Throwing;
|
||||
}
|
||||
bool walkToDeclPre(Decl *D, CharSourceRange Range) override {
|
||||
return false;
|
||||
}
|
||||
bool walkToDeclPost(Decl *D) override { return !Throwing; }
|
||||
bool walkToStmtPost(Stmt *S) override { return !Throwing; }
|
||||
bool walkToExprPost(Expr *E) override { return !Throwing; }
|
||||
bool isThrowing() { return Throwing; }
|
||||
};
|
||||
|
||||
return Nodes.end() != std::find_if(Nodes.begin(), Nodes.end(), [](ASTNode N) {
|
||||
ThrowingEntityAnalyzer Analyzer;
|
||||
N.walk(Analyzer);
|
||||
return Analyzer.isThrowing();
|
||||
});
|
||||
}
|
||||
|
||||
struct RangeResolver::Implementation {
|
||||
SourceFile &File;
|
||||
ASTContext &Ctx;
|
||||
@@ -319,24 +360,28 @@ private:
|
||||
assert(ContainedASTNodes.size() == 1);
|
||||
// Single node implies single entry point, or is it?
|
||||
bool SingleEntry = true;
|
||||
bool UnhandledError = hasUnhandledError({Node});
|
||||
OrphanKind Kind = getOrphanKind(ContainedASTNodes);
|
||||
if (Node.is<Expr*>())
|
||||
return ResolvedRangeInfo(RangeKind::SingleExpression,
|
||||
resolveNodeType(Node), Content,
|
||||
getImmediateContext(), SingleEntry, Kind,
|
||||
getImmediateContext(), SingleEntry,
|
||||
UnhandledError, Kind,
|
||||
llvm::makeArrayRef(ContainedASTNodes),
|
||||
llvm::makeArrayRef(DeclaredDecls),
|
||||
llvm::makeArrayRef(ReferencedDecls));
|
||||
else if (Node.is<Stmt*>())
|
||||
return ResolvedRangeInfo(RangeKind::SingleStatement, resolveNodeType(Node),
|
||||
Content, getImmediateContext(), SingleEntry, Kind,
|
||||
Content, getImmediateContext(), SingleEntry,
|
||||
UnhandledError, Kind,
|
||||
llvm::makeArrayRef(ContainedASTNodes),
|
||||
llvm::makeArrayRef(DeclaredDecls),
|
||||
llvm::makeArrayRef(ReferencedDecls));
|
||||
else {
|
||||
assert(Node.is<Decl*>());
|
||||
return ResolvedRangeInfo(RangeKind::SingleDecl, Type(), Content,
|
||||
getImmediateContext(), SingleEntry, Kind,
|
||||
getImmediateContext(), SingleEntry,
|
||||
UnhandledError, Kind,
|
||||
llvm::makeArrayRef(ContainedASTNodes),
|
||||
llvm::makeArrayRef(DeclaredDecls),
|
||||
llvm::makeArrayRef(ReferencedDecls));
|
||||
@@ -606,6 +651,7 @@ public:
|
||||
/* Last node has the type */
|
||||
resolveNodeType(DCInfo.EndMatches.back()), Content,
|
||||
getImmediateContext(), hasSingleEntryPoint(ContainedASTNodes),
|
||||
hasUnhandledError(ContainedASTNodes),
|
||||
getOrphanKind(ContainedASTNodes),
|
||||
llvm::makeArrayRef(ContainedASTNodes),
|
||||
llvm::makeArrayRef(DeclaredDecls),
|
||||
|
||||
45
test/IDE/range_info_throwing.swift
Normal file
45
test/IDE/range_info_throwing.swift
Normal file
@@ -0,0 +1,45 @@
|
||||
func foo() -> Int{
|
||||
var aaa = 1 + 2
|
||||
aaa = aaa + 3
|
||||
if aaa == 3 { aaa = 4 }
|
||||
return aaa
|
||||
}
|
||||
|
||||
func foo1() throws {}
|
||||
|
||||
enum MyError : Error {
|
||||
case E1
|
||||
case E2
|
||||
}
|
||||
|
||||
func foo2() throws {
|
||||
try foo1()
|
||||
try! foo1()
|
||||
do {
|
||||
try foo1()
|
||||
} catch {}
|
||||
do {
|
||||
try foo1()
|
||||
} catch MyError.E1 {}
|
||||
do {
|
||||
throw MyError.E1
|
||||
} catch MyError.E1 {}
|
||||
do {
|
||||
do {
|
||||
throw MyError.E1
|
||||
} catch MyError.E1 {}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
// RUN: %target-swift-ide-test -range -pos=2:1 -end-pos 4:26 -source-filename %s | %FileCheck %s -check-prefix=CHECK-NO-THROW
|
||||
// RUN: %target-swift-ide-test -range -pos=16:1 -end-pos 16:13 -source-filename %s | %FileCheck %s -check-prefix=CHECK-THROW
|
||||
// RUN: %target-swift-ide-test -range -pos=17:1 -end-pos 17:14 -source-filename %s | %FileCheck %s -check-prefix=CHECK-NO-THROW
|
||||
// RUN: %target-swift-ide-test -range -pos=18:1 -end-pos 20:13 -source-filename %s | %FileCheck %s -check-prefix=CHECK-NO-THROW
|
||||
// RUN: %target-swift-ide-test -range -pos=21:1 -end-pos 23:24 -source-filename %s | %FileCheck %s -check-prefix=CHECK-THROW
|
||||
// RUN: %target-swift-ide-test -range -pos=24:1 -end-pos 26:24 -source-filename %s | %FileCheck %s -check-prefix=CHECK-THROW
|
||||
// RUN: %target-swift-ide-test -range -pos=25:1 -end-pos 25:21 -source-filename %s | %FileCheck %s -check-prefix=CHECK-THROW
|
||||
// RUN: %target-swift-ide-test -range -pos=28:1 -end-pos 30:26 -source-filename %s | %FileCheck %s -check-prefix=CHECK-THROW
|
||||
// RUN: %target-swift-ide-test -range -pos=27:1 -end-pos 31:13 -source-filename %s | %FileCheck %s -check-prefix=CHECK-NO-THROW
|
||||
|
||||
// CHECK-THROW: <Error>Throwing</Error>
|
||||
// CHECK-NO-THROW-NOT: <Error>Throwing</Error>
|
||||
Reference in New Issue
Block a user