mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge pull request #82989 from CrazyFanFan/feature/fix-it-add-static-main
[Diagnostics] Add fix-it to `@main` struct without main static function.
This commit is contained in:
@@ -4276,6 +4276,14 @@ ERROR(attr_MainType_without_main,none,
|
||||
"%0 is annotated with '@main' and must provide a main static function "
|
||||
"of type %" SELECT_APPLICATION_MAIN_TYPES "1",
|
||||
(const ValueDecl *, bool))
|
||||
NOTE(note_add_main_sync,none,
|
||||
"add 'static func main()'", ())
|
||||
NOTE(note_add_main_sync_throws,none,
|
||||
"add 'static func main() throws'", ())
|
||||
NOTE(note_add_main_async,none,
|
||||
"add 'static func main() async'", ())
|
||||
NOTE(note_add_main_async_throws,none,
|
||||
"add 'static func main() async throws'", ())
|
||||
|
||||
#undef SELECT_APPLICATION_MAIN_TYPES
|
||||
#undef SELECT_APPLICATION_MAIN
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "TypeCheckObjC.h"
|
||||
#include "TypeCheckType.h"
|
||||
#include "TypeChecker.h"
|
||||
#include "swift/AST/ASTPrinter.h"
|
||||
#include "swift/AST/ASTVisitor.h"
|
||||
#include "swift/AST/AvailabilityInference.h"
|
||||
#include "swift/AST/ClangModuleLoader.h"
|
||||
@@ -3104,6 +3105,36 @@ synthesizeMainBody(AbstractFunctionDecl *fn, void *arg) {
|
||||
return std::make_pair(body, /*typechecked=*/false);
|
||||
}
|
||||
|
||||
static llvm::SmallString<128>
|
||||
generateMainFunctionText(ASTContext &C, NominalTypeDecl *parentDecl,
|
||||
bool isThrows, bool isAsync) {
|
||||
StringRef ExtraIndent;
|
||||
StringRef CurrentIndent = Lexer::getIndentationForLine(
|
||||
C.SourceMgr, parentDecl->getStartLoc(), &ExtraIndent);
|
||||
std::string MethodIndent = (CurrentIndent + ExtraIndent).str();
|
||||
|
||||
llvm::SmallString<128> Text;
|
||||
llvm::raw_svector_ostream OS(Text);
|
||||
ExtraIndentStreamPrinter Printer(OS, MethodIndent);
|
||||
|
||||
Printer.printNewline();
|
||||
|
||||
Printer << "static func main() ";
|
||||
if (isAsync)
|
||||
Printer << "async ";
|
||||
if (isThrows)
|
||||
Printer << "throws ";
|
||||
|
||||
// Print the "{ <#code#> }" placeholder body.
|
||||
Printer << "{\n";
|
||||
Printer.printIndent();
|
||||
Printer << ExtraIndent << getCodePlaceholder();
|
||||
Printer.printNewline();
|
||||
Printer << "}\n";
|
||||
|
||||
return Text;
|
||||
}
|
||||
|
||||
FuncDecl *
|
||||
SynthesizeMainFunctionRequest::evaluate(Evaluator &evaluator,
|
||||
Decl *D) const {
|
||||
@@ -3233,9 +3264,43 @@ SynthesizeMainFunctionRequest::evaluate(Evaluator &evaluator,
|
||||
const bool hasAsyncSupport =
|
||||
AvailabilityRange::forDeploymentTarget(context).isContainedIn(
|
||||
context.getBackDeployedConcurrencyAvailability());
|
||||
context.Diags.diagnose(attr->getLocation(),
|
||||
diag::attr_MainType_without_main,
|
||||
nominal, hasAsyncSupport);
|
||||
|
||||
auto location = attr->getLocation();
|
||||
auto fixLocation = braces.Start;
|
||||
|
||||
context.Diags.diagnose(location, diag::attr_MainType_without_main, nominal,
|
||||
hasAsyncSupport);
|
||||
|
||||
// Offer fix-its to add the `main` function for different combinations of
|
||||
// effects, starting with no effects.
|
||||
|
||||
context.Diags.diagnose(location, diag::note_add_main_sync)
|
||||
.fixItInsertAfter(fixLocation, generateMainFunctionText(
|
||||
context, nominal, /*isThrows*/ false,
|
||||
/*isAsync*/ false)
|
||||
.str());
|
||||
|
||||
context.Diags.diagnose(location, diag::note_add_main_sync_throws)
|
||||
.fixItInsertAfter(fixLocation, generateMainFunctionText(
|
||||
context, nominal, /*isThrows*/ true,
|
||||
/*isAsync*/ false)
|
||||
.str());
|
||||
|
||||
if (hasAsyncSupport) {
|
||||
context.Diags.diagnose(location, diag::note_add_main_async)
|
||||
.fixItInsertAfter(fixLocation,
|
||||
generateMainFunctionText(context, nominal,
|
||||
/*isThrows*/ false,
|
||||
/*isAsync*/ true)
|
||||
.str());
|
||||
|
||||
context.Diags.diagnose(location, diag::note_add_main_async_throws)
|
||||
.fixItInsertAfter(fixLocation,
|
||||
generateMainFunctionText(context, nominal,
|
||||
/*isThrows*/ true,
|
||||
/*isAsync*/ true)
|
||||
.str());
|
||||
}
|
||||
attr->setInvalid();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s
|
||||
|
||||
@main // expected-error{{'MyBase' is annotated with '@main' and must provide a main static function}}
|
||||
// expected-note@-1{{add 'static func main()'}} {{8:16-16=\n static func main() {\n <#code#>\n }\n}}
|
||||
// expected-note@-2{{add 'static func main() throws'}} {{8:16-16=\n static func main() throws {\n <#code#>\n }\n}}
|
||||
// expected-note@-3{{add 'static func main() async'}} {{8:16-16=\n static func main() async {\n <#code#>\n }\n}}
|
||||
// expected-note@-4{{add 'static func main() async throws'}} {{8:16-16=\n static func main() async throws {\n <#code#>\n }\n}}
|
||||
struct MyBase {
|
||||
static func main(_ argc: Int, _ argv: [String]) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s
|
||||
|
||||
@main // expected-error{{'Foo' is annotated with '@main' and must provide a main static function}}
|
||||
// expected-note@-1{{add 'static func main()'}} {{8:13-13=\n static func main() {\n <#code#>\n }\n}}
|
||||
// expected-note@-2{{add 'static func main() throws'}} {{8:13-13=\n static func main() throws {\n <#code#>\n }\n}}
|
||||
// expected-note@-3{{add 'static func main() async'}} {{8:13-13=\n static func main() async {\n <#code#>\n }\n}}
|
||||
// expected-note@-4{{add 'static func main() async throws'}} {{8:13-13=\n static func main() async throws {\n <#code#>\n }\n}}
|
||||
struct Foo {
|
||||
@dynamicCallable
|
||||
struct main {
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s
|
||||
|
||||
@main @dynamicMemberLookup // expected-error{{'Main' is annotated with '@main' and must provide a main static function}}
|
||||
// expected-note@-1{{add 'static func main()'}} {{8:14-14=\n static func main() {\n <#code#>\n }\n}}
|
||||
// expected-note@-2{{add 'static func main() throws'}} {{8:14-14=\n static func main() throws {\n <#code#>\n }\n}}
|
||||
// expected-note@-3{{add 'static func main() async'}} {{8:14-14=\n static func main() async {\n <#code#>\n }\n}}
|
||||
// expected-note@-4{{add 'static func main() async throws'}} {{8:14-14=\n static func main() async throws {\n <#code#>\n }\n}}
|
||||
struct Main {
|
||||
subscript(dynamicMember member: String) -> () -> Void {
|
||||
return {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,9 @@ class EntryPoint {
|
||||
}
|
||||
|
||||
@main // expected-error{{'EntryPoint' is annotated with '@main' and must provide a main static function}}
|
||||
// expected-note@-1{{add 'static func main()'}} {{11:23-23=\n static func main() {\n <#code#>\n }\n}}
|
||||
// expected-note@-2{{add 'static func main() throws'}} {{11:23-23=\n static func main() throws {\n <#code#>\n }\n}}
|
||||
// expected-note@-3{{add 'static func main() async'}} {{11:23-23=\n static func main() async {\n <#code#>\n }\n}}
|
||||
// expected-note@-4{{add 'static func main() async throws'}} {{11:23-23=\n static func main() async throws {\n <#code#>\n }\n}}
|
||||
extension EntryPoint {
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,23 @@
|
||||
// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s
|
||||
|
||||
@main // expected-error{{'MyBase' is annotated with '@main' and must provide a main static function}}
|
||||
// expected-note@-1{{add 'static func main()'}} {{8:15-15=\n static func main() {\n <#code#>\n }\n}}
|
||||
// expected-note@-2{{add 'static func main() throws'}} {{8:15-15=\n static func main() throws {\n <#code#>\n }\n}}
|
||||
// expected-note@-3{{add 'static func main() async'}} {{8:15-15=\n static func main() async {\n <#code#>\n }\n}}
|
||||
// expected-note@-4{{add 'static func main() async throws'}} {{8:15-15=\n static func main() async throws {\n <#code#>\n }\n}}
|
||||
class MyBase {
|
||||
func main() {
|
||||
}
|
||||
}
|
||||
|
||||
enum Nested {
|
||||
@main // expected-error{{'MyBase' is annotated with '@main' and must provide a main static function}}
|
||||
// expected-note@-1{{add 'static func main()'}} {{19:17-17=\n static func main() {\n <#code#>\n }\n}}
|
||||
// expected-note@-2{{add 'static func main() throws'}} {{19:17-17=\n static func main() throws {\n <#code#>\n }\n}}
|
||||
// expected-note@-3{{add 'static func main() async'}} {{19:17-17=\n static func main() async {\n <#code#>\n }\n}}
|
||||
// expected-note@-4{{add 'static func main() async throws'}} {{19:17-17=\n static func main() async throws {\n <#code#>\n }\n}}
|
||||
class MyBase {
|
||||
func main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// RUN: %target-swift-frontend -typecheck -parse-as-library -target %target-swift-5.0-abi-triple -verify %s
|
||||
// REQUIRES: OS=macosx && CPU=x86_64
|
||||
|
||||
@main // expected-error{{'MyBaseWithoutAsyncSupport' is annotated with '@main' and must provide a main static function}}
|
||||
// expected-note@-1{{add 'static func main()'}} {{7:34-34=\n static func main() {\n <#code#>\n }\n}}
|
||||
// expected-note@-2{{add 'static func main() throws'}} {{7:34-34=\n static func main() throws {\n <#code#>\n }\n}}
|
||||
class MyBaseWithoutAsyncSupport {
|
||||
func main() {
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
// RUN: %target-swift-frontend -typecheck -parse-as-library -verify %s
|
||||
|
||||
@main // expected-error{{'MyBase' is annotated with '@main' and must provide a main static function}}
|
||||
// expected-note@-1{{add 'static func main()'}} {{8:16-16=\n static func main() {\n <#code#>\n }\n}}
|
||||
// expected-note@-2{{add 'static func main() throws'}} {{8:16-16=\n static func main() throws {\n <#code#>\n }\n}}
|
||||
// expected-note@-3{{add 'static func main() async'}} {{8:16-16=\n static func main() async {\n <#code#>\n }\n}}
|
||||
// expected-note@-4{{add 'static func main() async throws'}} {{8:16-16=\n static func main() async throws {\n <#code#>\n }\n}}
|
||||
struct MyBase {
|
||||
static func main() -> Int {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,11 @@ extension Runnable where Self : OtherThing {
|
||||
}
|
||||
|
||||
@main //expected-error{{'EntryPoint' is annotated with '@main' and must provide a main static function}}
|
||||
// expected-note@-1{{add 'static func main()'}} {{23:31-31=\n static func main() {\n <#code#>\n }\n}}
|
||||
// expected-note@-2{{add 'static func main() throws'}} {{23:31-31=\n static func main() throws {\n <#code#>\n }\n}}
|
||||
// expected-note@-3{{add 'static func main() async'}} {{23:31-31=\n static func main() async {\n <#code#>\n }\n}}
|
||||
// expected-note@-4{{add 'static func main() async throws'}} {{23:31-31=\n static func main() async throws {\n <#code#>\n }\n}}
|
||||
struct EntryPoint : Runnable {
|
||||
func run() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user