[java, formatter] add options to set up wrapping in multi-catch IDEA-178941

GitOrigin-RevId: affcf268f09042ffef48b120867c8b37dc805043
This commit is contained in:
Roman Ivanov
2021-11-17 17:14:15 +01:00
committed by intellij-monorepo-bot
parent d2772e6c08
commit 2da0ff581e
7 changed files with 80 additions and 2 deletions

View File

@@ -240,6 +240,12 @@ public class JavaLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSett
"RPAREN_ON_NEW_LINE_IN_RECORD_HEADER",
ApplicationBundle.message("wrapping.rpar.on.new.line"),
recordComponentsGroup);
consumer.showCustomOption(JavaCodeStyleSettings.class,
"MULTI_CATCH_TYPES_WRAP",
JavaBundle.message("wrapping.multi.catch.types"),
ApplicationBundle.message("wrapping.try.statement"),
getInstance().WRAP_OPTIONS, CodeStyleSettingsCustomizable.WRAP_VALUES);
}
else if (settingsType == SettingsType.BLANK_LINES_SETTINGS) {
consumer.showAllStandardOptions();

View File

@@ -149,6 +149,10 @@ public class JavaCodeStyleSettings extends CustomCodeStyleSettings implements Im
*/
public boolean SPACE_WITHIN_RECORD_HEADER = false;
@WrapConstant
public int MULTI_CATCH_TYPES_WRAP = CommonCodeStyleSettings.WRAP_AS_NEEDED;
public boolean ALIGN_TYPES_IN_MULTI_CATCH = true;
// region JavaDoc
@Property(externalName = "doc_enable_formatting")

View File

@@ -409,7 +409,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
@Nullable
protected Wrap createChildWrap() {
//when detecting indent we do not care about wraps
return isBuildIndentsOnly() ? null : JavaFormatterUtil.createDefaultWrap(this, getSettings(), this);
return isBuildIndentsOnly() ? null : JavaFormatterUtil.createDefaultWrap(this, mySettings, myJavaSettings, this);
}
@Nullable
@@ -454,6 +454,9 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
}
return createAlignment(mySettings.ALIGN_MULTILINE_BINARY_OPERATION, defaultAlignment);
}
if (JavaFormatterUtil.isTopLevelTypeInCatchSection(nodeType, myNode)) {
return createAlignment(myJavaSettings.ALIGN_TYPES_IN_MULTI_CATCH, null);
}
if (isTextBlock(myNode.getPsi())) {
return createAlignment(myJavaSettings.ALIGN_MULTILINE_TEXT_BLOCKS,null);
}
@@ -514,6 +517,13 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
return processChild(result, child, alignmentStrategy, defaultWrap, childIndent, -1);
}
/**
* Creates blocks for nodes starting from child.
* @param result mutable list of child blocks
* @param child current child to create block for
* @param defaultWrap default wrap returned by {@link AbstractJavaBlock#createChildWrap() }
* @return next node to handle
*/
@Nullable
protected ASTNode processChild(@NotNull final List<Block> result,
@NotNull ASTNode child,
@@ -582,6 +592,11 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
child = myNode.getLastChildNode();
result.addAll(newlyCreated);
}
else if (childType == JavaTokenType.OR && nodeType == JavaElementType.TYPE) {
// by default in "Foo | Bar | Baz" each child will have same (default) wrap, but we need to distinguish types and "|"
Wrap wrap = Wrap.createWrap(WrapType.NONE, false);
result.add(new SimpleJavaBlock(child, wrap, alignmentStrategy, childIndent, mySettings, myJavaSettings, myFormattingMode));
}
else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.PARENTH_EXPRESSION) {
child = processParenthesisBlock(result, child,
WrappingStrategy.DO_NOT_WRAP,

View File

@@ -122,6 +122,8 @@ public final class JavaFormatterUtil {
/**
* Creates {@link Wrap wrap} to be used with the children blocks of the given block.
*
* It is important that single instance of wrap will be used for all children which use default wrap.
*
* @param block target block which sub-blocks should use wrap created by the current method
* @param settings code formatting settings to consider during wrap construction
* @param reservedWrapsProvider reserved {@code 'element type -> wrap instance'} mappings provider. <b>Note:</b> this
@@ -130,9 +132,13 @@ public final class JavaFormatterUtil {
* @return wrap to use for the sub-blocks of the given block
*/
@Nullable
static Wrap createDefaultWrap(ASTBlock block, CommonCodeStyleSettings settings, ReservedWrapsProvider reservedWrapsProvider) {
static Wrap createDefaultWrap(ASTBlock block,
CommonCodeStyleSettings settings,
JavaCodeStyleSettings javaSettings,
ReservedWrapsProvider reservedWrapsProvider) {
ASTNode node = block.getNode();
Wrap wrap = block.getWrap();
if (node == null) return null;
final IElementType nodeType = node.getElementType();
if (nodeType == JavaElementType.EXTENDS_LIST ||
nodeType == JavaElementType.IMPLEMENTS_LIST ||
@@ -174,11 +180,22 @@ public final class JavaFormatterUtil {
else if (isAssignment(node)) {
return Wrap.createWrap(settings.ASSIGNMENT_WRAP, true);
}
else if (isTopLevelTypeInCatchSection(nodeType, node)) {
return Wrap.createWrap(javaSettings.MULTI_CATCH_TYPES_WRAP, false);
}
else {
return null;
}
}
static boolean isTopLevelTypeInCatchSection(@NotNull IElementType nodeType, ASTNode node) {
if (nodeType != JavaElementType.TYPE) return false;
ASTNode parent = node.getTreeParent();
if (parent == null || parent.getElementType() != JavaElementType.PARAMETER) return false;
ASTNode grandParent = parent.getTreeParent();
return grandParent != null && grandParent.getElementType() == JavaElementType.CATCH_SECTION;
}
/**
* Tries to define the wrap to use for the {@link Block block} for the given {@code 'child'} node. It's assumed that
* given {@code 'child'} node is descendant (direct or indirect) of the given {@code 'parent'} node.

View File

@@ -24,6 +24,7 @@
"align_multiline_throws_list": false,
"align_subsequent_simple_methods": false,
"align_throws_keyword": false,
"align_types_in_multi_catch": true,
"annotation_parameter_wrap": "off",
"array_initializer_new_line_after_left_brace": false,
"array_initializer_right_brace_on_new_line": false,
@@ -139,6 +140,7 @@
"method_parameters_right_paren_on_new_line": false,
"method_parameters_wrap": "normal",
"modifier_list_wrap": false,
"multi_catch_types_wrap": "normal",
"names_count_to_use_import_on_demand": 3,
"new_line_after_lparen_in_annotation": false,
"new_line_after_lparen_in_record_header": false,

View File

@@ -952,6 +952,38 @@ public class JavaFormatterAlignmentTest extends AbstractJavaFormatterTest {
);
}
public void testAlign() {
getJavaSettings().MULTI_CATCH_TYPES_WRAP = CommonCodeStyleSettings.WRAP_ALWAYS;
doTextTest(
"public class Main {\n" +
"\n" +
" public static void main(String[] args) {\n" +
" try {\n" +
" \n" +
" } catch (FooException | BarException | FooBarException | FooBarFooException | BarBarFooException | BarFooFooException e) {\n" +
" \n" +
" }\n" +
" }\n" +
"}",
"public class Main {\n" +
"\n" +
" public static void main(String[] args) {\n" +
" try {\n" +
"\n" +
" } catch (FooException |\n" +
" BarException |\n" +
" FooBarException |\n" +
" FooBarFooException |\n" +
" BarBarFooException |\n" +
" BarFooFooException e) {\n" +
"\n" +
" }\n" +
" }\n" +
"}"
);
}
@SuppressWarnings("unused")
public void _testIdea199677() {
getSettings().ALIGN_CONSECUTIVE_VARIABLE_DECLARATIONS = true;

View File

@@ -1259,6 +1259,8 @@ usage.target.package.in.directory={0} (in {1})
use.external.annotations=Use &external annotations
wrapping.annotation.parameters=Annotation parameters
wrapping.record.components=Record components
wrapping.multi.catch.types=Types in multi-catch clauses
align.types.in.multi.catch=Align type in multi-catch
wrapping.text.blocks=Text blocks
wrong.package.statement=Wrong package statement
title.code.vision=Code vision