All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openrewrite.staticanalysis.FinalizeMethodArguments Maven / Gradle / Ivy

/**
 * Copyright 2023 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.staticanalysis; import lombok.EqualsAndHashCode; import lombok.Value; import org.openrewrite.*; import org.openrewrite.internal.ListUtils; import org.openrewrite.java.JavaIsoVisitor; import org.openrewrite.java.tree.*; import org.openrewrite.marker.Markers; import java.util.List; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; import static java.util.Collections.emptyList; /** * Finalize method arguments v2 */ public class FinalizeMethodArguments extends Recipe { @Override public String getDisplayName() { return "Finalize method arguments"; } @Override public String getDescription() { return "Adds the `final` modifier keyword to method parameters."; } @Override public TreeVisitor getVisitor() { return new JavaIsoVisitor() { @Override public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration methodDeclaration, ExecutionContext ctx) { J.MethodDeclaration declarations = super.visitMethodDeclaration(methodDeclaration, ctx); if (isWrongKind(methodDeclaration) || isEmpty(declarations.getParameters()) || hasFinalModifiers(declarations.getParameters()) || isAbstractMethod(methodDeclaration)) { return declarations; } final AtomicBoolean assigned = new AtomicBoolean(false); methodDeclaration.getParameters().forEach(p -> checkIfAssigned(assigned, p)); if (assigned.get()) { return declarations; } List parameters = ListUtils.map(declarations.getParameters(), FinalizeMethodArguments::updateParam); declarations = declarations.withParameters(parameters); return declarations; } private void checkIfAssigned(final AtomicBoolean assigned, final Statement p) { if (p instanceof J.VariableDeclarations) { J.VariableDeclarations variableDeclarations = (J.VariableDeclarations) p; if (variableDeclarations.getVariables().stream() .anyMatch(namedVariable -> FindAssignmentReferencesToVariable.find(getCursor() .getParentTreeCursor() .getValue(), namedVariable) .get())) { assigned.set(true); } } } }; } private static boolean isWrongKind(final J.MethodDeclaration methodDeclaration) { return Optional.ofNullable(methodDeclaration.getMethodType()) .map(JavaType.Method::getDeclaringType) .map(JavaType.FullyQualified::getKind) .filter(JavaType.FullyQualified.Kind.Interface::equals) .isPresent(); } private static boolean isAbstractMethod(J.MethodDeclaration method) { return method.getModifiers().stream().anyMatch(modifier -> modifier.getType() == J.Modifier.Type.Abstract); } @Value @EqualsAndHashCode(callSuper = false) private static class FindAssignmentReferencesToVariable extends JavaIsoVisitor { J.VariableDeclarations.NamedVariable variable; /** * @param subtree The subtree to search. * @param variable A {@link J.VariableDeclarations.NamedVariable} to check for any reassignment calls. * @return An {@link AtomicBoolean} that is true if the variable has been reassigned and false otherwise. */ static AtomicBoolean find(J subtree, J.VariableDeclarations.NamedVariable variable) { return new FindAssignmentReferencesToVariable(variable) .reduce(subtree, new AtomicBoolean()); } @Override public J.Assignment visitAssignment(J.Assignment a, AtomicBoolean hasAssignment) { // Return quickly if the variable has been reassigned before if (hasAssignment.get()) { return a; } J.Assignment assignment = super.visitAssignment(a, hasAssignment); if (assignment.getVariable() instanceof J.Identifier) { J.Identifier identifier = (J.Identifier) assignment.getVariable(); if (identifier.getSimpleName().equals(variable.getSimpleName())) { hasAssignment.set(true); } } return assignment; } @Override public J.Unary visitUnary(final J.Unary unary, final AtomicBoolean hasAssignment) { if (hasAssignment.get()) { return unary; } final J.Unary u = super.visitUnary(unary, hasAssignment); if (u.getOperator().isModifying() && u.getExpression() instanceof J.Identifier) { final J.Identifier i = (J.Identifier) u.getExpression(); if (i.getSimpleName().equals(this.variable.getSimpleName())) { hasAssignment.set(true); } } return u; } @Override public J.AssignmentOperation visitAssignmentOperation(final J.AssignmentOperation assignOp, final AtomicBoolean hasAssignment) { if (hasAssignment.get()) { return assignOp; } final J.AssignmentOperation a = super.visitAssignmentOperation(assignOp, hasAssignment); if (a.getVariable() instanceof J.Identifier) { final J.Identifier i = (J.Identifier) a.getVariable(); if (i.getSimpleName().equals(this.variable.getSimpleName())) { hasAssignment.set(true); } } return a; } } private static Statement updateParam(final Statement p) { if (p instanceof J.VariableDeclarations) { J.VariableDeclarations variableDeclarations = (J.VariableDeclarations) p; if (variableDeclarations.getModifiers().isEmpty()) { variableDeclarations = updateModifiers(variableDeclarations, !((J.VariableDeclarations) p).getLeadingAnnotations().isEmpty()); variableDeclarations = updateDeclarations(variableDeclarations); return variableDeclarations; } } return p; } private static J.VariableDeclarations updateDeclarations(final J.VariableDeclarations variableDeclarations) { return variableDeclarations.withTypeExpression(variableDeclarations.getTypeExpression() != null ? variableDeclarations.getTypeExpression().withPrefix(Space.SINGLE_SPACE) : null); } private static J.VariableDeclarations updateModifiers(final J.VariableDeclarations variableDeclarations, final boolean leadingAnnotations) { List modifiers = variableDeclarations.getModifiers(); J.Modifier finalModifier = new J.Modifier(Tree.randomId(), Space.EMPTY, Markers.EMPTY, null, J.Modifier.Type.Final, emptyList()); if (leadingAnnotations) { finalModifier = finalModifier.withPrefix(Space.SINGLE_SPACE); } return variableDeclarations.withModifiers(ListUtils.concat(finalModifier, modifiers)); } private boolean hasFinalModifiers(final List parameters) { return parameters.stream().allMatch(p -> { if (p instanceof J.VariableDeclarations) { final List modifiers = ((J.VariableDeclarations) p).getModifiers(); return !modifiers.isEmpty() && modifiers.stream() .allMatch(m -> m.getType().equals(J.Modifier.Type.Final)); } return false; }); } private boolean isEmpty(final List parameters) { return parameters.size() == 1 && (parameters.get(0) instanceof J.Empty); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy