@@ -932,6 +932,45 @@ static Optional<std::string> buildDefaultInitializerString(DeclContext *dc,
932
932
llvm_unreachable (" Unhandled PatternKind in switch." );
933
933
}
934
934
935
+ // / Create a fix-it string for the 'decodable_suggest_overriding_init_here' and
936
+ // / optionally, the 'codable_suggest_overriding_init_here' diagnostics.
937
+ static std::string getFixItStringForDecodable (ClassDecl *CD,
938
+ bool includeEncodeTo) {
939
+ auto &ctx = CD->getASTContext ();
940
+ SourceLoc indentationLoc = CD->getBraces ().End ;
941
+ StringRef extraIndentation;
942
+ StringRef indentation = Lexer::getIndentationForLine (
943
+ ctx.SourceMgr , indentationLoc, &extraIndentation);
944
+ std::string fixItStringToReturn;
945
+ {
946
+ llvm::raw_string_ostream out (fixItStringToReturn);
947
+ ExtraIndentStreamPrinter printer (out, indentation);
948
+
949
+ printer.printNewline ();
950
+ printer << " override init(from decoder: Decoder) throws" ;
951
+
952
+ // Add a dummy body.
953
+ auto printDummyBody = [&]() {
954
+ printer << " {" ;
955
+ printer.printNewline ();
956
+ printer << extraIndentation << getCodePlaceholder ();
957
+ printer.printNewline ();
958
+ printer << " }" ;
959
+ };
960
+
961
+ printDummyBody ();
962
+
963
+ if (includeEncodeTo) {
964
+ printer.printNewline ();
965
+ printer.printNewline ();
966
+ printer << " override func encode(to encoder: Encoder) throws" ;
967
+ printDummyBody ();
968
+ }
969
+ }
970
+
971
+ return fixItStringToReturn;
972
+ }
973
+
935
974
// / Diagnose a class that does not have any initializers.
936
975
static void diagnoseClassWithoutInitializers (ClassDecl *classDecl) {
937
976
ASTContext &C = classDecl->getASTContext ();
@@ -950,7 +989,6 @@ static void diagnoseClassWithoutInitializers(ClassDecl *classDecl) {
950
989
// It is helpful to suggest here that the user may have forgotten to override
951
990
// init(from:) (and encode(to:), if applicable) in a note, before we start
952
991
// listing the members that prevented initializer synthesis.
953
- // TODO: Add a fixit along with this suggestion.
954
992
if (auto *superclassDecl = classDecl->getSuperclassDecl ()) {
955
993
auto *decodableProto = C.getProtocol (KnownProtocolKind::Decodable);
956
994
auto superclassType = superclassDecl->getDeclaredInterfaceType ();
@@ -975,6 +1013,7 @@ static void diagnoseClassWithoutInitializers(ClassDecl *classDecl) {
975
1013
diagDest = result.front ().getValueDecl ();
976
1014
977
1015
auto diagName = diag::decodable_suggest_overriding_init_here;
1016
+ auto shouldEmitFixItForEncodeTo = false ;
978
1017
979
1018
// This is also a bit of a hack, but the best place we've got at the
980
1019
// moment to suggest this.
@@ -992,11 +1031,18 @@ static void diagnoseClassWithoutInitializers(ClassDecl *classDecl) {
992
1031
// The direct lookup here won't see an encode(to:) if it is inherited
993
1032
// from the superclass.
994
1033
auto encodeTo = DeclName (C, C.Id_encode , C.Id_to );
995
- if (classDecl->lookupDirect (encodeTo).empty ())
1034
+ if (classDecl->lookupDirect (encodeTo).empty ()) {
996
1035
diagName = diag::codable_suggest_overriding_init_here;
1036
+ shouldEmitFixItForEncodeTo = true ;
1037
+ }
997
1038
}
998
1039
999
- C.Diags .diagnose (diagDest, diagName);
1040
+ auto insertionLoc =
1041
+ Lexer::getLocForEndOfLine (C.SourceMgr , classDecl->getBraces ().Start );
1042
+ auto fixItString =
1043
+ getFixItStringForDecodable (classDecl, shouldEmitFixItForEncodeTo);
1044
+ C.Diags .diagnose (diagDest, diagName)
1045
+ .fixItInsert (insertionLoc, fixItString);
1000
1046
}
1001
1047
}
1002
1048
0 commit comments