mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
[java-completion] Complete statement: process loops uniformly; wrap loop body
Fixes IDEA-73881 "Complete Current Statement" incorrectly handles for with non-block loop statement GitOrigin-RevId: 0e92756e7536f5d939db3f2f0ed42c8e716076c3
This commit is contained in:
committed by
intellij-monorepo-bot
parent
c62e2b7740
commit
b5838faa84
@@ -72,7 +72,10 @@ public class ForStatementFixer implements Fixer {
|
||||
|
||||
final PsiExpression condition = forStatement.getCondition();
|
||||
if (condition == null) {
|
||||
registerErrorOffset(editor, processor, initialization, forStatement);
|
||||
boolean endlessLoop = initialization instanceof PsiEmptyStatement && forStatement.getUpdate() == null;
|
||||
if (!endlessLoop) {
|
||||
registerErrorOffset(editor, processor, initialization, forStatement);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -56,13 +56,11 @@ public class JavaSmartEnterProcessor extends SmartEnterProcessor {
|
||||
new DoWhileConditionFixer(),
|
||||
new BlockBraceFixer(),
|
||||
new MissingIfBranchesFixer(),
|
||||
new MissingWhileBodyFixer(),
|
||||
new MissingTryBodyFixer(),
|
||||
new MissingSwitchBodyFixer(),
|
||||
new MissingCatchBodyFixer(),
|
||||
new MissingSynchronizedBodyFixer(),
|
||||
new MissingForBodyFixer(),
|
||||
new MissingForeachBodyFixer(),
|
||||
new MissingLoopBodyFixer(),
|
||||
new ParameterListFixer(),
|
||||
new MissingCommaFixer(),
|
||||
new MissingMethodBodyFixer(),
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class MissingForBodyFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
PsiForStatement forStatement = getForStatementParent(psiElement);
|
||||
if (forStatement == null) return;
|
||||
|
||||
final Document doc = editor.getDocument();
|
||||
|
||||
PsiElement body = forStatement.getBody();
|
||||
if (body instanceof PsiBlockStatement) return;
|
||||
if (body != null && startLine(doc, body) == startLine(doc, forStatement)) return;
|
||||
|
||||
PsiElement eltToInsertAfter = forStatement.getRParenth();
|
||||
String braces = "{\n}";
|
||||
String text = braces;
|
||||
if (eltToInsertAfter == null) {
|
||||
eltToInsertAfter = forStatement;
|
||||
text = ")" + text;
|
||||
}
|
||||
int offset = eltToInsertAfter.getTextRange().getEndOffset();
|
||||
doc.insertString(offset, text);
|
||||
editor.getCaretModel().moveToOffset(offset + text.length() - braces.length());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiForStatement getForStatementParent(PsiElement psiElement) {
|
||||
PsiForStatement statement = PsiTreeUtil.getParentOfType(psiElement, PsiForStatement.class);
|
||||
if (statement == null) return null;
|
||||
|
||||
PsiStatement init = statement.getInitialization();
|
||||
PsiStatement update = statement.getUpdate();
|
||||
PsiExpression check = statement.getCondition();
|
||||
|
||||
return isValidChild(init, psiElement) || isValidChild(update, psiElement) || isValidChild(check, psiElement) ? statement : null;
|
||||
}
|
||||
|
||||
private static boolean isValidChild(PsiElement ancestor, PsiElement psiElement) {
|
||||
if (ancestor != null) {
|
||||
if (PsiTreeUtil.isAncestor(ancestor, psiElement, false)) {
|
||||
if (PsiTreeUtil.hasErrorElements(ancestor)) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int startLine(Document doc, PsiElement psiElement) {
|
||||
return doc.getLineNumber(psiElement.getTextRange().getStartOffset());
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
|
||||
/**
|
||||
* @author Maxim.Mossienko
|
||||
*/
|
||||
public class MissingForeachBodyFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
PsiForeachStatement forStatement = getForeachStatementParent(psiElement);
|
||||
if (forStatement == null) return;
|
||||
|
||||
final Document doc = editor.getDocument();
|
||||
|
||||
PsiElement body = forStatement.getBody();
|
||||
if (body instanceof PsiBlockStatement) return;
|
||||
if (body != null && startLine(doc, body) == startLine(doc, forStatement)) return;
|
||||
|
||||
PsiElement eltToInsertAfter = forStatement.getRParenth();
|
||||
String text = "{}";
|
||||
if (eltToInsertAfter == null) {
|
||||
eltToInsertAfter = forStatement;
|
||||
text = "){}";
|
||||
}
|
||||
doc.insertString(eltToInsertAfter.getTextRange().getEndOffset(), text);
|
||||
}
|
||||
|
||||
private static PsiForeachStatement getForeachStatementParent(PsiElement psiElement) {
|
||||
PsiForeachStatement statement = PsiTreeUtil.getParentOfType(psiElement, PsiForeachStatement.class);
|
||||
if (statement == null) return null;
|
||||
|
||||
PsiExpression iterated = statement.getIteratedValue();
|
||||
PsiParameter parameter = statement.getIterationParameter();
|
||||
|
||||
return PsiTreeUtil.isAncestor(iterated, psiElement, false) || PsiTreeUtil.isAncestor(parameter, psiElement, false) ? statement : null;
|
||||
}
|
||||
|
||||
private static int startLine(Document doc, PsiElement psiElement) {
|
||||
return doc.getLineNumber(psiElement.getTextRange().getStartOffset());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
|
||||
public class MissingLoopBodyFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
PsiLoopStatement loopStatement = getLoopParent(psiElement);
|
||||
if (loopStatement == null) return;
|
||||
|
||||
final Document doc = editor.getDocument();
|
||||
|
||||
PsiElement body = loopStatement.getBody();
|
||||
if (body instanceof PsiBlockStatement) return;
|
||||
if (body != null && startLine(doc, body) == startLine(doc, loopStatement)) return;
|
||||
|
||||
PsiElement eltToInsertAfter;
|
||||
if (loopStatement instanceof PsiWhileStatement) {
|
||||
eltToInsertAfter = ((PsiWhileStatement)loopStatement).getRParenth();
|
||||
}
|
||||
else if (loopStatement instanceof PsiForStatement) {
|
||||
eltToInsertAfter = ((PsiForStatement)loopStatement).getRParenth();
|
||||
}
|
||||
else if (loopStatement instanceof PsiForeachStatement) {
|
||||
eltToInsertAfter = ((PsiForeachStatement)loopStatement).getRParenth();
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
fixLoopBody(editor, processor, loopStatement, doc, body, eltToInsertAfter);
|
||||
}
|
||||
|
||||
private static PsiLoopStatement getLoopParent(PsiElement element) {
|
||||
PsiLoopStatement statement = PsiTreeUtil.getParentOfType(element, PsiLoopStatement.class);
|
||||
if (statement == null) return null;
|
||||
if (statement instanceof PsiForeachStatement) {
|
||||
return isForEachApplicable((PsiForeachStatement)statement, element) ? statement : null;
|
||||
}
|
||||
if (statement instanceof PsiForStatement) {
|
||||
return isForApplicable((PsiForStatement)statement, element) ? statement : null;
|
||||
}
|
||||
if (statement instanceof PsiWhileStatement) {
|
||||
return statement;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isForApplicable(PsiForStatement statement, PsiElement psiElement) {
|
||||
PsiStatement init = statement.getInitialization();
|
||||
PsiStatement update = statement.getUpdate();
|
||||
PsiExpression check = statement.getCondition();
|
||||
|
||||
return isValidChild(init, psiElement) || isValidChild(update, psiElement) || isValidChild(check, psiElement);
|
||||
}
|
||||
|
||||
private static boolean isValidChild(PsiElement ancestor, PsiElement psiElement) {
|
||||
if (ancestor != null) {
|
||||
if (PsiTreeUtil.isAncestor(ancestor, psiElement, false)) {
|
||||
if (PsiTreeUtil.hasErrorElements(ancestor)) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isForEachApplicable(PsiForeachStatement statement, PsiElement psiElement) {
|
||||
PsiExpression iterated = statement.getIteratedValue();
|
||||
PsiParameter parameter = statement.getIterationParameter();
|
||||
|
||||
return PsiTreeUtil.isAncestor(iterated, psiElement, false) || PsiTreeUtil.isAncestor(parameter, psiElement, false);
|
||||
}
|
||||
|
||||
private static int startLine(Document doc, PsiElement psiElement) {
|
||||
return doc.getLineNumber(psiElement.getTextRange().getStartOffset());
|
||||
}
|
||||
|
||||
static void fixLoopBody(Editor editor,
|
||||
JavaSmartEnterProcessor processor,
|
||||
PsiLoopStatement loop,
|
||||
Document doc,
|
||||
PsiElement body,
|
||||
PsiElement eltToInsertAfter) {
|
||||
if (body != null && eltToInsertAfter != null) {
|
||||
int endOffset = body.getTextRange().getEndOffset();
|
||||
doc.insertString(endOffset, "\n}");
|
||||
int offset = eltToInsertAfter.getTextRange().getEndOffset();
|
||||
doc.insertString(offset, "{");
|
||||
editor.getCaretModel().moveToOffset(endOffset + "{".length());
|
||||
processor.setSkipEnter(true);
|
||||
processor.reformat(loop);
|
||||
}
|
||||
else {
|
||||
String prefix = "{}";
|
||||
String text = prefix;
|
||||
if (eltToInsertAfter == null) {
|
||||
eltToInsertAfter = loop;
|
||||
text = ")" + text;
|
||||
}
|
||||
int offset = eltToInsertAfter.getTextRange().getEndOffset();
|
||||
doc.insertString(offset, text);
|
||||
editor.getCaretModel().moveToOffset(offset + text.length() - prefix.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInsight.editorActions.smartEnter;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.PsiBlockStatement;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiJavaToken;
|
||||
import com.intellij.psi.PsiWhileStatement;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
|
||||
public class MissingWhileBodyFixer implements Fixer {
|
||||
@Override
|
||||
public void apply(Editor editor, JavaSmartEnterProcessor processor, PsiElement psiElement) throws IncorrectOperationException {
|
||||
if (!(psiElement instanceof PsiWhileStatement)) return;
|
||||
PsiWhileStatement whileStatement = (PsiWhileStatement) psiElement;
|
||||
|
||||
final Document doc = editor.getDocument();
|
||||
|
||||
PsiElement body = whileStatement.getBody();
|
||||
if (body instanceof PsiBlockStatement) return;
|
||||
if (body != null && startLine(doc, body) == startLine(doc, whileStatement) && whileStatement.getCondition() != null) return;
|
||||
|
||||
final PsiJavaToken rParenth = whileStatement.getRParenth();
|
||||
assert rParenth != null;
|
||||
|
||||
doc.insertString(rParenth.getTextRange().getEndOffset(), "{}");
|
||||
}
|
||||
|
||||
private static int startLine(Document doc, PsiElement psiElement) {
|
||||
return doc.getLineNumber(psiElement.getTextRange().getStartOffset());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class X {{
|
||||
int[] a = new int[3];
|
||||
long res = 0;
|
||||
for (int val : a)<caret>
|
||||
res+=val
|
||||
}}
|
||||
@@ -0,0 +1,7 @@
|
||||
class X {{
|
||||
int[] a = new int[3];
|
||||
long res = 0;
|
||||
for (int val : a) {
|
||||
res += val
|
||||
}
|
||||
}}
|
||||
@@ -0,0 +1,5 @@
|
||||
class X {{
|
||||
int[] a = new int[3];
|
||||
for (int i = 0; i < a.length; ++i)
|
||||
a[i] = 1<caret>
|
||||
}}
|
||||
@@ -0,0 +1,6 @@
|
||||
class X {{
|
||||
int[] a = new int[3];
|
||||
for (int i = 0; i < a.length; ++i) {
|
||||
a[i] = 1;
|
||||
}
|
||||
}}
|
||||
@@ -75,6 +75,8 @@ public class CompleteStatementTest extends EditorActionTestCase {
|
||||
public void testBlock1() { doTest(); }
|
||||
public void testAfterFor() { doTest(); }
|
||||
public void testBeforeFor() { doTest(); }
|
||||
public void testForSingleStatementInBody() { doTest(); }
|
||||
public void testForEachSingleStatementInBody() { doTest(); }
|
||||
public void testAtBlockEnd() { doTest(); }
|
||||
public void testForceBlock() { doTest(); }
|
||||
public void testElseIf() { doTest(); }
|
||||
|
||||
Reference in New Issue
Block a user