KT-1053 Incorrect auto formatting of when expression

This commit is contained in:
Nikolay Krasko
2012-01-18 19:27:41 +04:00
parent cbcfeaa1b7
commit dd1fd26461
15 changed files with 321 additions and 9 deletions
@@ -84,16 +84,15 @@ public class JetBlock implements ASTBlock {
private List<Block> buildSubBlocks() {
List<Block> blocks = new ArrayList<Block>();
for (ASTNode child = myNode.getFirstChildNode(); child != null; child = child.getTreeNext()) {
IElementType childType = child.getElementType();
IElementType childType = child.getElementType();
if (child.getTextRange().getLength() == 0) continue;
if (child.getTextRange().getLength() == 0) continue;
if (childType == TokenType.WHITE_SPACE) {
continue;
}
if (childType == TokenType.WHITE_SPACE) {
continue;
}
blocks.add(buildSubBlock(child));
blocks.add(buildSubBlock(child));
}
return Collections.unmodifiableList(blocks);
}
@@ -106,8 +105,21 @@ public class JetBlock implements ASTBlock {
if (CODE_BLOCKS.contains(myNode.getElementType())) {
childIndent = indentIfNotBrace(child);
}
else if (myNode.getElementType() == JetNodeTypes.WHEN) {
childIndent = indentIfNotBrace(child);
else if (child.getTreeParent() != null && child.getTreeParent().getElementType() == JetNodeTypes.BODY &&
child.getElementType() != JetNodeTypes.BLOCK) {
// For a single statement if 'for'
childIndent = Indent.getNormalIndent();
}
else if (child.getElementType() == JetNodeTypes.WHEN_ENTRY) {
// For the entry in when
// TODO: Add an option for configuration?
childIndent = Indent.getNormalIndent();
}
else if (child.getTreeParent() != null && child.getTreeParent().getElementType() == JetNodeTypes.WHEN_ENTRY) {
ASTNode prev = getPrevWithoutWhitespace(child);
if (prev != null && prev.getText().equals("->")) {
childIndent = indentIfNotBrace(child);
}
}
else if (STATEMENT_PARTS.contains(myNode.getElementType()) && child.getElementType() != JetNodeTypes.BLOCK) {
childIndent = Indent.getNormalIndent();
@@ -122,6 +134,15 @@ public class JetBlock implements ASTBlock {
: Indent.getNormalIndent();
}
private static ASTNode getPrevWithoutWhitespace(ASTNode node) {
node = node.getTreePrev();
while (node != null && node.getElementType() == TokenType.WHITE_SPACE) {
node = node.getTreePrev();
}
return node;
}
@Override
public Spacing getSpacing(Block child1, Block child2) {
return mySpacingBuilder.getSpacing(this, child1, child2);
+5
View File
@@ -0,0 +1,5 @@
fun some() {
for (var a in 1..12) {
a += 1
}
}
@@ -0,0 +1,5 @@
fun some() {
for (var a in 1..12) {
a += 1
}
}
+3
View File
@@ -0,0 +1,3 @@
class Some() {
val a : Int
}
+3
View File
@@ -0,0 +1,3 @@
class Some() {
val a : Int
}
+6
View File
@@ -0,0 +1,6 @@
fun testSome() {
var a = 12
for (var a in 1..10)
a = 11
a = 10
}
@@ -0,0 +1,6 @@
fun testSome() {
var a = 12
for (var a in 1..10)
a = 11
a = 10
}
+6
View File
@@ -0,0 +1,6 @@
fun some() {
if (3 > 2)
2
else
1
}
+6
View File
@@ -0,0 +1,6 @@
fun some() {
if (3 > 2)
2
else
1
}
+6
View File
@@ -0,0 +1,6 @@
fun some(x : Any) {
when (x) {
is Int -> 0
else -> 1
}
}
+9
View File
@@ -0,0 +1,9 @@
fun some(x : Any) {
when (x) {
is Int ->
0
else -> {
1
}
}
}
@@ -0,0 +1,9 @@
fun some(x : Any) {
when (x) {
is Int ->
0
else -> {
1
}
}
}
+6
View File
@@ -0,0 +1,6 @@
fun some(x : Any) {
when (x) {
is Int -> 0
else -> 1
}
}
@@ -0,0 +1,191 @@
/*
* Copyright 2000-2010 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 org.jetbrains.jet.formatter;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.impl.DocumentImpl;
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.testFramework.LightIdeaTestCase;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.jet.plugin.PluginTestCaseBase;
import java.io.File;
import java.util.EnumMap;
import java.util.Map;
// Based on from com.intellij.psi.formatter.java.AbstractJavaFormatterTest
@SuppressWarnings("UnusedDeclaration")
public abstract class AbstractKotlinFormatterTest extends LightIdeaTestCase {
protected enum Action {REFORMAT, INDENT}
private interface TestFormatAction {
void run(PsiFile psiFile, int startOffset, int endOffset);
}
private static final Map<Action, TestFormatAction> ACTIONS = new EnumMap<Action, TestFormatAction>(Action.class);
static {
ACTIONS.put(Action.REFORMAT, new TestFormatAction() {
@Override
public void run(PsiFile psiFile, int startOffset, int endOffset) {
CodeStyleManager.getInstance(getProject()).reformatText(psiFile, startOffset, endOffset);
}
});
ACTIONS.put(Action.INDENT, new TestFormatAction() {
@Override
public void run(PsiFile psiFile, int startOffset, int endOffset) {
CodeStyleManager.getInstance(getProject()).adjustLineIndent(psiFile, startOffset);
}
});
}
private static final String BASE_PATH =
new File(PluginTestCaseBase.getTestDataPathBase(), "/formatter/").getAbsolutePath();
public TextRange myTextRange;
public TextRange myLineRange;
@Override
protected void setUp() throws Exception {
super.setUp();
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.HIGHEST);
}
// public static CommonCodeStyleSettings getSettings() {
// CodeStyleSettings rootSettings = CodeStyleSettingsManager.getSettings(getProject());
// return rootSettings.getCommonSettings(JavaLanguage.INSTANCE);
// }
//
// public static CommonCodeStyleSettings.IndentOptions getIndentOptions() {
// return getSettings().getRootSettings().getIndentOptions(StdFileTypes.JAVA);
// }
public void doTest() throws Exception {
doTest(getTestName(false) + ".kt", getTestName(false) + "_after.kt");
}
public void doTest(@NonNls String fileNameBefore, @NonNls String fileNameAfter) throws Exception {
doTextTest(Action.REFORMAT, loadFile(fileNameBefore), loadFile(fileNameAfter));
}
public void doTextTest(@NonNls final String text, @NonNls String textAfter) throws IncorrectOperationException {
doTextTest(Action.REFORMAT, text, textAfter);
}
public void doTextTest(final Action action, final String text, String textAfter) throws IncorrectOperationException {
final PsiFile file = createFile("A.kt", text);
if (myLineRange != null) {
final DocumentImpl document = new DocumentImpl(text);
myTextRange =
new TextRange(document.getLineStartOffset(myLineRange.getStartOffset()), document.getLineEndOffset(myLineRange.getEndOffset()));
}
final PsiDocumentManager manager = PsiDocumentManager.getInstance(getProject());
final Document document = manager.getDocument(file);
CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
document.replaceString(0, document.getTextLength(), text);
manager.commitDocument(document);
try {
TextRange rangeToUse = myTextRange;
if (rangeToUse == null) {
rangeToUse = file.getTextRange();
}
ACTIONS.get(action).run(file, rangeToUse.getStartOffset(), rangeToUse.getEndOffset());
}
catch (IncorrectOperationException e) {
assertTrue(e.getLocalizedMessage(), false);
}
}
});
}
}, "", "");
if (document == null) {
fail("Don't expect the document to be null");
return;
}
assertEquals(prepareText(textAfter), prepareText(document.getText()));
manager.commitDocument(document);
assertEquals(prepareText(textAfter), prepareText(file.getText()));
}
// public void doMethodTest(@NonNls final String before, @NonNls final String after) throws Exception {
// doTextTest(
// Action.REFORMAT,
// "class Foo{\n" + " void foo() {\n" + before + '\n' + " }\n" + "}",
// "class Foo {\n" + " void foo() {\n" + StringUtil.shiftIndentInside(after, 8, false) + '\n' + " }\n" + "}"
// );
// }
//
// public void doClassTest(@NonNls final String before, @NonNls final String after) throws Exception {
// doTextTest(
// Action.REFORMAT,
// "class Foo{\n" + before + '\n' + "}",
// "class Foo {\n" + StringUtil.shiftIndentInside(after, 4, false) + '\n' + "}"
// );
// }
private static String prepareText(String actual) {
if (actual.startsWith("\n")) {
actual = actual.substring(1);
}
if (actual.startsWith("\n")) {
actual = actual.substring(1);
}
// Strip trailing spaces
final Document doc = EditorFactory.getInstance().createDocument(actual);
CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
((DocumentImpl)doc).stripTrailingSpaces();
}
});
}
}, "formatting", null);
return doc.getText();
}
private static String loadFile(String name) throws Exception {
String text = FileUtil.loadFile(new File(BASE_PATH, name));
text = StringUtil.convertLineSeparators(text);
return text;
}
}
@@ -0,0 +1,30 @@
package org.jetbrains.jet.formatter;
/**
* Based on com.intellij.psi.formatter.java.JavaFormatterTest
*/
public class KotlinFormatterTest extends AbstractKotlinFormatterTest {
public void testBlockFor() throws Exception {
doTest();
}
public void testClass() throws Exception {
doTest();
}
public void testForNoBraces() throws Exception {
doTest();
}
public void testIf() throws Exception {
doTest();
}
public void testWhen() throws Exception {
doTest();
}
public void testWhenEntryExpr() throws Exception {
doTest();
}
}