mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-104026 (Java type annotation formatting)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -45,6 +45,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.psi.formatter.java.JavaFormatterUtil.getWrapType;
|
||||
|
||||
public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlock, ReservedWrapsProvider {
|
||||
|
||||
/**
|
||||
@@ -82,7 +84,6 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
protected boolean myUseChildAttributes = false;
|
||||
@NotNull protected final AlignmentStrategy myAlignmentStrategy;
|
||||
private boolean myIsAfterClassKeyword = false;
|
||||
private Wrap myAnnotationWrap = null;
|
||||
|
||||
protected Alignment myReservedAlignment;
|
||||
protected Alignment myReservedAlignment2;
|
||||
@@ -137,15 +138,14 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
}
|
||||
return strategy.getAlignment(node.getElementType());
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public static Block createJavaBlock(@NotNull ASTNode child,
|
||||
@NotNull CommonCodeStyleSettings settings,
|
||||
@NotNull JavaCodeStyleSettings javaSettings,
|
||||
@Nullable Indent indent,
|
||||
@Nullable Wrap wrap,
|
||||
Alignment alignment)
|
||||
{
|
||||
Alignment alignment) {
|
||||
return createJavaBlock(child, settings, javaSettings,indent, wrap, AlignmentStrategy.wrap(alignment));
|
||||
}
|
||||
|
||||
@@ -166,8 +166,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
@Nullable Indent indent,
|
||||
Wrap wrap,
|
||||
@NotNull AlignmentStrategy alignmentStrategy,
|
||||
int startOffset)
|
||||
{
|
||||
int startOffset) {
|
||||
Indent actualIndent = indent == null ? getDefaultSubtreeIndent(child, getJavaIndentOptions(settings)) : indent;
|
||||
final IElementType elementType = child.getElementType();
|
||||
Alignment alignment = alignmentStrategy.getAlignment(elementType);
|
||||
@@ -189,8 +188,9 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
if (isStatement(child, child.getTreeParent())) {
|
||||
return new CodeBlockBlock(child, wrap, alignment, actualIndent, settings, javaSettings);
|
||||
}
|
||||
if (child instanceof PsiComment && child instanceof PsiLanguageInjectionHost && InjectedLanguageUtil
|
||||
.hasInjections((PsiLanguageInjectionHost)child)) {
|
||||
if (child instanceof PsiComment &&
|
||||
child instanceof PsiLanguageInjectionHost &&
|
||||
InjectedLanguageUtil.hasInjections((PsiLanguageInjectionHost)child)) {
|
||||
return new CommentWithInjectionBlock(child, wrap, alignment, indent, settings, javaSettings);
|
||||
}
|
||||
if (child instanceof LeafElement) {
|
||||
@@ -500,36 +500,26 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
if (mySettings.PREFER_PARAMETERS_WRAP) {
|
||||
wrap.ignoreParentWraps();
|
||||
}
|
||||
child = processParenthesisBlock(result,
|
||||
child,
|
||||
child = processParenthesisBlock(result, child,
|
||||
WrappingStrategy.createDoNotWrapCommaStrategy(wrap),
|
||||
mySettings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS);
|
||||
}
|
||||
else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.PARAMETER_LIST) {
|
||||
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);
|
||||
}
|
||||
Wrap wrap = Wrap.createWrap(getWrapType(mySettings.METHOD_PARAMETERS_WRAP), false);
|
||||
child = processParenthesisBlock(result, child,
|
||||
WrappingStrategy.createDoNotWrapCommaStrategy(wrap),
|
||||
mySettings.ALIGN_MULTILINE_PARAMETERS);
|
||||
}
|
||||
else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.RESOURCE_LIST) {
|
||||
final Wrap reservedWrap = getReservedWrap(JavaElementType.MODIFIER_LIST);
|
||||
final Wrap wrap = reservedWrap != null
|
||||
? Wrap.createChildWrap(reservedWrap, getWrapType(mySettings.RESOURCE_LIST_WRAP), false)
|
||||
: Wrap.createWrap(getWrapType(mySettings.RESOURCE_LIST_WRAP), false);
|
||||
child = processParenthesisBlock(result, child, WrappingStrategy.createDoNotWrapCommaStrategy(wrap),
|
||||
mySettings.ALIGN_MULTILINE_RESOURCES);
|
||||
Wrap wrap = Wrap.createWrap(getWrapType(mySettings.RESOURCE_LIST_WRAP), false);
|
||||
child = processParenthesisBlock(result, child,
|
||||
WrappingStrategy.createDoNotWrapCommaStrategy(wrap),
|
||||
mySettings.ALIGN_MULTILINE_RESOURCES);
|
||||
}
|
||||
else if (childType == JavaTokenType.LPARENTH && nodeType == JavaElementType.ANNOTATION_PARAMETER_LIST) {
|
||||
final Wrap wrap = Wrap.createWrap(getWrapType(mySettings.CALL_PARAMETERS_WRAP), false);
|
||||
Wrap wrap = Wrap.createWrap(getWrapType(mySettings.CALL_PARAMETERS_WRAP), false);
|
||||
child = processParenthesisBlock(result, child,
|
||||
WrappingStrategy.createDoNotWrapCommaStrategy(wrap),
|
||||
mySettings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS);
|
||||
@@ -548,63 +538,37 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
else if (childType == JavaElementType.FIELD) {
|
||||
child = processField(result, child, alignmentStrategy, defaultWrap, childIndent);
|
||||
}
|
||||
else if (childType == JavaElementType.LOCAL_VARIABLE
|
||||
|| childType == JavaElementType.DECLARATION_STATEMENT && myNode.getElementType() == JavaElementType.METHOD)
|
||||
{
|
||||
else if (childType == JavaElementType.LOCAL_VARIABLE ||
|
||||
childType == JavaElementType.DECLARATION_STATEMENT && myNode.getElementType() == JavaElementType.METHOD) {
|
||||
result.add(new SimpleJavaBlock(child, defaultWrap, alignmentStrategy, childIndent, mySettings, myJavaSettings));
|
||||
}
|
||||
else {
|
||||
AlignmentStrategy alignmentStrategyToUse = AlignmentStrategy.wrap(arrangeChildAlignment(child, alignmentStrategy));
|
||||
if (myAlignmentStrategy.getAlignment(nodeType, childType) != null
|
||||
&& (nodeType == JavaElementType.IMPLEMENTS_LIST || nodeType == JavaElementType.CLASS))
|
||||
{
|
||||
if (myAlignmentStrategy.getAlignment(nodeType, childType) != null &&
|
||||
(nodeType == JavaElementType.IMPLEMENTS_LIST || nodeType == JavaElementType.CLASS)) {
|
||||
alignmentStrategyToUse = myAlignmentStrategy;
|
||||
}
|
||||
final Block block = createJavaBlock(
|
||||
child, mySettings, myJavaSettings, childIndent, arrangeChildWrap(child, defaultWrap), alignmentStrategyToUse, childOffset
|
||||
);
|
||||
|
||||
if (childType == JavaElementType.MODIFIER_LIST && containsAnnotations(child)) {
|
||||
myAnnotationWrap = Wrap.createWrap(getWrapType(getAnnotationWrapType(child)), true);
|
||||
}
|
||||
Wrap wrap = arrangeChildWrap(child, defaultWrap);
|
||||
|
||||
Block block = createJavaBlock(child, mySettings, myJavaSettings, childIndent, wrap, alignmentStrategyToUse, childOffset);
|
||||
|
||||
if (block instanceof AbstractJavaBlock) {
|
||||
final AbstractJavaBlock javaBlock = (AbstractJavaBlock)block;
|
||||
if (nodeType == JavaElementType.METHOD_CALL_EXPRESSION && childType == JavaElementType.REFERENCE_EXPRESSION
|
||||
|| nodeType == JavaElementType.REFERENCE_EXPRESSION && childType == JavaElementType.METHOD_CALL_EXPRESSION)
|
||||
{
|
||||
if (nodeType == JavaElementType.METHOD_CALL_EXPRESSION && childType == JavaElementType.REFERENCE_EXPRESSION ||
|
||||
nodeType == JavaElementType.REFERENCE_EXPRESSION && childType == JavaElementType.METHOD_CALL_EXPRESSION) {
|
||||
javaBlock.setReservedWrap(getReservedWrap(nodeType), nodeType);
|
||||
javaBlock.setReservedWrap(getReservedWrap(childType), childType);
|
||||
}
|
||||
else if (nodeType == JavaElementType.BINARY_EXPRESSION) {
|
||||
javaBlock.setReservedWrap(defaultWrap, nodeType);
|
||||
}
|
||||
else if (childType == JavaElementType.MODIFIER_LIST) {
|
||||
javaBlock.setReservedWrap(myAnnotationWrap, JavaElementType.MODIFIER_LIST);
|
||||
if (!lastChildIsAnnotation(child)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
@@ -647,7 +611,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
* <code>'Composite field definition'</code> looks like {@code 'int i1, i2 = 2'}. It produces two nodes of type
|
||||
* {@link JavaElementType#FIELD} - {@code 'int i1'} and {@code 'i2 = 2'}. This method returns the second node if the first one
|
||||
* is given (the given node is returned for <code>'single'</code> fields).
|
||||
*
|
||||
*
|
||||
* @param child child field node to check
|
||||
* @return last child field node at the field group identified by the given node if any; given child otherwise
|
||||
*/
|
||||
@@ -777,62 +741,6 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean firstChildIsAnnotation(@NotNull 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(@NotNull final ASTNode child) {
|
||||
ASTNode current = child.getLastChildNode();
|
||||
while (current != null && current.getElementType() == TokenType.WHITE_SPACE) {
|
||||
current = current.getTreePrev();
|
||||
}
|
||||
return current != null && current.getElementType() == JavaElementType.ANNOTATION;
|
||||
}
|
||||
|
||||
private static boolean containsAnnotations(@NotNull final ASTNode child) {
|
||||
PsiElement psi = child.getPsi();
|
||||
return psi instanceof PsiModifierList && ((PsiModifierList)psi).getAnnotations().length > 0;
|
||||
}
|
||||
|
||||
private int getAnnotationWrapType(@NotNull ASTNode child) {
|
||||
final IElementType nodeType = myNode.getElementType();
|
||||
if (nodeType == JavaElementType.METHOD) {
|
||||
return mySettings.METHOD_ANNOTATION_WRAP;
|
||||
}
|
||||
if (nodeType == JavaElementType.CLASS) {
|
||||
// There is a possible case that current document state is invalid from language syntax point of view, e.g. the user starts
|
||||
// typing field definition and re-formatting is triggered by 'auto insert javadoc' processing. Example:
|
||||
// class Test {
|
||||
// @NotNull Object
|
||||
// }
|
||||
// Here '@NotNull' has a 'class' node as a parent but we want to use field annotation setting value. Hence, we check if subsequent
|
||||
// parsed info is valid.
|
||||
for (ASTNode node = child.getTreeNext(); node != null; node = node.getTreeNext()) {
|
||||
if (TokenType.WHITE_SPACE == node.getElementType() || node instanceof PsiTypeElement) {
|
||||
continue;
|
||||
}
|
||||
if (node instanceof PsiErrorElement) {
|
||||
return mySettings.FIELD_ANNOTATION_WRAP;
|
||||
}
|
||||
}
|
||||
return mySettings.CLASS_ANNOTATION_WRAP;
|
||||
}
|
||||
if (nodeType == JavaElementType.FIELD) {
|
||||
return mySettings.FIELD_ANNOTATION_WRAP;
|
||||
}
|
||||
if (nodeType == JavaElementType.PARAMETER) {
|
||||
return mySettings.PARAMETER_ANNOTATION_WRAP;
|
||||
}
|
||||
if (nodeType == JavaElementType.LOCAL_VARIABLE) {
|
||||
return mySettings.VARIABLE_ANNOTATION_WRAP;
|
||||
}
|
||||
return CommonCodeStyleSettings.DO_NOT_WRAP;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Alignment arrangeChildAlignment(@NotNull final ASTNode child, @NotNull final AlignmentStrategy alignmentStrategy) {
|
||||
int role = getChildRole(child);
|
||||
@@ -905,7 +813,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
else {
|
||||
return defaultAlignment;
|
||||
}
|
||||
@@ -944,21 +852,6 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
return myAlignmentStrategy.getAlignment(childType);
|
||||
}
|
||||
|
||||
/*
|
||||
private boolean isAfterClassKeyword(final ASTNode child) {
|
||||
ASTNode treePrev = child.getTreePrev();
|
||||
while (treePrev != null) {
|
||||
if (treePrev.getElementType() == ElementType.CLASS_KEYWORD ||
|
||||
treePrev.getElementType() == ElementType.INTERFACE_KEYWORD) {
|
||||
return true;
|
||||
}
|
||||
treePrev = treePrev.getTreePrev();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
@Nullable
|
||||
private static Alignment createAlignment(final boolean alignOption, @Nullable final Alignment defaultAlignment) {
|
||||
return alignOption ? createAlignmentOrDefault(null, defaultAlignment) : defaultAlignment;
|
||||
@@ -971,37 +864,14 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
|
||||
@Nullable
|
||||
protected Wrap arrangeChildWrap(final ASTNode child, Wrap defaultWrap) {
|
||||
if (myAnnotationWrap != null) {
|
||||
try {
|
||||
return myAnnotationWrap;
|
||||
}
|
||||
finally {
|
||||
myAnnotationWrap = null;
|
||||
}
|
||||
}
|
||||
return myWrapManager.arrangeChildWrap(child, myNode, getSettings(), defaultWrap, this);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static WrapType getWrapType(final int wrap) {
|
||||
switch (wrap) {
|
||||
case CommonCodeStyleSettings.WRAP_ALWAYS:
|
||||
return WrapType.ALWAYS;
|
||||
case CommonCodeStyleSettings.WRAP_AS_NEEDED:
|
||||
return WrapType.NORMAL;
|
||||
case CommonCodeStyleSettings.DO_NOT_WRAP:
|
||||
return WrapType.NONE;
|
||||
default:
|
||||
return WrapType.CHOP_DOWN_IF_LONG;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ASTNode processParenthesisBlock(@NotNull List<Block> result,
|
||||
@NotNull ASTNode child,
|
||||
@NotNull WrappingStrategy wrappingStrategy,
|
||||
final boolean doAlign) {
|
||||
|
||||
myUseChildAttributes = true;
|
||||
|
||||
final IElementType from = JavaTokenType.LPARENTH;
|
||||
@@ -1010,7 +880,6 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
return processParenthesisBlock(from, to, result, child, wrappingStrategy, doAlign);
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private ASTNode processParenthesisBlock(@NotNull IElementType from,
|
||||
@Nullable final IElementType to,
|
||||
@@ -1084,22 +953,22 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
|
||||
private static boolean canUseAnonymousClassAlignment(@NotNull ASTNode child) {
|
||||
// The general idea is to handle situations like below:
|
||||
// test(new Runnable() {
|
||||
// test(new Runnable() {
|
||||
// public void run() {
|
||||
// }
|
||||
// }, new Runnable() {
|
||||
// }
|
||||
// }, new Runnable() {
|
||||
// public void run() {
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// );
|
||||
// I.e. we want to align subsequent anonymous class argument to the previous one if it's not preceded by another argument
|
||||
// I.e. we want to align subsequent anonymous class argument to the previous one if it's not preceded by another argument
|
||||
// at the same line, e.g.:
|
||||
// test("this is a long argument", new Runnable() {
|
||||
// test("this is a long argument", new Runnable() {
|
||||
// public void run() {
|
||||
// }
|
||||
// }, new Runnable() {
|
||||
// }
|
||||
// }, new Runnable() {
|
||||
// public void run() {
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// );
|
||||
if (!isAnonymousClass(child)) {
|
||||
@@ -1122,7 +991,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private boolean shouldEnforceIndentToChildren() {
|
||||
if (myNode.getElementType() != JavaElementType.EXPRESSION_LIST) {
|
||||
return false;
|
||||
@@ -1144,7 +1013,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
ASTNode lastChild = node.getLastChildNode();
|
||||
return lastChild != null && lastChild.getElementType() == JavaElementType.ANONYMOUS_CLASS;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private ASTNode processEnumBlock(@NotNull List<Block> result,
|
||||
@Nullable ASTNode child,
|
||||
@@ -1194,7 +1063,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
protected Indent getCodeBlockInternalIndent(final int baseChildrenIndent) {
|
||||
return getCodeBlockInternalIndent(baseChildrenIndent, false);
|
||||
}
|
||||
|
||||
|
||||
protected Indent getCodeBlockInternalIndent(final int baseChildrenIndent, boolean enforceParentIndent) {
|
||||
if (isTopLevelClass() && mySettings.DO_NOT_INDENT_TOP_LEVEL_CLASS_MEMBERS) {
|
||||
return Indent.getNoneIndent();
|
||||
@@ -1209,7 +1078,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
protected static Indent createNormalIndent(final int baseChildrenIndent) {
|
||||
return createNormalIndent(baseChildrenIndent, false);
|
||||
}
|
||||
|
||||
|
||||
protected static Indent createNormalIndent(final int baseChildrenIndent, boolean enforceIndentToChildren) {
|
||||
if (baseChildrenIndent == 1) {
|
||||
return Indent.getIndent(Indent.Type.NORMAL, false, enforceIndentToChildren);
|
||||
@@ -1370,9 +1239,9 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
}
|
||||
final boolean rBrace = isRBrace(child);
|
||||
Indent childIndent = rBrace ? Indent.getNoneIndent() : getCodeBlockInternalIndent(childrenIndent, false);
|
||||
if (!rBrace && child.getElementType() == JavaElementType.CODE_BLOCK
|
||||
&& (getBraceStyle() == CommonCodeStyleSettings.NEXT_LINE_SHIFTED
|
||||
|| getBraceStyle() == CommonCodeStyleSettings.NEXT_LINE_SHIFTED2))
|
||||
if (!rBrace && child.getElementType() == JavaElementType.CODE_BLOCK
|
||||
&& (getBraceStyle() == CommonCodeStyleSettings.NEXT_LINE_SHIFTED
|
||||
|| getBraceStyle() == CommonCodeStyleSettings.NEXT_LINE_SHIFTED2))
|
||||
{
|
||||
childIndent = Indent.getNormalIndent();
|
||||
}
|
||||
@@ -1384,7 +1253,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (child != null) {
|
||||
child = child.getTreeNext();
|
||||
}
|
||||
@@ -1418,11 +1287,11 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
* <p/>
|
||||
* <pre>
|
||||
* int i1, i2 = 2;
|
||||
* </pre>
|
||||
* </pre>
|
||||
* <p/>
|
||||
* Parsing such a code produces two fields - {@code 'int i1'} and {@code 'i2 = 2'}. This method returns <code>true</code>
|
||||
* for the second one.
|
||||
*
|
||||
*
|
||||
* @param node node to check
|
||||
* @return <code>true</code> if given node is a non-first part of composite field definition; <code>false</code> otherwise
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.psi.formatter.java;
|
||||
|
||||
import com.intellij.formatting.WrapType;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
|
||||
@@ -39,8 +40,7 @@ public class JavaFormatterUtil {
|
||||
JavaElementType.ASSIGNMENT_EXPRESSION, JavaElementType.LOCAL_VARIABLE, JavaElementType.FIELD
|
||||
));
|
||||
|
||||
private JavaFormatterUtil() {
|
||||
}
|
||||
private JavaFormatterUtil() { }
|
||||
|
||||
/**
|
||||
* Allows to answer if given node wraps assignment operation.
|
||||
@@ -119,4 +119,17 @@ public class JavaFormatterUtil {
|
||||
&& node.textContains('\n');
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static WrapType getWrapType(int wrap) {
|
||||
switch (wrap) {
|
||||
case CommonCodeStyleSettings.WRAP_ALWAYS:
|
||||
return WrapType.ALWAYS;
|
||||
case CommonCodeStyleSettings.WRAP_AS_NEEDED:
|
||||
return WrapType.NORMAL;
|
||||
case CommonCodeStyleSettings.DO_NOT_WRAP:
|
||||
return WrapType.NONE;
|
||||
default:
|
||||
return WrapType.CHOP_DOWN_IF_LONG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+76
-18
@@ -18,9 +18,7 @@ package com.intellij.psi.formatter.java.wrap.impl;
|
||||
import com.intellij.formatting.Wrap;
|
||||
import com.intellij.formatting.WrapType;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiPolyadicExpression;
|
||||
import com.intellij.psi.PsiStatement;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
|
||||
import com.intellij.psi.formatter.FormatterUtil;
|
||||
import com.intellij.psi.formatter.java.JavaFormatterUtil;
|
||||
@@ -33,6 +31,9 @@ import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.psi.formatter.java.JavaFormatterUtil.getWrapType;
|
||||
import static com.intellij.psi.impl.PsiImplUtil.isTypeAnnotation;
|
||||
|
||||
/**
|
||||
* Encapsulates the implementation of
|
||||
* {@link JavaWrapManager#arrangeChildWrap(ASTNode, ASTNode, CommonCodeStyleSettings, Wrap, ReservedWrapsProvider)}.
|
||||
@@ -43,7 +44,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
* @since Apr 21, 2010
|
||||
*/
|
||||
public class JavaChildWrapArranger {
|
||||
|
||||
/**
|
||||
* Provides implementation of {@link JavaWrapManager#arrangeChildWrap} method.
|
||||
*
|
||||
@@ -116,7 +116,7 @@ public class JavaChildWrapArranger {
|
||||
return suggestedWrap;
|
||||
}
|
||||
|
||||
else if (JavaFormatterUtil.isAssignment(parent)) {
|
||||
else if (JavaFormatterUtil.isAssignment(parent) && role != ChildRole.TYPE) {
|
||||
if (role == ChildRole.INITIALIZER_EQ) return settings.PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE ? suggestedWrap : null;
|
||||
if (role == ChildRole.OPERATION_SIGN) return settings.PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE ? suggestedWrap : null;
|
||||
if (role == ChildRole.INITIALIZER) return settings.PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE ? null : suggestedWrap;
|
||||
@@ -148,29 +148,44 @@ public class JavaChildWrapArranger {
|
||||
}
|
||||
}
|
||||
|
||||
else if (nodeType == JavaElementType.METHOD) {
|
||||
if (role == ChildRole.THROWS_LIST) {
|
||||
return suggestedWrap;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
else if (parent.getPsi() instanceof PsiModifierListOwner) {
|
||||
ASTNode prev = FormatterUtil.getPreviousNonWhitespaceSibling(child);
|
||||
if (prev != null && prev.getElementType() == JavaElementType.MODIFIER_LIST) {
|
||||
ASTNode last = prev.getLastChildNode();
|
||||
if (last != null && last.getElementType() == JavaElementType.ANNOTATION) {
|
||||
if (isTypeAnnotation(last.getPsi())) {
|
||||
return Wrap.createWrap(WrapType.NONE, false);
|
||||
}
|
||||
else {
|
||||
return Wrap.createWrap(getWrapType(getAnnotationWrapType(parent, child, settings)), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
else if (nodeType == JavaElementType.MODIFIER_LIST) {
|
||||
if (childType == JavaElementType.ANNOTATION) {
|
||||
return reservedWrapsProvider.getReservedWrap(JavaElementType.MODIFIER_LIST);
|
||||
if (isTypeAnnotation(child.getPsi())) {
|
||||
ASTNode prev = FormatterUtil.getPreviousNonWhitespaceSibling(child);
|
||||
if (prev == null || prev.getElementType() != JavaElementType.ANNOTATION || isTypeAnnotation(prev.getPsi())) {
|
||||
return Wrap.createWrap(WrapType.NONE, false);
|
||||
}
|
||||
}
|
||||
|
||||
return Wrap.createWrap(getWrapType(getAnnotationWrapType(parent.getTreeParent(), child, settings)), true);
|
||||
}
|
||||
else if (childType == JavaTokenType.END_OF_LINE_COMMENT) {
|
||||
return Wrap.createWrap(WrapType.NORMAL, true);
|
||||
}
|
||||
ASTNode prevElement = FormatterUtil.getPreviousNonWhitespaceSibling(child);
|
||||
if (prevElement != null && prevElement.getElementType() == JavaElementType.ANNOTATION) {
|
||||
return reservedWrapsProvider.getReservedWrap(JavaElementType.MODIFIER_LIST);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
|
||||
ASTNode prev = FormatterUtil.getPreviousNonWhitespaceSibling(child);
|
||||
if (prev != null && prev.getElementType() == JavaElementType.ANNOTATION) {
|
||||
return Wrap.createWrap(getWrapType(getAnnotationWrapType(parent.getTreeParent(), child, settings)), true);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
else if (nodeType == JavaElementType.ASSERT_STATEMENT) {
|
||||
@@ -240,4 +255,47 @@ public class JavaChildWrapArranger {
|
||||
|
||||
return suggestedWrap;
|
||||
}
|
||||
|
||||
private static int getAnnotationWrapType(ASTNode parent, ASTNode child, CommonCodeStyleSettings settings) {
|
||||
IElementType nodeType = parent.getElementType();
|
||||
|
||||
if (nodeType == JavaElementType.METHOD) {
|
||||
return settings.METHOD_ANNOTATION_WRAP;
|
||||
}
|
||||
|
||||
if (nodeType == JavaElementType.CLASS) {
|
||||
// There is a possible case that current document state is invalid from language syntax point of view, e.g. the user starts
|
||||
// typing field definition and re-formatting is triggered by 'auto insert javadoc' processing. Example:
|
||||
// class Test {
|
||||
// @NotNull Object
|
||||
// }
|
||||
// Here '@NotNull' has a 'class' node as a parent but we want to use field annotation setting value.
|
||||
// Hence we check if subsequent parsed info is valid.
|
||||
for (ASTNode node = child.getTreeNext(); node != null; node = node.getTreeNext()) {
|
||||
if (node.getElementType() == TokenType.WHITE_SPACE || node instanceof PsiTypeElement) {
|
||||
continue;
|
||||
}
|
||||
if (node instanceof PsiErrorElement) {
|
||||
return settings.FIELD_ANNOTATION_WRAP;
|
||||
}
|
||||
}
|
||||
return settings.CLASS_ANNOTATION_WRAP;
|
||||
}
|
||||
|
||||
if (nodeType == JavaElementType.FIELD) {
|
||||
return settings.FIELD_ANNOTATION_WRAP;
|
||||
}
|
||||
|
||||
if (nodeType == JavaElementType.PARAMETER ||
|
||||
nodeType == JavaElementType.RECEIVER_PARAMETER ||
|
||||
nodeType == JavaElementType.RESOURCE_VARIABLE) {
|
||||
return settings.PARAMETER_ANNOTATION_WRAP;
|
||||
}
|
||||
|
||||
if (nodeType == JavaElementType.LOCAL_VARIABLE) {
|
||||
return settings.VARIABLE_ANNOTATION_WRAP;
|
||||
}
|
||||
|
||||
return CommonCodeStyleSettings.DO_NOT_WRAP;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-4
@@ -133,8 +133,7 @@ import java.util.Collection;
|
||||
@Target(ElementType.TYPE_USE) @interface TA { }
|
||||
|
||||
class Test {
|
||||
@TA
|
||||
Collection<caret> c;
|
||||
@TA Collection<caret> c;
|
||||
}
|
||||
'''
|
||||
}
|
||||
@@ -157,8 +156,7 @@ import java.util.Collection;
|
||||
@Target(ElementType.TYPE_USE) @interface TA { }
|
||||
|
||||
class Test {
|
||||
@TA
|
||||
Collection<caret> c;
|
||||
@TA Collection<caret> c;
|
||||
}
|
||||
'''
|
||||
}
|
||||
|
||||
@@ -15,11 +15,14 @@
|
||||
*/
|
||||
package com.intellij.psi.formatter.java;
|
||||
|
||||
import com.intellij.idea.Bombed;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
* Is intended to hold specific java formatting tests for 'wrapping' settings.
|
||||
*
|
||||
@@ -242,6 +245,7 @@ public class JavaFormatterWrapTest extends AbstractJavaFormatterTest {
|
||||
);
|
||||
}
|
||||
|
||||
@Bombed(user = "Roman Shevchenko", year = 2014, month = Calendar.MARCH, day = 14)
|
||||
public void testWrapMethodAnnotationBeforeParams() {
|
||||
// Inspired by IDEA-59536
|
||||
getSettings().getRootSettings().RIGHT_MARGIN = 90;
|
||||
@@ -251,8 +255,7 @@ public class JavaFormatterWrapTest extends AbstractJavaFormatterTest {
|
||||
doClassTest(
|
||||
"@SuppressWarnings({\"SomeInspectionIWantToIgnore\"}) public void doSomething(int x, int y) {}",
|
||||
"@SuppressWarnings({\"SomeInspectionIWantToIgnore\"})\n" +
|
||||
"public void doSomething(int x, int y) {" +
|
||||
"\n}"
|
||||
"public void doSomething(int x, int y) {\n}"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -399,4 +402,34 @@ public class JavaFormatterWrapTest extends AbstractJavaFormatterTest {
|
||||
|
||||
doMethodTest(before, after);
|
||||
}
|
||||
|
||||
public void testFieldAnnotationWithoutModifier() {
|
||||
doClassTest("@NotNull String myFoo = null;", "@NotNull\nString myFoo = null;");
|
||||
}
|
||||
|
||||
public void testTypeAnnotationsInModifierList() {
|
||||
getSettings().getRootSettings().FORMATTER_TAGS_ENABLED = true;
|
||||
|
||||
String prefix =
|
||||
"import java.lang.annotation.*;\n\n" +
|
||||
"//@formatter:off\n" +
|
||||
"@interface A { }\n" +
|
||||
"@Target({ElementType.TYPE_USE}) @interface TA { int value() default 0; }\n" +
|
||||
"//@formatter:on\n\n";
|
||||
|
||||
doTextTest(
|
||||
prefix + "interface C {\n" +
|
||||
" @TA(0)String m();\n" +
|
||||
" @A @TA(1) @TA(2)String m();\n" +
|
||||
" @A public @TA String m();\n" +
|
||||
"}",
|
||||
|
||||
prefix + "interface C {\n" +
|
||||
" @TA(0) String m();\n\n" +
|
||||
" @A\n" +
|
||||
" @TA(1) @TA(2) String m();\n\n" +
|
||||
" @A\n" +
|
||||
" public @TA String m();\n" +
|
||||
"}");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user