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 f911625cbe74..83772ffff2e6 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 @@ -1275,173 +1275,179 @@ public Boolean visitVariable(VariableTree node, Void p) { } private Boolean scanRecord(ClassTree node, Void p) { - boolean old = continuationIndent; - int oldIndent = indent; - try { - ModifiersTree mods = node.getModifiers(); - if (mods != null) { - if (scan(mods, p)) { - continuationIndent = true; - if (cs.placeNewLineAfterModifiers()) { - newline(); - } else { - space(); - } - } else if (afterAnnotation) { + boolean oldContinuationIndent = continuationIndent; + ModifiersTree mods = node.getModifiers(); + if (mods != null) { + if (scan(mods, p)) { + continuationIndent = true; + if (cs.placeNewLineAfterModifiers()) { newline(); + } else { + space(); } - afterAnnotation = false; + } else if (afterAnnotation) { + newline(); } - accept(IDENTIFIER); - continuationIndent = true; - space(); + afterAnnotation = false; + } + accept(IDENTIFIER); + continuationIndent = true; + space(); - if (!ERROR.contentEquals(node.getSimpleName())) { - accept(IDENTIFIER, UNDERSCORE); - } + if (!ERROR.contentEquals(node.getSimpleName())) { + accept(IDENTIFIER, UNDERSCORE); + } - List tparams = node.getTypeParameters(); - if (tparams != null && !tparams.isEmpty()) { - if (LT == accept(LT)) { - tpLevel++; - } + List tparams = node.getTypeParameters(); + if (tparams != null && !tparams.isEmpty()) { + if (LT == accept(LT)) { + tpLevel++; + } - for (Iterator it = tparams.iterator(); it.hasNext();) { - TypeParameterTree tparam = it.next(); - scan(tparam, p); - if (it.hasNext()) { - spaces(cs.spaceBeforeComma() ? 1 : 0); - accept(COMMA); - spaces(cs.spaceAfterComma() ? 1 : 0); - } + for (Iterator it = tparams.iterator(); it.hasNext();) { + TypeParameterTree tparam = it.next(); + scan(tparam, p); + if (it.hasNext()) { + spaces(cs.spaceBeforeComma() ? 1 : 0); + accept(COMMA); + spaces(cs.spaceAfterComma() ? 1 : 0); } - JavaTokenId accepted; - if (tpLevel > 0 && (accepted = accept(GT, GTGT, GTGTGT)) != null) { - switch (accepted) { - case GTGTGT: - tpLevel -= 3; - break; - case GTGT: - tpLevel -= 2; - break; - case GT: - tpLevel--; - break; - } + } + JavaTokenId accepted; + if (tpLevel > 0 && (accepted = accept(GT, GTGT, GTGTGT)) != null) { + switch (accepted) { + case GTGTGT: + tpLevel -= 3; + break; + case GTGT: + tpLevel -= 2; + break; + case GT: + tpLevel--; + break; } - spaces(0, true); } + spaces(0, true); + } - spaces(cs.spaceBeforeMethodDeclParen() ? 1 : 0); - accept(LPAREN); - List members = node.getMembers(); - List recParams = new ArrayList(); + spaces(cs.spaceBeforeMethodDeclParen() ? 1 : 0); + accept(LPAREN); - for (Tree member : members) { - if (member.getKind() == Tree.Kind.VARIABLE) { - ModifiersTree modifiers = ((VariableTree) member).getModifiers(); - Set modifierSet = modifiers.getFlags(); + List members = node.getMembers(); + List recParams = new ArrayList(); - if (!modifierSet.contains(Modifier.STATIC)) { - recParams.add(member); - } + for (Tree member : members) { + if (member.getKind() == Tree.Kind.VARIABLE) { + ModifiersTree modifiers = ((VariableTree) member).getModifiers(); + Set modifierSet = modifiers.getFlags(); + + if (!modifierSet.contains(Modifier.STATIC)) { + recParams.add(member); } } + } - if (!recParams.isEmpty()) { - spaces(cs.spaceWithinMethodDeclParens() ? 1 : 0, true); - wrapList(cs.wrapMethodParams(), cs.alignMultilineMethodParams(), false, COMMA, recParams); - spaces(cs.spaceWithinMethodDeclParens() ? 1 : 0, true); // solves #7403 - } - accept(RPAREN); - List 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(); - - CodeStyle.BracePlacement bracePlacement = cs.getClassDeclBracePlacement(); - boolean spaceBeforeLeftBrace = cs.spaceBeforeClassDeclLeftBrace(); - switch (bracePlacement) { - case SAME_LINE: - spaces(spaceBeforeLeftBrace ? 1 : 0, tokens.offset() < startOffset); - accept(LBRACE); - if (tokens.token().id() == RBRACE) { - accept(RBRACE); - indent = oldIndent; - lastIndent = oldLastIndent; - return true; - } - 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); - newline(); - accept(LBRACE); - indent = oldLast + indentSize; - break; - case NEW_LINE_INDENTED: - indent = lastIndent + indentSize; - newline(); - accept(LBRACE); - break; - } + if (!recParams.isEmpty()) { + spaces(cs.spaceWithinMethodDeclParens() ? 1 : 0, true); + wrapList(cs.wrapMethodParams(), cs.alignMultilineMethodParams(), false, COMMA, recParams); + spaces(cs.spaceWithinMethodDeclParens() ? 1 : 0, true); // solves #7403 + } + accept(RPAREN); + List impls = node.getImplementsClause(); + if (impls != null && !impls.isEmpty()) { + wrapToken(cs.wrapExtendsImplementsKeyword(), 1, IMPLEMENTS); + wrapList(cs.wrapExtendsImplementsList(), cs.alignMultilineImplements(), true, COMMA, impls); + } + continuationIndent = oldContinuationIndent; - continuationIndent = old; - try { - if (members != null && !members.isEmpty()) { + int lastMaxPreservedBlankLines = maxPreservedBlankLines; + maxPreservedBlankLines = cs.getMaximumBlankLinesInDeclarations(); - boolean isFirstMember = true; - blankLines(node.getSimpleName().length() == 0 ? 0 : cs.getBlankLinesAfterClassHeader()); - for (Tree member : members) { - 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()); + CodeStyle.BracePlacement bracePlacement = cs.getClassDeclBracePlacement(); + boolean spaceBeforeLeftBrace = cs.spaceBeforeClassDeclLeftBrace(); + + // check for empty {} body and leave as is across all brace placement modes + int i = tokens.index(); + int c = col; + Diff d = diffs.isEmpty() ? null : diffs.getFirst(); + spaces(spaceBeforeLeftBrace ? 1 : 0, tokens.offset() < startOffset); + accept(LBRACE); + if (tokens.token().id() == RBRACE) { + accept(RBRACE); + return true; + } else { + // not empty body so rollback and continue + rollback(i, c, d); + } + + int oldIndent = 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; + } + + if (members != null && !members.isEmpty()) { + + boolean isFirstMember = true; + blankLines(node.getSimpleName().length() == 0 ? 0 : cs.getBlankLinesAfterClassHeader()); + for (Tree member : members) { + 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()); } - if (isFirstMember) { - isFirstMember = false; + break; + default: + if (!isFirstMember) { + blankLines(cs.getBlankLinesBeforeMethods()); } - } + scan(member, p); + blankLines(cs.getBlankLinesAfterMethods()); + } + if (isFirstMember) { + isFirstMember = false; } - } finally { - indent = oldIndent; - lastIndent = oldLastIndent; - continuationIndent = old; - maxPreservedBlankLines = lastMaxPreservedBlankLines; } - newline(); - accept(RBRACE); - } finally { - continuationIndent = old; } + indent = halfIndent; + newline(); + accept(RBRACE); + indent = lastIndent = oldIndent; + continuationIndent = oldContinuationIndent; + maxPreservedBlankLines = lastMaxPreservedBlankLines; return true; } 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 fb1dbcf5dac4..e7caf2bd3467 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 @@ -6696,7 +6696,7 @@ public void testRecord1() throws Exception { try { SourceVersion.valueOf("RELEASE_16"); //NOI18N } catch (IllegalArgumentException ex) { - //OK, no RELEASE_14, skip test + //OK, no RELEASE_16, skip test return; } sourceLevel="16"; @@ -6732,7 +6732,7 @@ public void testRecord2() throws Exception { try { SourceVersion.valueOf("RELEASE_16"); //NOI18N } catch (IllegalArgumentException ex) { - //OK, no RELEASE_14, skip test + //OK, no RELEASE_16, skip test return; } sourceLevel="16"; @@ -6774,7 +6774,7 @@ public void testRecord3() throws Exception { try { SourceVersion.valueOf("RELEASE_16"); //NOI18N } catch (IllegalArgumentException ex) { - //OK, no RELEASE_14, skip test + //OK, no RELEASE_16, skip test return; } sourceLevel="16"; @@ -6811,7 +6811,7 @@ public void testRecord4() throws Exception { try { SourceVersion.valueOf("RELEASE_16"); //NOI18N } catch (IllegalArgumentException ex) { - //OK, no RELEASE_14, skip test + //OK, no RELEASE_16, skip test return; } sourceLevel="16"; @@ -6842,6 +6842,101 @@ public record g3(@Override int a, @Override int b) { reformat(doc, content, golden); } + public void testRecordBracePlacement() throws Exception { + try { + SourceVersion.valueOf("RELEASE_16"); //NOI18N + } catch (IllegalArgumentException ex) { + //OK, no RELEASE_16, skip test + return; + } + sourceLevel = "16"; + JavacParser.DISABLE_SOURCE_LEVEL_DOWNGRADE = true; + 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; + + public class Test { + + record R1(int x) {} + + record R2(int x, int y) { + + public void run() { + } + } + } + """; + reformat(doc, content, content); + Preferences preferences = MimeLookup.getLookup( + JavaTokenId.language().mimeType()).lookup(Preferences.class); + + preferences.put("classDeclBracePlacement", CodeStyle.BracePlacement.NEW_LINE.name()); + String golden = """ + package hierbas.del.litoral; + + public class Test + { + + record R1(int x) {} + + record R2(int x, int y) + { + + public void run() { + } + } + } + """; + reformat(doc, content, golden); + + preferences.put("classDeclBracePlacement", + CodeStyle.BracePlacement.NEW_LINE_HALF_INDENTED.name()); + golden = """ + package hierbas.del.litoral; + + public class Test + { + + record R1(int x) {} + + record R2(int x, int y) + { + + public void run() { + } + } + } + """; + reformat(doc, content, golden); + + preferences.put("classDeclBracePlacement", + CodeStyle.BracePlacement.NEW_LINE_INDENTED.name()); + golden = """ + package hierbas.del.litoral; + + public class Test + { + + record R1(int x) {} + + record R2(int x, int y) + { + + public void run() { + } + } + } + """; + reformat(doc, content, golden); + + } + // #6573 public void testRecordConstructorReformat() throws Exception { sourceLevel="16";