Search in sources :

Example 1 with JavaMethodElement

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);
}
Also used : JavaMethodElement(org.revapi.java.spi.JavaMethodElement) AnnotationValue(javax.lang.model.element.AnnotationValue) Difference(org.revapi.Difference)

Example 2 with JavaMethodElement

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);
}
Also used : JavaMethodElement(org.revapi.java.spi.JavaMethodElement) TypeElement(javax.lang.model.element.TypeElement) ExecutableElement(javax.lang.model.element.ExecutableElement) Difference(org.revapi.Difference)

Example 3 with JavaMethodElement

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;
}
Also used : CoIterator(org.revapi.CoIterator) JavaMethodElement(org.revapi.java.spi.JavaMethodElement) TypeElement(javax.lang.model.element.TypeElement) ArrayList(java.util.ArrayList) Util(org.revapi.java.spi.Util) Difference(org.revapi.Difference) TypeMirror(javax.lang.model.type.TypeMirror) Nullable(javax.annotation.Nullable)

Example 4 with JavaMethodElement

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)));
}
Also used : TypeMirror(javax.lang.model.type.TypeMirror) JavaMethodElement(org.revapi.java.spi.JavaMethodElement) Code(org.revapi.java.spi.Code) Nullable(javax.annotation.Nullable)

Aggregations

JavaMethodElement (org.revapi.java.spi.JavaMethodElement)4 Difference (org.revapi.Difference)3 Nullable (javax.annotation.Nullable)2 TypeElement (javax.lang.model.element.TypeElement)2 TypeMirror (javax.lang.model.type.TypeMirror)2 ArrayList (java.util.ArrayList)1 AnnotationValue (javax.lang.model.element.AnnotationValue)1 ExecutableElement (javax.lang.model.element.ExecutableElement)1 CoIterator (org.revapi.CoIterator)1 Code (org.revapi.java.spi.Code)1 Util (org.revapi.java.spi.Util)1