Search in sources :

Example 1 with Element

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

the class JavaApiAnalyzer method determineOrder.

private static void determineOrder(List<Element> l1, List<Element> l2, IdentityHashMap<MethodElement, Integer> l1MethodOrder, IdentityHashMap<MethodElement, Integer> l2MethodOrder) {
    TreeMap<String, List<MethodElement>> l1MethodsByName = new TreeMap<>();
    TreeMap<String, List<MethodElement>> l2MethodsByName = new TreeMap<>();
    int l1MethodsSize = addAllMethods(l1, l1MethodsByName);
    int l2MethodsSize = addAllMethods(l2, l2MethodsByName);
    // rehash overloads that are present in both collections - those are then reordered using their mutual
    // resemblance
    int index = 0;
    Iterator<Map.Entry<String, List<MethodElement>>> l1MethodsIterator = l1MethodsByName.entrySet().iterator();
    Iterator<Map.Entry<String, List<MethodElement>>> l2MethodsIterator = l2MethodsByName.entrySet().iterator();
    // iterate over the maps, sorted by name and assign the comparison index to the methods.
    // we iterate over the maps sorted by method name
    CoIterator<Map.Entry<String, List<MethodElement>>> coit = new CoIterator<>(l1MethodsIterator, l2MethodsIterator, (e1, e2) -> e1.getKey().compareTo(e2.getKey()));
    List<Element> l2MethodsInOrder = new ArrayList<>(l1MethodsSize);
    List<Element> l1MethodsInOrder = new ArrayList<>(l2MethodsSize);
    while (coit.hasNext()) {
        coit.next();
        Map.Entry<String, List<MethodElement>> l1e = coit.getLeft();
        Map.Entry<String, List<MethodElement>> l2e = coit.getRight();
        if (l1e == null) {
            // no overloads with the name present in l1
            for (MethodElement m : l2e.getValue()) {
                l2MethodOrder.put(m, index++);
                l2MethodsInOrder.add(m);
            }
        } else if (l2e == null) {
            // no overloads with the name present in l2
            for (MethodElement m : l1e.getValue()) {
                l1MethodOrder.put(m, index++);
                l1MethodsInOrder.add(m);
            }
        } else {
            // overloads of the same name present in both maps
            // the lists were already sorted by the method above
            List<MethodElement> l1Overloads = l1e.getValue();
            List<MethodElement> l2Overloads = l2e.getValue();
            if (l1Overloads.size() == 1 && l2Overloads.size() == 1) {
                // fast path for hopefully the vast majority of cases
                // just indicate the same order for both methods from l1 and l2
                MethodElement m1 = l1Overloads.get(0);
                MethodElement m2 = l2Overloads.get(0);
                l1MethodsInOrder.add(m1);
                l2MethodsInOrder.add(m2);
                l2MethodOrder.put(m2, index);
                l1MethodOrder.put(m1, index++);
            } else {
                // slow path - for each overload in l1, we need to pick the appropriate one from l2 and put it in the
                // same place
                List<MethodElement> as = l1Overloads;
                List<MethodElement> bs = l2Overloads;
                List<Element> aio = l1MethodsInOrder;
                List<Element> bio = l2MethodsInOrder;
                IdentityHashMap<MethodElement, Integer> ao = l1MethodOrder;
                IdentityHashMap<MethodElement, Integer> bo = l2MethodOrder;
                if (l1Overloads.size() > l2Overloads.size()) {
                    as = l2Overloads;
                    bs = l1Overloads;
                    aio = l2MethodsInOrder;
                    bio = l1MethodsInOrder;
                    ao = l2MethodOrder;
                    bo = l1MethodOrder;
                }
                for (MethodElement aMethod : as) {
                    ao.put(aMethod, index);
                    aio.add(aMethod);
                    MethodElement bMethod = removeBestMatch(aMethod, bs);
                    bo.put(bMethod, index++);
                    bio.add(bMethod);
                }
                // add the rest
                for (MethodElement m : bs) {
                    bo.put(m, index++);
                    bio.add(m);
                }
            }
        }
    }
    // ok, so now we have the method indices right in the comparison matrices...
    // but we also have to reorder the lists themselves to contain the methods in that order so that we
    // conform to the restrictions imposed by the co-iteration of the lists during the analysis
    // the lists are already sorted in the natural order of the java elements which is first and foremost sorted
    // by element type (see org.revapi.java.model.JavaElementFactory). Let's exploit that and just remove all the
    // methods in the list and re-add them in the correct order.
    reAddSortedMethods(l1, l1MethodsInOrder);
    reAddSortedMethods(l2, l2MethodsInOrder);
}
Also used : CoIterator(org.revapi.CoIterator) Element(org.revapi.Element) TypeElement(org.revapi.java.model.TypeElement) MethodElement(org.revapi.java.model.MethodElement) IdentityHashMap(java.util.IdentityHashMap) MethodElement(org.revapi.java.model.MethodElement) ArrayList(java.util.ArrayList) TreeMap(java.util.TreeMap) ArrayList(java.util.ArrayList) Collectors.toList(java.util.stream.Collectors.toList) List(java.util.List) HashMap(java.util.HashMap) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap) TreeMap(java.util.TreeMap)

