mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[Java. Formatting] Move semicolon to the new line with long chain calls implementation
IDEA-291765 GitOrigin-RevId: b67a9be7fd9d57febe95f2d65fc5fae3dfb4151c
This commit is contained in:
committed by
intellij-monorepo-bot
parent
d657d89ed1
commit
9cf690d4e1
@@ -823,7 +823,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
@NotNull
|
||||
private Block createMethodCallExpressionBlock(@NotNull ASTNode node, Wrap blockWrap, Alignment alignment, Indent indent) {
|
||||
final ArrayList<ASTNode> nodes = new ArrayList<>();
|
||||
collectNodes(nodes, node);
|
||||
JavaFormatterUtil.collectCallExpressionNodes(nodes, node);
|
||||
if (Registry.is(LegacyChainedMethodCallsBlockBuilder.COMPATIBILITY_KEY)) {
|
||||
return
|
||||
new LegacyChainedMethodCallsBlockBuilder(alignment, blockWrap, indent, mySettings, myJavaSettings, myFormattingMode).build(nodes);
|
||||
@@ -831,23 +831,6 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
|
||||
return new ChainMethodCallsBlockBuilder(alignment, blockWrap, indent, mySettings, myJavaSettings, myFormattingMode).build(nodes);
|
||||
}
|
||||
|
||||
private static void collectNodes(@NotNull List<? super ASTNode> nodes, @NotNull ASTNode node) {
|
||||
ASTNode child = node.getFirstChildNode();
|
||||
while (child != null) {
|
||||
if (!FormatterUtil.containsWhiteSpacesOnly(child)) {
|
||||
IElementType type = child.getElementType();
|
||||
if (type == JavaElementType.METHOD_CALL_EXPRESSION ||
|
||||
type == JavaElementType.REFERENCE_EXPRESSION) {
|
||||
collectNodes(nodes, child);
|
||||
}
|
||||
else {
|
||||
nodes.add(child);
|
||||
}
|
||||
}
|
||||
child = child.getTreeNext();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldAlignChild(@NotNull final ASTNode child) {
|
||||
int role = getChildRole(child);
|
||||
final IElementType nodeType = myNode.getElementType();
|
||||
|
||||
+23
-8
@@ -46,6 +46,8 @@ class ChainMethodCallsBlockBuilder {
|
||||
|
||||
private final FormattingMode myFormattingMode;
|
||||
|
||||
private static final int MANY_METHOD_CALLS_FACTOR = 3;
|
||||
|
||||
ChainMethodCallsBlockBuilder(Alignment alignment,
|
||||
Wrap wrap,
|
||||
Indent indent,
|
||||
@@ -70,7 +72,7 @@ class ChainMethodCallsBlockBuilder {
|
||||
}
|
||||
|
||||
private List<Block> buildBlocksFrom(List<? extends ASTNode> nodes) {
|
||||
List<ChainedCallChunk> methodCall = splitMethodCallOnChunksByDots(nodes);
|
||||
List<ChainedCallChunk> methodCall = splitMethodCallOnChunksByDots(nodes, mySettings);
|
||||
|
||||
Wrap wrap = Wrap.createWrap(getWrapType(mySettings.METHOD_CALL_CHAIN_WRAP), true);
|
||||
Wrap builderMethodWrap = Wrap.createWrap(WrapType.ALWAYS, true);
|
||||
@@ -83,7 +85,7 @@ class ChainMethodCallsBlockBuilder {
|
||||
CallChunkBlockBuilder builder = new CallChunkBlockBuilder(mySettings, myJavaSettings, myFormattingMode);
|
||||
for (int i = 0; i < methodCall.size(); i++) {
|
||||
ChainedCallChunk currentCallChunk = methodCall.get(i);
|
||||
if (isMethodCall(currentCallChunk) && !isBuilderMethod(currentCallChunk) || isComment(currentCallChunk)) {
|
||||
if (isMethodCall(currentCallChunk) && !isBuilderMethod(currentCallChunk, mySettings) || isComment(currentCallChunk)) {
|
||||
if (chainedCallsAlignment == null) {
|
||||
chainedCallsAlignment = createCallChunkAlignment(i, methodCall);
|
||||
}
|
||||
@@ -93,7 +95,7 @@ class ChainMethodCallsBlockBuilder {
|
||||
}
|
||||
|
||||
Wrap currWrap = isMethodCall(currentCallChunk) && canWrap(i, methodCall)
|
||||
? isBuilderMethod(currentCallChunk) ? builderMethodWrap : wrap
|
||||
? isBuilderMethod(currentCallChunk, mySettings) ? builderMethodWrap : wrap
|
||||
: null;
|
||||
|
||||
blocks.add(builder.create(currentCallChunk.nodes,
|
||||
@@ -107,7 +109,7 @@ class ChainMethodCallsBlockBuilder {
|
||||
private int getCommonIndentSize(@NotNull List<ChainedCallChunk> chunks) {
|
||||
String commonIndent = null;
|
||||
for (ChainedCallChunk chunk : chunks) {
|
||||
if (isMethodCall(chunk) && isBuilderMethod(chunk)) {
|
||||
if (isMethodCall(chunk) && isBuilderMethod(chunk, mySettings)) {
|
||||
String currIndent = chunk.getIndentString();
|
||||
if (currIndent != null) {
|
||||
if (commonIndent == null) {
|
||||
@@ -140,9 +142,9 @@ class ChainMethodCallsBlockBuilder {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isBuilderMethod(@NotNull ChainedCallChunk chunk) {
|
||||
private static boolean isBuilderMethod(@NotNull ChainedCallChunk chunk, CommonCodeStyleSettings settings) {
|
||||
String identifier = chunk.getIdentifier();
|
||||
return identifier != null && mySettings.isBuilderMethod(identifier);
|
||||
return identifier != null && settings.isBuilderMethod(identifier);
|
||||
}
|
||||
|
||||
private boolean canWrap(int chunkIndex, @NotNull List<? extends ChainedCallChunk> methodCall) {
|
||||
@@ -170,12 +172,12 @@ class ChainMethodCallsBlockBuilder {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<ChainedCallChunk> splitMethodCallOnChunksByDots(@NotNull List<? extends ASTNode> nodes) {
|
||||
private static List<ChainedCallChunk> splitMethodCallOnChunksByDots(@NotNull List<? extends ASTNode> nodes, CommonCodeStyleSettings settings) {
|
||||
List<ChainedCallChunk> result = new ArrayList<>();
|
||||
|
||||
List<ASTNode> current = new ArrayList<>();
|
||||
for (ASTNode node : nodes) {
|
||||
if (JavaFormatterUtil.isStartOfCallChunk(mySettings, node) || node.getPsi() instanceof PsiComment) {
|
||||
if (JavaFormatterUtil.isStartOfCallChunk(settings, node) || node.getPsi() instanceof PsiComment) {
|
||||
if (!current.isEmpty()) {
|
||||
result.add(new ChainedCallChunk(current));
|
||||
}
|
||||
@@ -209,6 +211,19 @@ class ChainMethodCallsBlockBuilder {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isLongCallChain(List<ASTNode> nodes, CommonCodeStyleSettings settings) {
|
||||
List<ChainedCallChunk> chunks = splitMethodCallOnChunksByDots(nodes, settings);
|
||||
|
||||
int methodCallCount = 0;
|
||||
|
||||
for (ChainedCallChunk chunk : chunks) {
|
||||
if (isMethodCall(chunk) && !isBuilderMethod(chunk, settings) && !isComment(chunk)) {
|
||||
methodCallCount++;
|
||||
}
|
||||
}
|
||||
return methodCallCount >= MANY_METHOD_CALLS_FACTOR;
|
||||
}
|
||||
|
||||
|
||||
private record ChainedCallChunk(@NotNull List<ASTNode> nodes) {
|
||||
boolean isEmpty() {
|
||||
|
||||
@@ -23,6 +23,8 @@ import com.intellij.util.ArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.impl.PsiImplUtil.isTypeAnnotation;
|
||||
|
||||
public final class JavaFormatterUtil {
|
||||
@@ -514,4 +516,27 @@ public final class JavaFormatterUtil {
|
||||
|
||||
return CommonCodeStyleSettings.DO_NOT_WRAP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses the children of the node and collects nodes with type method calls or reference expressions to the list
|
||||
* @param nodes List in which the method add nodes
|
||||
* @param node Node to traverse
|
||||
*
|
||||
*/
|
||||
public static void collectCallExpressionNodes(@NotNull List<? super ASTNode> nodes, @NotNull ASTNode node) {
|
||||
ASTNode child = node.getFirstChildNode();
|
||||
while (child != null) {
|
||||
if (!FormatterUtil.containsWhiteSpacesOnly(child)) {
|
||||
IElementType type = child.getElementType();
|
||||
if (type == JavaElementType.METHOD_CALL_EXPRESSION ||
|
||||
type == JavaElementType.REFERENCE_EXPRESSION) {
|
||||
collectCallExpressionNodes(nodes, child);
|
||||
}
|
||||
else {
|
||||
nodes.add(child);
|
||||
}
|
||||
}
|
||||
child = child.getTreeNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+62
-13
@@ -12,6 +12,7 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
@@ -457,23 +458,27 @@ public final class JavaSpacePropertyProcessor extends JavaElementVisitor {
|
||||
else if (myRole1 == ChildRole.CLASS_INITIALIZER) {
|
||||
if (myRole2 == ChildRole.RBRACE) {
|
||||
int minLineFeeds = getMinLineFeedsBetweenRBraces(myChild1);
|
||||
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, minLineFeeds, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE);
|
||||
myResult =
|
||||
Spacing.createSpacing(0, Integer.MAX_VALUE, minLineFeeds, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE);
|
||||
}
|
||||
else if (myRole2 == ChildRole.CLASS) {
|
||||
setAroundClassSpacing();
|
||||
}
|
||||
else {
|
||||
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);
|
||||
myResult =
|
||||
Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
|
||||
}
|
||||
}
|
||||
else if (myRole1 == ChildRole.CLASS) {
|
||||
if (myRole2 == ChildRole.RBRACE) {
|
||||
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, getLineBreaksBeforeClassEnd(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE);
|
||||
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, getLineBreaksBeforeClassEnd(), mySettings.KEEP_LINE_BREAKS,
|
||||
mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE);
|
||||
}
|
||||
else {
|
||||
int blankLines = mySettings.BLANK_LINES_AROUND_CLASS + 1;
|
||||
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
|
||||
myResult =
|
||||
Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
|
||||
}
|
||||
}
|
||||
else if (myRole2 == ChildRole.CLASS) {
|
||||
@@ -482,7 +487,8 @@ public final class JavaSpacePropertyProcessor extends JavaElementVisitor {
|
||||
}
|
||||
else {
|
||||
int blankLines = mySettings.BLANK_LINES_AROUND_CLASS + 1;
|
||||
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
|
||||
myResult =
|
||||
Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,7 +501,8 @@ public final class JavaSpacePropertyProcessor extends JavaElementVisitor {
|
||||
}
|
||||
else {
|
||||
int blankLines = getLinesAroundField() + 1;
|
||||
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
|
||||
myResult =
|
||||
Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,7 +523,8 @@ public final class JavaSpacePropertyProcessor extends JavaElementVisitor {
|
||||
}
|
||||
else {
|
||||
int blankLines = getLinesAroundField() + 1;
|
||||
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
|
||||
myResult =
|
||||
Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
|
||||
}
|
||||
}
|
||||
else if (myRole2 == ChildRole.COMMA || myType2 == JavaTokenType.SEMICOLON) {
|
||||
@@ -570,7 +578,8 @@ public final class JavaSpacePropertyProcessor extends JavaElementVisitor {
|
||||
}
|
||||
else if (myRole1 == ChildRole.CLASS_INITIALIZER) {
|
||||
int blankLines = myJavaSettings.BLANK_LINES_AROUND_INITIALIZER + 1;
|
||||
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE);
|
||||
myResult =
|
||||
Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE);
|
||||
}
|
||||
else {
|
||||
int blankLines = getLinesAroundMethod() + 1;
|
||||
@@ -591,7 +600,8 @@ public final class JavaSpacePropertyProcessor extends JavaElementVisitor {
|
||||
}
|
||||
else {
|
||||
int blankLines = getLinesAroundMethod() + 1;
|
||||
myResult = Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
|
||||
myResult =
|
||||
Spacing.createSpacing(0, Integer.MAX_VALUE, blankLines, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS);
|
||||
}
|
||||
}
|
||||
return myResult != null;
|
||||
@@ -695,7 +705,7 @@ public final class JavaSpacePropertyProcessor extends JavaElementVisitor {
|
||||
int keepLines = myType1 == JavaTokenType.C_STYLE_COMMENT
|
||||
? mySettings.KEEP_BLANK_LINES_BETWEEN_PACKAGE_DECLARATION_AND_HEADER
|
||||
: mySettings.KEEP_BLANK_LINES_IN_DECLARATIONS;
|
||||
myResult = Spacing.createSpacing(0, 0, lf, mySettings.KEEP_LINE_BREAKS,keepLines);
|
||||
myResult = Spacing.createSpacing(0, 0, lf, mySettings.KEEP_LINE_BREAKS, keepLines);
|
||||
}
|
||||
|
||||
else if (myType1 == JavaElementType.IMPORT_LIST) {
|
||||
@@ -758,7 +768,8 @@ public final class JavaSpacePropertyProcessor extends JavaElementVisitor {
|
||||
myResult = Spacing.createSpacing(1, 1, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
|
||||
}
|
||||
else {
|
||||
myResult = Spacing.createDependentLFSpacing(0, 1, myParent.getTextRange(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
|
||||
myResult =
|
||||
Spacing.createDependentLFSpacing(0, 1, myParent.getTextRange(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1108,6 +1119,10 @@ public final class JavaSpacePropertyProcessor extends JavaElementVisitor {
|
||||
else if (myRole1 == ChildRole.TYPE || myRole2 == ChildRole.TYPE) {
|
||||
createSpaceInCode(true);
|
||||
}
|
||||
else if (myType2 == JavaTokenType.SEMICOLON && isAllowedToMoveSemicolonInLongCallChain()) {
|
||||
myResult =
|
||||
Spacing.createDependentLFSpacing(0, 0, myChild1.getTextRange(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
|
||||
}
|
||||
else if (myType2 == JavaTokenType.SEMICOLON) {
|
||||
createSpaceProperty(false, false, 0);
|
||||
}
|
||||
@@ -1131,6 +1146,11 @@ public final class JavaSpacePropertyProcessor extends JavaElementVisitor {
|
||||
|| myRole1 == ChildRole.TYPE) {
|
||||
createSpaceInCode(true);
|
||||
}
|
||||
else if (myType2 == JavaTokenType.SEMICOLON &&
|
||||
isAllowedToMoveSemicolonInLongCallChain()) {
|
||||
myResult =
|
||||
Spacing.createDependentLFSpacing(0, 0, myChild1.getTextRange(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
|
||||
}
|
||||
else if (myType2 == JavaTokenType.SEMICOLON) {
|
||||
PsiElement pp = myParent.getParent();
|
||||
if (pp instanceof PsiDeclarationStatement) {
|
||||
@@ -1140,11 +1160,21 @@ public final class JavaSpacePropertyProcessor extends JavaElementVisitor {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
createSpaceProperty(false, false, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInsidePsiForStatement() {
|
||||
PsiElement pp = myParent.getParent();
|
||||
if (pp instanceof PsiDeclarationStatement) {
|
||||
PsiElement ppp = pp.getParent();
|
||||
if (ppp instanceof PsiForStatement) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isFinalKeywordBefore(ASTNode node) {
|
||||
ASTNode prevLeaf = TreeUtil.prevLeaf(node);
|
||||
if (prevLeaf != null && prevLeaf.getElementType() == TokenType.WHITE_SPACE) {
|
||||
@@ -1662,7 +1692,11 @@ public final class JavaSpacePropertyProcessor extends JavaElementVisitor {
|
||||
|
||||
@Override
|
||||
public void visitStatement(@NotNull PsiStatement statement) {
|
||||
if (myRole2 == ChildRole.CLOSING_SEMICOLON) {
|
||||
if (myRole2 == ChildRole.CLOSING_SEMICOLON &&
|
||||
isAllowedToMoveSemicolonInLongCallChain()) {
|
||||
myResult =
|
||||
Spacing.createDependentLFSpacing(0, 0, myChild1.getTextRange(), mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
|
||||
} else if (myRole2 == ChildRole.CLOSING_SEMICOLON) {
|
||||
createSpaceInCode(false);
|
||||
}
|
||||
|
||||
@@ -1987,6 +2021,21 @@ public final class JavaSpacePropertyProcessor extends JavaElementVisitor {
|
||||
return text;
|
||||
}
|
||||
|
||||
private boolean isAllowedToMoveSemicolonInLongCallChain() {
|
||||
if (!myJavaSettings.WRAP_SEMICOLON_AFTER_CALL_CHAIN) return false;
|
||||
|
||||
if (Registry.is(LegacyChainedMethodCallsBlockBuilder.COMPATIBILITY_KEY)) return false;
|
||||
|
||||
if(!(myChild1 instanceof PsiMethodCallExpression) || myType1 != JavaElementType.METHOD_CALL_EXPRESSION) return false;
|
||||
|
||||
if (isInsidePsiForStatement()) return false;
|
||||
|
||||
List<ASTNode> nodes = new ArrayList<>();
|
||||
JavaFormatterUtil.collectCallExpressionNodes(nodes, myChild1);
|
||||
|
||||
return ChainMethodCallsBlockBuilder.isLongCallChain(nodes, mySettings);
|
||||
}
|
||||
|
||||
private static boolean sameTokens(IElementType type, String text, IElementType reparsedType, String reparsedText) {
|
||||
return reparsedType == type ||
|
||||
reparsedType == JavaTokenType.IDENTIFIER && ElementType.KEYWORD_BIT_SET.contains(type) && Objects.equals(text, reparsedText);
|
||||
|
||||
Reference in New Issue
Block a user