Skip to content

Commit a6a96da

Browse files
committed
AST: Source range of FuncDecl/ConstructorDecl should include the thrown type
When a function declaration has a body, its source range ends at the closing curly brace, so it includes the `throws(E)`. However, a protocol requirement doesn't have a body, and due to an oversight, getSourceRange() was never updated to include the extra tokens that appear after `throws` when the function declares a thrown error type. As a result, unqualified lookup would fail to find a generic parameter type, if that happened to be the thrown type. Fixes rdar://problem/143950572.
1 parent 4937d0a commit a6a96da

File tree

6 files changed

+69
-43
lines changed

6 files changed

+69
-43
lines changed

include/swift/AST/Decl.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8078,7 +8078,11 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
80788078
/// source buffers for e.g. code-completion.
80798079
SourceRange getOriginalBodySourceRange() const;
80808080

8081-
/// Retrieve the source range of the function declaration name + patterns.
8081+
/// Retrieve the source range of the function declaration name and parameter list.
8082+
SourceRange getParameterListSourceRange() const;
8083+
8084+
/// Retrieve the source range of the function declaration name, parameter list,
8085+
/// and effects. For FuncDecl, this does not include the return type.
80828086
SourceRange getSignatureSourceRange() const;
80838087

80848088
CaptureInfo getCaptureInfo() const;

lib/AST/Decl.cpp

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9950,13 +9950,30 @@ SourceRange AbstractFunctionDecl::getSignatureSourceRange() const {
99509950
if (isImplicit())
99519951
return SourceRange();
99529952

9953-
auto paramList = getParameters();
9953+
SourceLoc endLoc;
99549954

9955-
auto endLoc = paramList->getSourceRange().End;
9956-
if (endLoc.isValid())
9957-
return SourceRange(getNameLoc(), endLoc);
9955+
// name(parameter list...) async throws(E)
9956+
if (auto *typeRepr = getThrownTypeRepr())
9957+
endLoc = typeRepr->getSourceRange().End;
9958+
if (endLoc.isInvalid())
9959+
endLoc = getThrowsLoc();
9960+
if (endLoc.isInvalid())
9961+
endLoc = getAsyncLoc();
99589962

9959-
return getNameLoc();
9963+
if (endLoc.isInvalid())
9964+
return getParameterListSourceRange();
9965+
return SourceRange(getNameLoc(), endLoc);
9966+
}
9967+
9968+
SourceRange AbstractFunctionDecl::getParameterListSourceRange() const {
9969+
if (isImplicit())
9970+
return SourceRange();
9971+
9972+
auto endLoc = getParameters()->getSourceRange().End;
9973+
if (endLoc.isInvalid())
9974+
return getNameLoc();
9975+
9976+
return SourceRange(getNameLoc(), endLoc);
99609977
}
99619978

