You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by sk...@apache.org on 2020/05/22 09:36:31 UTC

[netbeans] branch master updated: [NETBEANS-4235]:Fixed formatting issue in Java Record

This is an automated email from the ASF dual-hosted git repository.

skygo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new d7dc630  [NETBEANS-4235]:Fixed formatting issue in Java Record
     new 11d2883  Merge pull request #2138 from arusinha/netbeans-4235
d7dc630 is described below

commit d7dc630a7e9baafda9d3cd14d381f39457ef6fae
Author: Arunava Sinha <ar...@oracle.com>
AuthorDate: Fri May 15 12:51:11 2020 +0530

    [NETBEANS-4235]:Fixed formatting issue in Java Record
---
 .../modules/java/source/save/Reformatter.java      | 132 +++++++++++++++------
 .../modules/java/source/save/Reindenter.java       | 103 ++++++++++++++++
 .../modules/java/source/save/FormatingTest.java    | 102 ++++++++++++++++
 .../modules/java/source/save/ReindenterTest.java   |  89 ++++++++++++++
 4 files changed, 391 insertions(+), 35 deletions(-)

diff --git a/java/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java b/java/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java
index 799e173..1df27b2 100644
--- a/java/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java
+++ b/java/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java
@@ -1268,13 +1268,15 @@ public class Reformatter implements ReformatTask {
             return true;
         }
 
