blob: abccefa50eecfb55b743322da076b59a9f51ead7 [file] [log] [blame]
package org.checkerframework.framework.ajava;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.comments.Comment;
import com.github.javaparser.ast.nodeTypes.NodeWithAnnotations;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Given two ASTs representing the same Java file that may differ in annotations, tests if they have
* the same annotations.
*
* <p>To use this class, have the first AST node accept the visitor and pass the second AST node as
* the second argument. Then, check {@link #getAnnotationsMatch}.
*/
public class AnnotationEqualityVisitor extends DoubleJavaParserVisitor {
/** Whether or not a node with mismatched annotations has been seen. */
private boolean annotationsMatch;
/** If a node with mismatched annotations has been seen, stores the node from the first AST. */
private @MonotonicNonNull NodeWithAnnotations<?> mismatchedNode1;
/** If a node with mismatched annotations has been seen, stores the node from the second AST. */
private @MonotonicNonNull NodeWithAnnotations<?> mismatchedNode2;
/** Constructs an {@code AnnotationEqualityVisitor}. */
public AnnotationEqualityVisitor() {
annotationsMatch = true;
mismatchedNode1 = null;
mismatchedNode2 = null;
}
/**
* Returns whether a visited pair of nodes differed in annotations.
*
* @return true if some visited pair of nodes differed in annotations
*/
public boolean getAnnotationsMatch() {
return annotationsMatch;
}
/**
* If a visited pair of nodes has had mismatched annotations, returns the node from the first AST
* where annotations differed, or null otherwise.
*
* @return the node from the first AST with differing annotations or null
*/
public @Nullable NodeWithAnnotations<?> getMismatchedNode1() {
return mismatchedNode1;
}
/**
* If a visited pair of nodes has had mismatched annotations, returns the node from the second AST
* where annotations differed, or null otherwise.
*
* @return the node from the second AST with differing annotations or null
*/
public @Nullable NodeWithAnnotations<?> getMismatchedNode2() {
return mismatchedNode2;
}
@Override
public <T extends Node> void defaultAction(T node1, T node2) {
if (!(node1 instanceof NodeWithAnnotations<?>) || !(node2 instanceof NodeWithAnnotations<?>)) {
return;
}
// Comparing annotations with "equals" considers comments in the AST attached to the
// annotations. These should be ignored because two valid ASTs for the same file may differ in
// where comments appear, or whether they appear at all. So, to check if two nodes have the same
// annotations we create copies with all comments removed and compare their lists of annotations
// directly.
Node node1Copy = node1.clone();
Node node2Copy = node2.clone();
for (Comment comment : node1Copy.getAllContainedComments()) {
comment.remove();
}
for (Comment comment : node2Copy.getAllContainedComments()) {
comment.remove();
}
if (!((NodeWithAnnotations<?>) node1Copy)
.getAnnotations()
.equals(((NodeWithAnnotations<?>) node2Copy).getAnnotations())) {
annotationsMatch = false;
mismatchedNode1 = (NodeWithAnnotations<?>) node1;
mismatchedNode2 = (NodeWithAnnotations<?>) node2;
}
}
}