Search in sources :

Example 11 with Difference

use of org.revapi.Difference in project revapi by revapi.

the class NowImplementsInterface method doEnd.

@Override
protected List<Difference> doEnd() {
    CheckBase.ActiveElements<JavaTypeElement> types = popIfActive();
    if (types == null) {
        return null;
    }
    List<Difference> result = new ArrayList<>();
    List<? extends TypeMirror> newInterfaces = types.newElement.getDeclaringElement().getInterfaces();
    List<? extends TypeMirror> oldInterfaces = types.oldElement.getDeclaringElement().getInterfaces();
    for (TypeMirror newIface : newInterfaces) {
        if (!Util.isSubtype(newIface, oldInterfaces, getNewTypeEnvironment().getTypeUtils())) {
            result.add(createDifference(Code.CLASS_NOW_IMPLEMENTS_INTERFACE, Code.attachmentsFor(types.oldElement, types.newElement, "interface", Util.toHumanReadableString(newIface))));
        }
    }
    return result;
}
Also used : CheckBase(org.revapi.java.spi.CheckBase) TypeMirror(javax.lang.model.type.TypeMirror) ArrayList(java.util.ArrayList) Difference(org.revapi.Difference) JavaTypeElement(org.revapi.java.spi.JavaTypeElement)

Example 12 with Difference

use of org.revapi.Difference 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 13 with Difference

use of org.revapi.Difference in project revapi by revapi.

the class TextReporter method report.

@Override
public void report(@Nonnull Report report) {
    if (report.getDifferences().isEmpty()) {
        return;
    }
    DifferenceSeverity maxReportedSeverity = DifferenceSeverity.NON_BREAKING;
    for (Difference d : report.getDifferences()) {
        for (DifferenceSeverity c : d.classification.values()) {
            if (c.compareTo(maxReportedSeverity) > 0) {
                maxReportedSeverity = c;
            }
        }
    }
    if (maxReportedSeverity.compareTo(minLevel) < 0) {
        return;
    }
    reports.add(report);
}
Also used : DifferenceSeverity(org.revapi.DifferenceSeverity) Difference(org.revapi.Difference)

Example 14 with Difference

use of org.revapi.Difference in project revapi by revapi.

the class InheritanceChainChanged method doEnd.

@Override
protected List<Difference> doEnd() {
    ActiveElements<JavaTypeElement> types = popIfActive();
    if (types != null) {
        List<Difference> ret = new ArrayList<>();
        @SuppressWarnings("unchecked") List<TypeMirror> oldSuperClasses = (List<TypeMirror>) types.context[0];
        @SuppressWarnings("unchecked") List<TypeMirror> newSuperClasses = (List<TypeMirror>) types.context[1];
        Comparator<TypeMirror> typeNameComparator = Comparator.comparing(Util::toUniqueString);
        List<TypeMirror> removedSuperClasses = new ArrayList<>();
        List<TypeMirror> addedSuperClasses = new ArrayList<>();
        oldSuperClasses.sort(typeNameComparator);
        newSuperClasses.sort(typeNameComparator);
        CoIterator<TypeMirror> iterator = new CoIterator<>(oldSuperClasses.iterator(), newSuperClasses.iterator(), typeNameComparator);
        while (iterator.hasNext()) {
            iterator.next();
            TypeMirror oldType = iterator.getLeft();
            TypeMirror newType = iterator.getRight();
            if (oldType == null) {
                addedSuperClasses.add(newType);
            } else if (newType == null) {
                removedSuperClasses.add(oldType);
            }
        }
        // this will give us the equivalent of removed/added superclasses but ordered by the inheritance chain
        // not by name
        removedSuperClasses = retainInCopy(oldSuperClasses, removedSuperClasses);
        addedSuperClasses = retainInCopy(newSuperClasses, addedSuperClasses);
        Iterator<TypeMirror> removedIt = removedSuperClasses.iterator();
        Iterator<TypeMirror> addedIt = addedSuperClasses.iterator();
        // always report the most concrete classes
        if (removedIt.hasNext()) {
            removedIt.next();
        }
        if (addedIt.hasNext()) {
            addedIt.next();
        }
        // ok, now we only have super types left of the most concrete removed/added super class.
        // we are only going to report those that changed their inheritance hierarchy in the other version of the API.
        removeClassesWithEquivalentSuperClassChain(removedIt, getOldTypeEnvironment(), getNewTypeEnvironment());
        removeClassesWithEquivalentSuperClassChain(addedIt, getNewTypeEnvironment(), getOldTypeEnvironment());
        for (TypeMirror t : removedSuperClasses) {
            String str = Util.toHumanReadableString(t);
            ret.add(createDifference(Code.CLASS_NO_LONGER_INHERITS_FROM_CLASS, Code.attachmentsFor(types.oldElement, types.newElement, "superClass", str)));
        }
        for (TypeMirror t : addedSuperClasses) {
            String str = Util.toHumanReadableString(t);
            Code code = types.oldElement.getDeclaringElement().getModifiers().contains(Modifier.FINAL) ? Code.CLASS_FINAL_CLASS_INHERITS_FROM_NEW_CLASS : Code.CLASS_NON_FINAL_CLASS_INHERITS_FROM_NEW_CLASS;
            ret.add(createDifference(code, Code.attachmentsFor(types.oldElement, types.newElement, "superClass", str)));
            // additionally add a difference about checked exceptions
            if (changedToCheckedException(getNewTypeEnvironment().getTypeUtils(), t, oldSuperClasses)) {
                ret.add(createDifference(Code.CLASS_NOW_CHECKED_EXCEPTION, Code.attachmentsFor(types.oldElement, types.newElement)));
            }
        }
        return ret;
    }
    return null;
}
Also used : CoIterator(org.revapi.CoIterator) ArrayList(java.util.ArrayList) Util(org.revapi.java.spi.Util) Difference(org.revapi.Difference) Code(org.revapi.java.spi.Code) JavaTypeElement(org.revapi.java.spi.JavaTypeElement) TypeMirror(javax.lang.model.type.TypeMirror) ArrayList(java.util.ArrayList) List(java.util.List)

