diff --git a/build.gradle b/build.gradle index eea5cdb9..e74c8882 100644 --- a/build.gradle +++ b/build.gradle @@ -86,9 +86,6 @@ dependencies { extraJavaModuleInfo { failOnMissingModuleInfo.set(false) // because of transitive dependencies - // Mapping-IO - automaticModule("net.fabricmc:mapping-io", "net.fabricmc.mappingio") - // CFR automaticModule("net.fabricmc:cfr", "cfr") diff --git a/gradle.properties b/gradle.properties index 555e1461..2c775d7f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,19 +2,19 @@ org.gradle.jvmargs=-Xmx2G # Gradle Plugins -javafx_plugin_version = 0.0.13 +javafx_plugin_version = 0.1.0 shadow_version = 7.1.2 -extra_java_module_info_version = 1.3 +extra_java_module_info_version = 1.6 # Poject Properties version = 0.1.0 # Project Dependencies -asm_version = 9.4 -fabric_cfr_version = 0.2.0 +asm_version = 9.6 +fabric_cfr_version = 0.2.1 vineflower_version = 1.9.3 procyon_version = 0.6.0 -mappingio_version = 0.3.0 -javaparser_version = 3.24.2 -javafx_version = 17.0.2 -checkstyle_version = 10.3.4 +mappingio_version = 0.5.0 +javaparser_version = 3.25.6 +javafx_version = 21.0.1 +checkstyle_version = 10.12.5 diff --git a/src/main/java/matcher/gui/menu/FileMenu.java b/src/main/java/matcher/gui/menu/FileMenu.java index 59a7f9da..8a1f93dc 100644 --- a/src/main/java/matcher/gui/menu/FileMenu.java +++ b/src/main/java/matcher/gui/menu/FileMenu.java @@ -65,21 +65,17 @@ private void init() { getItems().add(menuItem); menuItem.setOnAction(event -> loadMappings(null)); - menuItem = new MenuItem("Load mappings (Enigma)"); + menuItem = new MenuItem("Load mappings (Enigma dir)"); getItems().add(menuItem); - menuItem.setOnAction(event -> loadMappings(MappingFormat.ENIGMA)); - - menuItem = new MenuItem("Load mappings (MCP dir)"); - getItems().add(menuItem); - menuItem.setOnAction(event -> loadMappings(MappingFormat.MCP)); + menuItem.setOnAction(event -> loadMappings(MappingFormat.ENIGMA_DIR)); menuItem = new MenuItem("Save mappings"); getItems().add(menuItem); menuItem.setOnAction(event -> saveMappings(null)); - menuItem = new MenuItem("Save mappings (Enigma)"); + menuItem = new MenuItem("Save mappings (Enigma dir)"); getItems().add(menuItem); - menuItem.setOnAction(event -> saveMappings(MappingFormat.ENIGMA)); + menuItem.setOnAction(event -> saveMappings(MappingFormat.ENIGMA_DIR)); menuItem = new MenuItem("Clear mappings"); getItems().add(menuItem); @@ -361,7 +357,7 @@ private static boolean isDirEmpty(Path dir) { } private static MappingFormat getFormat(Path file) { - if (Files.isDirectory(file)) return MappingFormat.ENIGMA; + if (Files.isDirectory(file)) return MappingFormat.ENIGMA_DIR; String name = file.getFileName().toString().toLowerCase(Locale.ENGLISH); diff --git a/src/main/java/matcher/mapping/MappingWriterImpl.java b/src/main/java/matcher/mapping/MappingWriterImpl.java deleted file mode 100644 index 55847100..00000000 --- a/src/main/java/matcher/mapping/MappingWriterImpl.java +++ /dev/null @@ -1,346 +0,0 @@ -package matcher.mapping; - -import java.io.Closeable; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.io.Writer; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.util.EnumSet; -import java.util.List; -import java.util.Set; - -import net.fabricmc.mappingio.FlatMappingVisitor; -import net.fabricmc.mappingio.MappingFlag; -import net.fabricmc.mappingio.format.MappingFormat; - -public class MappingWriterImpl implements FlatMappingVisitor, Closeable { - public MappingWriterImpl(Path file, MappingFormat format) throws IOException { - this.file = file; - this.format = format; - - switch (format) { - case TINY: - case SRG: - writer = Files.newBufferedWriter(file, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE); - break; - default: - throw new IllegalArgumentException("invalid mapping format: "+format.name()); - } - } - - @Override - public Set getFlags() { - Set ret = EnumSet.of(MappingFlag.NEEDS_UNIQUENESS); - - ret.add(MappingFlag.NEEDS_SRC_METHOD_DESC); - - if (format == MappingFormat.SRG || format == MappingFormat.MCP) { - ret.add(MappingFlag.NEEDS_DST_METHOD_DESC); - } else { - ret.add(MappingFlag.NEEDS_SRC_FIELD_DESC); - } - - return ret; - } - - @Override - public void visitNamespaces(String srcNamespace, List dstNamespaces) { - try { - switch (format) { - case TINY: - writer.write("v1\t"); - writer.write(srcNamespace); - - for (String dstNamespace : dstNamespaces) { - writer.write('\t'); - writer.write(dstNamespace); - } - - writer.write('\n'); - break; - case MCP: - case SRG: - // not supported - break; - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Override - public void visitMetadata(String key, String value) { - try { - switch (format) { - case TINY: - switch (key) { - case Mappings.metaUidNextClass: - case Mappings.metaUidNextMethod: - case Mappings.metaUidNextField: - writer.write("# INTERMEDIARY-COUNTER "); - writer.write(key.equals(Mappings.metaUidNextClass) ? "class" : (key.equals(Mappings.metaUidNextMethod) ? "method" : "field")); - writer.write(' '); - writer.write(value); - writer.write('\n'); - break; - default: - // not supported - } - - break; - case MCP: - case SRG: - // not supported - break; - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Override - public boolean visitClass(String srcName, String[] dstNames) { - try { - switch (format) { - case TINY: - if (isAnyPresent(dstNames)) { - writer.write("CLASS\t"); - writer.write(srcName); - - for (String dstName : dstNames) { - writer.write('\t'); - - if (dstName != null) { - writer.write(dstName); - } - } - - writer.write('\n'); - } - - break; - case SRG: - if (isFirstPresent(dstNames)) { - writer.write("CL: "); - writer.write(srcName); - writer.write(' '); - writer.write(dstNames[0]); - writer.write('\n'); - } - - break; - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - - return true; - } - - @Override - public void visitClassComment(String srcName, String[] dstNames, String comment) { - switch (format) { - case TINY: - case SRG: - // not supported - break; - } - } - - @Override - public boolean visitMethod(String srcClsName, String srcName, String srcDesc, String[] dstClsNames, String[] dstNames, String[] dstDescs) { - try { - switch (format) { - case TINY: - if (isAnyPresent(dstNames)) { - writer.write("METHOD\t"); - writer.write(srcClsName); - writer.write('\t'); - writer.write(srcDesc); - writer.write('\t'); - writer.write(srcName); - - for (String dstName : dstNames) { - writer.write('\t'); - if (dstName != null) writer.write(dstName); - } - - writer.write('\n'); - } - - break; - case SRG: - if (isFirstPresent(dstNames)) { - writer.write("MD: "); - writer.write(srcClsName); - writer.write('/'); - writer.write(srcName); - writer.write(' '); - writer.write(srcDesc); - writer.write(' '); - writer.write(isFirstPresent(dstClsNames) ? dstClsNames[0] : srcClsName); // TODO: handle null better - writer.write('/'); - writer.write(dstNames[0]); - writer.write(' '); - writer.write(dstDescs[0]); // TODO: handle null - writer.write('\n'); - } - - break; - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - - return true; - } - - @Override - public void visitMethodComment(String srcClsName, String srcName, String srcDesc, - String[] dstClsNames, String[] dstNames, String[] dstDescs, - String comment) { - switch (format) { - case TINY: - case SRG: - // not supported - break; - } - } - - @Override - public boolean visitMethodArg(String srcClsName, String srcMethodName, String srcMethodDesc, int argPosition, int lvIndex, String srcArgName, - String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstArgNames) { - switch (format) { - case TINY: - case SRG: - // not supported - return false; - } - - return true; - } - - @Override - public void visitMethodArgComment(String srcClsName, String srcMethodName, String srcMethodDesc, int argIndex, int lvIndex, String srcArgName, - String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstArgNames, - String comment) { - switch (format) { - case TINY: - case SRG: - // not supported - break; - } - } - - @Override - public boolean visitMethodVar(String srcClsName, String srcMethodName, String srcMethodDesc, - int asmIndex, int lvIndex, int startOpIdx, String srcVarName, - String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstVarNames) { - switch (format) { - case TINY: - case SRG: - // not supported - return false; - } - - return true; - } - - @Override - public void visitMethodVarComment(String srcClsName, String srcMethodName, String srcMethodDesc, - int asmIndex, int lvIndex, int startOpIdx, String srcVarName, - String[] dstClsNames, String[] dstMethodNames, String[] dstMethodDescs, String[] dstVarNames, - String comment) { - switch (format) { - case TINY: - case SRG: - // not supported - break; - } - } - - @Override - public boolean visitField(String srcClsName, String srcName, String srcDesc, String[] dstClsNames, String[] dstNames, String[] dstDescs) { - try { - switch (format) { - case TINY: - if (isAnyPresent(dstNames)) { - writer.write("FIELD\t"); - writer.write(srcClsName); - writer.write('\t'); - writer.write(srcDesc); - writer.write('\t'); - writer.write(srcName); - - for (String dstName : dstNames) { - writer.write('\t'); - if (dstName != null) writer.write(dstName); - } - - writer.write('\n'); - } - - break; - case SRG: - if (isFirstPresent(dstNames)) { - writer.write("FD: "); - writer.write(srcClsName); - writer.write('/'); - writer.write(srcName); - writer.write(' '); - writer.write(isFirstPresent(dstClsNames) ? dstClsNames[0] : srcClsName); - writer.write('/'); - writer.write(dstNames[0]); - writer.write('\n'); - } - - break; - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - - return true; - } - - @Override - public void visitFieldComment(String srcClsName, String srcName, String srcDesc, - String[] dstClsNames, String[] dstNames, String[] dstDescs, - String comment) { - switch (format) { - case TINY: - case SRG: - // not supported - break; - } - } - - public void flush() throws IOException { - if (writer != null) writer.flush(); - } - - @Override - public void close() throws IOException { - if (writer != null) writer.close(); - } - - private static boolean isAnyPresent(String[] strs) { - if (strs == null) return false; - - for (String s : strs) { - if (s != null) return true; - } - - return false; - } - - private static boolean isFirstPresent(String[] strs) { - return strs != null && strs.length > 0 && strs[0] != null; - } - - private final Path file; - private final MappingFormat format; - private final Writer writer; -} diff --git a/src/main/java/matcher/mapping/Mappings.java b/src/main/java/matcher/mapping/Mappings.java index 97827a78..0194a08f 100644 --- a/src/main/java/matcher/mapping/Mappings.java +++ b/src/main/java/matcher/mapping/Mappings.java @@ -1,8 +1,6 @@ package matcher.mapping; -import java.io.Closeable; import java.io.IOException; -import java.io.UncheckedIOException; import java.net.URI; import java.nio.file.Path; import java.util.ArrayList; @@ -124,7 +122,7 @@ public boolean visitMethodArg(int argPosition, int lvIndex, String srcArgName) { } @Override - public boolean visitMethodVar(int asmIndex, int lvIndex, int startOpIdx, String srcArgName) { + public boolean visitMethodVar(int asmIndex, int lvIndex, int startOpIdx, int endOpIdx, String srcArgName) { arg = null; cur = var = getMethodVar(-1, lvIndex, startOpIdx, asmIndex, false); @@ -511,67 +509,61 @@ public static boolean save(Path file, MappingFormat format, LocalClassEnv env, List vars = new ArrayList<>(); Set> exportedHierarchies = verbosity == MappingsExportVerbosity.MINIMAL ? Util.newIdentityHashSet() : null; - try (Closeable closable = format == MappingFormat.TINY_2 || format == MappingFormat.ENIGMA ? MappingWriter.create(file, format) : new MappingWriterImpl(file, format)) { - FlatMappingVisitor writer = closable instanceof FlatMappingVisitor ? (FlatMappingVisitor) closable : new RegularAsFlatMappingVisitor((MappingVisitor) closable); + FlatMappingVisitor writer = new RegularAsFlatMappingVisitor(MappingWriter.create(file, format)); + writer.visitNamespaces(nsNames.get(0), nsNames.subList(1, nsNames.size())); - writer.visitNamespaces(nsNames.get(0), nsNames.subList(1, nsNames.size())); - - for (ClassInstance cls : classes) { - String srcClsName = cls.getName(nsTypes.get(0)); - if (srcClsName == null) continue; - boolean hasAnyDstName = false; - - for (int i = 1; i < nsTypes.size(); i++) { - NameType dstType = nsTypes.get(i); - String dstName = cls.getName(dstType); // FIXME: this may actually not be unique, record exported and suffix conflicting? - - if (dstName != null && (dstName.equals(srcClsName) || dstType != dstType.withMapped(false) && cls.hasNoFullyMappedName())) { - // don't save no-op or partial mappings (partial = only outer class is mapped) - dstName = null; - } + for (ClassInstance cls : classes) { + String srcClsName = cls.getName(nsTypes.get(0)); + if (srcClsName == null) continue; + boolean hasAnyDstName = false; - hasAnyDstName |= dstName != null; - dstClassNames[i - 1] = dstName; - } + for (int i = 1; i < nsTypes.size(); i++) { + NameType dstType = nsTypes.get(i); + String dstName = cls.getName(dstType); // FIXME: this may actually not be unique, record exported and suffix conflicting? - if (!hasAnyDstName - && (!format.supportsComments || cls.getMappedComment() == null) - && !shouldExportAny(cls.getMethods(), format, nsTypes, verbosity, forAnyInput, exportedHierarchies) - && !shouldExportAny(cls.getFields(), format, nsTypes)) { - continue; // no data for the class, skip + if (dstName != null && (dstName.equals(srcClsName) || dstType != dstType.withMapped(false) && cls.hasNoFullyMappedName())) { + // don't save no-op or partial mappings (partial = only outer class is mapped) + dstName = null; } - if (!writer.visitClass(srcClsName, dstClassNames)) { - continue; - } + hasAnyDstName |= dstName != null; + dstClassNames[i - 1] = dstName; + } - // comment + if (!hasAnyDstName + && (!format.supportsComments || cls.getMappedComment() == null) + && !shouldExportAny(cls.getMethods(), format, nsTypes, verbosity, forAnyInput, exportedHierarchies) + && !shouldExportAny(cls.getFields(), format, nsTypes)) { + continue; // no data for the class, skip + } - if (cls.getMappedComment() != null) writer.visitClassComment(srcClsName, dstClassNames, cls.getMappedComment()); + if (!writer.visitClass(srcClsName, dstClassNames)) { + continue; + } - if (fieldsFirst) { - exportFields(cls, srcClsName, dstClassNames, format, nsTypes, - dstMemberNames, dstMemberDescs, fields, memberCmp, writer); - } + // comment - exportMethods(cls, srcClsName, dstClassNames, - format, nsTypes, verbosity, forAnyInput, - dstMemberNames, dstMemberDescs, dstVarNames, - methods, vars, exportedHierarchies, - memberCmp, methodArgCmp, methodVarCmp, - writer); + if (cls.getMappedComment() != null) writer.visitClassComment(srcClsName, dstClassNames, cls.getMappedComment()); - if (!fieldsFirst) { - exportFields(cls, srcClsName, dstClassNames, format, nsTypes, - dstMemberNames, dstMemberDescs, fields, memberCmp, writer); - } + if (fieldsFirst) { + exportFields(cls, srcClsName, dstClassNames, format, nsTypes, + dstMemberNames, dstMemberDescs, fields, memberCmp, writer); } - writer.visitEnd(); - } catch (UncheckedIOException e) { - throw e.getCause(); + exportMethods(cls, srcClsName, dstClassNames, + format, nsTypes, verbosity, forAnyInput, + dstMemberNames, dstMemberDescs, dstVarNames, + methods, vars, exportedHierarchies, + memberCmp, methodArgCmp, methodVarCmp, + writer); + + if (!fieldsFirst) { + exportFields(cls, srcClsName, dstClassNames, format, nsTypes, + dstMemberNames, dstMemberDescs, fields, memberCmp, writer); + } } + writer.visitEnd(); return true; } @@ -672,7 +664,7 @@ private static void exportMethods(ClassInstance cls, String srcClsName, String[] dstClassNames, dstMethodNames, dstMemberDescs, dstVarNames); } else { writer.visitMethodVar(srcClsName, srcName, desc, - var.getAsmIndex(), var.getLvIndex(), var.getStartOpIdx(), srcVarName, + var.getAsmIndex(), var.getLvIndex(), var.getStartOpIdx(), -1, srcVarName, dstClassNames, dstMethodNames, dstMemberDescs, dstVarNames); } } @@ -687,7 +679,7 @@ private static void exportMethods(ClassInstance cls, String srcClsName, String[] comment); } else { writer.visitMethodVarComment(srcClsName, srcName, desc, - var.getAsmIndex(), var.getLvIndex(), var.getStartOpIdx(), srcVarName, + var.getAsmIndex(), var.getLvIndex(), var.getStartOpIdx(), -1, srcVarName, dstClassNames, dstMethodNames, dstMemberDescs, dstVarNames, comment); } diff --git a/src/main/java/matcher/srcprocess/HtmlPrinter.java b/src/main/java/matcher/srcprocess/HtmlPrinter.java index 4598f4ce..1bca18ca 100644 --- a/src/main/java/matcher/srcprocess/HtmlPrinter.java +++ b/src/main/java/matcher/srcprocess/HtmlPrinter.java @@ -1,5 +1,5 @@ /* - * Most of this file is copied from DefaultPrettyPrinterVisitor, + * Most of this file is copied from DefaultPrettyPrinterVisitor (commit 19e0559), * tweaked to output HTML instead of plain text. Original license: * * Copyright (C) 2011, 2013-2021 The JavaParser Team. @@ -27,13 +27,12 @@ import static com.github.javaparser.utils.Utils.isNullOrEmpty; import java.util.ArrayList; -import java.util.Arrays; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.Collectors; +import java.util.regex.Pattern; import com.github.javaparser.ast.ArrayCreationLevel; import com.github.javaparser.ast.ImportDeclaration; @@ -216,7 +215,7 @@ protected void printTypeArgs(final NodeWithTypeArguments nodeWithTypeArgument NodeList typeArguments = nodeWithTypeArguments.getTypeArguments().orElse(null); if (!isNullOrEmpty(typeArguments)) { - printer.print("<"); + printer.print("<"); // < for (final Iterator i = typeArguments.iterator(); i.hasNext(); ) { final Type t = i.next(); @@ -227,14 +226,14 @@ protected void printTypeArgs(final NodeWithTypeArguments nodeWithTypeArgument } } - printer.print(">"); + printer.print(">"); // > } } @Override protected void printTypeParameters(final NodeList args, final Void arg) { if (!isNullOrEmpty(args)) { - printer.print("<"); + printer.print("<"); // < for (final Iterator i = args.iterator(); i.hasNext(); ) { final TypeParameter t = i.next(); @@ -245,7 +244,7 @@ protected void printTypeParameters(final NodeList args, final Voi } } - printer.print(">"); + printer.print(">"); // > } } @@ -318,6 +317,19 @@ public void visit(final ClassOrInterfaceDeclaration n, final Void arg) { } } + if (!n.getPermittedTypes().isEmpty()) { + printer.print(" permits "); + + for (final Iterator i = n.getPermittedTypes().iterator(); i.hasNext(); ) { + final ClassOrInterfaceType c = i.next(); + c.accept(this, arg); + + if (i.hasNext()) { + printer.print(", "); + } + } + } + printer.println(" {"); printer.indent(); @@ -344,6 +356,8 @@ public void visit(RecordDeclaration n, Void arg) { n.getName().accept(this, arg); printer.print(""); + printTypeParameters(n.getTypeParameters(), arg); + printer.print("("); if (!isNullOrEmpty(n.getParameters())) { @@ -358,7 +372,6 @@ public void visit(RecordDeclaration n, Void arg) { } printer.print(")"); - printTypeParameters(n.getTypeParameters(), arg); if (!n.getImplementedTypes().isEmpty()) { printer.print(" implements "); @@ -391,12 +404,11 @@ public void visit(final JavadocComment n, final Void arg) { printOrphanCommentsBeforeThisChildNode(n); if (getOption(ConfigOption.PRINT_COMMENTS).isPresent() && getOption(ConfigOption.PRINT_JAVADOC).isPresent()) { - printer.println("/**"); + printer.print(""); + printer.println(n.getHeader()); final String commentContent = Utils.normalizeEolInTextBlock(HtmlUtil.escape(n.getContent()), getOption(ConfigOption.END_OF_LINE_CHARACTER).get().asString()); String[] lines = commentContent.split("\\R"); - boolean skippingLeadingEmptyLines = true; - boolean prependEmptyLine = false; - boolean prependSpace = Arrays.stream(lines).anyMatch(line -> !line.isEmpty() && !line.startsWith(" ")); + List strippedLines = new ArrayList<>(); for (String line : lines) { final String trimmedLine = line.trim(); @@ -406,7 +418,14 @@ public void visit(final JavadocComment n, final Void arg) { } line = Utils.trimTrailingSpaces(line); + strippedLines.add(line); + } + boolean skippingLeadingEmptyLines = true; + boolean prependEmptyLine = false; + boolean prependSpace = strippedLines.stream().anyMatch(line -> !line.isEmpty() && !line.startsWith(" ")); + + for (String line : strippedLines) { if (line.isEmpty()) { if (!skippingLeadingEmptyLines) { prependEmptyLine = true; @@ -429,7 +448,9 @@ public void visit(final JavadocComment n, final Void arg) { } } - printer.println(" */"); + printer.print(" ") + .print(n.getFooter()) + .println(""); } } @@ -678,11 +699,11 @@ public void visit(final InstanceOfExpr n, final Void arg) { printComment(n.getComment(), arg); n.getExpression().accept(this, arg); printer.print(" instanceof "); - n.getType().accept(this, arg); - if (n.getName().isPresent()) { - printer.print(" "); - n.getName().get().accept(this, arg); + if (n.getPattern().isPresent()) { + n.getPattern().get().accept(this, arg); + } else { + n.getType().accept(this, arg); } } @@ -983,6 +1004,13 @@ public void visit(final ConstructorDeclaration n, final Void arg) { printer.print(""); printer.print("("); + n.getReceiverParameter().ifPresent(rp -> { + rp.accept(this, arg); + + if (!isNullOrEmpty(n.getParameters())) { + printer.print(", "); + } + }); if (!n.getParameters().isEmpty()) { for (final Iterator i = n.getParameters().iterator(); i.hasNext(); ) { @@ -1024,7 +1052,6 @@ public void visit(final CompactConstructorDeclaration n, final Void arg) { printComment(n.getComment(), arg); printMemberAnnotations(n.getAnnotations(), arg); printModifiers(n.getModifiers()); - printTypeParameters(n.getTypeParameters(), arg); if (n.isGeneric()) { @@ -1065,7 +1092,6 @@ public void visit(final MethodDeclaration n, final Void arg) { } printOrphanCommentsBeforeThisChildNode(n); - printComment(n.getComment(), arg); printMemberAnnotations(n.getAnnotations(), arg); printModifiers(n.getModifiers()); @@ -1209,13 +1235,13 @@ private void printSwitchNode(SwitchNode n, Void arg) { printer.println(") {"); if (n.getEntries() != null) { - if (getOption(ConfigOption.INDENT_CASE_IN_SWITCH).isPresent()) printer.indent(); + indentIf(getOption(ConfigOption.INDENT_CASE_IN_SWITCH).isPresent()); for (final SwitchEntry e : n.getEntries()) { e.accept(this, arg); } - if (getOption(ConfigOption.INDENT_CASE_IN_SWITCH).isPresent()) printer.indent(); + unindentIf(getOption(ConfigOption.INDENT_CASE_IN_SWITCH).isPresent()); } printer.print("}"); @@ -1748,8 +1774,9 @@ public void visit(final LineComment n, final Void arg) { } printer.print(""); - printer.print("// ") - .println(Utils.normalizeEolInTextBlock(HtmlUtil.escape(n.getContent()), "").trim()); + printer.print(n.getHeader()) + .print(" ") + .println(Utils.normalizeEolInTextBlock(HtmlUtil.escape(RTRIM.matcher(n.getContent()).replaceAll("")), "")); printer.println(""); } @@ -1761,15 +1788,17 @@ public void visit(final BlockComment n, final Void arg) { final String commentContent = Utils.normalizeEolInTextBlock(n.getContent(), getOption(ConfigOption.END_OF_LINE_CHARACTER).get().asString()); String[] lines = commentContent.split("\\R", -1); // as BlockComment should not be formatted, -1 to preserve any trailing empty line if present - printer.print("/*"); + printer.print(""); + printer.print(n.getHeader()); for (int i = 0; i < (lines.length - 1); i++) { printer.print(lines[i]); printer.print(getOption(ConfigOption.END_OF_LINE_CHARACTER).get().asString()); // Avoids introducing indentation in blockcomments. ie: do not use println() as it would trigger indentation at the next print call. } - printer.print(lines[lines.length - 1]); // last line is not followed by a newline, and simply terminated with `*/` - printer.println("*/"); + printer.print(lines[lines.length - 1]) // last line is not followed by a newline, and simply terminated with `*/` + .print(n.getFooter()) + .println(""); } @Override @@ -1893,8 +1922,7 @@ private void printOrphanCommentsBeforeThisChildNode(final Node node) { private void printOrphanCommentsEnding(final Node node) { if (!getOption(ConfigOption.PRINT_COMMENTS).isPresent()) return; - // extract all nodes for which the position/range is indicated to avoid to skip orphan comments - List everything = node.getChildNodes().stream().filter(n -> n.getRange().isPresent()).collect(Collectors.toList()); + List everything = new ArrayList<>(node.getChildNodes()); sortByBeginPosition(everything); if (everything.isEmpty()) { @@ -1918,6 +1946,20 @@ private void printOrphanCommentsEnding(final Node node) { } } + private void indentIf(boolean expr) { + if (expr) printer.indent(); + } + + private void unindentIf(boolean expr) { + if (expr) printer.unindent(); + } + + private Optional getOption(ConfigOption option) { + return configuration.get(new DefaultConfigurationOption(option)); + } + + // Matcher-introduced methods + private static boolean canAddNewLine(Node n) { Node prev = getPrev(n); @@ -1955,10 +1997,7 @@ private static Node getNext(Node n) { return parent.getChildNodes().get(idx + 1); } - private Optional getOption(ConfigOption option) { - return configuration.get(new DefaultConfigurationOption(option)); - } - + private static Pattern RTRIM = Pattern.compile("\\s+$"); protected final TypeResolver typeResolver; protected boolean instantiationAhead; protected int recursionCounter;