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

org.openrewrite.java.trait.VariableAccess Maven / Gradle / Ivy

There is a newer version: 8.40.2
Show newest version
/*
 * Copyright 2024 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.trait; import lombok.Value; import org.jspecify.annotations.Nullable; import org.openrewrite.*; import org.openrewrite.java.JavaVisitor; import org.openrewrite.java.trait.internal.MaybeParenthesesPair; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaType; import org.openrewrite.java.tree.Javadoc; import org.openrewrite.java.tree.TypeUtils; import org.openrewrite.trait.SimpleTraitMatcher; import org.openrewrite.trait.Trait; import org.openrewrite.trait.VisitFunction2; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; @Incubating(since = "8.30.0") @Value public class VariableAccess implements Trait { Cursor cursor; /** * A write access to a variable occurs as the destination of an assignment. */ public boolean isWriteAccess() { MaybeParenthesesPair pair = MaybeParenthesesPair.from(cursor); if (pair.getParent() instanceof J.Assignment) { J.Assignment assignment = (J.Assignment) pair.getParent(); return assignment.getVariable() == pair.getTree(); } if (pair.getParent() instanceof J.Unary) { J.Unary unary = (J.Unary) pair.getParent(); return unary.getExpression() == pair.getTree() && unary.getOperator().isModifying(); } return false; } /** * A read access to a variable. In other words, it is a variable access that does * _not_ occur as the destination of a simple assignment, but it may occur as * the destination of a compound assignment or a unary assignment. */ public boolean isReadAccess() { if (isWriteAccess()) { return false; } MaybeParenthesesPair pair = MaybeParenthesesPair.from(cursor); if (pair.getParent() instanceof J.Assignment) { J.Assignment assignment = (J.Assignment) pair.getParent(); return assignment.getVariable() != pair.getTree(); } if (pair.getParent() instanceof J.Unary) { J.Unary unary = (J.Unary) pair.getParent(); return unary.getExpression() == pair.getTree() && !unary.getOperator().isModifying(); } return true; } public static class Matcher extends SimpleTraitMatcher { private Predicate typeTest = t -> true; public Matcher isOfType(JavaType type) { this.typeTest = t -> TypeUtils.isOfType(t, type); return this; } public Matcher isOfClassType(String fullyQualifiedName) { this.typeTest = t -> TypeUtils.isOfClassType(t, fullyQualifiedName); return this; } @Override public

TreeVisitor asVisitor(VisitFunction2 visitor) { return new JavaVisitor

() { @Override public J visitIdentifier(J.Identifier ident, P p) { VariableAccess varAccess = test(getCursor()); return varAccess != null ? (J) visitor.visit(varAccess, p) : super.visitIdentifier(ident, p); } }; } /** * Since variable access is a trait of a leaf LST element (J.Identifier), * there are no higher elements in the tree that could potentially match. */ @Override public Stream higher(Cursor cursor) { return Stream.empty(); } @Override protected @Nullable VariableAccess test(Cursor cursor) { if (!(cursor.getValue() instanceof J.Identifier)) { return null; } J.Identifier ident = cursor.getValue(); String name = ident.getSimpleName(); if (name.equals("this") || name.equals("super") || checkNamePart(cursor, J.VariableDeclarations.NamedVariable.class, J.VariableDeclarations.NamedVariable::getName)) { return null; } if (ident.getFieldType() != null) { return checkFilters(cursor); } if (checkNamePart(cursor, J.ClassDeclaration.class, J.ClassDeclaration::getName) || checkNamePart(cursor, J.MethodDeclaration.class, J.MethodDeclaration::getName) || checkNamePart(cursor, J.MethodInvocation.class, J.MethodInvocation::getName) || checkNamePart(cursor, J.NewClass.class, J.NewClass::getClazz) || checkNamePart(cursor, J.FieldAccess.class, J.FieldAccess::getName) || checkNamePart(cursor, J.MethodInvocation.class, J.MethodInvocation::getName) || checkNamePart(cursor, J.ParameterizedType.class, J.ParameterizedType::getClazz) || cursor.firstEnclosing(Javadoc.class) != null) { return null; } Cursor parent = cursor.getParentTreeCursor(); if (checkParent(parent, J.TypeCast.class, j -> j.getClazz().getTree() == ident)) { return null; } // Special case for annotations, where the left side of the assignment is the annotation field name, // and not a variable access. if (checkNamePart(cursor, J.Assignment.class, J.Assignment::getVariable) && checkParent(parent, J.Annotation.class, j -> j.getArguments() != null && j.getArguments().contains(ident))) { return null; } if (checkNamePart(cursor, J.ArrayAccess.class, J.ArrayAccess::getIndexed) || checkNamePart(cursor, J.ArrayDimension.class, J.ArrayDimension::getIndex) || checkNamePart(cursor, J.ControlParentheses.class, J.ControlParentheses::getTree) || checkNamePart(cursor, J.ForEachLoop.Control.class, J.ForEachLoop.Control::getIterable) || checkNamePart(cursor, J.ForLoop.Control.class, J.ForLoop.Control::getCondition) || checkNamePart(cursor, J.Parentheses.class, J.Parentheses::getTree) || checkNamePart(cursor, J.TypeCast.class, J.TypeCast::getExpression) || checkNamePart(cursor, J.Unary.class, J.Unary::getExpression) || checkNamePart(cursor, J.VariableDeclarations.NamedVariable.class, J.VariableDeclarations.NamedVariable::getInitializer) || checkParent(cursor, J.Assignment.class, a -> a.getVariable() == ident || a.getAssignment() == ident) || checkParent(cursor, J.Binary.class, b -> b.getLeft() == ident || b.getRight() == ident) || checkParent(cursor, J.MethodInvocation.class, m -> m.getSelect() == ident || m.getArguments().contains(ident)) || checkParent(cursor, J.NewClass.class, n -> n.getEnclosing() == ident || n.getArguments().contains(ident)) || checkParent(cursor, J.NewArray.class, n -> n.getInitializer() != null && n.getInitializer().contains(ident)) || checkParent(cursor, J.Ternary.class, t -> t.getCondition() == ident || t.getTruePart() == ident || t.getFalsePart() == ident) || checkParent(cursor, J.Annotation.class, parentAnnotation -> parentAnnotation.getArguments() != null && parentAnnotation.getArguments().contains(ident))) { return checkFilters(cursor); } // Catchall. Useful point for setting a breakpoint when debugging. return null; } private @Nullable VariableAccess checkFilters(Cursor cursor) { return typeTest.test(cursor.getValue().getType()) ? new VariableAccess(cursor) : null; } private boolean checkParent(Cursor cursor, Class parentType, Predicate test) { if (cursor.getValue() instanceof SourceFile) { return false; } Object parent = cursor.getParentTreeCursor().getValue(); return parentType.isInstance(parent) && test.test(parentType.cast(parent)); } private boolean checkNamePart(Cursor cursor, Class parentType, Function nameExtractor) { return checkParent(cursor, parentType, j -> nameExtractor.apply(j) == cursor.getValue()); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy