[java] module formatting

This commit is contained in:
Roman Shevchenko
2016-07-18 14:26:31 +02:00
parent db07e03aa0
commit f736ecb86e
6 changed files with 101 additions and 23 deletions
@@ -185,7 +185,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
return new PartialWhitespaceBlock(child, range, wrap, alignment, actualIndent, settings, javaSettings);
}
if (childPsi instanceof PsiClass) {
if (childPsi instanceof PsiClass || childPsi instanceof PsiJavaModule) {
return new CodeBlockBlock(child, wrap, alignment, actualIndent, settings, javaSettings);
}
if (child.getElementType() == JavaElementType.METHOD) {
@@ -203,7 +203,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
InjectedLanguageUtil.hasInjections((PsiLanguageInjectionHost)child)) {
return new CommentWithInjectionBlock(child, wrap, alignment, indent, settings, javaSettings);
}
if (child instanceof LeafElement) {
if (child instanceof LeafElement || childPsi instanceof PsiJavaModuleReference) {
final LeafBlock block = new LeafBlock(child, wrap, alignment, actualIndent);
block.setStartOffset(startOffset);
return block;
@@ -120,7 +120,8 @@ public class CodeBlockBlock extends AbstractJavaBlock {
if (child.getElementType() == JavaElementType.SWITCH_LABEL_STATEMENT) {
child = processCaseAndStatementAfter(result, child, childAlignment, childWrap, indent);
}
else if (myNode.getPsi() instanceof PsiClass && child.getElementType() == JavaTokenType.LBRACE) {
else if ((myNode.getPsi() instanceof PsiClass || myNode.getPsi() instanceof PsiJavaModule) &&
child.getElementType() == JavaTokenType.LBRACE) {
child = composeCodeBlock(result, child, getCodeBlockExternalIndent(), myChildrenIndent, null);
}
else if (myNode.getElementType() == JavaElementType.CODE_BLOCK &&
@@ -252,7 +253,8 @@ public class CodeBlockBlock extends AbstractJavaBlock {
|| elementType == JavaTokenType.CLASS_KEYWORD
|| elementType == JavaTokenType.INTERFACE_KEYWORD
|| elementType == JavaTokenType.IDENTIFIER
|| elementType == JavaTokenType.ENUM_KEYWORD) {
|| elementType == JavaTokenType.ENUM_KEYWORD
|| elementType == JavaElementType.MODULE_REFERENCE) {
return Indent.getNoneIndent();
}
else {
@@ -1313,6 +1313,26 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor {
}
}
@Override
public void visitModule(PsiJavaModule module) {
if (myType2 == JavaTokenType.RBRACE || ElementType.JAVA_MODULE_STATEMENT_BIT_SET.contains(myType2)) {
myResult = Spacing.createSpacing(0, 0, 1, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
else if (myType1 == JavaElementType.MODULE_REFERENCE || myType2 == JavaElementType.MODULE_REFERENCE) {
createSpaceInCode(true);
}
}
@Override
public void visitModuleStatement(PsiElement statement) {
if (myType1 == JavaElementType.MODULE_REFERENCE) {
createSpaceInCode(myType2 != JavaTokenType.SEMICOLON && myType2 != JavaTokenType.COMMA);
}
if (myType2 == JavaElementType.MODULE_REFERENCE) {
createSpaceInCode(true);
}
}
@Override
public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) {
if ((myRole1 == ChildRole.DOUBLE_COLON && myRole2 == ChildRole.REFERENCE_NAME) ||
@@ -1768,25 +1788,36 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor {
Pair<IElementType, IElementType> pair = Pair.create(type1, type2);
Boolean res = myCanStickJavaTokensMatrix.get(pair);
if (res == null) {
if (!checkToken(token1) || !checkToken(token2)) return true;
String text = token1.getText() + token2.getText();
Lexer lexer = JavaParserDefinition.createLexer(LanguageLevel.HIGHEST);
lexer.start(text);
boolean canMerge = lexer.getTokenType() == type1;
lexer.advance();
canMerge &= lexer.getTokenType() == type2;
res = canMerge;
TokenCheckResult res1 = checkToken(token1, lexer), res2 = checkToken(token2, lexer);
if (res1 == TokenCheckResult.INCORRECT || res2 == TokenCheckResult.INCORRECT) return true;
if (res1 == TokenCheckResult.RESTRICTED_KEYWORD || type1 == JavaTokenType.IDENTIFIER && res2 == TokenCheckResult.RESTRICTED_KEYWORD) {
res = false;
}
else {
lexer.start(token1.getText() + token2.getText());
boolean canMerge = lexer.getTokenType() == type1;
lexer.advance();
canMerge &= lexer.getTokenType() == type2;
res = canMerge;
}
myCanStickJavaTokensMatrix.put(pair, res);
}
return res.booleanValue();
}
private static boolean checkToken(final ASTNode token1) {
Lexer lexer = JavaParserDefinition.createLexer(LanguageLevel.HIGHEST);
final String text = token1.getText();
lexer.start(text);
if (lexer.getTokenType() != token1.getElementType()) return false;
private enum TokenCheckResult {OK, INCORRECT, RESTRICTED_KEYWORD}
private static TokenCheckResult checkToken(ASTNode token, Lexer lexer) {
lexer.start(token.getText());
if (lexer.getTokenType() != token.getElementType()) {
boolean kw = lexer.getTokenType() == JavaTokenType.IDENTIFIER && ElementType.KEYWORD_BIT_SET.contains(token.getElementType());
return kw ? TokenCheckResult.RESTRICTED_KEYWORD : TokenCheckResult.INCORRECT;
}
lexer.advance();
return lexer.getTokenType() == null;
return lexer.getTokenType() == null ? TokenCheckResult.OK : TokenCheckResult.INCORRECT;
}
}
}
@@ -395,19 +395,23 @@ public abstract class JavaElementVisitor extends PsiElementVisitor {
visitElement(moduleRef);
}
public void visitRequiresStatement(PsiRequiresStatement statement) {
public void visitModuleStatement(PsiElement statement) {
visitElement(statement);
}
public void visitRequiresStatement(PsiRequiresStatement statement) {
visitModuleStatement(statement);
}
public void visitExportsStatement(PsiExportsStatement statement) {
visitElement(statement);
visitModuleStatement(statement);
}
public void visitUsesStatement(PsiUsesStatement statement) {
visitElement(statement);
visitModuleStatement(statement);
}
public void visitProvidesStatement(PsiProvidesStatement statement) {
visitElement(statement);
visitModuleStatement(statement);
}
}
@@ -70,8 +70,10 @@ public interface ElementType extends JavaTokenType, JavaDocTokenType, JavaElemen
WHILE_STATEMENT, FOR_STATEMENT, FOREACH_STATEMENT, DO_WHILE_STATEMENT, SWITCH_STATEMENT, SWITCH_LABEL_STATEMENT, BREAK_STATEMENT,
CONTINUE_STATEMENT, RETURN_STATEMENT, THROW_STATEMENT, SYNCHRONIZED_STATEMENT, TRY_STATEMENT, LABELED_STATEMENT, ASSERT_STATEMENT);
TokenSet JAVA_MODULE_STATEMENT_BIT_SET = TokenSet.create(REQUIRES_STATEMENT, EXPORTS_STATEMENT, USES_STATEMENT, PROVIDES_STATEMENT);
TokenSet IMPORT_STATEMENT_BASE_BIT_SET = TokenSet.create(IMPORT_STATEMENT, IMPORT_STATIC_STATEMENT);
TokenSet CLASS_KEYWORD_BIT_SET = TokenSet.create(CLASS_KEYWORD, INTERFACE_KEYWORD, ENUM_KEYWORD);
TokenSet MEMBER_BIT_SET = TokenSet.create(CLASS, FIELD, ENUM_CONSTANT, METHOD, ANNOTATION_METHOD);
TokenSet FULL_MEMBER_BIT_SET = TokenSet.orSet(MEMBER_BIT_SET, TokenSet.create(CLASS_INITIALIZER));
}
}
@@ -0,0 +1,39 @@
/*
* Copyright 2000-2016 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.psi.formatter.java
import com.intellij.openapi.roots.LanguageLevelProjectExtension
import com.intellij.pom.java.LanguageLevel
import com.intellij.testFramework.LightPlatformTestCase
class JavaModuleFormatterTest : AbstractJavaFormatterTest() {
override fun setUp() {
super.setUp()
LanguageLevelProjectExtension.getInstance(LightPlatformTestCase.getProject()).languageLevel = LanguageLevel.JDK_1_9
}
fun testEmpty() {
doTextTest("module A.B { }", "module A.B {\n}")
}
fun testCommentBody() {
doTextTest("module m { /* comment */ }", "module m { /* comment */\n}")
}
fun testStatements() {
doTextTest("module m { requires java.base; exports a.b; }", "module m {\n requires java.base;\n exports a.b;\n}")
}
}