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