Example 2 with Element

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

the class JavaApiAnalyzer method addAllMethods.

private static int addAllMethods(Collection<? extends Element> els, TreeMap<String, List<MethodElement>> methods) {
    int ret = 0;
    for (Element e : els) {
        if (e instanceof MethodElement) {
            add((MethodElement) e, methods);
            ret++;
        }
    }
    return ret;
}
Also used : Element(org.revapi.Element) TypeElement(org.revapi.java.model.TypeElement) MethodElement(org.revapi.java.model.MethodElement) MethodElement(org.revapi.java.model.MethodElement)

Example 3 with Element

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

the class JavaApiAnalyzer method getCorrespondenceDeducer.

@Override
@Nonnull
public CorrespondenceComparatorDeducer getCorrespondenceDeducer() {
    return (l1, l2) -> {
        if (l1.isEmpty() || l2.isEmpty()) {
            return Comparator.naturalOrder();
        }
        // quickly peek inside to see if there even can be methods in the lists - all of the elements in either list
        // will have a common parent and parents of both lists will have the same type or be both null.
        Element parent = l1.get(0).getParent();
        if (!(parent instanceof TypeElement)) {
            return Comparator.naturalOrder();
        }
        IdentityHashMap<MethodElement, Integer> c1MethodOrder = new IdentityHashMap<>(l1.size());
        IdentityHashMap<MethodElement, Integer> c2MethodOrder = new IdentityHashMap<>(l2.size());
        // this will reorder the methods in the lists and will also fill in the method order indices in the maps
        // so that they can be used for comparisons below
        determineOrder(l1, l2, c1MethodOrder, c2MethodOrder);
        // and return a comparator
        return (e1, e2) -> {
            int ret = JavaElementFactory.compareByType(e1, e2);
            if (ret != 0) {
                return ret;
            }
            // let's just look that up.
            if (e1 instanceof MethodElement && e2 instanceof MethodElement) {
                MethodElement m1 = (MethodElement) e1;
                MethodElement m2 = (MethodElement) e2;
                return c1MethodOrder.get(m1) - c2MethodOrder.get(m2);
            } else {
                return e1.compareTo(e2);
            }
        };
    };
}
Also used : DifferenceAnalyzer(org.revapi.DifferenceAnalyzer) CompilationValve(org.revapi.java.compilation.CompilationValve) BiFunction(java.util.function.BiFunction) Element(org.revapi.Element) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) CoIterator(org.revapi.CoIterator) Charset(java.nio.charset.Charset) Util(org.revapi.java.spi.Util) Map(java.util.Map) ArchiveAnalyzer(org.revapi.ArchiveAnalyzer) ThreadFactory(java.util.concurrent.ThreadFactory) ApiAnalyzer(org.revapi.ApiAnalyzer) Nonnull(javax.annotation.Nonnull) InclusionFilter(org.revapi.java.compilation.InclusionFilter) ExecutorService(java.util.concurrent.ExecutorService) Nullable(javax.annotation.Nullable) API(org.revapi.API) CorrespondenceComparatorDeducer(org.revapi.CorrespondenceComparatorDeducer) ProbingEnvironment(org.revapi.java.compilation.ProbingEnvironment) IdentityHashMap(java.util.IdentityHashMap) Iterator(java.util.Iterator) AnalysisContext(org.revapi.AnalysisContext) Collection(java.util.Collection) TypeElement(org.revapi.java.model.TypeElement) Set(java.util.Set) IOException(java.io.IOException) ServiceLoader(java.util.ServiceLoader) Reader(java.io.Reader) Types(javax.lang.model.util.Types) InputStreamReader(java.io.InputStreamReader) Executors(java.util.concurrent.Executors) JavaElementFactory(org.revapi.java.model.JavaElementFactory) Collectors.toList(java.util.stream.Collectors.toList) List(java.util.List) StringReader(java.io.StringReader) TreeMap(java.util.TreeMap) MethodElement(org.revapi.java.model.MethodElement) Check(org.revapi.java.spi.Check) ModelNode(org.jboss.dmr.ModelNode) Pattern(java.util.regex.Pattern) Comparator(java.util.Comparator) TypeElement(org.revapi.java.model.TypeElement) Element(org.revapi.Element) TypeElement(org.revapi.java.model.TypeElement) MethodElement(org.revapi.java.model.MethodElement) IdentityHashMap(java.util.IdentityHashMap) MethodElement(org.revapi.java.model.MethodElement) Nonnull(javax.annotation.Nonnull)

Example 4 with Element

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

the class AntReporter method report.

@Override
public void report(@Nonnull Report report) {
    Element element = report.getOldElement();
    if (element == null) {
        element = report.getNewElement();
    }
    if (element == null) {
        throw new IllegalStateException("This should not ever happen. Both elements in a report were null.");
    }
    for (Difference difference : report.getDifferences()) {
        DifferenceSeverity maxSeverity = DifferenceSeverity.NON_BREAKING;
        for (Map.Entry<CompatibilityType, DifferenceSeverity> e : difference.classification.entrySet()) {
            if (e.getValue().compareTo(maxSeverity) >= 0) {
                maxSeverity = e.getValue();
            }
        }
        if (maxSeverity.compareTo(minSeverity) < 0) {
            continue;
        }
        StringBuilder message = new StringBuilder();
        message.append(element.getFullHumanReadableString()).append(": ").append(difference.code).append(": ").append(difference.description).append(" [");
        for (Map.Entry<CompatibilityType, DifferenceSeverity> e : difference.classification.entrySet()) {
            message.append(e.getKey()).append(": ").append(e.getValue()).append(", ");
        }
        message.replace(message.length() - 2, message.length(), "]");
        logger.log(message.toString(), Project.MSG_ERR);
    }
}
Also used : DifferenceSeverity(org.revapi.DifferenceSeverity) CompatibilityType(org.revapi.CompatibilityType) Element(org.revapi.Element) Difference(org.revapi.Difference) Map(java.util.Map)

Example 5 with Element

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

the class AnnotatedElementFilterTest method testWith.

private void testWith(String configJSON, Consumer<List<Element>> test) throws Exception {
    ArchiveAndCompilationPath archive = createCompiledJar("test.jar", "annotationfilter/NonPublic.java", "annotationfilter/NonPublicClass.java", "annotationfilter/Public.java", "annotationfilter/PublicClass.java", "annotationfilter/UndecisiveClass.java");
    try {
        JavaArchiveAnalyzer analyzer = new JavaArchiveAnalyzer(new API(Arrays.asList(new ShrinkwrapArchive(archive.archive)), null), Executors.newSingleThreadExecutor(), null, false, InclusionFilter.acceptAll());
        JavaElementForest forest = analyzer.analyze();
        AnnotatedElementFilter filter = new AnnotatedElementFilter();
        Revapi r = new Revapi(emptySet(), emptySet(), emptySet(), singleton(AnnotatedElementFilter.class));
        AnalysisContext ctx = AnalysisContext.builder(r).withConfigurationFromJSON(configJSON).build();
        AnalysisContext filterCtx = r.prepareAnalysis(ctx).getFirstConfigurationOrNull(AnnotatedElementFilter.class);
        filter.initialize(filterCtx);
        List<Element> results = forest.search(Element.class, true, filter, null);
        analyzer.getCompilationValve().removeCompiledResults();
        test.accept(results);
    } finally {
        deleteDir(archive.compilationPath);
    }
}
Also used : JavaElementForest(org.revapi.java.model.JavaElementForest) Revapi(org.revapi.Revapi) Element(org.revapi.Element) MethodParameterElement(org.revapi.java.model.MethodParameterElement) MethodElement(org.revapi.java.model.MethodElement) AnnotatedElement(java.lang.reflect.AnnotatedElement) API(org.revapi.API) AnalysisContext(org.revapi.AnalysisContext) AnnotatedElementFilter(org.revapi.java.filters.AnnotatedElementFilter)

Aggregations

Element (org.revapi.Element)15 API (org.revapi.API)5 AnalysisContext (org.revapi.AnalysisContext)5 MethodElement (org.revapi.java.model.MethodElement)5 TypeElement (org.revapi.java.model.TypeElement)5 Map (java.util.Map)4 IOException (java.io.IOException)3 ArrayList (java.util.ArrayList)3 HashMap (java.util.HashMap)3 Nonnull (javax.annotation.Nonnull)3 InputStreamReader (java.io.InputStreamReader)2 Reader (java.io.Reader)2 Charset (java.nio.charset.Charset)2 IdentityHashMap (java.util.IdentityHashMap)2 Iterator (java.util.Iterator)2 List (java.util.List)2 Set (java.util.Set)2 TreeMap (java.util.TreeMap)2 Executors (java.util.concurrent.Executors)2 Collectors.toList (java.util.stream.Collectors.toList)2