RefDiff
RefDiff is a tool to mine refactorings in the commit history of git repositories. Currently, three programming languages are supported: Java, JavaScript, and C.
RefDiff finds relationships between code elements of two given revisions of the project. Relationships indicate that both elements are the same, or that a refactoring operation involving them was applied. The following relationship types are supported:
- Same
- Convert Type
- Change Signature of Method/Function
- Pull Up Method
- Push Down Method
- Rename
- Move
- Move and Rename
- Extract Supertype (e.g., Class/Interface)
- Extract Method/Function
- Inline Method/Function
Getting started
Before building the project, make sure you have git and a Java Development Kit (JDK) version 8 installed in your system. Also, set the JAVA_HOME environment variable to point to the installation directory of the desired JDK.
git clone https://github.com/aserg-ufmg/RefDiff.git
Use gradle to create the Eclipse IDE project metadata. For example, in Windows systems:
cd RefDiff
gradlew eclipse
Note that in Linux or Mac you should run ./gradlew eclipse
to run the gradle wrapper.
Import all projects within RefDiff
folder to Eclipse. Then, see the examples in RefDiffExample.java
from refdiff-example
.
You can detect refactorings in a certain repository/commit using the following code:
private static void runExamples() throws Exception {
// This is a temp folder to clone or checkout git repositories.
File tempFolder = new File("temp");
// Creates a RefDiff instance configured with the JavaScript plugin.
JsPlugin jsPlugin = new JsPlugin();
RefDiff refDiffJs = new RefDiff(jsPlugin);
// Clone the angular.js GitHub repo.
File angularJsRepo = refDiffJs.cloneGitRepository(
new File(tempFolder, "angular.js"),
"https://github.com/refdiff-study/angular.js.git");
// You can compute the relationships between the code elements in a commit with
// its previous commit. The result of this operation is a CstDiff object, which
// contains all relationships between CstNodes. Relationships whose type is different
// from RelationshipType.SAME are refactorings.
CstDiff diffForCommit = refDiffJs.computeDiffForCommit(angularJsRepo, "2636105");
printRefactorings("Refactorings found in angular.js 2636105", diffForCommit);
}
private static void printRefactorings(String headLine, CstDiff diff) {
System.out.println(headLine);
for (Relationship rel : diff.getRefactoringRelationships()) {
System.out.println(rel.getStandardDescription());
}
}
You can also mine refactorings from the commit history:
// You can also mine refactoring from the commit history. In this example we navigate
// the commit graph backwards up to 5 commits. Merge commits are skipped.
refDiffJs.computeDiffForCommitHistory(angularJsRepo, 5, (commit, diff) -> {
printRefactorings("Refactorings found in angular.js " + commit.getId().name(), diff);
});
You can use different language plugins to mine refactorings in other programming languages:
// In this example, we use the plugin for C.
CPlugin cPlugin = new CPlugin();
RefDiff refDiffC = new RefDiff(cPlugin);
File gitRepo = refDiffC.cloneGitRepository(
new File(tempFolder, "git"),
"https://github.com/refdiff-study/git.git");
printRefactorings(
"Refactorings found in git ba97aea",
refDiffC.computeDiffForCommit(gitRepo, "ba97aea1659e249a3a58ecc5f583ee2056a90ad8"));
// Now, we use the plugin for Java.
JavaPlugin javaPlugin = new JavaPlugin(tempFolder);
RefDiff refDiffJava = new RefDiff(javaPlugin);
File eclipseThemesRepo = refDiffC.cloneGitRepository(
new File(tempFolder, "eclipse-themes"),
"https://github.com/icse18-refactorings/eclipse-themes.git");
printRefactorings(
"Refactorings found in eclipse-themes 72f61ec",
refDiffJava.computeDiffForCommit(eclipseThemesRepo, "72f61ec"));
Maven artifacts
RefDiff artifacts are also published to Maven central repository under the group id com.github.aserg-ufmg
. There are individual artifacts for each supported language: refdiff-java
, refdiff-c
, and refdiff-js
.
For example, to use RefDiff in Java, you should add the following dependency to your pom.xml
:
<dependency>
<groupId>com.github.aserg-ufmg</groupId>
<artifactId>refdiff-java</artifactId>
<version>2.0.0</version>
</dependency>
Extending RefDiff to support other programming languages
You can implement the LanguagePlugin
interface to support other programming languages. The LanguagePlugin
interface is provided by the refdiff-core
Maven artifact. Soon, we will provide a detailed tutorial on how to do this.
Evaluation
Our evaluation with an oracle containing 3,248 real refactoring instances from public Java repositories shows that RefDiff’s precision is 96% and recall is 80%:
The data used in the evaluation is available in the following links:
Publications
The algorithm RefDiff uses is described in details in the following papers:
-
Danilo Silva, Joao Paulo da Silva, Gustavo Santos, Ricardo Terra, Marco Tulio Valente. RefDiff 2.0: A Multi-language Refactoring Detection Tool. IEEE Transactions on Software Engineering, 2020.
-
Danilo Silva, Marco Tulio Valente. RefDiff: Detecting Refactorings in Version Histories. In 14th International Conference on Mining Software Repositories (MSR), 2017.
Learn more about our research group at http://aserg.labsoft.dcc.ufmg.br/