Example 15 with Difference

use of org.revapi.Difference in project revapi by revapi.

the class FormalTypeParametersChanged method doEnd.

@Nullable
@Override
protected List<Difference> doEnd() {
    ActiveElements<JavaModelElement> els = popIfActive();
    if (els == null) {
        return null;
    }
    @SuppressWarnings("unchecked") List<TypeParameterElement> added = (List<TypeParameterElement>) els.context[0];
    @SuppressWarnings("unchecked") List<TypeParameterElement> removed = (List<TypeParameterElement>) els.context[1];
    @SuppressWarnings("unchecked") Map<TypeParameterElement, TypeParameterElement> changed = (Map<TypeParameterElement, TypeParameterElement>) els.context[2];
    Parameterizable oldT = (Parameterizable) els.oldElement.getDeclaringElement();
    List<Difference> diffs = new ArrayList<>();
    if (oldT.getTypeParameters().isEmpty()) {
        diffs.add(createDifference(Code.GENERICS_ELEMENT_NOW_PARAMETERIZED, Code.attachmentsFor(els.oldElement, els.newElement)));
    }
    for (TypeParameterElement e : added) {
        diffs.add(createDifferenceWithExplicitParams(Code.GENERICS_FORMAL_TYPE_PARAMETER_ADDED, Code.attachmentsFor(els.oldElement, els.newElement), Util.toHumanReadableString(e)));
    }
    for (TypeParameterElement e : removed) {
        diffs.add(createDifferenceWithExplicitParams(Code.GENERICS_FORMAL_TYPE_PARAMETER_REMOVED, Code.attachmentsFor(els.oldElement, els.newElement), Util.toHumanReadableString(e)));
    }
    for (Map.Entry<TypeParameterElement, TypeParameterElement> e : changed.entrySet()) {
        String oldP = Util.toHumanReadableString(e.getKey());
        String newP = Util.toHumanReadableString(e.getValue());
        diffs.add(createDifferenceWithExplicitParams(Code.GENERICS_FORMAL_TYPE_PARAMETER_CHANGED, Code.attachmentsFor(els.oldElement, els.newElement, "oldTypeParameter", oldP, "newTypeParameter", newP), oldP, newP));
    }
    return diffs;
}
Also used : JavaModelElement(org.revapi.java.spi.JavaModelElement) ArrayList(java.util.ArrayList) Difference(org.revapi.Difference) TypeParameterElement(javax.lang.model.element.TypeParameterElement) Parameterizable(javax.lang.model.element.Parameterizable) ArrayList(java.util.ArrayList) List(java.util.List) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) Nullable(javax.annotation.Nullable)

Aggregations

Difference (org.revapi.Difference)22 ArrayList (java.util.ArrayList)7 Test (org.junit.Test)6 AnalysisContext (org.revapi.AnalysisContext)6 JavaTypeElement (org.revapi.java.spi.JavaTypeElement)6 TypeElement (javax.lang.model.element.TypeElement)5 Map (java.util.Map)4 TypeMirror (javax.lang.model.type.TypeMirror)4 Report (org.revapi.Report)4 List (java.util.List)3 JavaMethodElement (org.revapi.java.spi.JavaMethodElement)3 Nullable (javax.annotation.Nullable)2 AnnotationValue (javax.lang.model.element.AnnotationValue)2 ExecutableElement (javax.lang.model.element.ExecutableElement)2 CoIterator (org.revapi.CoIterator)2 DifferenceSeverity (org.revapi.DifferenceSeverity)2 Element (org.revapi.Element)2 Util (org.revapi.java.spi.Util)2 HashMap (java.util.HashMap)1 LinkedHashMap (java.util.LinkedHashMap)1