diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java index e6f14c03dc91..5da4faeb8fcf 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/AbstractJavaBlock.java @@ -474,7 +474,16 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo } else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.PARAMETER_LIST) { - final Wrap wrap = Wrap.createWrap(getWrapType(mySettings.METHOD_PARAMETERS_WRAP), false); + final Wrap wrap; + Wrap reservedWrap = getReservedWrap(JavaElementType.MODIFIER_LIST); + // There is a possible case that particular annotated method definition is too long. We may wrap either after annotation + // or after opening lbrace then. Our strategy is to wrap after annotation whenever possible. + if (reservedWrap == null) { + wrap = Wrap.createWrap(getWrapType(mySettings.METHOD_PARAMETERS_WRAP), false); + } + else { + wrap = Wrap.createChildWrap(reservedWrap, getWrapType(mySettings.METHOD_PARAMETERS_WRAP), false); + } child = processParenthesisBlock(result, child, WrappingStrategy.createDoNotWrapCommaStrategy(wrap), mySettings.ALIGN_MULTILINE_PARAMETERS); @@ -533,6 +542,19 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo myAnnotationWrap = null; } } + else if (childType == JavaElementType.PARAMETER_LIST && nodeType == JavaElementType.METHOD) { + // We prefer wrapping after method annotation to wrapping method parameter list, hence, deliver target wrap object + // to child block if necessary. + if (!result.isEmpty()) { + Block firstChildBlock = result.get(0); + if (firstChildBlock instanceof AbstractJavaBlock) { + AbstractJavaBlock childJavaBlock = (AbstractJavaBlock)firstChildBlock; + if (firstChildIsAnnotation(childJavaBlock.getNode())) { + javaBlock.setReservedWrap(childJavaBlock.getReservedWrap(JavaElementType.MODIFIER_LIST), JavaElementType.MODIFIER_LIST); + } + } + } + } } result.add(block); @@ -747,6 +769,14 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo } + private static boolean firstChildIsAnnotation(final ASTNode child) { + ASTNode current = child.getFirstChildNode(); + while (current != null && current.getElementType() == TokenType.WHITE_SPACE) { + current = current.getTreeNext(); + } + return current != null && current.getElementType() == JavaElementType.ANNOTATION; + } + private static boolean lastChildIsAnnotation(final ASTNode child) { ASTNode current = child.getLastChildNode(); while (current != null && current.getElementType() == TokenType.WHITE_SPACE) { diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterWrapTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterWrapTest.java index f60b7feb1e94..493ddd23ab85 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterWrapTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterWrapTest.java @@ -17,6 +17,7 @@ package com.intellij.psi.formatter.java; import com.intellij.openapi.util.TextRange; import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; /** * Is intended to hold specific java formatting tests for 'wrapping' settings. @@ -224,4 +225,18 @@ public class JavaFormatterWrapTest extends AbstractJavaFormatterTest { "}" ); } + + public void testWrapMethodAnnotationBeforeParams() throws Exception { + // Inspired by IDEA-59536 + getSettings().RIGHT_MARGIN = 90; + getSettings().METHOD_ANNOTATION_WRAP = CommonCodeStyleSettings.WRAP_AS_NEEDED; + getSettings().METHOD_PARAMETERS_WRAP = CommonCodeStyleSettings.WRAP_AS_NEEDED; + + doClassTest( + "@SuppressWarnings({\"SomeInspectionIWantToIgnore\"}) public void doSomething(int x, int y) {}", + "@SuppressWarnings({\"SomeInspectionIWantToIgnore\"})\n" + + "public void doSomething(int x, int y) {" + + "\n}" + ); + } }