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);
}
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;
}
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);
}
};
};
}
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);
}
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;
}
Aggregations