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

org.openrewrite.java.search.SemanticallyEqual Maven / Gradle / Ivy

/*
 * 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.search; import org.openrewrite.Incubating; import org.openrewrite.Tree; import org.openrewrite.java.AbstractJavaSourceVisitor; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaType; import org.openrewrite.java.tree.NameTree; import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; /* * Semantically Equal recursively checks the equality of each element of two ASTs to determine if the two trees are semantically equal. * This is necessary because ASTs are so frequently recreated that merely comparing the IDs of two ASTs is ineffective. * SemanticallyEqual has only been implemented for annotations for now. */ @Incubating(since = "6.0.0") public class SemanticallyEqual extends AbstractJavaSourceVisitor { private final Tree tree; public SemanticallyEqual(Tree tree) { this.tree = tree; } @Override public Boolean defaultTo(Tree t) { return true; } @Override public Boolean reduce(Boolean r1, Boolean r2) { return r1 && r2; } @Override public Boolean visitAnnotation(J.Annotation otherAnnotation) { if(tree instanceof J.Annotation) { J.Annotation annotation = (J.Annotation) tree; boolean areArgsEqual; if(annotation.getArgs() != null && otherAnnotation.getArgs() != null) { if(annotation.getArgs().getArgs() != null && otherAnnotation.getArgs().getArgs() != null && annotation.getArgs().getArgs().size() == otherAnnotation.getArgs().getArgs().size()) { AtomicInteger index = new AtomicInteger(0); areArgsEqual = annotation.getArgs().getArgs().stream() .allMatch(arg -> new SemanticallyEqual(arg) .visit(otherAnnotation.getArgs().getArgs().get(index.getAndIncrement())) ); } else { return false; } } else if(annotation.getArgs() == null && otherAnnotation.getArgs() == null) { areArgsEqual = true; } else { return false; } return areArgsEqual && new SemanticallyEqual(annotation.getAnnotationType()).visitTypeName(otherAnnotation.getAnnotationType()); } return false; } @Override public Boolean visitIdentifier(J.Ident otherIdent) { if(tree instanceof J.Ident) { J.Ident ident = (J.Ident) tree; return Objects.equals(ident.getType(), otherIdent.getType()) && ident.getSimpleName().equals(otherIdent.getSimpleName()); } return false; } @Override public Boolean visitFieldAccess(J.FieldAccess otherFieldAccess) { if(tree instanceof J.FieldAccess) { J.FieldAccess fieldAccess = (J.FieldAccess) tree; // Class literals are the only kind of FieldAccess which can appear within annotations // Functionality to correctly determine semantic equality of other kinds of field access will come later if(fieldAccess.getSimpleName().equals("class")) { if(!otherFieldAccess.getSimpleName().equals("class")) { return false; } else { return typeEquals(fieldAccess.getType(), otherFieldAccess.getType()) && typeEquals(fieldAccess.getTarget().getType(), otherFieldAccess.getTarget().getType()); } } } return false; } @Override public Boolean visitAssign(J.Assign otherAssign) { if(tree instanceof J.Assign) { J.Assign assign = (J.Assign) tree; return Objects.equals(assign.getType(), otherAssign.getType()) && new SemanticallyEqual(assign.getVariable()).visit(otherAssign.getVariable()) && new SemanticallyEqual(assign.getAssignment()).visit(otherAssign.getAssignment()); } return false; } @Override public Boolean visitLiteral(J.Literal otherLiteral) { if(tree instanceof J.Literal) { J.Literal literal = (J.Literal) tree; return Objects.equals(literal.getValue(), otherLiteral.getValue()); } return false; } @Override public Boolean visitTypeName(NameTree name) { if(this.tree instanceof J.Ident) { if(!(name instanceof J.Ident)) { return false; } return identEquals((J.Ident) this.tree, (J.Ident) name); } return super.visitTypeName(name); } private static boolean identEquals(J.Ident thisIdent, J.Ident otherIdent) { return Objects.equals(thisIdent.getSimpleName(), otherIdent.getSimpleName()) && typeEquals(thisIdent.getType(), otherIdent.getType()); } private static boolean typeEquals(JavaType thisType, JavaType otherType) { if(thisType == null) { return otherType == null; } if(thisType instanceof JavaType.FullyQualified) { if (!(otherType instanceof JavaType.FullyQualified)) { return false; } return ((JavaType.FullyQualified) thisType).getFullyQualifiedName().equals(((JavaType.FullyQualified) otherType).getFullyQualifiedName()); } return thisType.deepEquals(otherType); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy