Search in sources :

Example 1 with MethodElement

use of org.revapi.java.model.MethodElement 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 MethodElement

use of org.revapi.java.model.MethodElement 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 MethodElement

use of org.revapi.java.model.MethodElement 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 MethodElement

use of org.revapi.java.model.MethodElement in project revapi by revapi.

the class JavaApiAnalyzer method reAddSortedMethods.

private static void reAddSortedMethods(List<Element> elements, List<Element> sortedMethods) {
    int methodRank = JavaElementFactory.getModelTypeRank(MethodElement.class);
    int index = 0;
    for (; index < elements.size(); ++index) {
        Element e = elements.get(index);
        if (JavaElementFactory.getModelTypeRank(e.getClass()) >= methodRank) {
            break;
        }
    }
    // remove all the method elements
    while (index < elements.size()) {
        Element e = elements.get(index);
        if (e instanceof MethodElement) {
            elements.remove(index);
        } else {
            break;
        }
    }
    // and re-add them in the newly established order
    elements.addAll(index, sortedMethods);
}
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 5 with MethodElement

use of org.revapi.java.model.MethodElement in project revapi by revapi.

the class JavaApiAnalyzer method removeBestMatch.

private static MethodElement removeBestMatch(MethodElement blueprint, List<MethodElement> candidates) {
    MethodElement best = null;
    float maxScore = 0;
    int bestIdx = -1;
    List<String> fullBlueprintSignature = methodParamsSignature(blueprint, false);
    List<String> erasedBlueprintSignature = methodParamsSignature(blueprint, true);
    String fullBlueprintReturnType = Util.toUniqueString(blueprint.getModelRepresentation().getReturnType());
    String erasedBlueprintReturnType = Util.toUniqueString(blueprint.getTypeEnvironment().getTypeUtils().erasure(blueprint.getModelRepresentation().getReturnType()));
    int idx = 0;
    for (MethodElement candidate : candidates) {
        float score = computeMatchScore(fullBlueprintReturnType, fullBlueprintSignature, erasedBlueprintReturnType, erasedBlueprintSignature, candidate);
        if (maxScore <= score) {
            best = candidate;
            maxScore = score;
            bestIdx = idx;
        }
        idx++;
    }
    if (bestIdx != -1) {
        candidates.remove(bestIdx);
    }
    return best;
}
Also used : MethodElement(org.revapi.java.model.MethodElement)

Aggregations

MethodElement (org.revapi.java.model.MethodElement)7 TypeElement (org.revapi.java.model.TypeElement)5 Element (org.revapi.Element)4 ArrayList (java.util.ArrayList)3 List (java.util.List)3 HashMap (java.util.HashMap)2 IdentityHashMap (java.util.IdentityHashMap)2 Map (java.util.Map)2 TreeMap (java.util.TreeMap)2 Collectors.toList (java.util.stream.Collectors.toList)2 CoIterator (org.revapi.CoIterator)2 IOException (java.io.IOException)1 InputStreamReader (java.io.InputStreamReader)1 Reader (java.io.Reader)1 StringReader (java.io.StringReader)1 Charset (java.nio.charset.Charset)1 Collection (java.util.Collection)1 Collections.emptyList (java.util.Collections.emptyList)1 Comparator (java.util.Comparator)1 Iterator (java.util.Iterator)1