99629979
std::optional<Fingerprint> AbstractFunctionDecl::getBodyFingerprint() const {
@@ -10993,43 +11010,32 @@ DestructorDecl *DestructorDecl::getSuperDeinit() const {
1099311010
}
1099411011

1099511012
SourceRange FuncDecl::getSourceRange() const {
10996-
SourceLoc StartLoc = getStartLoc();
11013+
SourceLoc startLoc = getStartLoc();
1099711014

10998-
if (StartLoc.isInvalid())
11015+
if (startLoc.isInvalid())
1099911016
return SourceRange();
1100011017

1100111018
if (getBodyKind() == BodyKind::Unparsed)
11002-
return { StartLoc, BodyRange.End };
11003-
11004-
SourceLoc RBraceLoc = getOriginalBodySourceRange().End;
11005-
if (RBraceLoc.isValid()) {
11006-
return { StartLoc, RBraceLoc };
11007-
}
11008-
11009-
if (isa<AccessorDecl>(this))
11010-
return StartLoc;
11011-
11012-
if (getBodyKind() == BodyKind::Synthesize)
11013-
return SourceRange();
11014-
11015-
auto TrailingWhereClauseSourceRange = getGenericTrailingWhereClauseSourceRange();
11016-
if (TrailingWhereClauseSourceRange.isValid())
11017-
return { StartLoc, TrailingWhereClauseSourceRange.End };
11019+
return { startLoc, BodyRange.End };
1101811020

11019-
const auto ResultTyEndLoc = getResultTypeSourceRange().End;
11020-
if (ResultTyEndLoc.isValid())
11021-
return { StartLoc, ResultTyEndLoc };
11021+
SourceLoc endLoc = getOriginalBodySourceRange().End;
11022+
if (endLoc.isInvalid()) {
11023+
if (isa<AccessorDecl>(this))
11024+
return startLoc;
1102211025

11023-
if (hasThrows())
11024-
return { StartLoc, getThrowsLoc() };
11026+
if (getBodyKind() == BodyKind::Synthesize)
11027+
return SourceRange();
1102511028

11026-
if (hasAsync())
11027-
return { StartLoc, getAsyncLoc() };
11029+
endLoc = getGenericTrailingWhereClauseSourceRange().End;
11030+
}
11031+
if (endLoc.isInvalid())
11032+
endLoc = getResultTypeSourceRange().End;
11033+
if (endLoc.isInvalid())
11034+
endLoc = getSignatureSourceRange().End;
11035+
if (endLoc.isInvalid())
11036+
endLoc = startLoc;
1102811037

11029-
auto LastParamListEndLoc = getParameters()->getSourceRange().End;
11030-
if (LastParamListEndLoc.isValid())
11031-
return { StartLoc, LastParamListEndLoc };
11032-
return StartLoc;
11038+
return { startLoc, endLoc };
1103311039
}
1103411040

1103511041
EnumElementDecl::EnumElementDecl(SourceLoc IdentifierLoc, DeclName Name,
@@ -11133,8 +11139,6 @@ SourceRange ConstructorDecl::getSourceRange() const {
1113311139
SourceLoc End = getOriginalBodySourceRange().End;
1113411140
if (End.isInvalid())
1113511141
End = getGenericTrailingWhereClauseSourceRange().End;
11136-
if (End.isInvalid())
11137-
End = getThrowsLoc();
1113811142
if (End.isInvalid())
1113911143
End = getSignatureSourceRange().End;
1114011144

lib/IDE/SyntaxModel.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -873,7 +873,7 @@ ASTWalker::PreWalkAction ModelASTWalker::walkToDeclPre(Decl *D) {
873873
SN.BodyRange = innerCharSourceRangeFromSourceRange(SM,
874874
AFD->getBodySourceRange());
875875
SN.NameRange = charSourceRangeFromSourceRange(SM,
876-
AFD->getSignatureSourceRange());
876+
AFD->getParameterListSourceRange());
877877
if (FD) {
878878
SN.TypeRange = charSourceRangeFromSourceRange(SM,
879879
FD->getResultTypeSourceRange());

test/IDE/structure.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,18 @@ struct MyStruct {
4242
static func cfoo()
4343
}
4444

45+
enum MyError: Error {
46+
case x
47+
}
48+
4549
// CHECK: <protocol>protocol <name>MyProt</name> {
4650
// CHECK: <ifunc>func <name>foo()</name></ifunc>
4751
// CHECK: <ifunc>func <name>foo2()</name> throws</ifunc>
4852
// CHECK: <ifunc>func <name>foo3()</name> throws -> <type>Int</type></ifunc>
49-
// CHECK: <ifunc>func <name>foo4<<generic-param><name>T</name></generic-param>>()</name> where T: MyProt</ifunc>
53+
54+
// FIXME: The end of the source range needs to be advanced past the ')' here!
55+
// CHECK: <ifunc>func <name>foo4()</name> throws(MyError</ifunc>)
56+
// CHECK: <ifunc>func <name>foo5<<generic-param><name>T</name></generic-param>>()</name> where T: MyProt</ifunc>
5057
// CHECK: <ifunc><name>init()</name></ifunc>
5158
// CHECK: <ifunc><name>init(<param><name>a</name>: <type>Int</type></param>)</name> throws</ifunc>
5259
// CHECK: <ifunc><name>init<<generic-param><name>T</name></generic-param>>(<param><name>a</name>: <type>T</type></param>)</name> where T: MyProt</ifunc>
@@ -55,7 +62,8 @@ protocol MyProt {
5562
func foo()
5663
func foo2() throws
5764
func foo3() throws -> Int
58-
func foo4<T>() where T: MyProt
65+
func foo4() throws(MyError)
66+
func foo5<T>() where T: MyProt
5967
init()
6068
init(a: Int) throws
6169
init<T>(a: T) where T: MyProt

test/decl/protocol/typed_throws.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
// Make sure that the source range of a protocol requirement
4+
// with no body still includes the thrown type, by checking
5+
// that the name lookup from there finds the generic parameter.
6+
7+
protocol TypedThrowsProto {
8+
init<E>(y: () throws(E) -> Void) throws(E)
9+
func f<E>(y: () throws(E) -> Void) throws(E)
10+
}

tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -890,17 +890,17 @@ static void setLocationInfo(const ValueDecl *VD,
890890

891891
auto Loc = VD->getLoc(/*SerializedOK=*/true);
892892
if (Loc.isValid()) {
893-
auto getSignatureRange =
893+
auto getParameterListRange =
894894
[&](const ValueDecl *VD) -> std::optional<unsigned> {
895895
if (auto FD = dyn_cast<AbstractFunctionDecl>(VD)) {
896-
SourceRange R = FD->getSignatureSourceRange();
896+
SourceRange R = FD->getParameterListSourceRange();
897897
if (R.isValid())
898898
return getCharLength(SM, R);
899899
}
900900
return std::nullopt;
901901
};
902902
unsigned NameLen;
903-
if (auto SigLen = getSignatureRange(VD)) {
903+
if (auto SigLen = getParameterListRange(VD)) {
904904
NameLen = SigLen.value();
905905
} else if (VD->hasName()) {
906906
NameLen = VD->getBaseName().userFacingName().size();

0 commit comments

Comments
 (0)