@@ -697,6 +697,47 @@ class Class {
697697 library: library,
698698 );
699699
700+ final probeConstructors = ConstructorDetails .parseAll (
701+ declaration,
702+ configs,
703+ globalConfigs: globalConfigs,
704+ unitsExcludingGeneratedFiles: unitsExcludingGeneratedFiles,
705+ );
706+
707+ if (probeConstructors.isEmpty) {
708+ final mergedProps = _collectMergedPropsForPrecheck (
709+ declaration,
710+ configs,
711+ globalConfigs,
712+ unitsExcludingGeneratedFiles,
713+ );
714+ final target = declaration.copyWithTarget;
715+ if (target != null ) {
716+ final cloneableNames = {
717+ for (final p in mergedProps.cloneableProperties) p.name,
718+ };
719+ for (final parameter in target.parameters.parameters) {
720+ if (parameter.isOptional) continue ;
721+ final paramName = parameter.name? .lexeme;
722+ if (paramName == null ) continue ;
723+ if (! cloneableNames.contains (paramName)) {
724+ throw InvalidGenerationSourceError (
725+ '''
726+ The class ${declaration .name .lexeme } requested a copyWith implementation, yet the parameter `$paramName ` is not cloneable.
727+
728+ To fix, either:
729+ - Disable copyWith using @Freezed(copyWith: false)
730+ - Make `$paramName ` optional
731+ - Make sure `this.$paramName ` is accessible from the copyWith method
732+ ''' ,
733+ element: declaration.declaredFragment? .element,
734+ node: declaration,
735+ );
736+ }
737+ }
738+ }
739+ }
740+
700741 return Class ._from (
701742 declaration,
702743 configs,
@@ -1198,6 +1239,109 @@ To fix, either:
11981239
11991240 return '$escapedElementName $generics ' ;
12001241 }
1242+
1243+ static PropertyList _collectMergedPropsForPrecheck (
1244+ ClassDeclaration declaration,
1245+ ClassConfig configs,
1246+ Freezed globalConfigs,
1247+ List <CompilationUnit > unitsExcludingGeneratedFiles,
1248+ ) {
1249+ final props = PropertyList ();
1250+ final userLibrary = declaration.declaredFragment! .element.library2;
1251+
1252+ final localConstructors = ConstructorDetails .parseAll (
1253+ declaration,
1254+ configs,
1255+ globalConfigs: globalConfigs,
1256+ unitsExcludingGeneratedFiles: unitsExcludingGeneratedFiles,
1257+ );
1258+
1259+ props.readableProperties.addAll (
1260+ _computeReadableProperties (declaration, localConstructors),
1261+ );
1262+ props.cloneableProperties.addAll (
1263+ _computeCloneableProperties (
1264+ declaration,
1265+ localConstructors,
1266+ configs,
1267+ ).where (
1268+ (cloneable) =>
1269+ props.readableProperties.any ((e) => e.name == cloneable.name),
1270+ ),
1271+ );
1272+
1273+ final seenReadable = {for (final p in props.readableProperties) p.name};
1274+ final seenCloneable = {for (final p in props.cloneableProperties) p.name};
1275+
1276+ var superName = declaration.extendsClause? .superclass.name2.lexeme;
1277+ while (superName != null ) {
1278+ final parentDecl = _findClassDeclaration (
1279+ unitsExcludingGeneratedFiles,
1280+ superName,
1281+ );
1282+ if (parentDecl == null ) break ;
1283+
1284+ final parentConstructors = ConstructorDetails .parseAll (
1285+ parentDecl,
1286+ configs,
1287+ globalConfigs: globalConfigs,
1288+ unitsExcludingGeneratedFiles: unitsExcludingGeneratedFiles,
1289+ );
1290+
1291+ final parentProps = PropertyList ();
1292+ parentProps.readableProperties.addAll (
1293+ _computeReadableProperties (parentDecl, parentConstructors),
1294+ );
1295+ parentProps.cloneableProperties.addAll (
1296+ _computeCloneableProperties (
1297+ parentDecl,
1298+ parentConstructors,
1299+ configs,
1300+ ).where (
1301+ (cloneable) => parentProps.readableProperties.any (
1302+ (e) => e.name == cloneable.name,
1303+ ),
1304+ ),
1305+ );
1306+
1307+ final ownerLibrary = parentDecl.declaredFragment! .element.library2;
1308+
1309+ for (final sp in parentProps.readableProperties) {
1310+ if (! _isAccessible (sp.name, ownerLibrary, userLibrary)) continue ;
1311+ if (seenReadable.add (sp.name)) {
1312+ props.readableProperties.add (
1313+ sp.copyWith (originClass: parentDecl.name.lexeme),
1314+ );
1315+ }
1316+ }
1317+ for (final sp in parentProps.cloneableProperties) {
1318+ if (! _isAccessible (sp.name, ownerLibrary, userLibrary)) continue ;
1319+ if (seenCloneable.add (sp.name)) {
1320+ props.cloneableProperties.add (
1321+ sp.copyWith (originClass: parentDecl.name.lexeme),
1322+ );
1323+ }
1324+ }
1325+
1326+ superName = parentDecl.extendsClause? .superclass.name2.lexeme;
1327+ }
1328+
1329+ return props;
1330+ }
1331+
1332+ static ClassDeclaration ? _findClassDeclaration (
1333+ List <CompilationUnit > units,
1334+ String name,
1335+ ) {
1336+ for (final unit in units) {
1337+ for (final declaration in unit.declarations) {
1338+ if (declaration is ClassDeclaration && declaration.name.lexeme == name) {
1339+ return declaration;
1340+ }
1341+ }
1342+ }
1343+ return null ;
1344+ }
12011345}
12021346
12031347class PropertyList {
0 commit comments