io.rivulet.internal.rerun.ReplacementSetBuilder Maven / Gradle / Ivy
The newest version!
package io.rivulet.internal.rerun;
import edu.columbia.cs.psl.phosphor.struct.SinglyLinkedList;
import io.rivulet.internal.Violation;
import java.util.Iterator;
import java.util.LinkedHashSet;
/* Generates ReplacementSets based on supplied criteria. */
public class ReplacementSetBuilder implements ReplacementBuilder {
// List of builders for the elements of the generated ReplacementSets
private final SinglyLinkedList builders;
// Whether a rerun configuration generated with this builder must contain at least one of at least one of the
// ReplacementSets generated by this builder.
private boolean requiredForGeneration;
/* Constructs a new empty ReplacementSetBuilder. */
public ReplacementSetBuilder() {
this.builders = new SinglyLinkedList<>();
requiredForGeneration = false;
}
/* Adds the specified builder to the builder list. */
public ReplacementSetBuilder addBuilder(ReplacementBuilder builder) {
if(builder.isRequiredForGeneration()) {
requiredForGeneration = true;
}
this.builders.enqueue(builder);
return this;
}
@Override
public boolean isRequiredForGeneration() {
return requiredForGeneration;
}
@Override
public LinkedHashSet build(Violation violation) {
if(!checkBuilders(violation)) {
return new LinkedHashSet<>();
} else {
LinkedHashSet> sets = RerunConfigBuilder.getAllCombinations(builders, violation);
LinkedHashSet result = new LinkedHashSet<>();
for(LinkedHashSet set : sets) {
// If at least one of the Replacements in the set is required, then the whole set should be required
boolean required = false;
for(Replacement r : set) {
if(r.isRequired()) {
required = true;
break;
}
}
ReplacementSet replacementSet = new ReplacementSet(required);
// Add the Replacements to the set
for(Replacement r : set) {
replacementSet.addReplacement(r);
}
result.add(replacementSet);
}
return result;
}
}
/* If this instance is required for successful rerun generation checks that at least one of its builders that is
* required for rerun generation can be bound to a violation label and binds that builder to the label. Returns
* whether this binding was successful if needed, otherwise true. */
private boolean checkBuilders(Violation violation) {
if(isRequiredForGeneration()) {
boolean foundMatch = false;
Iterator it = builders.iterator();
for(ReplacementBuilder builder = it.next(); it.hasNext(); builder = it.next()) {
boolean bound = !builder.build(violation).isEmpty();
boolean isPayload = builder instanceof ReplacementImplBuilder && ((ReplacementImplBuilder)builder).isPayload();
if((builder.isRequiredForGeneration() || isPayload) && bound) {
foundMatch = true;
} else if(!bound && builder instanceof ReplacementImplBuilder) {
ReplacementImplBuilder implBuilder = (ReplacementImplBuilder) builder;
if(implBuilder.hasBaseSource()) {
implBuilder.isPayload(false);
implBuilder.required(false);
} else if(implBuilder.isPayload()) {
// Payload builder without baseSource could not be bound to a label.
it.remove();
}
}
}
return foundMatch;
} else {
return true;
}
}
}