@@ -1199,104 +1199,10 @@ public boolean writeMethod(ClassNode node, StructMethod mt, int methodIndex, Tex
11991199        }
12001200
12011201        buffer .appendMethod (toValidJavaIdentifier (name ), true , cl .qualifiedName , mt .getName (), md );
1202-         buffer .append ('(' );
12031202
1204-         List <VarVersionPair > mask  = methodWrapper .synthParameters ;
1205- 
1206-         int  lastVisibleParameterIndex  = -1 ;
1207-         for  (int  i  = 0 ; i  < md .params .length ; i ++) {
1208-           if  (mask  == null  || mask .get (i ) == null ) {
1209-             lastVisibleParameterIndex  = i ;
1210-           }
1211-         }
1212-         if  (lastVisibleParameterIndex  != -1 ) {
1213-           buffer .pushNewlineGroup (indent , 1 );
1214-           buffer .appendPossibleNewline ();
1215-         }
1216- 
1217-         List <StructMethodParametersAttribute .Entry > methodParameters  = null ;
1218-         if  (DecompilerContext .getOption (IFernflowerPreferences .USE_METHOD_PARAMETERS )) {
1219-           StructMethodParametersAttribute  attr  = mt .getAttribute (StructGeneralAttribute .ATTRIBUTE_METHOD_PARAMETERS );
1220-           if  (attr  != null ) {
1221-             methodParameters  = attr .getEntries ();
1222-           }
1223-         }
1224- 
1225-         int  index  = isEnum  && init  ? 3  : thisVar  ? 1  : 0 ;
1226-         int  start  = isEnum  && init  ? 2  : 0 ;
1227-         boolean  hasDescriptor  = descriptor  != null ;
1228-         //mask should now have the Outer.this in it... so this *shouldn't* be nessasary. 
1229-         //if (init && !isEnum && ((node.access & CodeConstants.ACC_STATIC) == 0) && node.type == ClassNode.CLASS_MEMBER) 
1230-         //    index++; 
1231- 
1232-         buffer .pushNewlineGroup (indent , 0 );
1233-         for  (int  i  = start ; i  < md .params .length ; i ++) {
1234-           boolean  real  = mask  == null  || mask .get (i ) == null ;
1235-           VarType  parameterType  = real  && hasDescriptor  && paramCount  < descriptor .parameterTypes .size () ? descriptor .parameterTypes .get (paramCount ) : md .params [i ];
1236-           if  (real ) {
1237-             if  (paramCount  > 0 ) {
1238-               buffer .append ("," );
1239-               buffer .appendPossibleNewline (" " );
1240-             }
1241- 
1242-             appendParameterAnnotations (buffer , mt , paramCount );
1243- 
1244-             if  (methodParameters  != null  && i  < methodParameters .size ()) {
1245-               appendModifiers (buffer , methodParameters .get (i ).myAccessFlags , CodeConstants .ACC_FINAL , isInterface , 0 );
1246-             }
1247-             else  if  (methodWrapper .varproc .getVarFinal (new  VarVersionPair (index , 0 )) == VarTypeProcessor .FinalType .EXPLICIT_FINAL ) {
1248-               buffer .append ("final " );
1249-             }
1250- 
1251-             String  typeName ;
1252-             boolean  isVarArg  = i  == lastVisibleParameterIndex  && mt .hasModifier (CodeConstants .ACC_VARARGS ) && parameterType .arrayDim  > 0 ;
1253-             if  (isVarArg ) {
1254-                 parameterType  = parameterType .decreaseArrayDim ();
1255-             }
1256-             typeName  = ExprProcessor .getCastTypeName (parameterType );
1257- 
1258-             if  (ExprProcessor .UNDEFINED_TYPE_STRING .equals (typeName ) &&
1259-                 DecompilerContext .getOption (IFernflowerPreferences .UNDEFINED_PARAM_TYPE_OBJECT )) {
1260-               typeName  = ExprProcessor .getCastTypeName (VarType .VARTYPE_OBJECT );
1261-             }
1262-             buffer .appendCastTypeName (typeName , parameterType );
1263-             if  (isVarArg ) {
1264-               buffer .append ("..." );
1265-             }
1266- 
1267-             buffer .append (' ' );
1268- 
1269-             String  parameterName ;
1270-             String  clashingName  = methodWrapper .varproc .getClashingName (new  VarVersionPair (index , 0 ));
1271-             if  (clashingName  != null ) {
1272-               parameterName  = clashingName ;
1273-             } else  if  (methodParameters  != null  && i  < methodParameters .size () && methodParameters .get (i ).myName  != null ) {
1274-               parameterName  = methodParameters .get (i ).myName ;
1275-             } else  {
1276-               parameterName  = methodWrapper .varproc .getVarName (new  VarVersionPair (index , 0 ));
1277-             }
1278- 
1279-             String  newParameterName  = methodWrapper .methodStruct .getVariableNamer ().renameParameter (flags , parameterType , parameterName , index );
1280-             if  ((flags  & (CodeConstants .ACC_ABSTRACT  | CodeConstants .ACC_NATIVE )) != 0  && Objects .equals (newParameterName , parameterName )) {
1281-               newParameterName  = DecompilerContext .getStructContext ().renameAbstractParameter (methodWrapper .methodStruct .getClassQualifiedName (), mt .getName (), mt .getDescriptor (), index  - (((flags  & CodeConstants .ACC_STATIC ) == 0 ) ? 1  : 0 ), parameterName );
1282-             }
1283-             parameterName  = newParameterName ;
1284- 
1285-             buffer .appendVariable (parameterName  == null  ? "param"  + index  : parameterName , // null iff decompiled with errors 
1286-               true , true , cl .qualifiedName , mt .getName (), md , index , parameterName );
1287- 
1288-             paramCount ++;
1289-           }
1290- 
1291-           index  += parameterType .stackSize ;
1292-         }
1293-         buffer .popNewlineGroup ();
1294- 
1295-         if  (lastVisibleParameterIndex  != -1 ) {
1296-           buffer .appendPossibleNewline ("" , true );
1297-           buffer .popNewlineGroup ();
1203+         if  (!methodWrapper .isCompactRecordConstructor ) {
1204+           paramCount  = writeMethodParameterHeader (mt , buffer , indent , methodWrapper , md , isEnum , init , thisVar , descriptor , paramCount , isInterface , flags , cl );
12981205        }
1299-         buffer .append (')' );
13001206
13011207        StructExceptionsAttribute  attr  = mt .getAttribute (StructGeneralAttribute .ATTRIBUTE_EXCEPTIONS );
13021208        if  ((descriptor  != null  && !descriptor .exceptionTypes .isEmpty ()) || attr  != null ) {
@@ -1344,7 +1250,7 @@ else if (methodWrapper.varproc.getVarFinal(new VarVersionPair(index, 0)) == VarT
13441250            } else  {
13451251              TextBuffer  code  = root .toJava (indent  + 1 );
13461252              code .addBytecodeMapping (root .getDummyExit ().bytecode );
1347-               hideMethod  = code .length () == 0  && (clInit  || dInit  || hideConstructor (node , init , throwsExceptions , paramCount , flags ));
1253+               hideMethod  = code .length () == 0  && (clInit  || dInit  || hideConstructor (node , init , throwsExceptions , paramCount , flags ,  mt ));
13481254              buffer .append (code , cl .qualifiedName , InterpreterUtil .makeUniqueKey (mt .getName (), mt .getDescriptor ()));
13491255            }
13501256          }
@@ -1375,6 +1281,108 @@ else if (methodWrapper.varproc.getVarFinal(new VarVersionPair(index, 0)) == VarT
13751281    return  !hideMethod ;
13761282  }
13771283
1284+   private  static  int  writeMethodParameterHeader (StructMethod  mt , TextBuffer  buffer , int  indent , MethodWrapper  methodWrapper , MethodDescriptor  md , boolean  isEnum , boolean  init , boolean  thisVar , GenericMethodDescriptor  descriptor , int  paramCount , boolean  isInterface , int  flags , StructClass  cl ) {
1285+     buffer .append ('(' );
1286+ 
1287+     List <VarVersionPair > mask  = methodWrapper .synthParameters ;
1288+ 
1289+     int  lastVisibleParameterIndex  = -1 ;
1290+     for  (int  i  = 0 ; i  < md .params .length ; i ++) {
1291+       if  (mask  == null  || mask .get (i ) == null ) {
1292+         lastVisibleParameterIndex  = i ;
1293+       }
1294+     }
1295+     if  (lastVisibleParameterIndex  != -1 ) {
1296+       buffer .pushNewlineGroup (indent , 1 );
1297+       buffer .appendPossibleNewline ();
1298+     }
1299+ 
1300+     List <StructMethodParametersAttribute .Entry > methodParameters  = null ;
1301+     if  (DecompilerContext .getOption (IFernflowerPreferences .USE_METHOD_PARAMETERS )) {
1302+       StructMethodParametersAttribute  attr  = mt .getAttribute (StructGeneralAttribute .ATTRIBUTE_METHOD_PARAMETERS );
1303+       if  (attr  != null ) {
1304+         methodParameters  = attr .getEntries ();
1305+       }
1306+     }
1307+ 
1308+     int  index  = isEnum  && init  ? 3  : thisVar  ? 1  : 0 ;
1309+     int  start  = isEnum  && init  ? 2  : 0 ;
1310+     boolean  hasDescriptor  = descriptor  != null ;
1311+     //mask should now have the Outer.this in it... so this *shouldn't* be nessasary. 
1312+     //if (init && !isEnum && ((node.access & CodeConstants.ACC_STATIC) == 0) && node.type == ClassNode.CLASS_MEMBER) 
1313+     //    index++; 
1314+ 
1315+     buffer .pushNewlineGroup (indent , 0 );
1316+     for  (int  i  = start ; i  < md .params .length ; i ++) {
1317+       boolean  real  = mask  == null  || mask .get (i ) == null ;
1318+       VarType  parameterType  = real  && hasDescriptor  && paramCount  < descriptor .parameterTypes .size () ? descriptor .parameterTypes .get (paramCount ) : md .params [i ];
1319+       if  (real ) {
1320+         if  (paramCount  > 0 ) {
1321+           buffer .append ("," );
1322+           buffer .appendPossibleNewline (" " );
1323+         }
1324+ 
1325+         appendParameterAnnotations (buffer , mt , paramCount );
1326+ 
1327+         if  (methodParameters  != null  && i  < methodParameters .size ()) {
1328+           appendModifiers (buffer , methodParameters .get (i ).myAccessFlags , CodeConstants .ACC_FINAL , isInterface , 0 );
1329+         }
1330+         else  if  (methodWrapper .varproc .getVarFinal (new  VarVersionPair (index , 0 )) == VarTypeProcessor .FinalType .EXPLICIT_FINAL ) {
1331+           buffer .append ("final " );
1332+         }
1333+ 
1334+         String  typeName ;
1335+         boolean  isVarArg  = i  == lastVisibleParameterIndex  && mt .hasModifier (CodeConstants .ACC_VARARGS ) && parameterType .arrayDim  > 0 ;
1336+         if  (isVarArg ) {
1337+             parameterType  = parameterType .decreaseArrayDim ();
1338+         }
1339+         typeName  = ExprProcessor .getCastTypeName (parameterType );
1340+ 
1341+         if  (ExprProcessor .UNDEFINED_TYPE_STRING .equals (typeName ) &&
1342+             DecompilerContext .getOption (IFernflowerPreferences .UNDEFINED_PARAM_TYPE_OBJECT )) {
1343+           typeName  = ExprProcessor .getCastTypeName (VarType .VARTYPE_OBJECT );
1344+         }
1345+         buffer .appendCastTypeName (typeName , parameterType );
1346+         if  (isVarArg ) {
1347+           buffer .append ("..." );
1348+         }
1349+ 
1350+         buffer .append (' ' );
1351+ 
1352+         String  parameterName ;
1353+         String  clashingName  = methodWrapper .varproc .getClashingName (new  VarVersionPair (index , 0 ));
1354+         if  (clashingName  != null ) {
1355+           parameterName  = clashingName ;
1356+         } else  if  (methodParameters  != null  && i  < methodParameters .size () && methodParameters .get (i ).myName  != null ) {
1357+           parameterName  = methodParameters .get (i ).myName ;
1358+         } else  {
1359+           parameterName  = methodWrapper .varproc .getVarName (new  VarVersionPair (index , 0 ));
1360+         }
1361+ 
1362+         String  newParameterName  = methodWrapper .methodStruct .getVariableNamer ().renameParameter (flags , parameterType , parameterName , index );
1363+         if  ((flags  & (CodeConstants .ACC_ABSTRACT  | CodeConstants .ACC_NATIVE )) != 0  && Objects .equals (newParameterName , parameterName )) {
1364+           newParameterName  = DecompilerContext .getStructContext ().renameAbstractParameter (methodWrapper .methodStruct .getClassQualifiedName (), mt .getName (), mt .getDescriptor (), index  - (((flags  & CodeConstants .ACC_STATIC ) == 0 ) ? 1  : 0 ), parameterName );
1365+         }
1366+         parameterName  = newParameterName ;
1367+ 
1368+         buffer .appendVariable (parameterName  == null  ? "param"  + index  : parameterName , // null iff decompiled with errors 
1369+           true , true , cl .qualifiedName , mt .getName (), md , index , parameterName );
1370+ 
1371+         paramCount ++;
1372+       }
1373+ 
1374+       index  += parameterType .stackSize ;
1375+     }
1376+     buffer .popNewlineGroup ();
1377+ 
1378+     if  (lastVisibleParameterIndex  != -1 ) {
1379+       buffer .appendPossibleNewline ("" , true );
1380+       buffer .popNewlineGroup ();
1381+     }
1382+     buffer .append (')' );
1383+     return  paramCount ;
1384+   }
1385+ 
13781386  private  static  void  dumpError (TextBuffer  buffer , MethodWrapper  wrapper , int  indent ) {
13791387    List <String > lines  = new  ArrayList <>();
13801388    lines .add ("$VF: Couldn't be decompiled" );
@@ -1561,7 +1569,7 @@ private static void appendConstant(StringBuilder sb, PooledConstant constant) {
15611569    }
15621570  }
15631571
1564-   private  static  boolean  hideConstructor (ClassNode  node , boolean  init , boolean  throwsExceptions , int  paramCount , int  methodAccessFlags ) {
1572+   private  static  boolean  hideConstructor (ClassNode  node , boolean  init , boolean  throwsExceptions , int  paramCount , int  methodAccessFlags ,  StructMethod   structMethod ) {
15651573    if  (!init  || throwsExceptions  || paramCount  > 0  || !DecompilerContext .getOption (IFernflowerPreferences .HIDE_DEFAULT_CONSTRUCTOR )) {
15661574      return  false ;
15671575    }
@@ -1571,17 +1579,27 @@ private static boolean hideConstructor(ClassNode node, boolean init, boolean thr
15711579
15721580    int  classAccessFlags  = node .type  == ClassNode .Type .ROOT  ? cl .getAccessFlags () : node .access ;
15731581    boolean  isEnum  = cl .hasModifier (CodeConstants .ACC_ENUM ) && DecompilerContext .getOption (IFernflowerPreferences .DECOMPILE_ENUM );
1582+     boolean  isRecord  = cl .getRecordComponents () != null ;
15741583
15751584    // default constructor requires same accessibility flags. Exception: enum constructor which is always private 
1576-     if (!isEnum  && ((classAccessFlags  & ACCESSIBILITY_FLAGS ) != (methodAccessFlags  & ACCESSIBILITY_FLAGS ))) {
1585+     // Another exception: record classes can sometimes be generated with a private constructor 
1586+     if (!isEnum  && !isRecord  && ((classAccessFlags  & ACCESSIBILITY_FLAGS ) != (methodAccessFlags  & ACCESSIBILITY_FLAGS ))) {
15771587      return  false ;
15781588    }
15791589
1580-     int  count  = 0 ;
1581-     for  (StructMethod  mt  : cl .getMethods ()) {
1582-       if  (CodeConstants .INIT_NAME .equals (mt .getName ())) {
1583-         if  (++count  > 1 ) {
1584-           return  false ;
1590+     // Constructor with an annotation, we dont want to hide this. 
1591+     if  (isRecord  && RecordHelper .hasAnnotations (structMethod )) {
1592+       return  false ;
1593+     }
1594+ 
1595+     // We should not run this check in records 
1596+     if  (!isRecord ) {
1597+       int  count  = 0 ;
1598+       for  (StructMethod  mt  : cl .getMethods ()) {
1599+         if  (CodeConstants .INIT_NAME .equals (mt .getName ())) {
1600+           if  (++count  > 1 ) {
1601+             return  false ;
1602+           }
15851603        }
15861604      }
15871605    }
0 commit comments