|
26 | 26 | #include "swift/AST/Expr.h" |
27 | 27 | #include "swift/AST/GenericSignature.h" |
28 | 28 | #include "swift/AST/Initializer.h" |
| 29 | +#include "swift/AST/ImportCache.h" |
29 | 30 | #include "swift/AST/ParameterList.h" |
30 | 31 | #include "swift/AST/Pattern.h" |
31 | 32 | #include "swift/AST/ProtocolConformance.h" |
@@ -6486,6 +6487,9 @@ bool ArgumentMismatchFailure::diagnoseAsError() { |
6486 | 6487 | if (diagnosePropertyWrapperMismatch()) |
6487 | 6488 | return true; |
6488 | 6489 |
|
| 6490 | + if (diagnoseAttemptedRegexBuilder()) |
| 6491 | + return true; |
| 6492 | + |
6489 | 6493 | if (diagnoseTrailingClosureMismatch()) |
6490 | 6494 | return true; |
6491 | 6495 |
|
@@ -6730,6 +6734,91 @@ bool ArgumentMismatchFailure::diagnosePropertyWrapperMismatch() const { |
6730 | 6734 | return true; |
6731 | 6735 | } |
6732 | 6736 |
|
| 6737 | +/// Add a fix-it to insert an import of a module. |
| 6738 | +static void fixItImport(InFlightDiagnostic &diag, Identifier moduleName, |
| 6739 | + DeclContext *dc) { |
| 6740 | + auto *SF = dc->getParentSourceFile(); |
| 6741 | + if (!SF) |
| 6742 | + return; |
| 6743 | + |
| 6744 | + SourceLoc insertLoc; |
| 6745 | + bool isTrailing = true; |
| 6746 | + |
| 6747 | + // Check if we can insert as the last import statement. |
| 6748 | + auto decls = SF->getTopLevelDecls(); |
| 6749 | + for (auto *decl : decls) { |
| 6750 | + auto *importDecl = dyn_cast<ImportDecl>(decl); |
| 6751 | + if (!importDecl) { |
| 6752 | + if (insertLoc.isValid()) |
| 6753 | + break; |
| 6754 | + continue; |
| 6755 | + } |
| 6756 | + insertLoc = importDecl->getEndLoc(); |
| 6757 | + } |
| 6758 | + |
| 6759 | + // If not, insert it as the first decl with a valid source location. |
| 6760 | + if (insertLoc.isInvalid()) { |
| 6761 | + for (auto *decl : decls) { |
| 6762 | + if (auto loc = decl->getStartLoc()) { |
| 6763 | + insertLoc = loc; |
| 6764 | + isTrailing = false; |
| 6765 | + break; |
| 6766 | + } |
| 6767 | + } |
| 6768 | + } |
| 6769 | + |
| 6770 | + // If we didn't resolve to a valid location, give up. |
| 6771 | + if (insertLoc.isInvalid()) |
| 6772 | + return; |
| 6773 | + |
| 6774 | + SmallString<32> insertText; |
| 6775 | + if (isTrailing) { |
| 6776 | + insertText.append("\n"); |
| 6777 | + } |
| 6778 | + insertText.append("import "); |
| 6779 | + insertText.append(moduleName.str()); |
| 6780 | + if (isTrailing) { |
| 6781 | + diag.fixItInsertAfter(insertLoc, insertText); |
| 6782 | + } else { |
| 6783 | + insertText.append("\n\n"); |
| 6784 | + diag.fixItInsert(insertLoc, insertText); |
| 6785 | + } |
| 6786 | +} |
| 6787 | + |
| 6788 | +bool ArgumentMismatchFailure::diagnoseAttemptedRegexBuilder() const { |
| 6789 | + auto &ctx = getASTContext(); |
| 6790 | + |
| 6791 | + // Should be a lone trailing closure argument. |
| 6792 | + if (!Info.isTrailingClosure() || !Info.getArgList()->isUnary()) |
| 6793 | + return false; |
| 6794 | + |
| 6795 | + // Check if this an application of a Regex initializer, and the user has not |
| 6796 | + // imported RegexBuilder. |
| 6797 | + auto *ctor = dyn_cast_or_null<ConstructorDecl>(getCallee()); |
| 6798 | + if (!ctor) |
| 6799 | + return false; |
| 6800 | + |
| 6801 | + auto *ctorDC = ctor->getInnermostTypeContext(); |
| 6802 | + if (!ctorDC || ctorDC->getSelfNominalTypeDecl() != ctx.getRegexDecl()) |
| 6803 | + return false; |
| 6804 | + |
| 6805 | + // If the RegexBuilder module is loaded, make sure it hasn't been imported. |
| 6806 | + // Note this will cause us to diagnose even if another SourceFile has |
| 6807 | + // imported RegexBuilder, and its extensions have leaked into this file. This |
| 6808 | + // is a longstanding lookup bug, and it's probably a good idea to suggest |
| 6809 | + // explicitly importing RegexBuilder regardless in that case. |
| 6810 | + if (auto *regexBuilderModule = ctx.getLoadedModule(ctx.Id_RegexBuilder)) { |
| 6811 | + auto &importCache = getASTContext().getImportCache(); |
| 6812 | + if (importCache.isImportedBy(regexBuilderModule, getDC())) |
| 6813 | + return false; |
| 6814 | + } |
| 6815 | + |
| 6816 | + // Suggest importing RegexBuilder. |
| 6817 | + auto diag = emitDiagnostic(diag::must_import_regex_builder_module); |
| 6818 | + fixItImport(diag, ctx.Id_RegexBuilder, getDC()); |
| 6819 | + return true; |
| 6820 | +} |
| 6821 | + |
6733 | 6822 | bool ArgumentMismatchFailure::diagnoseTrailingClosureMismatch() const { |
6734 | 6823 | if (!Info.isTrailingClosure()) |
6735 | 6824 | return false; |
|
0 commit comments