From 98b4ec43a696f8d90c4e9d7689d4fa377e5d2056 Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Mon, 27 Oct 2014 21:56:12 +0400 Subject: [PATCH] Supported "initializer block" arrangement entry (IDEA-95115) Previous behaviour was to treat initializer block as field and stick it with previous field, now it's eliminated with matching and rearranging according to matching rules. See comments also in [CR-IC-6618] --- .../psi/codeStyle/JavaCodeStyleSettings.java | 2 + .../arrangement/JavaArrangementVisitor.java | 24 +----- .../codeStyle/arrangement/JavaRearranger.java | 34 +++++++- .../java/JavaSpacePropertyProcessor.java | 11 +-- ...JavaRearrangerByTypeAndModifierTest.groovy | 6 +- .../JavaRearrangerByTypeTest.groovy | 81 +++++++++++++++++++ .../java/JavaFormatterBlankLinesTest.java | 1 + .../arrangement/std/StdArrangementTokens.java | 1 + 8 files changed, 126 insertions(+), 34 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java b/java/java-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java index 8024f7bcd335..7ea13ffd9646 100644 --- a/java/java-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java +++ b/java/java-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java @@ -35,4 +35,6 @@ public class JavaCodeStyleSettings extends CustomCodeStyleSettings { public int ANNOTATION_PARAMETER_WRAP = CommonCodeStyleSettings.DO_NOT_WRAP; public boolean ALIGN_MULTILINE_ANNOTATION_PARAMETERS = false; + public int BLANK_LINES_AROUND_INITIALIZER = 1; + } diff --git a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementVisitor.java b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementVisitor.java index 21d2e1881d05..f4e54f9b7724 100644 --- a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementVisitor.java +++ b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementVisitor.java @@ -341,31 +341,11 @@ public class JavaArrangementVisitor extends JavaRecursiveElementVisitor { @Override public void visitClassInitializer(PsiClassInitializer initializer) { - JavaElementArrangementEntry entry = createNewEntry(initializer, initializer.getTextRange(), FIELD, null, true); + JavaElementArrangementEntry entry = createNewEntry(initializer, initializer.getTextRange(), INIT_BLOCK, null, true); if (entry == null) { return; } - - PsiElement classLBrace = null; - PsiClass clazz = initializer.getContainingClass(); - if (clazz != null) { - classLBrace = clazz.getLBrace(); - } - for (PsiElement e = initializer.getPrevSibling(); e != null; e = e.getPrevSibling()) { - JavaElementArrangementEntry prevEntry; - if (e == classLBrace) { - prevEntry = myEntries.get(clazz); - } - else { - prevEntry = myEntries.get(e); - } - if (prevEntry != null) { - entry.addDependency(prevEntry); - } - if (!(e instanceof PsiWhiteSpace)) { - break; - } - } + parseModifiers(initializer.getModifierList(), entry); } @NotNull diff --git a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java index 0baf085c6f64..8e79d7e67eff 100644 --- a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java +++ b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaRearranger.java @@ -27,6 +27,7 @@ import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; +import com.intellij.psi.codeStyle.JavaCodeStyleSettings; import com.intellij.psi.codeStyle.arrangement.engine.ArrangementEngine; import com.intellij.psi.codeStyle.arrangement.group.ArrangementGroupingRule; import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryMatcher; @@ -36,6 +37,7 @@ import com.intellij.psi.codeStyle.arrangement.model.ArrangementAtomMatchConditio import com.intellij.psi.codeStyle.arrangement.model.ArrangementCompositeMatchCondition; import com.intellij.psi.codeStyle.arrangement.model.ArrangementMatchCondition; import com.intellij.psi.codeStyle.arrangement.std.*; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtilRt; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -62,7 +64,7 @@ public class JavaRearranger implements Rearranger, // Type @NotNull private static final Set SUPPORTED_TYPES = ContainerUtilRt.newLinkedHashSet( - FIELD, CONSTRUCTOR, METHOD, CLASS, INTERFACE, ENUM, GETTER, SETTER, OVERRIDDEN + FIELD, INIT_BLOCK, CONSTRUCTOR, METHOD, CLASS, INTERFACE, ENUM, GETTER, SETTER, OVERRIDDEN ); // Modifier @NotNull private static final Set SUPPORTED_MODIFIERS = @@ -79,6 +81,9 @@ public class JavaRearranger implements Rearranger, @NotNull private static final Collection> MUTEXES = ContainerUtilRt.newArrayList(); + private static final Set TYPES_WITH_DISABLED_ORDER = ContainerUtil.newHashSet(); + private static final Set TYPES_WITH_DISABLED_NAME_MATCH = ContainerUtil.newHashSet(); + static { Set visibilityModifiers = ContainerUtilRt.newHashSet(PUBLIC, PROTECTED, PACKAGE_PRIVATE, PRIVATE); MUTEXES.add(visibilityModifiers); @@ -96,6 +101,11 @@ public class JavaRearranger implements Rearranger, MODIFIERS_BY_TYPE.put(GETTER, ContainerUtilRt.newHashSet()); MODIFIERS_BY_TYPE.put(SETTER, ContainerUtilRt.newHashSet()); MODIFIERS_BY_TYPE.put(OVERRIDDEN, ContainerUtilRt.newHashSet()); + MODIFIERS_BY_TYPE.put(INIT_BLOCK, ContainerUtilRt.newHashSet(STATIC)); + + TYPES_WITH_DISABLED_ORDER.add(INIT_BLOCK); + + TYPES_WITH_DISABLED_NAME_MATCH.add(INIT_BLOCK); } private static final Map> GROUPING_RULES = ContainerUtilRt.newLinkedHashMap(); @@ -129,6 +139,8 @@ public class JavaRearranger implements Rearranger, for (ArrangementSettingsToken modifier : visibility) { and(matchRules, FIELD, STATIC, modifier); } + and(matchRules, INIT_BLOCK, STATIC); + for (ArrangementSettingsToken modifier : visibility) { and(matchRules, FIELD, FINAL, modifier); } @@ -136,6 +148,7 @@ public class JavaRearranger implements Rearranger, and(matchRules, FIELD, modifier); } and(matchRules, FIELD); + and(matchRules, INIT_BLOCK); and(matchRules, CONSTRUCTOR); and(matchRules, METHOD, STATIC); and(matchRules, METHOD); @@ -304,10 +317,14 @@ public class JavaRearranger implements Rearranger, } CommonCodeStyleSettings commonSettings = settings.getCommonSettings(JavaLanguage.INSTANCE); + JavaCodeStyleSettings javaSettings = settings.getCustomSettings(JavaCodeStyleSettings.class); if (FIELD.equals(target.getType())) { if (parent != null && parent.getType() == INTERFACE) { return commonSettings.BLANK_LINES_AROUND_FIELD_IN_INTERFACE; } + else if (INIT_BLOCK.equals(previous.getType())) { + return javaSettings.BLANK_LINES_AROUND_INITIALIZER; + } else { return commonSettings.BLANK_LINES_AROUND_FIELD; } @@ -323,6 +340,9 @@ public class JavaRearranger implements Rearranger, else if (CLASS.equals(target.getType())) { return commonSettings.BLANK_LINES_AROUND_CLASS; } + else if (INIT_BLOCK.equals(target.getType())) { + return javaSettings.BLANK_LINES_AROUND_INITIALIZER; + } else { return -1; } @@ -363,9 +383,10 @@ public class JavaRearranger implements Rearranger, @Override public boolean isEnabled(@NotNull ArrangementSettingsToken token, @Nullable ArrangementMatchCondition current) { - if (SUPPORTED_TYPES.contains(token) || SUPPORTED_ORDERS.contains(token) || StdArrangementTokens.Regexp.NAME.equals(token)) { + if (SUPPORTED_TYPES.contains(token)) { return true; } + ArrangementSettingsToken type = null; if (current != null) { type = ArrangementUtil.parseType(current); @@ -373,6 +394,15 @@ public class JavaRearranger implements Rearranger, if (type == null) { type = NO_TYPE; } + + if (SUPPORTED_ORDERS.contains(token)) { + return !TYPES_WITH_DISABLED_ORDER.contains(type); + } + + if (StdArrangementTokens.Regexp.NAME.equals(token)) { + return !TYPES_WITH_DISABLED_NAME_MATCH.contains(type); + } + Set modifiers = MODIFIERS_BY_TYPE.get(type); return modifiers != null && modifiers.contains(token); } diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java index 84c15d5db1a9..8a89027e2d56 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java @@ -425,13 +425,8 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor { myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE); } else if (myRole1 == ChildRole.FIELD) { - int lines = Math.max(getLinesAroundField(), getLinesAroundMethod()) + 1; - // IJ has been keeping initialization block which starts at the same line as a field for a while. - // However, it's not convenient for a situation when particular code is created via PSI - it's easier to not bothering - // with whitespace elements when inserting, say, new initialization blocks. That's why we don't enforce new line - // only during explicit reformatting ('Reformat' action). - //int minLineFeeds = FormatterUtil.isFormatterCalledExplicitly() ? 0 : 1; - myResult = Spacing.createSpacing(0, mySettings.SPACE_BEFORE_CLASS_LBRACE ? 1 : 0, 1, true, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE, lines); + int blankLines = myJavaSettings.BLANK_LINES_AROUND_INITIALIZER + 1; + myResult = Spacing.createSpacing(0, mySettings.SPACE_BEFORE_CLASS_LBRACE ? 1 : 0, blankLines, true, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE); } else if (myRole1 == ChildRole.CLASS) { setAroundClassSpacing(); @@ -450,7 +445,7 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor { setAroundClassSpacing(); } else { - final int blankLines = getLinesAroundMethod() + 1; + final int blankLines = myJavaSettings.BLANK_LINES_AROUND_INITIALIZER + 1; myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS); } } diff --git a/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerByTypeAndModifierTest.groovy b/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerByTypeAndModifierTest.groovy index 23f6d1b566c2..1cc9c93bc9c5 100644 --- a/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerByTypeAndModifierTest.groovy +++ b/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerByTypeAndModifierTest.groovy @@ -83,9 +83,10 @@ class Test { expected: '''\ class Test { public int j; - { j = 1; } protected int k; private int i; + + { j = 1; } }''', rules: [rule(FIELD, PUBLIC), rule(FIELD, PROTECTED), rule(FIELD, PRIVATE)]) } @@ -101,10 +102,11 @@ class Test { }''', expected: '''\ class Test { - { j = 1; } public int j; protected int k; private int i; + + { j = 1; } }''', rules: [rule(FIELD, PUBLIC), rule(FIELD, PROTECTED), rule(FIELD, PRIVATE)]) } diff --git a/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerByTypeTest.groovy b/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerByTypeTest.groovy index 7f15babc1e93..62fedc613f7f 100644 --- a/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerByTypeTest.groovy +++ b/java/java-tests/testSrc/com/intellij/psi/codeStyle/arrangement/JavaRearrangerByTypeTest.groovy @@ -569,4 +569,85 @@ class B extends A { rules: [rule(PUBLIC, METHOD), rule(PRIVATE, METHOD)] ) } + + void "test initializer block after fields"() { + doTest( + initial: '''\ +public class NewOneClass { + + { + a = 1; + } + + int a; + + { + b = 5; + } + + int b; + +} +''', + expected: '''\ +public class NewOneClass { + + int a; + int b; + + { + a = 1; + } + + { + b = 5; + } + +} +''', + rules: [rule(FIELD), rule(INIT_BLOCK)] + ) + } + + void "test static initializer block"() { + doTest( + initial: '''\ +public class NewOneClass { + + static { + a = 1; + } + + static int a; + + { + b = 5; + } + + int b; + +} +''', + expected: '''\ +public class NewOneClass { + + static int a; + + static { + a = 1; + } + + int b; + + { + b = 5; + } + +} +''', + rules: [rule(STATIC, FIELD), rule(STATIC, INIT_BLOCK), rule(FIELD), rule(INIT_BLOCK)] + ) + } + + } diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBlankLinesTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBlankLinesTest.java index fe005a84db3f..e0c845d066c6 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBlankLinesTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterBlankLinesTest.java @@ -25,6 +25,7 @@ public class JavaFormatterBlankLinesTest extends AbstractJavaFormatterTest { public void testBlankLinesAroundClassInitializationBlock() throws Exception { getSettings().BLANK_LINES_AROUND_METHOD = 3; + getJavaSettings().BLANK_LINES_AROUND_INITIALIZER = 3; doTextTest( "class T {\n" + " private final DecimalFormat fmt = new DecimalFormat();\n" + diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementTokens.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementTokens.java index 764f1bcea51f..a5753c8375bb 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementTokens.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementTokens.java @@ -164,6 +164,7 @@ public class StdArrangementTokens { @NotNull public static final ArrangementSettingsToken PROPERTY = invertible("PROPERTY", StdArrangementTokenType.ENTRY_TYPE); @NotNull public static final ArrangementSettingsToken EVENT_HANDLER = invertible("EVENT_HANDLER", StdArrangementTokenType.ENTRY_TYPE); @NotNull public static final ArrangementSettingsToken STATIC_INIT = invertible("STATIC_INIT", StdArrangementTokenType.ENTRY_TYPE); + @NotNull public static final ArrangementSettingsToken INIT_BLOCK = invertible("INITIALIZER BLOCK", StdArrangementTokenType.ENTRY_TYPE); @NotNull public static final ArrangementSettingsToken NAMESPACE = invertible("NAMESPACE", StdArrangementTokenType.ENTRY_TYPE); @NotNull public static final ArrangementSettingsToken TRAIT = invertible("TRAIT", StdArrangementTokenType.ENTRY_TYPE);