Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
164 commits
Select commit Hold shift + click to select a range
1b54094
basic patching idea
piameier Jul 17, 2025
692d6c6
code refactoring
piameier Jul 19, 2025
c35bebc
fixed bugs
piameier Jul 21, 2025
91f3ffa
find insert position for ADD and check neigbors for REM
piameier Jul 21, 2025
24cf2bf
refactoring checkNeighbors method
piameier Jul 22, 2025
1b59508
refactoring findInsertPosition method and formatting code
piameier Jul 22, 2025
28cd47b
consider order when patching (line numbers), fixed bugs
piameier Jul 23, 2025
c9f05da
feat: VariationDiff::computeAllFeatureNames()
pmbittner Sep 23, 2025
8ac9a86
feat: configurations from formula assignments
pmbittner Sep 23, 2025
58acae5
fix: LinkedHashSet for deterministic computeAllFeatureNames
pmbittner Sep 25, 2025
0437b28
basic patching idea
piameier Jul 17, 2025
a724fb9
code refactoring
piameier Jul 19, 2025
836d6ab
fixed bugs
piameier Jul 21, 2025
dcf2d88
find insert position for ADD and check neigbors for REM
piameier Jul 21, 2025
bb766ae
refactoring checkNeighbors method
piameier Jul 22, 2025
6fbdcb5
refactoring findInsertPosition method and formatting code
piameier Jul 22, 2025
0994bae
consider order when patching (line numbers), fixed bugs
piameier Jul 23, 2025
a3a02fb
fixed bug
piameier Jul 24, 2025
5fdc441
patch with diff generated from files
piameier Jul 24, 2025
02aa6ba
refactoring, detect alignment problem for ADD nodes, fixed: show subt…
piameier Jul 25, 2025
7cba4bd
changed gitignore
piameier Jul 25, 2025
b6e835a
examples add, rem, add-rem, add-alignment, rem-alignment
piameier Jul 25, 2025
dbe6ba5
detect alignment problem for REM nodes
piameier Jul 25, 2025
c67ea43
example rem-add-alignment
piameier Jul 27, 2025
8a33fb9
fixed bug: alignment problem detection in findInsertPosition()
piameier Jul 27, 2025
39e0483
check for zero variant drift before patching
piameier Jul 27, 2025
db7a551
compare patched variant and expected result
piameier Jul 29, 2025
cde3999
expected result for example rem-add
piameier Jul 29, 2025
8e81fa7
fixed bug in findInsertPosition
piameier Jul 29, 2025
cb25dce
fixed bugs
piameier Jul 30, 2025
5e58efb
added removeNode to recursively drop nodes
piameier Jul 30, 2025
e6a5ad6
fixed bug with untouched nodes but with changed parents
piameier Aug 1, 2025
170206d
example nodes-with-2-parents
piameier Aug 1, 2025
86d4c22
moved source code from PatchingExperiment to Patching class
piameier Aug 1, 2025
33efa25
removed unused imports
piameier Aug 1, 2025
3d3fd1c
prepared patching analysis
piameier Aug 1, 2025
f31cfbf
improved checkNeighbors with findNearestPositionToIndex()
piameier Aug 1, 2025
7e94413
added context size to check more than one neighbor before and after t…
piameier Aug 1, 2025
b48ac2d
fixed bugs
piameier Aug 4, 2025
dddff0f
implemented compareAncestors() and fixed bugs
piameier Aug 23, 2025
9da7092
fixed bugs, alternative methods for patching same variants
piameier Aug 24, 2025
a7c6672
simplified and fixed bugs
piameier Aug 24, 2025
580a777
fixed bugs for incorrect patched variation trees (new features were m…
piameier Sep 23, 2025
aa4c8f0
update patching experiment, possibility to write patch out to file
piameier Sep 24, 2025
b1c149e
fixed bugs: rejected insert due to unmodified nodes with two parents …
piameier Sep 24, 2025
4bd5546
fixed bug: FixTrueFalse Formula for deselecting features in view
piameier Sep 25, 2025
77b2d6a
fixed bug in resolve()
piameier Sep 30, 2025
ff05f1d
patch variants
piameier Oct 4, 2025
49018ae
refactoring code
piameier Oct 4, 2025
38ac7fe
experiment setup
piameier Oct 4, 2025
76eaa2a
added method arePatchedVariantsEquivalent
piameier Oct 5, 2025
01c2fe4
shell command classes for diff, gnu patch and mpatch
piameier Oct 5, 2025
1d3e9e0
fixed bug in arePatchedVariantsEquivalent
piameier Oct 5, 2025
d1237be
modify target patch to fix bug
piameier Oct 5, 2025
10693dd
remove artifact nodes which are children of the root to compare uncha…
piameier Oct 6, 2025
831344f
unchanged relevance predicate
piameier Oct 17, 2025
e0adf36
fixed method arePatchedVariantsEquivalent()
piameier Oct 17, 2025
c1287d5
fixed method arePatchedVariantsEquivalent()
piameier Oct 17, 2025
a798ab8
test equivalence for figure in master thesis
piameier Oct 17, 2025
bea648d
adjusted generator and fixed gnupatch and mpatch commands
piameier Oct 17, 2025
386b370
workaround: changed to LF lineendings
piameier Oct 17, 2025
80561b0
fixed bug in EliminateEmptyAlternatives
piameier Oct 23, 2025
dd34a35
eliminate empty alternatives after variant configurations
piameier Oct 23, 2025
0c0cbe2
work on generator
piameier Oct 27, 2025
f2158a4
refactor generator
piameier Oct 27, 2025
5dc1705
runpatchers in patching experiment
piameier Oct 27, 2025
c1a2322
fix from paul for updating labels in EliminateEmptyAlternatives
piameier Oct 29, 2025
0a711fc
work on experiment
piameier Oct 29, 2025
1df8e22
imrpoved performance of Unchanged() slicing criterion
piameier Nov 3, 2025
3ffeb1e
removed sysout in Unchanged()
piameier Nov 3, 2025
93a0841
improved performance of method arePatchedVariantsEquivalent()
piameier Nov 3, 2025
173c77d
fixed bugs in patching
piameier Nov 5, 2025
b5110e8
added changes from fixConfigure branch
piameier Nov 5, 2025
4f3a895
added node identifier by presence condition
piameier Nov 5, 2025
ec7816d
use view on source patch configured with target for unchanged
piameier Nov 5, 2025
53ec6b5
fixed checkNeighbors2 for patching different variants
piameier Nov 5, 2025
6175510
fixed bug for empty lists in checkNeighbors2
piameier Nov 5, 2025
0793eca
fixed bug for empty lists in checkNeighbors2
piameier Nov 5, 2025
259199a
added experiment with view on patch configured to target variant
piameier Nov 7, 2025
7b0e8bd
fixed bug in isSameList
piameier Nov 8, 2025
6e2a888
store diffs to filesystem if our patching transformator failed
piameier Nov 8, 2025
3a2a14c
store diffs of failed patches (patch transformer) after running all c…
piameier Nov 8, 2025
2e5d5db
fixed bug when removing nodes from a subtree
piameier Nov 8, 2025
d9cf4c7
fixed bug in blank lines (unchanged criterion), formatted file
piameier Nov 10, 2025
9f5fba6
write ore files to filesystem to analyze later
piameier Nov 10, 2025
c2f2f9b
extended unchanged: compare before and after line, test if node is pr…
piameier Nov 10, 2025
beef266
fixed view variants, fixed mpatch
piameier Nov 11, 2025
462f36c
process view variants (gnu, mpatch) afterwards with new files
piameier Nov 11, 2025
1678346
unchanged considering lines before and after
piameier Nov 11, 2025
6ab67a1
patch scenario update
piameier Nov 11, 2025
78f3885
main update
piameier Nov 11, 2025
35a414e
added commit hash to directory name when generating variants
piameier Nov 12, 2025
ff61a86
added dataset
piameier Nov 12, 2025
5a95a5b
fixed bugs for commit hash, use release mpatch
piameier Nov 12, 2025
f45fffa
removed unsused, not existing imports
piameier Nov 12, 2025
bcbc652
write rejected patches of the patch transformer to filesystem
piameier Nov 12, 2025
8e9c386
removed sysout for resultcode
piameier Nov 12, 2025
7b58ccd
removed sysout for resultcode
piameier Nov 12, 2025
773eda2
fixed bugs in unchanged
piameier Nov 12, 2025
4583e7b
fixed bug
piameier Nov 12, 2025
e839aae
clear rejected patches map after writing/end batch
piameier Nov 12, 2025
a6ddc0c
added counters for unchanged or configure comparison failure
piameier Nov 12, 2025
5c1cfbf
added relevance configure with full configuration
piameier Nov 12, 2025
00118cd
fixed bug
piameier Nov 12, 2025
53a697b
computeAllFeatureNames: changed return type to object
piameier Nov 12, 2025
116fa18
switched to configureWithFullConfig
piameier Nov 12, 2025
2ad7eac
updated patching
piameier Nov 12, 2025
5dc4043
fixed runPatchers method
piameier Nov 12, 2025
65d681b
clean up script for experiment directories
piameier Nov 12, 2025
2f145bd
test cases
piameier Nov 12, 2025
762d476
fixed bug: enforce brackets in updatedLabel
piameier Nov 13, 2025
79d2382
fixed bug: added true and false names to assignment
piameier Nov 13, 2025
174b291
merged
piameier Nov 13, 2025
371bd40
use elimEmptyAlternatives in Generator again, removed constraint for …
piameier Nov 13, 2025
783ec2d
disable logger output
piameier Nov 13, 2025
3bac321
work around for negated features by elim. empty altern.
piameier Nov 13, 2025
ae4d808
updated patching experiment
piameier Nov 13, 2025
ffe3056
updated generator
piameier Nov 13, 2025
4d75b41
compare with empty lines
piameier Nov 13, 2025
ec8f0c2
results busybox
piameier Nov 14, 2025
755c2bd
changed to non static map and elim method
piameier Nov 14, 2025
eacb6ab
fixed patching experiment counters
piameier Nov 14, 2025
51d5bde
resetted number of commits per thread
piameier Nov 15, 2025
6555f03
new eval results
piameier Nov 15, 2025
9665928
Merge branch 'VariantSync:main' into main
piameier Jan 25, 2026
996e53d
deleted example files
piameier Jan 25, 2026
5720cc5
README: Note on where to find code of L. Güthing
pmbittner Oct 21, 2025
531b30c
README: bachelor's thesis of Eugen Shulimov
pmbittner Oct 21, 2025
69f46fd
README: section on supported diff algorithms
pmbittner Oct 21, 2025
eea15e0
README: update commuting diagram
pmbittner Oct 21, 2025
8eaebed
Update README.md
pmbittner Oct 26, 2025
7f200e8
Update README.md
pmbittner Oct 26, 2025
5b5a4cb
refactor: reuse `VariationNode.assertConsistency` in `DiffNode`
ibbem Oct 30, 2025
f65479f
feat: assert that there is at most one ELIF/ELSE
ibbem Oct 30, 2025
7c4366a
feat: assert that the root `DiffNode` is unchanged
ibbem Oct 30, 2025
e556df0
feat: `VariationTree.assertConsistency`
ibbem Oct 30, 2025
a138e4f
refactor: improve the source tracing mechanism
ibbem Oct 23, 2025
bcef3b7
feat: improve the source tracking to reduce `Source.Unknown`
ibbem Oct 24, 2025
b55b781
feat: create an interface for and a collection of differs
ibbem Oct 13, 2025
88d6f38
fix: close `ZipFile` in `GitLoader`
ibbem Oct 23, 2025
c0f3a4f
doc: fix a typo in `VariationDiffLabelFormat`
ibbem Oct 23, 2025
13561e7
fix(README): path to visual abstract
pmbittner Nov 3, 2025
6da8855
remove unused symlink
pmbittner Nov 3, 2025
1a3b70f
fix: ConfigureSpec vs new Source interface
pmbittner Nov 5, 2025
a3c4098
Source::functionExplanation
pmbittner Nov 6, 2025
71340ca
make VariationTree a class instead of a record
pmbittner Nov 6, 2025
df60cf1
VariationTree::setSource
pmbittner Nov 6, 2025
c001d16
make ViewSource applicable to trees as well
pmbittner Nov 6, 2025
1f09fbc
fix: relevance not treated as source in ViewSource
pmbittner Nov 6, 2025
577d6e1
ViewSource::toString()
pmbittner Nov 6, 2025
8175f2f
use functionExplanation for VDiff/Vtree::toString
pmbittner Nov 6, 2025
d6f3684
make BadVDiff be a source
pmbittner Nov 6, 2025
ea50301
document TreeView as a source
pmbittner Nov 6, 2025
a7c5bbb
rename: VariationTree::root() -> VariationTree::getRoot()
pmbittner Nov 6, 2025
e4975db
use functionExplanation in Show titles
pmbittner Nov 6, 2025
7859361
increase version number to 2.4.0
pmbittner Nov 5, 2025
51b97ae
fixed bug in EliminateEmptyAlternatives
piameier Oct 23, 2025
08a4587
fix from paul for updating labels in EliminateEmptyAlternatives
piameier Oct 29, 2025
8e79d24
added changes from fixConfigure branch
piameier Nov 5, 2025
d2247c4
Merge branch 'main' into prototyping
piameier Feb 2, 2026
9bc7ae0
clean up
piameier Feb 2, 2026
97433b8
clean up
piameier Feb 3, 2026
2878951
elim empty alternatives
piameier Feb 3, 2026
a7b2208
fixed and clean up generator
piameier Feb 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.variantsync.diffdetective.experiments.thesis_pm;

import org.variantsync.diffdetective.variation.DiffLinesLabel;
import org.variantsync.diffdetective.variation.Label;
import org.variantsync.diffdetective.variation.diff.Time;
import org.variantsync.diffdetective.variation.diff.VariationDiff;
import org.variantsync.diffdetective.variation.diff.view.DiffView;
import org.variantsync.diffdetective.variation.tree.VariationTree;
import org.variantsync.diffdetective.variation.tree.view.TreeView;
import org.variantsync.diffdetective.variation.tree.view.relevance.Configure;
import org.variantsync.diffdetective.variation.tree.view.relevance.ConfigureWithFullConfig;
import org.variantsync.diffdetective.variation.tree.view.relevance.Unchanged;

public class PatchScenario<L extends Label> {
public VariationDiff<L> sourcePatch;
public VariationTree<L> targetVariantBefore;
public VariationDiff<L> patchGroundTruth;
public VariationTree<L> patchedVariantGroundTruth;
public ConfigureWithFullConfig sourceVariantConfig;
public ConfigureWithFullConfig targetVariantConfig;
public VariationTree<DiffLinesLabel> sourceVariantAfterRedToCrossVarFeatures;
public Unchanged unchangedAfter;
public VariationTree<DiffLinesLabel> targetVariantBeforeRedToUnchanged;

public PatchScenario(VariationDiff<L> sourcePatch,
VariationTree<L> targetVariantBefore, VariationDiff<L> patchGroundTruth,
VariationTree<L> patchedVariantGroundTruth, ConfigureWithFullConfig sourceVariantConfig, ConfigureWithFullConfig targetVariantConfig) {
this.sourcePatch = sourcePatch;
this.targetVariantBefore = targetVariantBefore;
this.patchGroundTruth = patchGroundTruth;
this.patchedVariantGroundTruth = patchedVariantGroundTruth;
this.sourceVariantConfig = sourceVariantConfig;
this.targetVariantConfig = targetVariantConfig;
this.sourceVariantAfterRedToCrossVarFeatures = (VariationTree<DiffLinesLabel>) TreeView.tree(sourcePatch.project(Time.AFTER), this.targetVariantConfig);
VariationDiff<DiffLinesLabel> sourcePatchConfiguredToCrossVarFeatures = (VariationDiff<DiffLinesLabel>) DiffView.optimized(sourcePatch, targetVariantConfig);
this.unchangedAfter = new Unchanged((VariationDiff<DiffLinesLabel>) sourcePatchConfiguredToCrossVarFeatures, Time.AFTER);
Unchanged unchangedBefore = new Unchanged((VariationDiff<DiffLinesLabel>) sourcePatchConfiguredToCrossVarFeatures, Time.BEFORE);
this.targetVariantBeforeRedToUnchanged = (VariationTree<DiffLinesLabel>) TreeView.tree(this.targetVariantBefore, unchangedBefore);
}
}

Large diffs are not rendered by default.

55 changes: 55 additions & 0 deletions src/main/java/org/variantsync/diffdetective/shell/DiffCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.variantsync.diffdetective.shell;

import java.util.List;

/** Single executable command with arguments. */
public class DiffCommand extends ShellCommand {
private final String[] parts;
private boolean filesDifferent;

/**
* Constructs a single command.
* The first argument has to be a path to an executable which will be given all of the
* remaining arguments as parameters on execution.
*
* @param cmd executable path and arguments for the executable
*/
public DiffCommand(final String... cmd) {
parts = cmd;
}

@Override
public String[] parts() {
return parts;
}

/**
* Interpret the result/exit code returned from a shell command.
* An {@code ShellException} is thrown if the result code is an error.
*
* @param resultCode the code that is to be parsed
* @param output the output of the shell command
* @return the output of the shell command
* @throws ShellException if {@code resultCode} is an error
*/
@Override
public List<String> interpretResult(int resultCode, List<String> output) throws ShellException {
// inputs are the same
if (resultCode == 0) {
filesDifferent = false;
return output;
}
// if inputs are different
if (resultCode == 1) {
filesDifferent = true;
return output;
}
// everything else: "serious trouble": exit code 2
throw new ShellException(output);

}

public boolean areFilesDifferent() {
return filesDifferent;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.variantsync.diffdetective.shell;

import java.util.List;

/** Single executable command with arguments. */
public class GnuPatchCommand extends ShellCommand {
private final String[] parts;
private boolean patchingSuccessful;

/**
* Constructs a single command.
* The first argument has to be a path to an executable which will be given all of the
* remaining arguments as parameters on execution.
*
* @param cmd executable path and arguments for the executable
*/
public GnuPatchCommand(final String... cmd) {
parts = cmd;
}

@Override
public String[] parts() {
return parts;
}

/**
* Interpret the result/exit code returned from a shell command.
* An {@code ShellException} is thrown if the result code is an error.
*
* @param resultCode the code that is to be parsed
* @param output the output of the shell command
* @return the output of the shell command
* @throws ShellException if {@code resultCode} is an error
*/
@Override
public List<String> interpretResult(int resultCode, List<String> output) throws ShellException {
// patching was successful
if (resultCode == 0) {
patchingSuccessful = true;
return null;
}
// some hunks cannot be applied or merge conflicts
if (resultCode == 1) {
patchingSuccessful = false;
return null;
}
// everything else: "serious trouble": exit code 2
throw new ShellException(output);

}

public boolean isPatchingSuccessful() {
return patchingSuccessful;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.variantsync.diffdetective.shell;

import java.util.List;

/** Single executable command with arguments. */
public class MPatchCommand extends ShellCommand {
private final String[] parts;
private boolean patchingSuccessful;

/**
* Constructs a single command.
* The first argument has to be a path to an executable which will be given all of the
* remaining arguments as parameters on execution.
*
* @param cmd executable path and arguments for the executable
*/
public MPatchCommand(final String... cmd) {
parts = cmd;
}

@Override
public String[] parts() {
return parts;
}

/**
* Interpret the result/exit code returned from a shell command.
* An {@code ShellException} is thrown if the result code is an error.
*
* @param resultCode the code that is to be parsed
* @param output the output of the shell command
* @return the output of the shell command
* @throws ShellException if {@code resultCode} is an error
*/
@Override
public List<String> interpretResult(int resultCode, List<String> output) throws ShellException {
// patching was successful ???
if (resultCode == 0) {
patchingSuccessful = true;
return null;
}
// some hunks cannot be applied or merge conflicts ???
if (resultCode == 1) {
patchingSuccessful = false;
return null;
}
// everything else: "serious trouble": exit code 2 ???
throw new ShellException(output);

}

public boolean isPatchingSuccessful() {
return patchingSuccessful;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/** A collection of useful utilities related to string processing. */
public class StringUtils {
/** An operating system independent line break used in almost all internal strings. */
public final static String LINEBREAK = "\r\n";
public final static String LINEBREAK = "\n";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this change is sensible. I do not remember why we chose CRLF here in the first place.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the comment states, we introduced LINEBREAK instead of using System.lineSeparator to ensure that the line endings of our outputs are independent of the operating system. In particular, if I remember correctly, there was an issue with some dependency (something line graph related according to the Git history) that caused issues on Windows. As windows applications typically take issue with parsing text files without carriage returns while Linux applications just treat the carriage return as data, we use '\r\n' for all outputs.

In summary, the biggest potential issue is probably Windows compatibility. As the output of DiffDetective will not match the expectations in that environment. However, I think we don't use this constant very consistently anyways.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the detailed analysis. If I remember correctly, some tests that read/write files failed on Windows but not Linux. 🤔

Maybe it is safest to just leave LINEBREAK as is, and maybe add a second constant LINEBREAK_LF for code parts of @piameier.

/** A regex to identify line breaks of any operating system .*/
public final static Pattern LINEBREAK_REGEX = Pattern.compile("\\r\\n|\\r|\\n");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,16 +378,16 @@ public int count(final Predicate<DiffNode<L>> nodesToCount) {
* This method is deterministic: It will return the feature names always in the same order, assuming the variation diff is not changed inbetween.
* @return A set of every occuring feature name.
*/
public LinkedHashSet<String> computeAllFeatureNames() {
LinkedHashSet<String> features = new LinkedHashSet<>();
public LinkedHashSet<Object> computeAllFeatureNames() {
LinkedHashSet<Object> features = new LinkedHashSet<>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was it necessary to turn these strings into objects, only to recover that lost information by casting a few lines later?

forAll(node -> {
if (node.isConditionalAnnotation()) {
features.addAll(node.getFormula().getUniqueContainedFeatures());
}
});
// Since FeatureIDE falsely reports constants "True" and "False" as feature names, we have to remove them from the resulting set.
features.removeIf(FixTrueFalse::isTrueLiteral);
features.removeIf(FixTrueFalse::isFalseLiteral);
features.removeIf(f -> FixTrueFalse.isTrueLiteral((String) f));
features.removeIf(f -> FixTrueFalse.isFalseLiteral((String) f));
return features;
}

Expand Down
Loading
Loading