-        public Boolean scanRecord(ClassTree node, Void p) {
+        private Boolean scanRecord(ClassTree node, Void p) {
             boolean old = continuationIndent;
+            int oldIndent = indent;
             try {
+                continuationIndent = true;
                 ModifiersTree mods = node.getModifiers();
                 if (mods != null) {
                     if (scan(mods, p)) {
-                        continuationIndent = true;
+
                         if (cs.placeNewLineAfterModifiers()) {
                             newline();
                         } else {
@@ -1287,12 +1289,17 @@ public class Reformatter implements ReformatTask {
                 }
                 accept(IDENTIFIER);
                 space();
+
+                if (!ERROR.contentEquals(node.getSimpleName())) {
+                    accept(IDENTIFIER, UNDERSCORE);
+                }
+
                 List<? extends TypeParameterTree> tparams = node.getTypeParameters();
                 if (tparams != null && !tparams.isEmpty()) {
                     if (LT == accept(LT)) {
                         tpLevel++;
                     }
-                    continuationIndent = true;
+
                     for (Iterator<? extends TypeParameterTree> it = tparams.iterator(); it.hasNext();) {
                         TypeParameterTree tparam = it.next();
                         scan(tparam, p);
@@ -1316,16 +1323,11 @@ public class Reformatter implements ReformatTask {
                                 break;
                         }
                     }
-                    spaces(1, true);
+                    spaces(0, true);
                 }
 
-                if (!ERROR.contentEquals(node.getSimpleName())) {
-                    accept(IDENTIFIER, UNDERSCORE);
-                }
-                //continuationIndent = true;
                 spaces(cs.spaceBeforeMethodDeclParen() ? 1 : 0);
                 accept(LPAREN);
-                int oldIndent = indent;
                 List<? extends Tree> members = node.getMembers();
                 List recParams = new ArrayList<Tree>();
 
@@ -1333,52 +1335,112 @@ public class Reformatter implements ReformatTask {
                     if (member.getKind() == Tree.Kind.VARIABLE) {
                         ModifiersTree modifiers = ((VariableTree) member).getModifiers();
                         Set<Modifier> modifierSet = modifiers.getFlags();
-                        boolean isPublicModPresent = false;
 
-                        if (modifiers == null || !modifierSet.contains(Modifier.STATIC)) {
+                        if (!modifierSet.contains(Modifier.STATIC)) {
                             recParams.add(member);
                         }
                     }
                 }
 
-                if (members != null && !members.isEmpty()) {
-                    int oldLastIndent = lastIndent;
-                    try {
-                        spaces(cs.spaceWithinMethodDeclParens() ? 1 : 0, true);
-                        wrapList(cs.wrapMethodParams(), cs.alignMultilineMethodParams(), false, COMMA, recParams);
-                        accept(RPAREN);
-                        spaces(true ? 1 : 0, tokens.offset() < startOffset);
-                        accept(LBRACE);
-                        continuationIndent = old;
-                        indent += indentSize;
+                if (!recParams.isEmpty()) {
+                    spaces(cs.spaceWithinMethodDeclParens() ? 1 : 0, true);
+                    wrapList(cs.wrapMethodParams(), cs.alignMultilineMethodParams(), false, COMMA, recParams);
+                }
+                accept(RPAREN);
+                List<? extends Tree> impls = node.getImplementsClause();
+                if (impls != null && !impls.isEmpty()) {
+                    wrapToken(cs.wrapExtendsImplementsKeyword(), 1, IMPLEMENTS);
+                    wrapList(cs.wrapExtendsImplementsList(), cs.alignMultilineImplements(), true, COMMA, impls);
+                }
+                int oldLastIndent = lastIndent;
+                int lastMaxPreservedBlankLines = maxPreservedBlankLines;
+                maxPreservedBlankLines = cs.getMaximumBlankLinesInDeclarations();
+                classLeftBracePlacement();
+
+                continuationIndent = old;
+                try {
+                    if (members != null && !members.isEmpty()) {
 
+                        boolean isFirstMember = true;
+                        blankLines(node.getSimpleName().length() == 0 ? 0 : cs.getBlankLinesAfterClassHeader());
                         for (Tree member : members) {
-                            if (member.getKind() != Tree.Kind.VARIABLE || !recParams.contains(member)) {
-                                newline();
-                                scan(member, p);
+                            if (recParams.contains(member)) {
+                                continue;
+                            }
+                            blankLines(0);
+                            switch (member.getKind()) {
+                                case VARIABLE:
+                                    boolean b = tokens.moveNext();
+                                    if (b) {
+                                        tokens.movePrevious();
+                                        if (!isFirstMember) {
+                                            blankLines(cs.getBlankLinesBeforeFields());
+                                        }
+                                        scan(member, p);
+                                        blankLines(cs.getBlankLinesAfterFields());
+                                    }
+                                    break;
+                                default:
+                                    if (!isFirstMember) {
+                                        blankLines(cs.getBlankLinesBeforeMethods());
+                                    }
+                                    scan(member, p);
+                                    blankLines(cs.getBlankLinesAfterMethods());
+                            }
+                            if (isFirstMember) {
+                                isFirstMember = false;
                             }
                         }
 
-                    } finally {
-                        indent = oldIndent;
-                        lastIndent = oldLastIndent;
-                        continuationIndent = isLastIndentContinuation;
+                        spaces(cs.spaceWithinMethodDeclParens() ? 1 : 0, true);
                     }
-                    spaces(cs.spaceWithinMethodDeclParens() ? 1 : 0, true);
-                } else {
-                    accept(RPAREN);
-                    accept(LBRACE);
+                } finally {
+                    indent = oldIndent;
+                    lastIndent = oldLastIndent;
+                    continuationIndent = old;
+                    maxPreservedBlankLines = lastMaxPreservedBlankLines;
                 }
-
                 newline();
-                indent = oldIndent;
                 accept(RBRACE);
             } finally {
                 continuationIndent = old;
             }
-
             return true;
         }
+
+        private void classLeftBracePlacement() {
+            CodeStyle.BracePlacement bracePlacement = cs.getClassDeclBracePlacement();
+            boolean spaceBeforeLeftBrace = cs.spaceBeforeClassDeclLeftBrace();
+            int old = indent = lastIndent;
+            int halfIndent = lastIndent;
+            switch (bracePlacement) {
+                case SAME_LINE:
+                    spaces(spaceBeforeLeftBrace ? 1 : 0, tokens.offset() < startOffset);
+                    accept(LBRACE);
+                    indent = lastIndent + indentSize;
+                    break;
+                case NEW_LINE:
+                    newline();
+                    accept(LBRACE);
+                    indent = lastIndent + indentSize;
+                    break;
+                case NEW_LINE_HALF_INDENTED:
+                    int oldLast = lastIndent;
+                    indent = lastIndent + (indentSize >> 1);
+                    halfIndent = indent;
+                    newline();
+                    accept(LBRACE);
+                    indent = oldLast + indentSize;
+                    break;
+                case NEW_LINE_INDENTED:
+                    indent = lastIndent + indentSize;
+                    halfIndent = indent;
+                    newline();
+                    accept(LBRACE);
+                    break;
+            }
+        }
+
         @Override
         public Boolean visitMethod(MethodTree node, Void p) {
             boolean old = continuationIndent;
diff --git a/java/java.source.base/src/org/netbeans/modules/java/source/save/Reindenter.java b/java/java.source.base/src/org/netbeans/modules/java/source/save/Reindenter.java
index 092df1c..361b681 100644
--- a/java/java.source.base/src/org/netbeans/modules/java/source/save/Reindenter.java
+++ b/java/java.source.base/src/org/netbeans/modules/java/source/save/Reindenter.java
@@ -40,6 +40,7 @@ import com.sun.source.tree.SynchronizedTree;
 import com.sun.source.tree.Tree;
 import com.sun.source.tree.Tree.Kind;
 import com.sun.source.tree.TryTree;
+import com.sun.source.tree.TypeParameterTree;
 import com.sun.source.tree.VariableTree;
 import com.sun.source.tree.WhileLoopTree;
 import com.sun.source.util.SourcePositions;
@@ -69,6 +70,7 @@ import com.sun.tools.javac.parser.ParserFactory;
 import com.sun.tools.javac.util.Log;
 import java.util.ArrayList;
 import java.util.Arrays;
+import javax.lang.model.element.Modifier;
 import org.netbeans.api.java.lexer.JavaTokenId;
 import org.netbeans.api.java.source.CodeStyle;
 import org.netbeans.api.lexer.TokenHierarchy;
@@ -815,6 +817,9 @@ public class Reindenter implements IndentTask {
                 if (last.getKind().toString().equals(TreeShims.SWITCH_EXPRESSION)) {
                    currentIndent = getSwitchIndent(startOffset, endOffset,nextTokenId,lastPos,currentIndent) ;
                 }
+                else if (last.getKind().toString().equals(TreeShims.RECORD)) {
+                    currentIndent = getRecordIndent(startOffset, endOffset, nextTokenId, lastPos, currentIndent);
+                }
                 else currentIndent = getContinuationIndent(path, currentIndent);
                 break;
         }
@@ -896,6 +901,104 @@ public class Reindenter implements IndentTask {
         return currentIndent;
     }
 
+    private int getRecordIndent(int startOffset, int endOffset, JavaTokenId nextTokenId, int lastPos, int currentIndent) throws BadLocationException {
+        LinkedList<? extends Tree> path = getPath(startOffset);
+        Tree last = path.getFirst();
+        TokenSequence<JavaTokenId> token = findFirstNonWhitespaceToken(startOffset, endOffset);
+        nextTokenId = token != null ? token.token().id() : null;
+        if (nextTokenId != null && nextTokenId == JavaTokenId.RBRACE) {
+            if (isLeftBraceOnNewLine(lastPos, startOffset)) {
+                switch (cs.getClassDeclBracePlacement()) {
+                    case NEW_LINE_INDENTED:
+                        currentIndent += cs.getIndentSize();
+                        break;
+                    case NEW_LINE_HALF_INDENTED:
+                        currentIndent += (cs.getIndentSize() / 2);
+                        break;
+                }
+            }
+        } else {
+
+            token = findFirstNonWhitespaceToken(startOffset, lastPos);
+            JavaTokenId prevTokenId = token != null ? token.token().id() : null;
+            if (prevTokenId != null) {
+                switch (prevTokenId) {
+                    case LBRACE:
+                        if (path.size() > 1 && path.get(1).getKind() == Kind.NEW_CLASS && isLeftBraceOnNewLine(lastPos, startOffset)) {
+                            switch (cs.getClassDeclBracePlacement()) {
+                                case SAME_LINE:
+                                case NEW_LINE:
+                                    currentIndent += cs.getIndentSize();
+                                    break;
+                                case NEW_LINE_HALF_INDENTED:
+                                    currentIndent += (cs.getIndentSize() - cs.getIndentSize() / 2);
+                                    break;
+                            }
+                        } else {
+                            currentIndent += cs.indentTopLevelClassMembers() ? cs.getIndentSize() : 0;
+                        }
+                        break;
+                    case COMMA:
+                        List<? extends Tree> implClauses = ((ClassTree) last).getImplementsClause();
+                        if (!implClauses.isEmpty() && getStartPosition(implClauses.get(0)) < token.offset()) {
+                            currentIndent = getMultilineIndent(implClauses, path, token.offset(), currentIndent, cs.alignMultilineImplements(), true);
+                            break;
+                        }
+                        List<? extends Tree> members = ((ClassTree) last).getMembers();
+                        if (!members.isEmpty() && getStartPosition(members.get(0)) < token.offset()) {
+                            currentIndent = getMultilineIndent(members, path, token.offset(), currentIndent, cs.alignMultilineMethodParams(), true);
+                            break;
+                        }
+                        List<? extends TypeParameterTree> typeParams = ((ClassTree) last).getTypeParameters();
+                        if (!typeParams.isEmpty() && getStartPosition(typeParams.get(0)) < token.offset()) {
+                            currentIndent = getMultilineIndent(typeParams, path, token.offset(), currentIndent, cs.alignMultilineMethodParams(), true);
+                            break;
+                        }
+                        break;
+                    case IDENTIFIER:
+                    case GT:
+                    case GTGT:
+                    case GTGTGT:
+                    case RPAREN:
+                        if (nextTokenId != null && nextTokenId == JavaTokenId.LBRACE) {
+                            switch (cs.getClassDeclBracePlacement()) {
+                                case NEW_LINE_INDENTED:
+                                    currentIndent += cs.getIndentSize();
+                                    break;
+                                case NEW_LINE_HALF_INDENTED:
+                                    currentIndent += (cs.getIndentSize() / 2);
+                                    break;
+                            }
+                        } else {
+                            currentIndent += cs.getContinuationIndentSize();
+                        }
+                        break;
+
+                    default:
+                        Tree t = null;
+                        for (Tree member : ((ClassTree) last).getMembers()) {
+
+                            if (member.getKind() == Tree.Kind.VARIABLE && !((VariableTree) member).getModifiers().getFlags().contains(Modifier.STATIC)) {
+                                continue;
+                            }
+                            if (getEndPosition(member) > startOffset) {
+                                break;
+                            }
+                            t = member;
+                        }
+                        if (t != null) {
+                            int i = getCurrentIndent(t, path);
+                            currentIndent = i < 0 ? currentIndent + (cs.indentTopLevelClassMembers() ? cs.getIndentSize() : 0) : i;
+                            return currentIndent;
+                        }
+
+                        currentIndent += cs.getContinuationIndentSize();
+                }
+            }
+        }
+        return currentIndent;
+    }
+
     private int getStartPosition(Tree last) {
         return (int) sp.getStartPosition(cut, last);
     }
diff --git a/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java b/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java
index fa1fd2e..7939666 100644
--- a/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java
+++ b/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java
@@ -5124,6 +5124,108 @@ public class FormatingTest extends NbTestCase {
         reformat(doc, content, golden);
     }
 
+    public void testRecord1() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_14, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content
+                = "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "public record g3<T extends Object>() implements Cloneable{\n"
+                + "public g3 {\n"
+                + "System.out.println(\"hello\");\n"
+                + "}}}";
+
+        String golden
+                = "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "    public record g3<T extends Object>() implements Cloneable {\n\n"
+                + "        public g3 {\n"
+                + "            System.out.println(\"hello\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n";
+        reformat(doc, content, golden);
+    }
+
+    public void testRecord2() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_14, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content
+                = "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n"
+                + "public record g3<T extends Object>() {static int r =10;\n"
+                + "public g3 {\n"
+                + "System.out.println(\"hello\");\n"
+                + "}"
+                + "static{}"
+                + "}}";
+
+        String golden
+                = "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "    public record g3<T extends Object>() {\n\n"
+                + "        static int r = 10;\n\n"
+                + "        public g3 {\n"
+                + "            System.out.println(\"hello\");\n"
+                + "        }\n\n"
+                + "        static {\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n";
+        Preferences preferences = MimeLookup.getLookup(JavaTokenId.language().mimeType()).lookup(Preferences.class);
+        reformat(doc, content, golden);
+    }
+
+    public void testRecord3() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_14, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content
+                = "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "public record g3(){}}";
+
+        String golden
+                = "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "    public record g3() {\n"
+                + "    }\n"
+                + "}\n";
+        reformat(doc, content, golden);
+    }
+   
     private void reformat(Document doc, String content, String golden) throws Exception {
         reformat(doc, content, golden, 0, content.length());
     }
diff --git a/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/ReindenterTest.java b/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/ReindenterTest.java
index 93a059a..e792883 100644
--- a/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/ReindenterTest.java
+++ b/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/ReindenterTest.java
@@ -1976,6 +1976,95 @@ public class ReindenterTest extends NbTestCase {
         performSpanIndentationTest("package t;\npublic class T {\n|private final String s = \"\"\"\n1\n  2\n 3\n\"\"\";|\n}\n",
                 "package t;\npublic class T {\n    private final String s = \"\"\"\n                             1\n                               2\n                              3\n                             \"\"\";\n}\n");
     }
+    
+    public void testLineIndentationBeforeRecord() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14");
+        } catch (IllegalArgumentException ex) {
+            //OK, skip test:
+            return;
+        }
+        performLineIndentationTest("package t;\n| public record T() {\n}\n",
+                "package t;\npublic record T() {\n}\n");
+    }
+
+    public void testNewLineIndentationBeforeRecodBody() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14");
+        } catch (IllegalArgumentException ex) {
+            //OK, skip test:
+            return;
+        }
+        performNewLineIndentationTest("package t;\npublic record T()|{\n}\n",
+                "package t;\npublic record T()\n{\n}\n");
+    }
+
+    public void testLineIndentationBeforeHalfIndentedRecordBody() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14");
+        } catch (IllegalArgumentException ex) {
+            //OK, skip test:
+            return;
+        }
+        Preferences preferences = MimeLookup.getLookup(JavaTokenId.language().mimeType()).lookup(Preferences.class);
+        preferences.put("classDeclBracePlacement", CodeStyle.BracePlacement.NEW_LINE_HALF_INDENTED.name());
+        try {
+            performLineIndentationTest("package t;\npublic record T()\n|{\n}\n",
+                    "package t;\npublic record T()\n  {\n}\n");
+        } finally {
+            preferences.remove("classDeclBracePlacement");
+        }
+    }
+
+    public void testNewLineIndentationInsideRecord() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14");
+        } catch (IllegalArgumentException ex) {
+            //OK, skip test:
+            return;
+        }
+        performNewLineIndentationTest("package t;\npublic record T() {|\n}\n",
+                "package t;\npublic record T() {\n    \n}\n");
+    }
+
+    public void testNewLineIndentationBeforeEmptyRecordEnd() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14");
+        } catch (IllegalArgumentException ex) {
+            //OK, skip test:
+            return;
+        }
+        performNewLineIndentationTest("package t;\npublic record T() {|}\n",
+                "package t;\npublic record T() {\n}\n");
+    }
+
+    public void testLineIndentationBeforeEmptyRecordEnd() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14");
+        } catch (IllegalArgumentException ex) {
+            //OK, skip test:
+            return;
+        }
+        performLineIndentationTest("package t;\npublic record T() {\n|}\n",
+                "package t;\npublic record T() {\n}\n");
+    }
+
+    public void testLineIndentationBeforeEmptyHalfIndentedRecordEnd() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14");
+        } catch (IllegalArgumentException ex) {
+            //OK, skip test:
+            return;
+        }
+        Preferences preferences = MimeLookup.getLookup(JavaTokenId.language().mimeType()).lookup(Preferences.class);
+        preferences.put("classDeclBracePlacement", CodeStyle.BracePlacement.NEW_LINE_HALF_INDENTED.name());
+        try {
+            performLineIndentationTest("package t;\npublic record T()\n  {\n|    }\n",
+                    "package t;\npublic record T()\n  {\n  }\n");
+        } finally {
+            preferences.remove("classDeclBracePlacement");
+        }
+    }
 
     private void performNewLineIndentationTest(String code, String golden) throws Exception {
         int pos = code.indexOf('|');


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists