org.openrewrite.java.format.BlankLinesVisitor Maven / Gradle / Ivy
Show all versions of rewrite-java Show documentation
/*
* Copyright 2020 the original author or authors.
*
* 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
*
* https://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.openrewrite.java.format;
import org.jspecify.annotations.Nullable;
import org.openrewrite.Tree;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.style.BlankLinesStyle;
import org.openrewrite.java.tree.*;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import static java.util.Objects.requireNonNull;
public class BlankLinesVisitor
extends JavaIsoVisitor
{
@Nullable
private final Tree stopAfter;
private final BlankLinesStyle style;
public BlankLinesVisitor(BlankLinesStyle style) {
this(style, null);
}
public BlankLinesVisitor(BlankLinesStyle style, @Nullable Tree stopAfter) {
this.style = style;
this.stopAfter = stopAfter;
}
@Override
public J visit(@Nullable Tree tree, P p) {
if (getCursor().getNearestMessage("stop") != null) {
return (J) tree;
}
if (tree instanceof JavaSourceFile) {
JavaSourceFile cu = (JavaSourceFile) requireNonNull(tree);
if (cu.getPackageDeclaration() != null) {
if (!cu.getPrefix().getComments().isEmpty()) {
cu = cu.withComments(ListUtils.mapLast(cu.getComments(), c -> {
String suffix = keepMaximumLines(c.getSuffix(), style.getKeepMaximum().getBetweenHeaderAndPackage());
suffix = minimumLines(suffix, style.getMinimum().getBeforePackage());
return c.withSuffix(suffix);
}));
} else {
/*
if comments are empty and package is present, leading whitespace is on the compilation unit and
should be removed
*/
cu = cu.withPrefix(Space.EMPTY);
}
}
if (cu.getPackageDeclaration() == null) {
if (cu.getComments().isEmpty()) {
/*
if package decl and comments are null/empty, leading whitespace is on the
compilation unit and should be removed
*/
cu = cu.withPrefix(Space.EMPTY);
} else {
cu = cu.withComments(ListUtils.mapLast(cu.getComments(), c ->
c.withSuffix(minimumLines(c.getSuffix(), style.getMinimum().getBeforeImports()))));
}
} else {
cu = cu.getPadding().withImports(ListUtils.mapFirst(cu.getPadding().getImports(), i ->
minimumLines(i, style.getMinimum().getAfterPackage())));
}
return super.visit(cu, p);
}
return super.visit(tree, p);
}
@Override
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, P p) {
J.ClassDeclaration j = super.visitClassDeclaration(classDecl, p);
if (j.getBody() != null) {
List> statements = j.getBody().getPadding().getStatements();
J.ClassDeclaration.Kind.Type classKind = j.getKind();
j = j.withBody(j.getBody().getPadding().withStatements(ListUtils.map(statements, (i, s) -> {
if (i == 0) {
if (classKind != J.ClassDeclaration.Kind.Type.Enum) {
s = minimumLines(s, style.getMinimum().getAfterClassHeader());
}
} else if (statements.get(i - 1).getElement() instanceof J.Block) {
s = minimumLines(s, style.getMinimum().getAroundInitializer());
} else if (s.getElement() instanceof J.ClassDeclaration) {
// Apply `style.getMinimum().getAroundClass()` to inner classes.
s = minimumLines(s, style.getMinimum().getAroundClass());
}
return s;
})));
j = j.withBody(j.getBody().withEnd(minimumLines(j.getBody().getEnd(),
style.getMinimum().getBeforeClassEnd())));
}
JavaSourceFile cu = getCursor().firstEnclosingOrThrow(JavaSourceFile.class);
boolean hasImports = !cu.getImports().isEmpty();
boolean firstClass = j.equals(cu.getClasses().get(0));
Set classes = new HashSet<>(cu.getClasses());
j = firstClass ?
(hasImports ? minimumLines(j, style.getMinimum().getAfterImports()) : j) :
// Apply `style.getMinimum().getAroundClass()` to classes declared in the SourceFile.
(classes.contains(j)) ? minimumLines(j, style.getMinimum().getAroundClass()) : j;
// style.getKeepMaximum().getInDeclarations() also sets the maximum new lines of class declaration prefixes.
j = firstClass ?
(hasImports ? keepMaximumLines(j, Math.max(style.getKeepMaximum().getInDeclarations(), style.getMinimum().getAfterImports())) : j) :
(classes.contains(j)) ? keepMaximumLines(j, style.getKeepMaximum().getInDeclarations()) : j;
if (!hasImports && firstClass) {
if (cu.getPackageDeclaration() == null) {
if (!j.getPrefix().getWhitespace().isEmpty()) {
j = j.withPrefix(j.getPrefix().withWhitespace(""));
}
} else {
j = minimumLines(j, style.getMinimum().getAfterPackage());
}
}
return j;
}
@Override
public J.EnumValue visitEnumValue(J.EnumValue _enum, P p) {
J.EnumValue e = super.visitEnumValue(_enum, p);
return keepMaximumLines(e, style.getKeepMaximum().getInDeclarations());
}
@Override
public J.Import visitImport(J.Import import_, P p) {
J.Import i = super.visitImport(import_, p);
JavaSourceFile cu = getCursor().firstEnclosingOrThrow(JavaSourceFile.class);
if (i.equals(cu.getImports().get(0)) && cu.getPackageDeclaration() == null && cu.getPrefix().equals(Space.EMPTY)) {
i = i.withPrefix(i.getPrefix().withWhitespace(""));
}
return i;
}
@Override
public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, P p) {
J.MethodDeclaration j = super.visitMethodDeclaration(method, p);
if (j.getBody() != null) {
if (j.getBody().getStatements().isEmpty()) {
Space end = minimumLines(j.getBody().getEnd(),
style.getMinimum().getBeforeMethodBody());
if (end.getIndent().isEmpty() && style.getMinimum().getBeforeMethodBody() > 0) {
end = end.withWhitespace(end.getWhitespace() + method.getPrefix().getIndent());
}
j = j.withBody(j.getBody().withEnd(end));
} else {
j = j.withBody(j.getBody().withStatements(ListUtils.mapFirst(j.getBody().getStatements(), s ->
minimumLines(s, style.getMinimum().getBeforeMethodBody()))));
}
}
return j;
}
@Override
public J.NewClass visitNewClass(J.NewClass newClass, P p) {
J.NewClass j = super.visitNewClass(newClass, p);
if (j.getBody() != null) {
j = j.withBody(j.getBody().withStatements(ListUtils.mapFirst(j.getBody().getStatements(), s ->
minimumLines(s, style.getMinimum().getAfterAnonymousClassHeader()))));
}
return j;
}
@Override
public Statement visitStatement(Statement statement, P p) {
Statement j = super.visitStatement(statement, p);
Iterator