|
22 | 22 | #include "TypeCheckObjC.h"
|
23 | 23 | #include "TypeCheckType.h"
|
24 | 24 | #include "TypeChecker.h"
|
| 25 | +#include "swift/AST/ASTPrinter.h" |
25 | 26 | #include "swift/AST/ASTVisitor.h"
|
26 | 27 | #include "swift/AST/AvailabilityInference.h"
|
27 | 28 | #include "swift/AST/ClangModuleLoader.h"
|
@@ -3104,6 +3105,36 @@ synthesizeMainBody(AbstractFunctionDecl *fn, void *arg) {
|
3104 | 3105 | return std::make_pair(body, /*typechecked=*/false);
|
3105 | 3106 | }
|
3106 | 3107 |
|
| 3108 | +static llvm::SmallString<128> |
| 3109 | +generateMainFunctionText(ASTContext &C, NominalTypeDecl *parentDecl, |
| 3110 | + bool isThrows, bool isAsync) { |
| 3111 | + StringRef ExtraIndent; |
| 3112 | + StringRef CurrentIndent = Lexer::getIndentationForLine( |
| 3113 | + C.SourceMgr, parentDecl->getStartLoc(), &ExtraIndent); |
| 3114 | + std::string MethodIndent = (CurrentIndent + ExtraIndent).str(); |
| 3115 | + |
| 3116 | + llvm::SmallString<128> Text; |
| 3117 | + llvm::raw_svector_ostream OS(Text); |
| 3118 | + ExtraIndentStreamPrinter Printer(OS, MethodIndent); |
| 3119 | + |
| 3120 | + Printer.printNewline(); |
| 3121 | + |
| 3122 | + Printer << "static func main() "; |
| 3123 | + if (isAsync) |
| 3124 | + Printer << "async "; |
| 3125 | + if (isThrows) |
| 3126 | + Printer << "throws "; |
| 3127 | + |
| 3128 | + // Print the "{ <#code#> }" placeholder body. |
| 3129 | + Printer << "{\n"; |
| 3130 | + Printer.printIndent(); |
| 3131 | + Printer << ExtraIndent << getCodePlaceholder(); |
| 3132 | + Printer.printNewline(); |
| 3133 | + Printer << "}\n"; |
| 3134 | + |
| 3135 | + return Text; |
| 3136 | +} |
| 3137 | + |
3107 | 3138 | FuncDecl *
|
3108 | 3139 | SynthesizeMainFunctionRequest::evaluate(Evaluator &evaluator,
|
3109 | 3140 | Decl *D) const {
|
@@ -3233,9 +3264,43 @@ SynthesizeMainFunctionRequest::evaluate(Evaluator &evaluator,
|
3233 | 3264 | const bool hasAsyncSupport =
|
3234 | 3265 | AvailabilityRange::forDeploymentTarget(context).isContainedIn(
|
3235 | 3266 | context.getBackDeployedConcurrencyAvailability());
|
3236 |
| - context.Diags.diagnose(attr->getLocation(), |
3237 |
| - diag::attr_MainType_without_main, |
3238 |
| - nominal, hasAsyncSupport); |
| 3267 | + |
| 3268 | + auto location = attr->getLocation(); |
| 3269 | + auto fixLocation = braces.Start; |
| 3270 | + |
| 3271 | + context.Diags.diagnose(location, diag::attr_MainType_without_main, nominal, |
| 3272 | + hasAsyncSupport); |
| 3273 | + |
| 3274 | + // Offer fix-its to add the `main` function for different combinations of |
| 3275 | + // effects, starting with no effects. |
| 3276 | + |
| 3277 | + context.Diags.diagnose(location, diag::note_add_main_sync) |
| 3278 | + .fixItInsertAfter(fixLocation, generateMainFunctionText( |
| 3279 | + context, nominal, /*isThrows*/ false, |
| 3280 | + /*isAsync*/ false) |
| 3281 | + .str()); |
| 3282 | + |
| 3283 | + context.Diags.diagnose(location, diag::note_add_main_sync_throws) |
| 3284 | + .fixItInsertAfter(fixLocation, generateMainFunctionText( |
| 3285 | + context, nominal, /*isThrows*/ true, |
| 3286 | + /*isAsync*/ false) |
| 3287 | + .str()); |
| 3288 | + |
| 3289 | + if (hasAsyncSupport) { |
| 3290 | + context.Diags.diagnose(location, diag::note_add_main_async) |
| 3291 | + .fixItInsertAfter(fixLocation, |
| 3292 | + generateMainFunctionText(context, nominal, |
| 3293 | + /*isThrows*/ false, |
| 3294 | + /*isAsync*/ true) |
| 3295 | + .str()); |
| 3296 | + |
| 3297 | + context.Diags.diagnose(location, diag::note_add_main_async_throws) |
| 3298 | + .fixItInsertAfter(fixLocation, |
| 3299 | + generateMainFunctionText(context, nominal, |
| 3300 | + /*isThrows*/ true, |
| 3301 | + /*isAsync*/ true) |
| 3302 | + .str()); |
| 3303 | + } |
3239 | 3304 | attr->setInvalid();
|
3240 | 3305 | return nullptr;
|
3241 | 3306 | }
|
|
0 commit comments