Skip to content

Commit

Permalink
[fact] Actually attach content conflicts to spoon nodes #43
Browse files Browse the repository at this point in the history
  • Loading branch information
slarse committed Mar 9, 2020
1 parent 448ca28 commit 18e4f98
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 35 deletions.
37 changes: 37 additions & 0 deletions src/main/java/se/kth/spork/spoon/ContentConflict.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package se.kth.spork.spoon;

import spoon.reflect.path.CtRole;

import java.util.Optional;

public class ContentConflict {
public static final String METADATA_KEY = "SPORK_CONTENT_CONFLICT";

private final CtRole role;
private final Optional<Object> base;
private final Object left;
private final Object right;

public ContentConflict(CtRole role, Optional<Object> base, Object left, Object right) {
this.role = role;
this.base = base;
this.left = left;
this.right = right;
}

public CtRole getRole() {
return role;
}

public Optional<Object> getBase() {
return base;
}

public Object getLeft() {
return left;
}

public Object getRight() {
return right;
}
}
9 changes: 9 additions & 0 deletions src/main/java/se/kth/spork/spoon/RoledValues.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@
* @author Simon Larsén
*/
class RoledValues extends ArrayList<Pair<CtRole, Object>> {

public RoledValues() {
super();
}

public RoledValues(Collection<? extends Pair<CtRole, Object>> collection) {
super(collection);
}

public void add(CtRole role, Object value) {
add(new Pair<>(role, value));
}
Expand Down
87 changes: 52 additions & 35 deletions src/main/java/se/kth/spork/spoon/Spoon3dmMerge.java
Original file line number Diff line number Diff line change
Expand Up @@ -203,64 +203,81 @@ private static void handleContentConflicts(TStar<SpoonNode, RoledValues> delta)
RoledValues leftRoledValues = revisions.second.getValue();
RoledValues rightRoledValues = revisions.third.getValue();

RoledValues mergedRoledValues = new RoledValues(leftRoledValues);

assert leftRoledValues.size() == rightRoledValues.size();

int conflicts = 0;
Deque<ContentConflict> unresolvedConflicts = new ArrayDeque<>();

for (int i = 0; i < leftRoledValues.size(); i++) {
int finalI = i;
Pair<CtRole, Object> leftPair = leftRoledValues.get(i);
Pair<CtRole, Object> rightPair = rightRoledValues.get(i);
assert leftPair.first == rightPair.first;

Optional<Object> baseValOpt = baseOpt.map(Content::getValue).map(rv -> rv.get(finalI))
.map(p -> p.second);

CtRole role = leftPair.first;
Object leftVal = leftPair.second;
Object rightVal = rightPair.second;

if (leftPair.equals(rightPair)) {
// this pair is not part of the conflict
// this pair cannot possibly conflict
continue;
} else {
// this pair is conflicting
++conflicts;
}

assert leftPair.first == rightPair.first;
CtRole role = leftPair.first;
// left and right pairs differ and are so conflicting
// we add them as a conflict, but will later remove it if the conflict can be resolved
unresolvedConflicts.push(
new ContentConflict(role, baseValOpt, leftVal, rightVal)
);

Optional<Object> base = baseOpt.map(Content::getValue).map(rv -> rv.get(finalI))
.map(p -> p.second);
Object leftVal = leftPair.second;
Object rightVal = rightPair.second;

Optional<?> merged = Optional.empty();

switch (role) {
case MODIFIER:
merged = mergeModifierKinds(
base.map(o -> (Set<ModifierKind>) o),
(Set<ModifierKind>) leftVal,
(Set<ModifierKind>) rightVal);
break;
case NAME:
case VALUE:
// FIXME This is not a merge, but a conflict embedding which should be done later, FIX
merged = Optional.of(SporkPrettyPrinter.START_CONFLICT + "\n"
+ leftVal + "\n" + SporkPrettyPrinter.MID_CONFLICT + "\n"
+ rightVal + "\n" + SporkPrettyPrinter.END_CONFLICT);
break;
default:
// pass
// if either value is equal to base, we keep THE OTHER one
if (baseValOpt.isPresent() && baseValOpt.get().equals(leftVal)) {
merged = Optional.of(rightVal);
} else if (baseValOpt.isPresent() && baseValOpt.get().equals(rightVal)) {
merged = Optional.of(leftVal);
} else {
// we need to actually work for this merge :(
switch (role) {
case MODIFIER:
merged = mergeModifierKinds(
baseValOpt.map(o -> (Set<ModifierKind>) o),
(Set<ModifierKind>) leftVal,
(Set<ModifierKind>) rightVal);
break;
case NAME:
case VALUE:
// FIXME This is not a merge, but a conflict embedding which should be done later, FIX
merged = Optional.of(SporkPrettyPrinter.START_CONFLICT + "\n"
+ leftVal + "\n" + SporkPrettyPrinter.MID_CONFLICT + "\n"
+ rightVal + "\n" + SporkPrettyPrinter.END_CONFLICT);
break;
default:
// pass
}
}



if (merged.isPresent()) {
leftRoledValues.set(i, role, merged.get());
rightRoledValues.set(i, role, merged.get());
--conflicts;
mergedRoledValues.set(i, role, merged.get());
unresolvedConflicts.pop();
}
}

if (conflicts == 0) {
// all content conflicts for this node were resolved
Set<Content<SpoonNode, RoledValues>> contents = new HashSet<>();
contents.add(new Content<>(pcs, leftRoledValues));
delta.setContent(pred, contents);
if (!unresolvedConflicts.isEmpty()) {
// at least one conflict was not resolved
pred.getElement().putMetadata(ContentConflict.METADATA_KEY, new ArrayList<>(unresolvedConflicts));
}

Set<Content<SpoonNode, RoledValues>> contents = new HashSet<>();
contents.add(new Content<>(pcs, mergedRoledValues));
delta.setContent(pred, contents);
}
}
}
Expand Down

0 comments on commit 18e4f98

Please sign in to comment.