package japicmp.output.semver; import com.google.common.collect.ImmutableSet; import japicmp.config.Options; import japicmp.model.*; import japicmp.output.Filter; import japicmp.output.OutputGenerator; import java.util.Iterator; import java.util.List; import static japicmp.util.ModifierHelper.isNotPrivate; public class SemverOut extends OutputGenerator<String> { private enum SemverStatus { UNCHANGED, CHANGED_BINARY_COMPATIBLE, CHANGED_BINARY_INCOMPATIBLE; } public SemverOut(Options options, List<JApiClass> jApiClasses) { super(options, jApiClasses); } @Override public String generate() { final ImmutableSet.Builder<SemverStatus> builder = ImmutableSet.builder(); Filter.filter(jApiClasses, new Filter.FilterVisitor() { @Override public void visit(Iterator<JApiClass> iterator, JApiClass jApiClass) { builder.add(signs(jApiClass)); } @Override public void visit(Iterator<JApiMethod> iterator, JApiMethod jApiMethod) { builder.add(signs(jApiMethod)); } @Override public void visit(Iterator<JApiConstructor> iterator, JApiConstructor jApiConstructor) { builder.add(signs(jApiConstructor)); } @Override public void visit(Iterator<JApiImplementedInterface> iterator, JApiImplementedInterface jApiImplementedInterface) { builder.add(signs(jApiImplementedInterface)); } @Override public void visit(Iterator<JApiField> iterator, JApiField jApiField) { builder.add(signs(jApiField)); } @Override public void visit(Iterator<JApiAnnotation> iterator, JApiAnnotation jApiAnnotation) { builder.add(signs(jApiAnnotation)); } @Override public void visit(JApiSuperclass jApiSuperclass) { builder.add(signs(jApiSuperclass)); } }); ImmutableSet<SemverStatus> build = builder.build(); if (build.contains(SemverStatus.CHANGED_BINARY_INCOMPATIBLE)) { return "1.0.0"; } else if (build.contains(SemverStatus.CHANGED_BINARY_COMPATIBLE)) { return "0.1.0"; } else if (build.contains(SemverStatus.UNCHANGED)) { return "0.0.1"; } else if (build.isEmpty()) { return "0.0.0"; } else { return "N/A"; } } private SemverStatus signs(JApiHasChangeStatus hasChangeStatus) { JApiChangeStatus changeStatus = hasChangeStatus.getChangeStatus(); switch (changeStatus) { case UNCHANGED: return SemverStatus.UNCHANGED; case NEW: case REMOVED: case MODIFIED: if (hasChangeStatus instanceof JApiCompatibility) { JApiCompatibility binaryCompatibility = (JApiCompatibility) hasChangeStatus; if (binaryCompatibility.isBinaryCompatible()) { if (hasChangeStatus instanceof JApiHasAccessModifier) { JApiHasAccessModifier jApiHasAccessModifier = (JApiHasAccessModifier) hasChangeStatus; if (isNotPrivate(jApiHasAccessModifier)) { if (jApiHasAccessModifier instanceof JApiClass) { JApiClass jApiClass = (JApiClass) jApiHasAccessModifier; if (jApiClass.isChangeCausedByClassElement()) { return SemverStatus.UNCHANGED; } else { return SemverStatus.CHANGED_BINARY_COMPATIBLE; } } return SemverStatus.CHANGED_BINARY_COMPATIBLE; } else { return SemverStatus.UNCHANGED; } } else { return SemverStatus.CHANGED_BINARY_COMPATIBLE; } } else { if (hasChangeStatus instanceof JApiHasAccessModifier) { JApiHasAccessModifier jApiHasAccessModifier = (JApiHasAccessModifier) hasChangeStatus; if (isNotPrivate(jApiHasAccessModifier)) { return SemverStatus.CHANGED_BINARY_INCOMPATIBLE; } else { return SemverStatus.CHANGED_BINARY_COMPATIBLE; } } else { return SemverStatus.CHANGED_BINARY_INCOMPATIBLE; } } } else { throw new IllegalStateException("Element '" + hasChangeStatus.getClass().getCanonicalName() + " does not implement '" + JApiCompatibility.class.getCanonicalName() + "'."); } default: throw new IllegalStateException("The following JApiChangeStatus is not supported: " + (changeStatus == null ? "null" : changeStatus.name())); } } }