Skip to content

Commit

Permalink
[fact] Refactor project layout
Browse files Browse the repository at this point in the history
  • Loading branch information
slarse committed Apr 15, 2020
1 parent c95b20e commit 6ed9c2c
Show file tree
Hide file tree
Showing 27 changed files with 182 additions and 143 deletions.
5 changes: 3 additions & 2 deletions src/main/java/se/kth/spork/base3dm/ChangeSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,9 @@ public List<Pcs<T>> getOtherRoots(Pcs<T> pcs) {
return Stream.of(pcs.getPredecessor(), pcs.getSuccessor()).flatMap(
node -> Stream.of(predecessors.get(node), successors.get(node))
.filter(Objects::nonNull)
.flatMap(Set::stream)
).filter(p -> !p.getRoot().equals(pcs.getRoot())).collect(Collectors.toList());
.flatMap(Set::stream))
.filter(p -> !p.getRoot().equals(pcs.getRoot()))
.collect(Collectors.toList());
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/main/java/se/kth/spork/cli/Cli.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import se.kth.spork.spoon.Compare;
import se.kth.spork.spoon.Parser;
import se.kth.spork.spoon.Spoon3dmMerge;
import se.kth.spork.spoon.printer.PrinterPreprocessor;
import se.kth.spork.util.LineBasedMerge;
import se.kth.spork.util.Pair;
import spoon.reflect.declaration.*;
Expand Down
1 change: 1 addition & 0 deletions src/main/java/se/kth/spork/spoon/ContentConflict.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package se.kth.spork.spoon;

import se.kth.spork.spoon.wrappers.RoledValue;
import spoon.reflect.path.CtRole;

import java.util.Optional;
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/se/kth/spork/spoon/ContentResolver.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package se.kth.spork.spoon;

import se.kth.spork.spoon.wrappers.RoledValue;
import se.kth.spork.spoon.wrappers.RoledValues;
import se.kth.spork.spoon.wrappers.SpoonNode;
import spoon.reflect.code.*;
import spoon.reflect.declaration.*;
import spoon.reflect.path.CtRole;
Expand Down
48 changes: 0 additions & 48 deletions src/main/java/se/kth/spork/spoon/MappingRemover.java

This file was deleted.

4 changes: 2 additions & 2 deletions src/main/java/se/kth/spork/spoon/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import se.kth.spork.cli.SourceExtractor;
import se.kth.spork.cli.SporkPrettyPrinter;
import se.kth.spork.spoon.printer.SourceExtractor;
import se.kth.spork.spoon.printer.SporkPrettyPrinter;
import se.kth.spork.util.Pair;
import spoon.Launcher;
import spoon.compiler.Environment;
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/se/kth/spork/spoon/PcsBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import se.kth.spork.base3dm.Pcs;
import se.kth.spork.base3dm.Revision;
import se.kth.spork.spoon.wrappers.NodeFactory;
import se.kth.spork.spoon.wrappers.SpoonNode;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.visitor.CtScanner;

Expand Down
71 changes: 13 additions & 58 deletions src/main/java/se/kth/spork/spoon/Spoon3dmMerge.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import se.kth.spork.base3dm.*;
import se.kth.spork.spoon.matching.ClassRepresentatives;
import se.kth.spork.spoon.matching.MappingRemover;
import se.kth.spork.spoon.matching.SpoonMapping;
import se.kth.spork.spoon.pcsinterpreter.PcsInterpreter;
import se.kth.spork.spoon.wrappers.RoledValues;
import se.kth.spork.spoon.wrappers.SpoonNode;
import se.kth.spork.util.Pair;
import spoon.reflect.declaration.*;

