Skip to content

Commit 1fc107a

Browse files
CrazyFanFankongkaikai
authored andcommitted
[Diagnostics] Add fix-it to @main struct without main static function.
Change-Id: Id23067a3b71eab0927adb18b2c84b575e1dbfa45
1 parent f2ef2d3 commit 1fc107a

File tree

2 files changed

+53
-4
lines changed

2 files changed

+53
-4
lines changed

lib/Sema/TypeCheckAttr.cpp

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "TypeCheckObjC.h"
2323
#include "TypeCheckType.h"
2424
#include "TypeChecker.h"
25+
#include "swift/AST/ASTPrinter.h"
2526
#include "swift/AST/ASTVisitor.h"
2627
#include "swift/AST/AvailabilityInference.h"
2728
#include "swift/AST/ClangModuleLoader.h"
@@ -3064,6 +3065,37 @@ synthesizeMainBody(AbstractFunctionDecl *fn, void *arg) {
30643065
return std::make_pair(body, /*typechecked=*/false);
30653066
}
30663067

3068+
llvm::SmallString<128> generateMainFunctionText(ASTContext &C, Decl *decl,
3069+
bool isThrows, bool isAsync) {
3070+
// Prepare the indent (same as `printRequirementStub`)
3071+
StringRef ExtraIndent;
3072+
StringRef CurrentIndent = Lexer::getIndentationForLine(
3073+
C.SourceMgr, decl->getStartLoc(), &ExtraIndent);
3074+
3075+
llvm::SmallString<128> Text;
3076+
llvm::raw_svector_ostream OS(Text);
3077+
ExtraIndentStreamPrinter Printer(OS, CurrentIndent);
3078+
3079+
Printer.printNewline();
3080+
Printer.printIndent();
3081+
3082+
Printer << ExtraIndent << "static func main() ";
3083+
if (isAsync)
3084+
Printer << "async ";
3085+
if (isThrows)
3086+
Printer << "throws ";
3087+
3088+
/// Print the "{ <#code#> }" placeholder body
3089+
Printer << "{\n";
3090+
Printer.printIndent();
3091+
Printer << ExtraIndent << ExtraIndent << getCodePlaceholder();
3092+
Printer.printNewline();
3093+
Printer.printIndent();
3094+
Printer << ExtraIndent << "}\n";
3095+
3096+
return Text;
3097+
}
3098+
30673099
FuncDecl *
30683100
SynthesizeMainFunctionRequest::evaluate(Evaluator &evaluator,
30693101
Decl *D) const {
@@ -3189,13 +3221,30 @@ SynthesizeMainFunctionRequest::evaluate(Evaluator &evaluator,
31893221
candidates[0].overloadChoices[locator].choice.getDecl());
31903222
}
31913223

3224+
auto location = braces.Start;
3225+
31923226
if (!mainFunction) {
31933227
const bool hasAsyncSupport =
31943228
AvailabilityRange::forDeploymentTarget(context).isContainedIn(
31953229
context.getBackDeployedConcurrencyAvailability());
3196-
context.Diags.diagnose(attr->getLocation(),
3197-
diag::attr_MainType_without_main,
3198-
nominal, hasAsyncSupport);
3230+
auto params =
3231+
hasAsyncSupport
3232+
? std::vector<std::pair<bool, bool>>{{false, false},
3233+
{true, false},
3234+
{false, true},
3235+
{true, true}}
3236+
: std::vector<std::pair<bool, bool>>{{false, false}, {true, false}};
3237+
3238+
auto diag = context.Diags.diagnose(attr->getLocation(),
3239+
diag::attr_MainType_without_main,
3240+
nominal, hasAsyncSupport);
3241+
3242+
for (auto [isThrowing, isAsync] : params) {
3243+
diag.fixItInsertAfter(
3244+
location,
3245+
generateMainFunctionText(context, D, isThrowing, isAsync).str());
3246+
}
3247+
31993248
attr->setInvalid();
32003249
return nullptr;
32013250
}

test/attr/ApplicationMain/attr_main_instance.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s
22

3-
@main // expected-error{{'MyBase' is annotated with '@main' and must provide a main static function}}
3+
@main // expected-error{{'MyBase' is annotated with '@main' and must provide a main static function}} {{4:15-15=\n static func main() {\n <#code#>\n }\n}} {{4:15-15=\n static func main() throws {\n <#code#>\n }\n}} {{4:15-15=\n static func main() async {\n <#code#>\n }\n}} {{4:15-15=\n static func main() async throws {\n <#code#>\n }\n}}
44
class MyBase {
55
func main() {
66
}

0 commit comments

Comments
 (0)