{"record":{"id":"82ce05e7a98c7161","repo":"JetBrains/intellij-community","slug":"changesignature-contract-converter-mutation-contra","errorCode":"changeSignature.contract.converter.mutation.contract","errorMessage":"Annotation contains mutation contract","messagePattern":"Annotation contains mutation contract","errorType":"exception","errorClass":"ContractConversionException","httpStatus":null,"severity":"error","filePath":"java/java-impl/src/com/intellij/refactoring/changeSignature/ContractConverter.java","lineNumber":42,"sourceCode":"  private ContractConverter() {}\n\n  public static @Nullable PsiAnnotation convertContract(@NotNull PsiMethod method, @NotNull JavaChangeInfo info) throws ContractConversionException {\n    return convertContract(method, info.getOldParameterNames(), info.getNewParameters());\n  }\n\n  public static @Nullable PsiAnnotation convertContract(@NotNull PsiMethod method,\n                                                        String @NotNull [] oldParameterNames,\n                                                        JavaParameterInfo @NotNull [] newParameters) throws ContractConversionException {\n    PsiAnnotation annotation = JavaMethodContractUtil.findContractAnnotation(method);\n    if (annotation == null || AnnotationUtil.isInferredAnnotation(annotation)) return null;\n    if (AnnotationUtil.isExternalAnnotation(annotation)) {\n      throw new ContractConversionException(JavaRefactoringBundle.message(\"changeSignature.contract.converter.external.annotations\"));\n    }\n    if (annotation.getOwner() != method.getModifierList()) {\n      throw new ContractInheritedException();\n    }\n    if (annotation.findDeclaredAttributeValue(MutationSignature.ATTR_MUTATES) != null) {\n      throw new ContractConversionException(JavaRefactoringBundle.message(\"changeSignature.contract.converter.mutation.contract\"));\n    }\n    String text = AnnotationUtil.getStringAttributeValue(annotation, null);\n    List<StandardMethodContract> contracts = Collections.emptyList();\n    if (text != null) {\n      try {\n        contracts = StandardMethodContract.parseContract(text);\n      }\n      catch (StandardMethodContract.ParseException exception) {\n        String definitionError = JavaRefactoringBundle.message(\"changeSignature.contract.converter.definition.error\",\n                                                               exception.getMessage());\n        throw new ContractConversionException(definitionError);\n      }\n    }\n    int[] newToOldIndex = StreamEx.of(newParameters).mapToInt(ParameterInfo::getOldIndex).toArray();\n    int[] oldToNewIndex = reverseIndex(oldParameterNames.length, newToOldIndex);\n\n    List<StandardMethodContract> result = new ArrayList<>();\n    for (StandardMethodContract contract : contracts) {","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/JetBrains/intellij-community/blob/be881553f2a76ac8b4ea53950d93f0de78295c19/java/java-impl/src/com/intellij/refactoring/changeSignature/ContractConverter.java#L24-L60","documentation":"Thrown by ContractConverter.convertContract when the method's @Contract annotation also declares the 'mutates' attribute (org.jetbrains.annotations.MutationSignature ATTR_MUTATES, used by @MutationContract-style contracts). The converter only knows how to rewrite value contracts, not mutation contracts that reference parameters by name for mutation semantics, so it aborts with ContractConversionException.","triggerScenarios":"Running Change Signature on a method annotated like @Contract(mutates = \"this,param1\", value = \"...\") or any contract whose attribute set includes mutates; the signature change would require reindexing the mutation contract's parameter references.","commonSituations":"Code using JetBrains mutation-contract annotations on builder/mutator methods; refactoring methods annotated with both value and mutates; recent IDE versions that parse mutates make previously ignorable cases fatal.","solutions":["Temporarily remove the mutates attribute from the @Contract annotation, run Change Signature, then re-add mutates with updated parameter references.","Update the mutation contract manually after performing the signature change without automatic conversion.","Keep parameter order stable for methods with mutation contracts, or refactor them by hand."],"exampleFix":"// before\n@Contract(mutates = \"param1\", value = \"null -> false\")\nboolean process(String a, List<String> out) { ... }\n// after (manual, params reordered)\n@Contract(mutates = \"param2\", value = \"null -> false\")\nboolean process(List<String> out, String a) { ... }","handlingStrategy":"validation","validationCode":"PsiAnnotation a = JavaMethodContractUtil.findContractAnnotation(method);\nif (a != null && a.findDeclaredAttributeValue(\"mutates\") != null) {\n  // mutation contract present; plan a manual contract update around the refactoring\n}","typeGuard":null,"tryCatchPattern":"try { ContractConverter.convertContract(method, info); } catch (ContractConversionException e) { /* if message mentions mutation contract, edit annotation manually then retry */ }","preventionTips":["For methods with mutates attributes, change signatures by hand and update both value and mutates strings.","Keep parameter names stable in mutation contracts; prefer refactoring before contracts grow complex.","Review @Contract attributes (including mutates) whenever parameters are renamed or reordered."],"tags":["java","refactoring","change-signature","contract-annotation","mutation-contract"],"backgroundTag":null,"analyzedSha":"be881553f2a76ac8b4ea53950d93f0de78295c19","analyzedAt":"2026-08-14T14:13:06.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}