Skip to content

Commit 0e10f89

Browse files
authored
Preserve default argument text through serialization (#18579)
This allows us to dump it in the generated interface, though it's still not syntax-highlighted. This is necessary for textual module interfaces, but it's also just a longstanding request for Xcode's "Generated Interface" / "Jump to Definition" feature. rdar://problem/18675831
1 parent b7e5137 commit 0e10f89

File tree

15 files changed

+117
-74
lines changed

15 files changed

+117
-74
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ CHANGELOG
2424
Swift 5.0
2525
---------
2626

27+
* [SR-2608][]
28+
29+
Default arguments are now printed in SourceKit-generated interfaces for Swift
30+
modules, instead of just using a placeholder `default`.
31+
2732
* Notable bug fix: unowned and unowned(unsafe) variables now support optional
2833
types.
2934

@@ -7151,3 +7156,4 @@ Swift 1.0
71517156
[SR-2131]: <https://bugs.swift.org/browse/SR-2131>
71527157
[SR-2388]: <https://bugs.swift.org/browse/SR-2388>
71537158
[SR-2394]: <https://bugs.swift.org/browse/SR-2394>
7159+
[SR-2608]: <https://bugs.swift.org/browse/SR-2608>

include/swift/AST/Decl.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4704,6 +4704,7 @@ class ParamDecl : public VarDecl {
47044704
struct StoredDefaultArgument {
47054705
Expr *DefaultArg = nullptr;
47064706
Initializer *InitContext = nullptr;
4707+
StringRef StringRepresentation;
47074708
};
47084709

47094710
/// The default value, if any, along with whether this is varargs.
@@ -4767,6 +4768,17 @@ class ParamDecl : public VarDecl {
47674768

47684769
void setDefaultArgumentInitContext(Initializer *initContext);
47694770

4771+
/// Returns a saved string representation of the parameter's default value.
4772+
///
4773+
/// This should only be called if the default value expression is absent or
4774+
/// doesn't have a valid source range; otherwise, clients should extract the
4775+
/// source text from that range.
4776+
///
4777+
/// \sa getDefaultValue
4778+
StringRef getDefaultValueStringRepresentation() const;
4779+
4780+
void setDefaultValueStringRepresentation(StringRef stringRepresentation);
4781+
47704782
/// Whether or not this parameter is varargs.
47714783
bool isVariadic() const { return DefaultValueAndIsVariadic.getInt(); }
47724784
void setVariadic(bool value = true) {DefaultValueAndIsVariadic.setInt(value);}

include/swift/AST/DefaultArgumentKind.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,6 @@ enum class DefaultArgumentKind : uint8_t {
5555
};
5656
enum { NumDefaultArgumentKindBits = 4 };
5757

58-
/// Retrieve the spelling of this default argument in source code, or
59-
/// an empty string if it has none.
60-
llvm::StringRef getDefaultArgumentSpelling(DefaultArgumentKind kind);
61-
6258
} // end namespace swift
6359

6460
#endif // LLVM_SWIFT_DEFAULTARGUMENTKIND_H

include/swift/Serialization/ModuleFormat.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const uint16_t VERSION_MAJOR = 0;
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
5757
/// Don't worry about adhering to the 80-column limit for this line.
58-
const uint16_t VERSION_MINOR = 431; // Last change: eliminate PARAMETERLIST_ELT
58+
const uint16_t VERSION_MINOR = 432; // Last change: default argument text
5959

6060
using DeclIDField = BCFixed<31>;
6161

@@ -1003,13 +1003,14 @@ namespace decls_block {
10031003

10041004
using ParamLayout = BCRecordLayout<
10051005
PARAM_DECL,
1006-
IdentifierIDField, // argument name
1007-
IdentifierIDField, // parameter name
1008-
DeclContextIDField, // context decl
1006+
IdentifierIDField, // argument name
1007+
IdentifierIDField, // parameter name
1008+
DeclContextIDField, // context decl
10091009
VarDeclSpecifierField, // specifier
1010-
TypeIDField, // interface type
1011-
BCFixed<1>, // isVariadic?
1012-
DefaultArgumentField // default argument
1010+
TypeIDField, // interface type
1011+
BCFixed<1>, // isVariadic?
1012+
DefaultArgumentField, // default argument kind
1013+
BCBlob // default argument text
10131014
>;
10141015

10151016
using FuncLayout = BCRecordLayout<

lib/AST/ASTPrinter.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2327,8 +2327,8 @@ void PrintAST::printOneParameter(const ParamDecl *param,
23272327
Printer << "...";
23282328

23292329
if (param->isDefaultArgument()) {
2330-
auto defaultArgStr
2331-
= getDefaultArgumentSpelling(param->getDefaultArgumentKind());
2330+
StringRef defaultArgStr = param->getDefaultValueStringRepresentation();
2331+
23322332
if (defaultArgStr.empty()) {
23332333
if (Options.PrintDefaultParameterPlaceholder)
23342334
Printer << " = " << tok::kw_default;
@@ -2341,6 +2341,7 @@ void PrintAST::printOneParameter(const ParamDecl *param,
23412341
case DefaultArgumentKind::Column:
23422342
case DefaultArgumentKind::Function:
23432343
case DefaultArgumentKind::DSOHandle:
2344+
case DefaultArgumentKind::NilLiteral:
23442345
Printer.printKeyword(defaultArgStr);
23452346
break;
23462347
default:

lib/AST/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ add_swift_library(swiftAST STATIC
2424
Decl.cpp
2525
DeclContext.cpp
2626
DeclNameLoc.cpp
27-
DefaultArgumentKind.cpp
2827
DiagnosticConsumer.cpp
2928
DiagnosticEngine.cpp
3029
DiagnosticList.cpp

lib/AST/Decl.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4880,6 +4880,43 @@ void ParamDecl::setDefaultArgumentInitContext(Initializer *initContext) {
48804880
DefaultValueAndIsVariadic.getPointer()->InitContext = initContext;
48814881
}
48824882

4883+
StringRef ParamDecl::getDefaultValueStringRepresentation() const {
4884+
switch (getDefaultArgumentKind()) {
4885+
case DefaultArgumentKind::None:
4886+
llvm_unreachable("called on a ParamDecl with no default value");
4887+
case DefaultArgumentKind::Normal:
4888+
assert(DefaultValueAndIsVariadic.getPointer() &&
4889+
"default value not provided yet");
4890+
return DefaultValueAndIsVariadic.getPointer()->StringRepresentation;
4891+
case DefaultArgumentKind::Inherited:
4892+
// FIXME: This needs /some/ kind of textual representation, but this isn't
4893+
// a great one.
4894+
return "super";
4895+
case DefaultArgumentKind::File: return "#file";
4896+
case DefaultArgumentKind::Line: return "#line";
4897+
case DefaultArgumentKind::Column: return "#column";
4898+
case DefaultArgumentKind::Function: return "#function";
4899+
case DefaultArgumentKind::DSOHandle: return "#dsohandle";
4900+
case DefaultArgumentKind::NilLiteral: return "nil";
4901+
case DefaultArgumentKind::EmptyArray: return "[]";
4902+
case DefaultArgumentKind::EmptyDictionary: return "[:]";
4903+
}
4904+
}
4905+
4906+
void
4907+
ParamDecl::setDefaultValueStringRepresentation(StringRef stringRepresentation) {
4908+
assert(getDefaultArgumentKind() == DefaultArgumentKind::Normal);
4909+
assert(!stringRepresentation.empty());
4910+
4911+
if (!DefaultValueAndIsVariadic.getPointer()) {
4912+
DefaultValueAndIsVariadic.setPointer(
4913+
getASTContext().Allocate<StoredDefaultArgument>());
4914+
}
4915+
4916+
DefaultValueAndIsVariadic.getPointer()->StringRepresentation =
4917+
stringRepresentation;
4918+
}
4919+
48834920
void DefaultArgumentInitializer::changeFunction(
48844921
DeclContext *parent, ParameterList *paramList) {
48854922
if (parent->isLocalContext()) {

lib/AST/DefaultArgumentKind.cpp

Lines changed: 0 additions & 39 deletions
This file was deleted.

lib/Parse/ParsePattern.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,9 @@ void Parser::DefaultArgumentInfo::setFunctionContext(
6363
}
6464
}
6565

66-
static ParserStatus parseDefaultArgument(Parser &P,
67-
Parser::DefaultArgumentInfo *defaultArgs,
68-
unsigned argIndex,
69-
Expr *&init,
70-
Parser::ParameterContextKind paramContext) {
66+
static ParserStatus parseDefaultArgument(
67+
Parser &P, Parser::DefaultArgumentInfo *defaultArgs, unsigned argIndex,
68+
Expr *&init, Parser::ParameterContextKind paramContext) {
7169
SyntaxParsingContext DefaultArgContext(P.SyntaxContext,
7270
SyntaxKind::InitializerClause);
7371
SourceLoc equalLoc = P.consumeToken(tok::equal);
@@ -576,8 +574,17 @@ mapParsedParameters(Parser &parser,
576574
paramContext == Parser::ParameterContextKind::Initializer ||
577575
paramContext == Parser::ParameterContextKind::EnumElement) &&
578576
"Default arguments are only permitted on the first param clause");
579-
result->setDefaultArgumentKind(getDefaultArgKind(param.DefaultArg));
577+
DefaultArgumentKind kind = getDefaultArgKind(param.DefaultArg);
578+
result->setDefaultArgumentKind(kind);
580579
result->setDefaultValue(param.DefaultArg);
580+
if (kind == DefaultArgumentKind::Normal) {
581+
SourceRange defaultArgRange = param.DefaultArg->getSourceRange();
582+
CharSourceRange charRange =
583+
Lexer::getCharSourceRangeFromSourceRange(parser.SourceMgr,
584+
defaultArgRange);
585+
StringRef defaultArgText = parser.SourceMgr.extractText(charRange);
586+
result->setDefaultValueStringRepresentation(defaultArgText);
587+
}
581588
}
582589

583590
elements.push_back(result);

lib/Serialization/Deserialization.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3040,8 +3040,11 @@ ModuleFile::getDeclCheckedImpl(DeclID DID, Optional<DeclContext *> ForcedContext
30403040

30413041
// Decode the default argument kind.
30423042
// FIXME: Default argument expression, if available.
3043-
if (auto defaultArg = getActualDefaultArgKind(rawDefaultArg))
3043+
if (auto defaultArg = getActualDefaultArgKind(rawDefaultArg)) {
30443044
param->setDefaultArgumentKind(*defaultArg);
3045+
if (!blobData.empty())
3046+
param->setDefaultValueStringRepresentation(blobData);
3047+
}
30453048
break;
30463049
}
30473050

lib/Serialization/Serialization.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3168,6 +3168,12 @@ void Serializer::writeDecl(const Decl *D) {
31683168
auto contextID = addDeclContextRef(param->getDeclContext());
31693169
Type interfaceType = param->getInterfaceType();
31703170

3171+
// Only save the text for normal default arguments, not any of the special
3172+
// ones.
3173+
StringRef defaultArgumentText;
3174+
if (param->getDefaultArgumentKind() == swift::DefaultArgumentKind::Normal)
3175+
defaultArgumentText = param->getDefaultValueStringRepresentation();
3176+
31713177
unsigned abbrCode = DeclTypeAbbrCodes[ParamLayout::Code];
31723178
ParamLayout::emitRecord(Out, ScratchRecord, abbrCode,
31733179
addDeclBaseNameRef(param->getArgumentName()),
@@ -3176,7 +3182,8 @@ void Serializer::writeDecl(const Decl *D) {
31763182
getRawStableVarDeclSpecifier(param->getSpecifier()),
31773183
addTypeRef(interfaceType),
31783184
param->isVariadic(),
3179-
getRawStableDefaultArgumentKind(param->getDefaultArgumentKind()));
3185+
getRawStableDefaultArgumentKind(param->getDefaultArgumentKind()),
3186+
defaultArgumentText);
31803187

31813188
if (interfaceType->hasError()) {
31823189
param->getDeclContext()->dumpContext();

test/IDE/print_ast_tc_decls.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,10 @@ struct d0100_FooStruct {
130130
// PASS_COMMON-NEXT: {{^}} func instanceFunc3(a: Int, b: Double){{$}}
131131

132132
func instanceFuncWithDefaultArg1(a: Int = 0) {}
133-
// PASS_COMMON-NEXT: {{^}} func instanceFuncWithDefaultArg1(a: Int = default){{$}}
133+
// PASS_COMMON-NEXT: {{^}} func instanceFuncWithDefaultArg1(a: Int = 0){{$}}
134134

135135
func instanceFuncWithDefaultArg2(a: Int = 0, b: Double = 0) {}
136-
// PASS_COMMON-NEXT: {{^}} func instanceFuncWithDefaultArg2(a: Int = default, b: Double = default){{$}}
136+
// PASS_COMMON-NEXT: {{^}} func instanceFuncWithDefaultArg2(a: Int = 0, b: Double = 0){{$}}
137137

138138
func varargInstanceFunc0(v: Int...) {}
139139
// PASS_COMMON-NEXT: {{^}} func varargInstanceFunc0(v: Int...){{$}}

test/IDE/print_type_interface.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ extension D {
7979
// RUN: %target-swift-ide-test -print-type-interface -usr=_TtGSaSS_ -module-name print_type_interface -source-filename %s | %FileCheck %s -check-prefix=TYPE5
8080
// TYPE5-DAG: public func prefix(_ maxLength: Int) -> ArraySlice<String>
8181
// TYPE5-DAG: public func suffix(_ maxLength: Int) -> ArraySlice<String>
82-
// TYPE5-DAG: public func split(separator: String, maxSplits: Int = default, omittingEmptySubsequences: Bool = default) -> [ArraySlice<String>]
82+
// TYPE5-DAG: public func split(separator: String, maxSplits: Int = Int.max, omittingEmptySubsequences: Bool = true) -> [ArraySlice<String>]
8383
// TYPE5-DAG: public func formIndex(_ i: inout Int, offsetBy distance: Int)
8484
// TYPE5-DAG: public func distance(from start: Int, to end: Int) -> Int
85-
// TYPE5-DAG: public func joined(separator: String = default) -> String
85+
// TYPE5-DAG: public func joined(separator: String = "") -> String
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -o %t/Test~partial.swiftmodule -module-name Test -primary-file %s
3+
// RUN: %target-swift-frontend -merge-modules -emit-module -o %t/Test.swiftmodule %t/Test~partial.swiftmodule
4+
// RUN: %target-swift-ide-test -print-module -module-to-print=Test -source-filename=x -I %t | %FileCheck %s
5+
6+
// CHECK-LABEL: func testDefaultArguments(
7+
public func testDefaultArguments(
8+
// CHECK-SAME: normal: Int = 0
9+
normal: Int = 0,
10+
// CHECK-SAME: multiToken: Int = Int.max
11+
multiToken: Int = Int.max,
12+
// CHECK-SAME: special: Int = #line
13+
special: Int = #line
14+
) {}
15+
// CHECK-SAME: )

test/SourceKit/CursorInfo/cursor_info.swift

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,8 @@ enum E7: String {
328328

329329
// RUN: %sourcekitd-test -req=cursor -pos=31:7 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | %FileCheck -check-prefix=CHECK13 %s
330330
// CHECK13: source.lang.swift.decl.function.free (31:6-31:37)
331-
// CHECK13: <Declaration>func testDefaultParam(arg1: <Type usr="s:Si">Int</Type> = default)</Declaration>
332-
// CHECK13: <decl.function.free><syntaxtype.keyword>func</syntaxtype.keyword> <decl.name>testDefaultParam</decl.name>(<decl.var.parameter><decl.var.parameter.argument_label>arg1</decl.var.parameter.argument_label>: <decl.var.parameter.type><ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter.type> = <syntaxtype.keyword>default</syntaxtype.keyword></decl.var.parameter>)</decl.function.free>
331+
// CHECK13: <Declaration>func testDefaultParam(arg1: <Type usr="s:Si">Int</Type> = 0)</Declaration>
332+
// CHECK13: <decl.function.free><syntaxtype.keyword>func</syntaxtype.keyword> <decl.name>testDefaultParam</decl.name>(<decl.var.parameter><decl.var.parameter.argument_label>arg1</decl.var.parameter.argument_label>: <decl.var.parameter.type><ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter.type> = 0</decl.var.parameter>)</decl.function.free>
333333

334334
// RUN: %sourcekitd-test -req=cursor -pos=34:4 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | %FileCheck -check-prefix=CHECK14 %s
335335
// CHECK14: source.lang.swift.ref.function.free ({{.*}}Foo.framework/Frameworks/FooSub.framework/Headers/FooSub.h:4:5-4:16)
@@ -652,13 +652,11 @@ enum E7: String {
652652
// CHECK73-SAME: = <syntaxtype.keyword>#file</syntaxtype.keyword>
653653
// CHECK73-SAME: = <syntaxtype.keyword>#line</syntaxtype.keyword>
654654
// CHECK73-SAME: = <syntaxtype.keyword>#column</syntaxtype.keyword>
655-
// FIXME: []
656-
// CHECK73-SAME: = <syntaxtype.keyword>default</syntaxtype.keyword>
657-
// FIXME: [:]
658-
// CHECK73-SAME: = <syntaxtype.keyword>default</syntaxtype.keyword>
659-
// FIXME: keyword nil
660-
// CHECK73-SAME: = <syntaxtype.keyword>default</syntaxtype.keyword>
661-
// CHECK73-SAME: = <syntaxtype.keyword>default</syntaxtype.keyword>
655+
// CHECK73-SAME: = []
656+
// CHECK73-SAME: = [:]
657+
// FIXME: should be <syntaxtype.keyword>nil</syntaxtype.keyword>
658+
// CHECK73-SAME: = nil
659+
// CHECK73-SAME: = 1
662660

663661
// RUN: %sourcekitd-test -req=cursor -pos=162:8 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | %FileCheck %s -check-prefix=CHECK74
664662
// CHECK74: source.lang.swift.decl.function.method.instance (162:8-162:20)

0 commit comments

Comments
 (0)