use of org.revapi.java.spi.JavaMethodElement in project revapi by revapi.
the class DefaultValueChanged method doEnd.
@Override
protected List<Difference> doEnd() {
ActiveElements<JavaMethodElement> methods = popIfActive();
if (methods == null) {
return null;
}
AnnotationValue oldValue = methods.oldElement.getDeclaringElement().getDefaultValue();
AnnotationValue newValue = methods.newElement.getDeclaringElement().getDefaultValue();
String attribute = methods.oldElement.getDeclaringElement().getSimpleName().toString();
String annotationType = ((TypeElement) methods.oldElement.getDeclaringElement().getEnclosingElement()).getQualifiedName().toString();
String ov = oldValue == null ? null : Util.toHumanReadableString(oldValue);
String nv = newValue == null ? null : Util.toHumanReadableString(newValue);
Difference difference;
if (ov == null) {
difference = createDifference(Code.METHOD_DEFAULT_VALUE_ADDED, Code.attachmentsFor(methods.oldElement, methods.newElement, "value", nv));
} else if (nv == null) {
difference = createDifference(Code.METHOD_DEFAULT_VALUE_REMOVED, Code.attachmentsFor(methods.oldElement, methods.newElement, "value", ov));
} else {
difference = createDifferenceWithExplicitParams(Code.METHOD_DEFAULT_VALUE_CHANGED, Code.attachmentsFor(methods.oldElement, methods.newElement, "oldValue", ov, "newValue", nv), attribute, annotationType, ov, nv);
}
return Collections.singletonList(difference);
}
use of org.revapi.java.spi.JavaMethodElement in project revapi by revapi.
the class Added method doEnd.
@Override
protected List<Difference> doEnd() {
ActiveElements<JavaMethodElement> methods = popIfActive();
if (methods == null) {
return null;
}
// we need to consider several cases here:
// 1) method added to a interface
// 2) method added to a final class
// 3) concrete method added to a non-final class
// 4) abstract method added to a non-final class
// 5) final method added to a non-final class
// 5) previously inherited method is now declared in class
ExecutableElement method = methods.newElement.getDeclaringElement();
if (methods.newElement.getParent() == null) {
LOG.warn("Could not find an enclosing class of method " + method + ". That's weird.");
return null;
}
TypeElement enclosingClass = (TypeElement) methods.newElement.getParent().getDeclaringElement();
Difference difference;
if (enclosingClass.getKind() == ElementKind.INTERFACE) {
if (method.isDefault()) {
difference = createDifference(Code.METHOD_DEFAULT_METHOD_ADDED_TO_INTERFACE, Code.attachmentsFor(methods.oldElement, methods.newElement));
} else if (method.getModifiers().contains(Modifier.STATIC)) {
// statics on interface can only be called using the interface they are declared on, even if a method
// with a same signature was declared on some of the super types in the old version, the users would
// not have been able to call those methods using the current type. So we don't need to specialize here
// based on the presence of a previously inherited method.
difference = createDifference(Code.METHOD_STATIC_METHOD_ADDED_TO_INTERFACE, Code.attachmentsFor(methods.oldElement, methods.newElement));
} else {
difference = createDifference(Code.METHOD_ADDED_TO_INTERFACE, Code.attachmentsFor(methods.oldElement, methods.newElement));
}
} else if (method.getModifiers().contains(Modifier.ABSTRACT)) {
difference = createDifference(Code.METHOD_ABSTRACT_METHOD_ADDED, Code.attachmentsFor(methods.oldElement, methods.newElement));
} else if (method.getModifiers().contains(Modifier.FINAL) && !enclosingClass.getModifiers().contains(Modifier.FINAL)) {
difference = createDifference(Code.METHOD_FINAL_METHOD_ADDED_TO_NON_FINAL_CLASS, Code.attachmentsFor(methods.oldElement, methods.newElement));
} else {
difference = createDifference(Code.METHOD_ADDED, Code.attachmentsFor(methods.oldElement, methods.newElement));
}
return Collections.singletonList(difference);
}
use of org.revapi.java.spi.JavaMethodElement in project revapi by revapi.
the class ExceptionsThrownChanged method doEnd.
@Nullable
@Override
protected List<Difference> doEnd() {
ActiveElements<JavaMethodElement> methods = popIfActive();
if (methods == null) {
return null;
}
List<? extends TypeMirror> oldExceptions = new ArrayList<>(methods.oldElement.getModelRepresentation().getThrownTypes());
List<? extends TypeMirror> newExceptions = new ArrayList<>(methods.newElement.getModelRepresentation().getThrownTypes());
Comparator<TypeMirror> byClassName = Comparator.comparing(Util::toUniqueString);
Collections.sort(oldExceptions, byClassName);
Collections.sort(newExceptions, byClassName);
CoIterator<TypeMirror> it = new CoIterator<>(oldExceptions.iterator(), newExceptions.iterator(), byClassName);
List<String> removedRuntimeExceptions = new ArrayList<>();
List<String> addedRuntimeExceptions = new ArrayList<>();
List<String> removedCheckedExceptions = new ArrayList<>();
List<String> addedCheckedExceptions = new ArrayList<>();
boolean reportSomething = false;
while (it.hasNext()) {
it.next();
TypeMirror oldType = it.getLeft();
TypeMirror newType = it.getRight();
if (oldType != null && newType != null) {
// they match, so move on, nothing to report here
continue;
}
reportSomething = true;
TypeElement oldException = oldType == null ? null : oldType.accept(CONVERT_TO_ELEMENT, null);
TypeElement newException = newType == null ? null : newType.accept(CONVERT_TO_ELEMENT, null);
if (oldException != null) {
if (isRuntimeException(oldException)) {
removedRuntimeExceptions.add(oldException.getQualifiedName().toString());
} else {
removedCheckedExceptions.add(oldException.getQualifiedName().toString());
}
} else if (newException != null) {
if (isRuntimeException(newException)) {
addedRuntimeExceptions.add(newException.getQualifiedName().toString());
} else {
addedCheckedExceptions.add(newException.getQualifiedName().toString());
}
}
}
if (!reportSomething) {
return null;
}
List<Difference> ret = new ArrayList<>();
if (!removedRuntimeExceptions.isEmpty()) {
removedRuntimeExceptions.forEach(ex -> ret.add(createDifference(Code.METHOD_RUNTIME_EXCEPTION_REMOVED, Code.attachmentsFor(methods.oldElement, methods.newElement, "exception", ex))));
}
if (!addedRuntimeExceptions.isEmpty()) {
addedRuntimeExceptions.forEach(ex -> ret.add(createDifference(Code.METHOD_RUNTIME_EXCEPTION_ADDED, Code.attachmentsFor(methods.oldElement, methods.newElement, "exception", ex))));
}
if (!addedCheckedExceptions.isEmpty()) {
addedCheckedExceptions.forEach(ex -> ret.add(createDifference(Code.METHOD_CHECKED_EXCEPTION_ADDED, Code.attachmentsFor(methods.oldElement, methods.newElement, "exception", ex))));
}
if (!removedCheckedExceptions.isEmpty()) {
removedCheckedExceptions.forEach(ex -> ret.add(createDifference(Code.METHOD_CHECKED_EXCEPTION_REMOVED, Code.attachmentsFor(methods.oldElement, methods.newElement, "exception", ex))));
}
return ret;
}
use of org.revapi.java.spi.JavaMethodElement in project revapi by revapi.
the class ReturnTypeChanged method doEnd.
@Nullable
@Override
protected List<Difference> doEnd() {
ActiveElements<JavaMethodElement> methods = popIfActive();
if (methods == null) {
return null;
}
TypeMirror oldReturnType = methods.oldElement.getModelRepresentation().getReturnType();
TypeMirror newReturnType = methods.newElement.getModelRepresentation().getReturnType();
TypeMirror erasedOldType = getOldTypeEnvironment().getTypeUtils().erasure(oldReturnType);
TypeMirror erasedNewType = getNewTypeEnvironment().getTypeUtils().erasure(newReturnType);
String oldR = Util.toUniqueString(oldReturnType);
String newR = Util.toUniqueString(newReturnType);
String oldER = Util.toUniqueString(erasedOldType);
String newER = Util.toUniqueString(erasedNewType);
Code code = null;
if (!oldER.equals(newER)) {
// we need to check if the returned type changed covariantly or not.
if (isPrimitiveOrVoid(erasedOldType) || isPrimitiveOrVoid(erasedNewType)) {
code = Code.METHOD_RETURN_TYPE_CHANGED;
} else if (isCovariant(erasedOldType, erasedNewType)) {
code = Code.METHOD_RETURN_TYPE_CHANGED_COVARIANTLY;
} else {
code = Code.METHOD_RETURN_TYPE_CHANGED;
}
} else {
if (!oldR.equals(newR)) {
code = Code.METHOD_RETURN_TYPE_TYPE_PARAMETERS_CHANGED;
}
}
String oldHR = Util.toHumanReadableString(oldReturnType);
String newHR = Util.toHumanReadableString(newReturnType);
return code == null ? null : Collections.singletonList(createDifference(code, Code.attachmentsFor(methods.oldElement, methods.newElement, "oldType", oldHR, "newType", newHR)));
}
Aggregations