Expand All @@ -31,8 +37,9 @@ public class Spoon3dmMerge {
*/
public static Pair<CtModule, Boolean> merge(Path base, Path left, Path right) {
long start = System.nanoTime();
LOGGER.info("Parsing files to Spoon trees");

// PARSING PHASE
LOGGER.info("Parsing files to Spoon trees");
CtModule baseTree = Parser.parse(base);
CtModule leftTree = Parser.parse(left);
CtModule rightTree = Parser.parse(right);
Expand All @@ -56,6 +63,7 @@ public static Pair<CtModule, Boolean> merge(Path base, Path left, Path right) {
public static <T extends CtElement> Pair<T, Boolean> merge(T base, T left, T right) {
long start = System.nanoTime();

// MATCHING PHASE
LOGGER.info("Converting to GumTree trees");
ITree baseGumtree = new SpoonGumTreeBuilder().getTree(base);
ITree leftGumtree = new SpoonGumTreeBuilder().getTree(left);
Expand All @@ -71,6 +79,7 @@ public static <T extends CtElement> Pair<T, Boolean> merge(T base, T left, T rig
SpoonMapping baseRight = SpoonMapping.fromGumTreeMapping(baseRightGumtreeMatch.getMappings());
SpoonMapping leftRight = SpoonMapping.fromGumTreeMapping(leftRightGumtreeMatch.getMappings());

// 3DM PHASE
LOGGER.info("Mapping nodes to class representatives");
Map<SpoonNode, SpoonNode> classRepMap = ClassRepresentatives.createClassRepresentativesMapping(
base, left, right, baseLeft, baseRight, leftRight);
Expand All @@ -87,11 +96,11 @@ public static <T extends CtElement> Pair<T, Boolean> merge(T base, T left, T rig
LOGGER.info("Resolving final PCS merge");
TdmMerge.resolveRawMerge(t0Star, delta);

Set<SpoonNode> rootConflictingNodes = extractRootConflictingNodes(delta.getStructuralConflicts());
Set<SpoonNode> rootConflictingNodes = StructuralConflict.extractRootConflictingNodes(delta.getStructuralConflicts());
if (!rootConflictingNodes.isEmpty()) {
LOGGER.info("Root conflicts detected, restarting merge");
LOGGER.info("Removing root conflicting nodes from tree matchings");
removeFromMappings(rootConflictingNodes, baseLeft, baseRight, leftRight);
MappingRemover.removeFromMappings(rootConflictingNodes, baseLeft, baseRight, leftRight);

LOGGER.info("Mapping nodes to class representatives");
classRepMap = ClassRepresentatives.createClassRepresentativesMapping(
Expand All @@ -104,6 +113,7 @@ public static <T extends CtElement> Pair<T, Boolean> merge(T base, T left, T rig
TdmMerge.resolveRawMerge(t0Star, delta);
}

// INTERPRETER PHASE
LOGGER.info("Interpreting resolved PCS merge");
Pair<CtElement, Boolean> merge = PcsInterpreter.fromMergedPcs(delta, baseLeft, baseRight);
// we can be certain that the merge tree has the same root type as the three constituents, so this cast is safe
Expand All @@ -120,61 +130,6 @@ public static <T extends CtElement> Pair<T, Boolean> merge(T base, T left, T rig
return Pair.of(mergeTree, hasConflicts);
}

/**
* Remove the provided nodes from the mappings, along with all of their descendants and any associated virtual
* nodes. This is a method of allowing certain forms of conflicts to pass by, such as root conflicts. By removing
* the mapping, problems with duplicated nodes is removed.
*/
private static void
removeFromMappings(Set<SpoonNode> nodes, SpoonMapping baseLeft, SpoonMapping baseRight, SpoonMapping leftRight) {
MappingRemover baseLeftMappingRemover = new MappingRemover(baseLeft);
MappingRemover baseRightMappingRemover = new MappingRemover(baseRight);
MappingRemover leftRightMappingRemover = new MappingRemover(leftRight);

for (SpoonNode node : nodes) {
switch (node.getRevision()) {
case BASE:
baseLeftMappingRemover.removeRelatedMappings(node);
baseRightMappingRemover.removeRelatedMappings(node);
break;
case LEFT:
baseLeftMappingRemover.removeRelatedMappings(node);
leftRightMappingRemover.removeRelatedMappings(node);
break;
case RIGHT:
baseRightMappingRemover.removeRelatedMappings(node);
leftRightMappingRemover.removeRelatedMappings(node);
break;
}
}
}

private static Set<SpoonNode>
extractRootConflictingNodes(Map<Pcs<SpoonNode>, Set<Pcs<SpoonNode>>> structuralConflicts) {
Set<SpoonNode> toIgnore = new HashSet<>();

for (Map.Entry<Pcs<SpoonNode>, Set<Pcs<SpoonNode>>> entry : structuralConflicts.entrySet()) {
Pcs<SpoonNode> pcs = entry.getKey();
for (Pcs<SpoonNode> other : entry.getValue()) {
if (isRootConflict(pcs, other)) {
if (pcs.getPredecessor().equals(other.getPredecessor())) {
toIgnore.add(other.getPredecessor());
}
if (pcs.getSuccessor().equals(other.getSuccessor())) {
toIgnore.add(other.getSuccessor());
}
}
}
}
return toIgnore;
}

private static boolean isRootConflict(Pcs<?> left, Pcs<?> right) {
return !Objects.equals(left.getRoot(), right.getRoot()) &&
(Objects.equals(left.getPredecessor(), right.getPredecessor()) ||
Objects.equals(left.getSuccessor(), right.getSuccessor()));
}

/**
* Merge import statements from base, left and right. Import statements are expected to be attached
* to each tree's root node metadata with the {@link Parser#IMPORT_STATEMENTS} key.
Expand Down
24 changes: 22 additions & 2 deletions src/main/java/se/kth/spork/spoon/StructuralConflict.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package se.kth.spork.spoon;

import se.kth.spork.base3dm.Pcs;
import se.kth.spork.spoon.wrappers.SpoonNode;
import spoon.reflect.declaration.CtElement;

import java.util.List;
import java.util.Objects;
import java.util.*;

/**
* A simple class that provides some information on a structural conflict. Meant to be put as metadata on a conflict
Expand Down Expand Up @@ -43,4 +43,24 @@ public static boolean isSuccessorConflict(Pcs<?> left, Pcs<?> right) {
Objects.equals(left.getPredecessor(), right.getPredecessor()) &&
Objects.equals(left.getRoot(), right.getRoot());
}

public static Set<SpoonNode>
extractRootConflictingNodes(Map<Pcs<SpoonNode>, Set<Pcs<SpoonNode>>> structuralConflicts) {
Set<SpoonNode> toIgnore = new HashSet<>();

for (Map.Entry<Pcs<SpoonNode>, Set<Pcs<SpoonNode>>> entry : structuralConflicts.entrySet()) {
Pcs<SpoonNode> pcs = entry.getKey();
for (Pcs<SpoonNode> other : entry.getValue()) {
if (isRootConflict(pcs, other)) {
if (pcs.getPredecessor().equals(other.getPredecessor())) {
toIgnore.add(other.getPredecessor());
}
if (pcs.getSuccessor().equals(other.getSuccessor())) {
toIgnore.add(other.getSuccessor());
}
}
}
}
return toIgnore;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package se.kth.spork.spoon;
package se.kth.spork.spoon.matching;

import se.kth.spork.base3dm.Revision;
import se.kth.spork.base3dm.TdmMerge;
import se.kth.spork.spoon.wrappers.SpoonNode;
import se.kth.spork.spoon.wrappers.NodeFactory;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.visitor.CtScanner;

Expand All @@ -16,7 +18,7 @@
*
* @author Simon Larsén
*/
class ClassRepresentatives {
public class ClassRepresentatives {
/**
* Create the class representatives mapping. The class representatives for the different revisions are defined as:
*
Expand All @@ -40,7 +42,7 @@ class ClassRepresentatives {
* @param leftRight A matching from left to right.
* @return The class representatives map.
*/
static Map<SpoonNode, SpoonNode> createClassRepresentativesMapping(
public static Map<SpoonNode, SpoonNode> createClassRepresentativesMapping(
CtElement base,
CtElement left,
CtElement right,
Expand Down
87 changes: 87 additions & 0 deletions src/main/java/se/kth/spork/spoon/matching/MappingRemover.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package se.kth.spork.spoon.matching;

import se.kth.spork.spoon.wrappers.SpoonNode;
import se.kth.spork.spoon.wrappers.NodeFactory;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.visitor.CtScanner;

import java.util.Set;

/**
* Utility class for removing a node, along with all of its descendants, from a {@link SpoonMapping} instance.
*
* @author Simon Larsén
*/
public class MappingRemover extends CtScanner {
private final SpoonMapping mapping;

/**
* Create a mapping remover for the provided mapping.
*
* @param mapping A mapping that this remover will operate on.
*/
public MappingRemover(SpoonMapping mapping) {
this.mapping = mapping;
}

/**
* Remove the provided nodes from the mappings, along with all of their descendants and any associated virtual
* nodes. This is a method of allowing certain forms of conflicts to pass by, such as root conflicts. By removing
* the mapping, problems with duplicated nodes is removed.
*
* @param nodes A set of nodes to remove from the mappings.
* @param baseLeft A base-to-left mapping.
* @param baseRight A base-to-right mapping.
* @param leftRight A left-to-right mapping.
*/
public static void
removeFromMappings(Set<SpoonNode> nodes, SpoonMapping baseLeft, SpoonMapping baseRight, SpoonMapping leftRight) {
MappingRemover baseLeftMappingRemover = new MappingRemover(baseLeft);
MappingRemover baseRightMappingRemover = new MappingRemover(baseRight);
MappingRemover leftRightMappingRemover = new MappingRemover(leftRight);

for (SpoonNode node : nodes) {
switch (node.getRevision()) {
case BASE:
leftRightMappingRemover.removeRelatedMappings(baseLeft.getDst(node));
baseLeftMappingRemover.removeRelatedMappings(node);
baseRightMappingRemover.removeRelatedMappings(node);
break;
case LEFT:
baseLeftMappingRemover.removeRelatedMappings(node);
leftRightMappingRemover.removeRelatedMappings(node);
break;
case RIGHT:
baseRightMappingRemover.removeRelatedMappings(node);
leftRightMappingRemover.removeRelatedMappings(node);
break;
}
}
}

/**
* Remove this node and its associated virtual nodes from the mapping, and recursively remove all of its
* descendants in the same way.
*
* @param node A node to remove from the mapping.
*/
public void removeRelatedMappings(SpoonNode node) {
CtElement elem = node.getElement();
scan(elem);
}

@Override
public void scan(CtElement element) {
if (element == null) {
return;
}

SpoonNode node = NodeFactory.wrap(element);

mapping.remove(node);
mapping.remove(NodeFactory.startOfChildList(node));
mapping.remove(NodeFactory.startOfChildList(node));

super.scan(element);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package se.kth.spork.spoon;
package se.kth.spork.spoon.matching;

import com.github.gumtreediff.matchers.Mapping;
import com.github.gumtreediff.matchers.MappingStore;
import com.github.gumtreediff.tree.ITree;
import com.github.gumtreediff.utils.Pair;
import gumtree.spoon.builder.SpoonGumTreeBuilder;
import se.kth.spork.spoon.wrappers.SpoonNode;
import se.kth.spork.spoon.wrappers.NodeFactory;
import se.kth.spork.util.GumTreeSpoonAstDiff;
import spoon.reflect.declaration.CtAnnotation;
import spoon.reflect.declaration.CtElement;
Expand Down
Loading

0 comments on commit 6ed9c2c

Please sign in to comment.