This commit is contained in:
Kui LIU
2017-07-31 10:15:57 +02:00
parent 925a1666b6
commit b4591c047e
19 changed files with 3099 additions and 95 deletions
@@ -0,0 +1,59 @@
package edu.lu.uni.serval.FixPatternParser;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;
/**
* Creator of a CompilationUnit.
*
* @author kui.liu
*
*/
public class CUCreator {
public CompilationUnit createCompilationUnit(File javaFile) {
CompilationUnit unit = null;
try {
char[] sourceCode = readFileToCharArray(new FileReader(javaFile));
ASTParser parser = createASTParser(sourceCode);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
unit = (CompilationUnit) parser.createAST(null);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return unit;
}
private ASTParser createASTParser(char[] javaCode) {
ASTParser parser = ASTParser.newParser(AST.JLS8);
parser.setSource(javaCode);
return parser;
}
private char[] readFileToCharArray(FileReader fileReader) throws IOException {
StringBuilder fileData = new StringBuilder();
BufferedReader br = new BufferedReader(fileReader);
char[] buf = new char[10];
int numRead = 0;
while ((numRead = br.read(buf)) != -1) {
String readData = String.valueOf(buf, 0, numRead);
fileData.append(readData);
buf = new char[1024];
}
br.close();
return fileData.toString().toCharArray();
}
}
@@ -0,0 +1,340 @@
package edu.lu.uni.serval.FixPatternParser;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import com.github.gumtreediff.actions.model.Action;
import com.github.gumtreediff.tree.ITree;
import edu.lu.uni.serval.config.Configuration;
import edu.lu.uni.serval.diffentry.DiffEntryHunk;
import edu.lu.uni.serval.diffentry.DiffEntryReader;
import edu.lu.uni.serval.gumtree.GumTreeComparer;
import edu.lu.uni.serval.gumtree.regroup.ActionFilter;
import edu.lu.uni.serval.gumtree.regroup.HierarchicalActionSet;
import edu.lu.uni.serval.gumtree.regroup.HierarchicalRegrouper;
import edu.lu.uni.serval.gumtree.regroup.HunkActionFilter;
import edu.lu.uni.serval.gumtree.regroup.HunkFixPattern;
import edu.lu.uni.serval.gumtree.regroup.SimpleTree;
import edu.lu.uni.serval.gumtree.regroup.SimplifyTree;
/**
* Parse fix patterns with GumTree.
*
* @author kui.liu
*
*/
public class HunkParser {
private String astEditScripts = ""; // it will be used for fix patterns mining.
private String patchesSourceCode = ""; // testing
private String buggyTrees = ""; // Compute similarity for bug localization.
private String sizes = ""; // fix patterns' selection before mining.
private String tokensOfSourceCode = ""; // Compute similarity for bug localization.
private String originalTree = ""; // Guide of generating patches.
private String actionSets = ""; // Guide of generating patches.
public void parseFixPatterns(File prevFile, File revFile, File diffEntryFile) throws FileNotFoundException, IOException {
// GumTree results
List<Action> gumTreeResults = new GumTreeComparer().compareTwoFilesWithGumTree(prevFile, revFile);
if (gumTreeResults != null && gumTreeResults.size() > 0) {
List<HierarchicalActionSet> actionSets = new HierarchicalRegrouper().regroupGumTreeResults(gumTreeResults);
ActionFilter filter = new ActionFilter();
// Filter out modified actions of changing method names, method parameters, variable names and field names in declaration part.
// TODO: variable effects range, sub-actions are these kinds of modification?
List<HierarchicalActionSet> allActionSets = filter.filterOutUselessActions(actionSets);
// DiffEntry size: filter out big hunks.
List<DiffEntryHunk> diffentryHunks = new DiffEntryReader().readHunks(diffEntryFile);
//Filter out the modify actions, which are not in the DiffEntry hunks.
HunkActionFilter hunkFilter = new HunkActionFilter();
List<HunkFixPattern> allHunkFixPatternss = hunkFilter.filterActionsByDiffEntryHunk2(diffentryHunks, allActionSets, revFile, prevFile);
for (HunkFixPattern hunkFixPattern : allHunkFixPatternss) {
/*
* Convert the ITree of buggy code to a simple tree.
* It will be used to compute the similarity.
*/
List<HierarchicalActionSet> hunkActionSets = hunkFixPattern.getHunkActionSets();
SimpleTree simpleTree = new SimpleTree();
simpleTree.setLabel("Block");
simpleTree.setNodeType("Block");
List<SimpleTree> children = new ArrayList<>();
String astEditScripts = "";
for (HierarchicalActionSet hunkActionSet : hunkActionSets) {
SimplifyTree abstractIdentifier = new SimplifyTree();
abstractIdentifier.abstractTree(hunkActionSet);
SimpleTree simpleT = hunkActionSet.getSimpleTree();
if (simpleTree == null) { // Failed to get the simple tree for INS actions.
continue;
}
children.add(simpleT);
/**
* Select edit scripts for deep learning.
* Edit scripts will be used to mine common fix patterns.
*/
// 1. First level: AST node type.
astEditScripts += getASTEditScripts(hunkActionSet);
// 2. source code: raw tokens
// 3. abstract identifiers:
// 4. semi-source code:
}
simpleTree.setChildren(children);
simpleTree.setParent(null);
int size = astEditScripts.split(" ").length;
this.sizes += size + "\n";
this.astEditScripts += astEditScripts + "\n";
this.buggyTrees += Configuration.BUGGY_TREE_TOKEN + "\n" + simpleTree.toString() + "\n";
this.tokensOfSourceCode += getTokensDeepFirst(simpleTree).trim() + "\n";
// this.actionSets += Configuration.BUGGY_TREE_TOKEN + "\n" + readActionSet(actionSet, "") + "\n";
// this.originalTree += Configuration.BUGGY_TREE_TOKEN + "\n" + actionSet.getOriginalTree().toString() + "\n";
// Source Code of patches.
// String patchSourceCode = getPatchSourceCode(sourceCode, startLineNum, endLineNum, startLineNum2,
// endLineNum2);
// if (patchSourceCode == null) continue;
// patchesSourceCode += "PATCH###\n" + patchSourceCode;
// patchesSourceCode += actionSet.toString() + "\n";
}
}
}
private String readActionSet(HierarchicalActionSet actionSet, String line) {
String str = line + actionSet.getActionString() + "\n";
List<HierarchicalActionSet> subActions = actionSet.getSubActions();
for (HierarchicalActionSet subAction : subActions) {
str += readActionSet(subAction, line + "---");
}
return str;
}
private String getTokensDeepFirst(SimpleTree simpleTree) {
String tokens = "";
List<SimpleTree> children = simpleTree.getChildren();
String astNodeType = simpleTree.getNodeType();
if ("AssertStatement".equals(astNodeType) || "DoStatement".equals(astNodeType)
|| "ForStatement".equals(astNodeType) || "IfStatement".equals(astNodeType)
|| "ReturnStatement".equals(astNodeType) || "SwitchStatement".equals(astNodeType)
|| "SynchronizedStatement".equals(astNodeType) || "ThrowStatement".equals(astNodeType)
|| "TryStatement".equals(astNodeType) || "WhileStatement".equals(astNodeType)) {
String label = simpleTree.getLabel();
label = label.substring(0, label.indexOf("S")).toLowerCase();
tokens += label + " ";
} else if ("EnhancedForStatement".equals(astNodeType)) {
tokens += "for ";
} else if ("CatchClause".equals(astNodeType)) {
tokens += "catch ";
} else if ("SwitchCase".equals(astNodeType)) {
tokens += "case ";
} else if ("SuperConstructorInvocation".equals(astNodeType)) {
tokens += "super ";
} else if ("ConstructorInvocation".equals(astNodeType)) {
tokens += "this ";
} else if ("FinallyBody".equals(astNodeType)) {
tokens += "finally ";
}
if (children.isEmpty()) {
tokens += simpleTree.getNodeType() + " " + simpleTree.getLabel() + " ";
} else {
for (SimpleTree child : children) {
tokens += getTokensDeepFirst(child);
}
}
return tokens;
}
private String getSemiSourceCodeEditScripts(HierarchicalActionSet actionSet) {
// TODO Auto-generated method stub
return null;
}
private String getAbstractIdentifiersEditScripts(HierarchicalActionSet actionSet) {
// TODO Auto-generated method stub
return null;
}
private String getRawTokenEditScripts(HierarchicalActionSet actionSet) {
// TODO Auto-generated method stub
return null;
}
private int getEndPosition(List<ITree> children) {
int endPosition = 0;
for (ITree child : children) {
if (child.getLabel().endsWith("Body")) {
endPosition = child.getPos() - 1;
break;
}
}
return endPosition;
}
private String getPatchSourceCode(String sourceCode, int startLineNum, int endLineNum, int startLineNum2, int endLineNum2) {
String buggyStatements = "";
String fixedStatements = "";
BufferedReader reader = null;
try {
reader = new BufferedReader(new StringReader(sourceCode));
String line = null;
int startLine = 0;
int counter = 0;
int range = 0;
int startLine2 = 0;
int counter2 = 0;
int range2 = 0;
int counter3 = 0; // counter of non-buggy code line.
while ((line = reader.readLine()) != null) {
if (startLine == 0 && line.startsWith("@@ -")) {
// RegExp.filterSignal(line)
int plusIndex = line.indexOf("+");
String lineNum = line.substring(4, plusIndex);
String[] nums = lineNum.split(",");
if (nums.length != 2) {
continue;
}
startLine = Integer.parseInt(nums[0].trim());
range = Integer.parseInt(nums[1].trim());
if (startLine > endLineNum) {
return null; // Wrong Matching.
}
if (startLine + range < startLineNum) {
startLine = 0;
continue;
}
String lineNum2 = line.substring(plusIndex) .trim();
lineNum2 = lineNum2.substring(1, lineNum2.length() - 2);
String[] nums2 = lineNum2.split(",");
if (nums2.length != 2) {
startLine = 0;
range = 0;
continue;
}
startLine2 = Integer.parseInt(nums2[0].trim());
range2 = Integer.parseInt(nums2[1].trim());
continue;
}
int lineNum1 = counter + counter3;
int lineNum2 = counter2 + counter3;
if (startLine > 0 && startLine2 > 0 && lineNum1 < range && lineNum2 < range2) {
if (line.startsWith("-") && startLine + lineNum1 >= startLineNum && startLine + lineNum1 <= endLineNum) {
buggyStatements += line + "\n";
} else if (line.startsWith("+") && startLine2 + lineNum2 >= startLineNum2 && startLine2 + lineNum2 <= endLineNum2) {
fixedStatements += line + "\n";
}
if (line.startsWith("-")) {
counter ++;
} else if (line.startsWith("+")) {
counter2 ++;
} else {
counter3 ++;
}
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
reader = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return buggyStatements + fixedStatements;
}
/**
* Get the AST node based edit script of patches in terms of breadth first.
*
* @param actionSet
* @return
*/
private String getASTEditScripts(HierarchicalActionSet actionSet) {
String editScript = "";
List<HierarchicalActionSet> actionSets = new ArrayList<>();
actionSets.add(actionSet);
while (actionSets.size() != 0) {
List<HierarchicalActionSet> subSets = new ArrayList<>();
for (HierarchicalActionSet set : actionSets) {
subSets.addAll(set.getSubActions());
String actionStr = set.getActionString();
int index = actionStr.indexOf("@@");
String singleEdit = actionStr.substring(0, index).replace(" ", "");
if (singleEdit.endsWith("SimpleName")) {
actionStr = actionStr.substring(index + 2);
if (actionStr.startsWith("MethodName")) {
singleEdit = singleEdit.replace("SimpleName", "MethodName");
} else {
if (actionStr.startsWith("Name")) {
actionStr = actionStr.substring(5, 6);
if (!actionStr.equals(actionStr.toLowerCase())) {
singleEdit = singleEdit.replace("SimpleName", "Name");
} else {
singleEdit = singleEdit.replace("SimpleName", "Variable");
}
} else {
singleEdit = singleEdit.replace("SimpleName", "Variable");
}
}
}
editScript += singleEdit + " ";
}
actionSets.clear();
actionSets.addAll(subSets);
}
return editScript;
}
private void clearITree(HierarchicalActionSet actionSet) {
actionSet.getAction().setNode(null);
for (HierarchicalActionSet subActionSet : actionSet.getSubActions()) {
clearITree(subActionSet);
}
}
public String getAstEditScripts() {
return astEditScripts;
}
public String getPatchesSourceCode() {
return patchesSourceCode;
}
public String getBuggyTrees() {
return buggyTrees;
}
public String getSizes() {
return sizes;
}
public String getTokensOfSourceCode() {
return tokensOfSourceCode;
}
public String getOriginalTree() {
return originalTree;
}
public String getActionSets() {
return actionSets;
}
}
@@ -8,20 +8,20 @@ import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.core.dom.CompilationUnit;
import com.github.gumtreediff.actions.model.Move;
import com.github.gumtreediff.actions.model.Action;
import com.github.gumtreediff.actions.model.Update;
import com.github.gumtreediff.tree.ITree;
import edu.lu.uni.serval.config.Configuration;
import edu.lu.uni.serval.diffentry.DiffEntryHunk;
import edu.lu.uni.serval.diffentry.DiffEntryReader;
import edu.lu.uni.serval.gumtree.GumTreeComparer;
import edu.lu.uni.serval.gumtree.regroup.ActionFilter;
import edu.lu.uni.serval.gumtree.regroup.HierarchicalActionSet;
import edu.lu.uni.serval.gumtree.regroup.HierarchicalRegrouper;
import edu.lu.uni.serval.gumtree.regroup.HunkActionFilter;
import edu.lu.uni.serval.gumtree.regroup.SimpleTree;
import edu.lu.uni.serval.gumtree.regroup.SimplifyTree;
import edu.lu.uni.serval.gumtree.utils.CUCreator;
import edu.lu.uni.serval.utils.FileHelper;
/**
* Parse fix patterns with GumTree.
@@ -31,24 +31,47 @@ import edu.lu.uni.serval.utils.FileHelper;
*/
public class Parser {
private String astEditScripts = "";
private String patchesSourceCode = "";
private String buggyTrees = "";
private String sizes = "";
private String astEditScripts = ""; // it will be used for fix patterns mining.
private String patchesSourceCode = ""; // testing
private String buggyTrees = ""; // Compute similarity for bug localization.
private String sizes = ""; // fix patterns' selection before mining.
private String tokensOfSourceCode = ""; // Compute similarity for bug localization.
private String originalTree = ""; // Guide of generating patches.
private String actionSets = ""; // Guide of generating patches.
public void parseFixPatterns(File prevFile, File revFile, File diffEntryFile) throws FileNotFoundException, IOException {
// GumTree results
List<HierarchicalActionSet> gumTreeResults = new GumTreeComparer().compareTwoFilesWithGumTree(prevFile, revFile);
List<Action> gumTreeResults = new GumTreeComparer().compareTwoFilesWithGumTree(prevFile, revFile);
// Filter out modified actions of changing method names, method parameters, variable names and field names in declaration part.
List<HierarchicalActionSet> hierarchicalActionSets = new ActionFilter().filterOutUselessActions(gumTreeResults);
if (hierarchicalActionSets.size() > 0) {
CUCreator cuCreator = new CUCreator();
CompilationUnit prevUnit = cuCreator.createCompilationUnit(prevFile);
CompilationUnit revUnit = cuCreator.createCompilationUnit(revFile);
String sourceCode = FileHelper.readFile(diffEntryFile);
if (gumTreeResults != null && gumTreeResults.size() > 0) {
List<HierarchicalActionSet> actionSets = new HierarchicalRegrouper().regroupGumTreeResults(gumTreeResults);
/**
* TODO What we need to discuss:
* 3. actions' nodes have the same parent belongs to one fix pattern?
* actions in the same method body.
* field, one by one,
* contains a body block.
*/
ActionFilter filter = new ActionFilter();
// Filter out modified actions of changing method names, method parameters, variable names and field names in declaration part.
List<HierarchicalActionSet> hierarchicalActionSets = filter.filterOutUselessActions(actionSets); // TODO: variable effects range, sub-actions are these kinds of modification?
// DiffEntry size:
List<DiffEntryHunk> diffentryHunks = new DiffEntryReader().readHunks(diffEntryFile); // filter out big hunks.
//Filter out the modify actions, which are not in the DiffEntry hunks.
HunkActionFilter hunkFilter = new HunkActionFilter();
hierarchicalActionSets = hunkFilter.filterActionsByDiffEntryHunk(diffentryHunks, actionSets, revFile, prevFile);
/**
* Patch size
* 1. one hunk is one patch。
* 2. one statement.
*/
//
for (HierarchicalActionSet actionSet : hierarchicalActionSets) {
// position of buggy statements
int startPosition = 0;
@@ -106,18 +129,6 @@ public class Parser {
// Get the buggy code and fixed code
if (startPosition != 0 && startPosition2 != 0) {
// Line numbers of buggy statements
int startLineNum = prevUnit.getLineNumber(startPosition);
int endLineNum = prevUnit.getLineNumber(endPosition);
// Line numbers of fixed statements
int startLineNum2 = revUnit.getLineNumber(startPosition2);
int endLineNum2 = revUnit.getLineNumber(endPosition2);
// Limit the range of buggy code and fixed code. TODO:
actionSet.setStartLineNum(startLineNum);
actionSet.setEndLineNum(endLineNum);
/*
* Convert the ITree of buggy code to a simple tree.
* It will be used to compute the similarity.
@@ -125,18 +136,9 @@ public class Parser {
SimplifyTree abstractIdentifier = new SimplifyTree();
abstractIdentifier.abstractTree(actionSet);
SimpleTree simpleTree = actionSet.getSimpleTree();
clearITree(actionSet);
if (simpleTree == null) { // Failed to get the simple tree for INS actions.
continue;
}
this.buggyTrees += Configuration.BUGGY_TREE_TOKEN + "\n" + simpleTree.toString() + "\n";
// Source Code of patches.
String patchSourceCode = getPatchSourceCode(sourceCode, startLineNum, endLineNum, startLineNum2,
endLineNum2);
if (patchSourceCode == null) continue;
patchesSourceCode += "PATCH###\n" + patchSourceCode;
patchesSourceCode += actionSet.toString() + "\n";
/**
* Select edit scripts for deep learning.
@@ -145,6 +147,11 @@ public class Parser {
// 1. First level: AST node type.
String astEditScripts = getASTEditScripts(actionSet);
int size = astEditScripts.split(" ").length;
if (size == 1) {
System.out.println(actionSet);
System.out.println(revFile.getPath());
// continue;
}
this.sizes += size + "\n";
this.astEditScripts += astEditScripts + "\n";
// 2. source code: raw tokens
@@ -153,11 +160,69 @@ public class Parser {
String abstractIdentifiersEditScripts = getAbstractIdentifiersEditScripts(actionSet);
// 4. semi-source code:
String semiSourceCodeEditScripts = getSemiSourceCodeEditScripts(actionSet);
this.buggyTrees += Configuration.BUGGY_TREE_TOKEN + "\n" + simpleTree.toString() + "\n";
this.tokensOfSourceCode += getTokensDeepFirst(simpleTree).trim() + "\n";
this.actionSets += Configuration.BUGGY_TREE_TOKEN + "\n" + readActionSet(actionSet, "") + "\n";
this.originalTree += Configuration.BUGGY_TREE_TOKEN + "\n" + actionSet.getOriginalTree().toString() + "\n";
// // Source Code of patches.
// String patchSourceCode = getPatchSourceCode(sourceCode, startLineNum, endLineNum, startLineNum2,
// endLineNum2);
// if (patchSourceCode == null) continue;
// patchesSourceCode += "PATCH###\n" + patchSourceCode;
// patchesSourceCode += actionSet.toString() + "\n";
}
}
}
}
private String readActionSet(HierarchicalActionSet actionSet, String line) {
String str = line + actionSet.getActionString() + "\n";
List<HierarchicalActionSet> subActions = actionSet.getSubActions();
for (HierarchicalActionSet subAction : subActions) {
str += readActionSet(subAction, line + "---");
}
return str;
}
private String getTokensDeepFirst(SimpleTree simpleTree) {
String tokens = "";
List<SimpleTree> children = simpleTree.getChildren();
String astNodeType = simpleTree.getNodeType();
if ("AssertStatement".equals(astNodeType) || "DoStatement".equals(astNodeType)
|| "ForStatement".equals(astNodeType) || "IfStatement".equals(astNodeType)
|| "ReturnStatement".equals(astNodeType) || "SwitchStatement".equals(astNodeType)
|| "SynchronizedStatement".equals(astNodeType) || "ThrowStatement".equals(astNodeType)
|| "TryStatement".equals(astNodeType) || "WhileStatement".equals(astNodeType)) {
String label = simpleTree.getLabel();
label = label.substring(0, label.indexOf("S")).toLowerCase();
tokens += label + " ";
} else if ("EnhancedForStatement".equals(astNodeType)) {
tokens += "for ";
} else if ("CatchClause".equals(astNodeType)) {
tokens += "catch ";
} else if ("SwitchCase".equals(astNodeType)) {
tokens += "case ";
} else if ("SuperConstructorInvocation".equals(astNodeType)) {
tokens += "super ";
} else if ("ConstructorInvocation".equals(astNodeType)) {
tokens += "this ";
} else if ("FinallyBody".equals(astNodeType)) {
tokens += "finally ";
}
if (children.isEmpty()) {
tokens += simpleTree.getNodeType() + " " + simpleTree.getLabel() + " ";
} else {
for (SimpleTree child : children) {
tokens += getTokensDeepFirst(child);
}
}
return tokens;
}
private String getSemiSourceCodeEditScripts(HierarchicalActionSet actionSet) {
// TODO Auto-generated method stub
return null;
@@ -184,49 +249,6 @@ public class Parser {
return endPosition;
}
private List<Move> getFirstAndLastMoveAction(HierarchicalActionSet gumTreeResult) {
List<Move> firstAndLastMoveActions = new ArrayList<>();
List<HierarchicalActionSet> actions = gumTreeResult.getSubActions();
if (actions.size() == 0) {
return null;
}
Move firstMoveAction = null;
Move lastMoveAction = null;
while (actions.size() > 0) {
List<HierarchicalActionSet> subActions = new ArrayList<>();
for (HierarchicalActionSet action : actions) {
subActions.addAll(action.getSubActions());
if (action.toString().startsWith("MOV")) {
if (firstMoveAction == null) {
firstMoveAction = (Move) action.getAction();
lastMoveAction = (Move) action.getAction();
} else {
int startPosition = action.getStartPosition();
int length = action.getLength();
int startPositionFirst = firstMoveAction.getPosition();
int startPositionLast = lastMoveAction.getPosition();
int lengthLast = lastMoveAction.getNode().getLength();
if (startPosition < startPositionFirst || (startPosition == startPositionFirst && length > firstMoveAction.getLength())) {
firstMoveAction = (Move) action.getAction();
}
if ((startPosition + length) > (startPositionLast + lengthLast)) {
lastMoveAction = (Move) action.getAction();
}
}
}
}
actions.clear();
actions.addAll(subActions);
}
if (firstMoveAction == null) {
return null;
}
firstAndLastMoveActions.add(firstMoveAction);
firstAndLastMoveActions.add(lastMoveAction);
return firstAndLastMoveActions;
}
private String getPatchSourceCode(String sourceCode, int startLineNum, int endLineNum, int startLineNum2, int endLineNum2) {
String buggyStatements = "";
String fixedStatements = "";
@@ -243,6 +265,7 @@ public class Parser {
int counter3 = 0; // counter of non-buggy code line.
while ((line = reader.readLine()) != null) {
if (startLine == 0 && line.startsWith("@@ -")) {
// RegExp.filterSignal(line)
int plusIndex = line.indexOf("+");
String lineNum = line.substring(4, plusIndex);
String[] nums = lineNum.split(",");
@@ -370,4 +393,16 @@ public class Parser {
public String getSizes() {
return sizes;
}
public String getTokensOfSourceCode() {
return tokensOfSourceCode;
}
public String getOriginalTree() {
return originalTree;
}
public String getActionSets() {
return actionSets;
}
}
@@ -0,0 +1,430 @@
package edu.lu.uni.serval.FixPatternParser;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.core.dom.CompilationUnit;
import com.github.gumtreediff.actions.model.Action;
import com.github.gumtreediff.actions.model.Move;
import com.github.gumtreediff.actions.model.Update;
import com.github.gumtreediff.tree.ITree;
import edu.lu.uni.serval.config.Configuration;
import edu.lu.uni.serval.diffentry.DiffEntryHunk;
import edu.lu.uni.serval.diffentry.DiffEntryReader;
import edu.lu.uni.serval.gumtree.GumTreeComparer;
import edu.lu.uni.serval.gumtree.regroup.ActionFilter;
import edu.lu.uni.serval.gumtree.regroup.HierarchicalActionSet;
import edu.lu.uni.serval.gumtree.regroup.HierarchicalRegrouper;
import edu.lu.uni.serval.gumtree.regroup.SimpleTree;
import edu.lu.uni.serval.gumtree.regroup.SimplifyTree;
/**
* Parse fix patterns with GumTree.
*
* @author kui.liu
*
*/
public class SingleStatementParser {
private String astEditScripts = ""; // it will be used for fix patterns mining.
private String patchesSourceCode = ""; // testing
private String buggyTrees = ""; // Compute similarity for bug localization.
private String sizes = ""; // fix patterns' selection before mining.
private String tokensOfSourceCode = ""; // Compute similarity for bug localization.
private String originalTree = ""; // Guide of generating patches.
private String actionSets = ""; // Guide of generating patches.
public void parseFixPatterns(File prevFile, File revFile, File diffEntryFile) throws FileNotFoundException, IOException {
// GumTree results
List<Action> gumTreeResults = new GumTreeComparer().compareTwoFilesWithGumTree(prevFile, revFile);
if (gumTreeResults != null && gumTreeResults.size() > 0) {
List<HierarchicalActionSet> allActionSets = new HierarchicalRegrouper().regroupGumTreeResults(gumTreeResults);
// Filter out modified actions of changing method names, method parameters, variable names and field names in declaration part.
// TODO: variable effects range, sub-actions are these kinds of modification?
List<HierarchicalActionSet> actionSets = new ActionFilter().filterOutUselessActions(allActionSets);
if (actionSets.size() > 0) {
// DiffEntry Hunks: filter out big hunks.
List<DiffEntryHunk> diffentryHunks = new DiffEntryReader().readHunks(diffEntryFile);
for (HierarchicalActionSet actionSet : actionSets) {
// position of buggy statements
int startPosition = 0;
int endPosition = 0;
// position of fixed statements
int startPosition2 = 0;
int endPosition2 = 0;
String actionStr = actionSet.getActionString();
String astNodeType = actionSet.getAstNodeType();
if (actionStr.startsWith("INS")) {
startPosition2 = actionSet.getStartPosition();
endPosition2 = startPosition2 + actionSet.getLength();
List<Move> firstAndLastMov = getFirstAndLastMoveAction(actionSet);
if (firstAndLastMov != null) {
startPosition = firstAndLastMov.get(0).getNode().getPos();
ITree lastTree = firstAndLastMov.get(1).getNode();
endPosition = lastTree.getPos() + lastTree.getLength();
} else { // Ignore the pure insert actions without any move actions.
continue;
}
} else if (actionStr.startsWith("UPD")) {
startPosition = actionSet.getStartPosition();
endPosition = startPosition + actionSet.getLength();
Update update = (Update) actionSet.getAction();
ITree newNode = update.getNewNode();
startPosition2 = newNode.getPos();
endPosition2 = startPosition2 + newNode.getLength();
if ("EnhancedForStatement".equals(astNodeType) || "ForStatement".equals(astNodeType)
|| "DoStatement".equals(astNodeType) || "WhileStatement".equals(astNodeType)
|| "LabeledStatement".equals(astNodeType) || "SynchronizedStatement".equals(astNodeType)
|| "IfStatement".equals(astNodeType) || "TryStatement".equals(astNodeType)) {
List<ITree> children = update.getNode().getChildren();
endPosition = getEndPosition(children);
List<ITree> newChildren = newNode.getChildren();
endPosition2 = getEndPosition(newChildren);
if (endPosition == 0) {
endPosition = startPosition + actionSet.getLength();
}
if (endPosition2 == 0) {
endPosition2 = startPosition2 + newNode.getLength();
}
}
} else {// DEL actions and MOV actions: we don't need these actions, as for now.
continue;
}
if (startPosition == 0 || startPosition2 == 0) {
continue;
}
CUCreator cuCreator = new CUCreator();
CompilationUnit prevUnit = cuCreator.createCompilationUnit(prevFile);
CompilationUnit revUnit = cuCreator.createCompilationUnit(revFile);
if (prevUnit == null || revUnit == null) {
continue;
}
// Get line numbers.
int startLine = prevUnit.getLineNumber(startPosition);
int endLine = prevUnit.getLineNumber(endPosition);
int startLine2 = revUnit.getLineNumber(startPosition2);
int endLine2 = revUnit.getLineNumber(endPosition2);
//Filter out the modify actions, which are not in the DiffEntry hunks.
DiffEntryHunk hunk = matchHunk(startLine, endLine, startLine2, endLine2, actionStr, diffentryHunks);
if (hunk == null) {
continue;
}
/*
* Convert the ITree of buggy code to a simple tree.
* It will be used to compute the similarity.
*/
SimplifyTree abstractIdentifier = new SimplifyTree();
abstractIdentifier.abstractTree(actionSet);
SimpleTree simpleTree = actionSet.getSimpleTree();
if (simpleTree == null) { // Failed to get the simple tree for INS actions.
continue;
}
/**
* Select edit scripts for deep learning.
* Edit scripts will be used to mine common fix patterns.
*/
// 1. First level: AST node type.
String astEditScripts = getASTEditScripts(actionSet);
int size = astEditScripts.split(" ").length;
if (size == 1) {
System.out.println(actionSet);
continue;
}
this.sizes += size + "\n";
this.astEditScripts += astEditScripts + "\n";
// 2. source code: raw tokens
String rawTokenEditScripts = getRawTokenEditScripts(actionSet);
// 3. abstract identifiers:
String abstractIdentifiersEditScripts = getAbstractIdentifiersEditScripts(actionSet);
// 4. semi-source code:
String semiSourceCodeEditScripts = getSemiSourceCodeEditScripts(actionSet);
this.buggyTrees += Configuration.BUGGY_TREE_TOKEN + "\n" + simpleTree.toString() + "\n";
this.tokensOfSourceCode += getTokensDeepFirst(simpleTree).trim() + "\n";
this.actionSets += Configuration.BUGGY_TREE_TOKEN + "\n" + readActionSet(actionSet, "") + "\n";
this.originalTree += Configuration.BUGGY_TREE_TOKEN + "\n" + actionSet.getOriginalTree().toString() + "\n";
// Source Code of patches.
String patchSourceCode = getPatchSourceCode(hunk, startLine, endLine, startLine2, endLine2);
patchesSourceCode += Configuration.PATCH_TOKEN +"\n" + patchSourceCode + "\n";
}
}
}
}
private DiffEntryHunk matchHunk(int startLine, int endLine, int startLine2, int endLine2, String actionStr, List<DiffEntryHunk> hunks) {
for (DiffEntryHunk hunk : hunks) {
int bugStartLine = hunk.getBugLineStartNum();
int bugRange = hunk.getBugRange();
int fixStartLine = hunk.getFixLineStartNum();
int fixRange = hunk.getFixRange();
if (actionStr.startsWith("INS")) {
if (fixStartLine + fixRange < startLine2) {
continue;
}
if (endLine2 < fixStartLine ) {
return null;
}
return hunk;
} else {
if (bugStartLine + bugRange < startLine) {
continue;
}
if (endLine < bugStartLine ) {
return null;
}
return hunk;
}
}
return null;
}
private List<Move> getFirstAndLastMoveAction(HierarchicalActionSet gumTreeResult) {
List<Move> firstAndLastMoveActions = new ArrayList<>();
List<HierarchicalActionSet> actions = gumTreeResult.getSubActions();
if (actions.size() == 0) {
return null;
}
Move firstMoveAction = null;
Move lastMoveAction = null;
while (actions.size() > 0) {
List<HierarchicalActionSet> subActions = new ArrayList<>();
for (HierarchicalActionSet action : actions) {
subActions.addAll(action.getSubActions());
if (action.toString().startsWith("MOV")) {
if (firstMoveAction == null) {
firstMoveAction = (Move) action.getAction();
lastMoveAction = (Move) action.getAction();
} else {
int startPosition = action.getStartPosition();
int length = action.getLength();
int startPositionFirst = firstMoveAction.getPosition();
int startPositionLast = lastMoveAction.getPosition();
int lengthLast = lastMoveAction.getNode().getLength();
if (startPosition < startPositionFirst || (startPosition == startPositionFirst && length > firstMoveAction.getLength())) {
firstMoveAction = (Move) action.getAction();
}
if ((startPosition + length) > (startPositionLast + lengthLast)) {
lastMoveAction = (Move) action.getAction();
}
}
}
}
actions.clear();
actions.addAll(subActions);
}
if (firstMoveAction == null) {
return null;
}
firstAndLastMoveActions.add(firstMoveAction);
firstAndLastMoveActions.add(lastMoveAction);
return firstAndLastMoveActions;
}
private String readActionSet(HierarchicalActionSet actionSet, String line) {
String str = line + actionSet.getActionString() + "\n";
List<HierarchicalActionSet> subActions = actionSet.getSubActions();
for (HierarchicalActionSet subAction : subActions) {
str += readActionSet(subAction, line + "---");
}
return str;
}
private String getTokensDeepFirst(SimpleTree simpleTree) {
String tokens = "";
List<SimpleTree> children = simpleTree.getChildren();
String astNodeType = simpleTree.getNodeType();
if ("AssertStatement".equals(astNodeType) || "DoStatement".equals(astNodeType)
|| "ForStatement".equals(astNodeType) || "IfStatement".equals(astNodeType)
|| "ReturnStatement".equals(astNodeType) || "SwitchStatement".equals(astNodeType)
|| "SynchronizedStatement".equals(astNodeType) || "ThrowStatement".equals(astNodeType)
|| "TryStatement".equals(astNodeType) || "WhileStatement".equals(astNodeType)) {
String label = simpleTree.getLabel();
label = label.substring(0, label.indexOf("S")).toLowerCase();
tokens += label + " ";
} else if ("EnhancedForStatement".equals(astNodeType)) {
tokens += "for ";
} else if ("CatchClause".equals(astNodeType)) {
tokens += "catch ";
} else if ("SwitchCase".equals(astNodeType)) {
tokens += "case ";
} else if ("SuperConstructorInvocation".equals(astNodeType)) {
tokens += "super ";
} else if ("ConstructorInvocation".equals(astNodeType)) {
tokens += "this ";
} else if ("FinallyBody".equals(astNodeType)) {
tokens += "finally ";
}
if (children.isEmpty()) {
tokens += simpleTree.getNodeType() + " " + simpleTree.getLabel() + " ";
} else {
for (SimpleTree child : children) {
tokens += getTokensDeepFirst(child);
}
}
return tokens;
}
private String getSemiSourceCodeEditScripts(HierarchicalActionSet actionSet) {
// TODO Auto-generated method stub
return null;
}
private String getAbstractIdentifiersEditScripts(HierarchicalActionSet actionSet) {
// TODO Auto-generated method stub
return null;
}
private String getRawTokenEditScripts(HierarchicalActionSet actionSet) {
// TODO Auto-generated method stub
return null;
}
private int getEndPosition(List<ITree> children) {
int endPosition = 0;
for (ITree child : children) {
if (child.getLabel().endsWith("Body")) {
endPosition = child.getPos() - 1;
break;
}
}
return endPosition;
}
private String getPatchSourceCode(DiffEntryHunk hunk, int startLineNum, int endLineNum, int startLineNum2, int endLineNum2) {
String sourceCode = hunk.getHunk();
int bugStartLine = hunk.getBugLineStartNum();
int fixStartLine = hunk.getFixLineStartNum();
String buggyStatements = "";
String fixedStatements = "";
BufferedReader reader = null;
try {
reader = new BufferedReader(new StringReader(sourceCode));
String line = null;
int bugLines = 0;
int fixLines = 0;
int contextLines = 0; // counter of non-buggy code line.
while ((line = reader.readLine()) != null) {
int bugLineIndex = bugLines + contextLines;
int fixLineIndex = fixLines + contextLines;
if (line.startsWith("-")) {
if (bugStartLine + bugLineIndex >= startLineNum && bugStartLine + bugLineIndex <= endLineNum) {
buggyStatements += line + "\n";
}
bugLines ++;
} else if (line.startsWith("+")) {
if (fixStartLine + fixLineIndex >= startLineNum2 && fixStartLine + fixLineIndex <= endLineNum2) {
fixedStatements += line + "\n";
}
} else {
contextLines ++;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
reader = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return buggyStatements + fixedStatements;
}
/**
* Get the AST node based edit script of patches in terms of breadth first.
*
* @param actionSet
* @return
*/
private String getASTEditScripts(HierarchicalActionSet actionSet) {
String editScript = "";
List<HierarchicalActionSet> actionSets = new ArrayList<>();
actionSets.add(actionSet);
while (actionSets.size() != 0) {
List<HierarchicalActionSet> subSets = new ArrayList<>();
for (HierarchicalActionSet set : actionSets) {
subSets.addAll(set.getSubActions());
String actionStr = set.getActionString();
int index = actionStr.indexOf("@@");
String singleEdit = actionStr.substring(0, index).replace(" ", "");
if (singleEdit.endsWith("SimpleName")) {
actionStr = actionStr.substring(index + 2);
if (actionStr.startsWith("MethodName")) {
singleEdit = singleEdit.replace("SimpleName", "MethodName");
} else {
if (actionStr.startsWith("Name")) {
actionStr = actionStr.substring(5, 6);
if (!actionStr.equals(actionStr.toLowerCase())) {
singleEdit = singleEdit.replace("SimpleName", "Name");
} else {
singleEdit = singleEdit.replace("SimpleName", "Variable");
}
} else {
singleEdit = singleEdit.replace("SimpleName", "Variable");
}
}
}
editScript += singleEdit + " ";
}
actionSets.clear();
actionSets.addAll(subSets);
}
return editScript;
}
public String getAstEditScripts() {
return astEditScripts;
}
public String getPatchesSourceCode() {
return patchesSourceCode;
}
public String getBuggyTrees() {
return buggyTrees;
}
public String getSizes() {
return sizes;
}
public String getTokensOfSourceCode() {
return tokensOfSourceCode;
}
public String getOriginalTree() {
return originalTree;
}
public String getActionSets() {
return actionSets;
}
}
@@ -20,8 +20,12 @@ public class TestParser {
FileHelper.deleteDirectory("OUTPUT/GumTreeResults_Exp_ASTNode/");
FileHelper.deleteDirectory("OUTPUT/GumTreeResults_Exp_RawCode/");
StringBuilder astEditScriptsBuilder = new StringBuilder();
StringBuilder sourceCodeBuilder = new StringBuilder();
StringBuilder astEditScripts = new StringBuilder();
StringBuilder originalTrees = new StringBuilder();
StringBuilder buggyTrees = new StringBuilder();
StringBuilder actionSets = new StringBuilder();
StringBuilder tokens = new StringBuilder();
StringBuilder sizes = new StringBuilder();
for (File file : files) {
String projectFolder = file.getPath();
@@ -36,8 +40,13 @@ public class TestParser {
Parser parser = new Parser();
try {
parser.parseFixPatterns(prevFile, revFile, diffentryFile);
astEditScriptsBuilder.append(parser.getAstEditScripts());
sourceCodeBuilder.append(parser.getPatchesSourceCode());
astEditScripts.append(parser.getAstEditScripts());
originalTrees.append(parser.getOriginalTree());
buggyTrees.append(parser.getBuggyTrees());
actionSets.append(parser.getActionSets());
tokens.append(parser.getTokensOfSourceCode());
sizes.append(parser.getSizes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
@@ -46,7 +55,11 @@ public class TestParser {
}
}
}
FileHelper.outputToFile("OUTPUT/GumTreeResults_Exp/EditScripts.list", astEditScriptsBuilder, false);
FileHelper.outputToFile("OUTPUT/GumTreeResults_Exp/Patches.list", sourceCodeBuilder, false);
FileHelper.outputToFile("OUTPUT/GumTreeResults_Exp/EditScripts.list", astEditScripts, false);
FileHelper.outputToFile("OUTPUT/GumTreeResults_Exp/OriginalTrees.list", originalTrees, false);
FileHelper.outputToFile("OUTPUT/GumTreeResults_Exp/BuggyTrees.list", buggyTrees, false);
FileHelper.outputToFile("OUTPUT/GumTreeResults_Exp/ActionSets.list", actionSets, false);
FileHelper.outputToFile("OUTPUT/GumTreeResults_Exp/Tokens.list", tokens, false);
FileHelper.outputToFile("OUTPUT/GumTreeResults_Exp/Sizes.list", sizes, false);
}
}
@@ -10,6 +10,7 @@ import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.japi.Creator;
import edu.lu.uni.serval.FixPatternParser.Parser;
import edu.lu.uni.serval.FixPatternParser.SingleStatementParser;
import edu.lu.uni.serval.utils.FileHelper;
public class ParseFixPatternWorker extends UntypedActor {
@@ -56,13 +57,13 @@ public class ParseFixPatternWorker extends UntypedActor {
File revFile = msgFile.getRevFile();
File prevFile = msgFile.getPrevFile();
File diffentryFile = msgFile.getDiffEntryFile();
Parser miner = new Parser();
SingleStatementParser parser = new SingleStatementParser();
log.info("Start to parse file: " + revFile.getPath());
miner.parseFixPatterns(prevFile, revFile, diffentryFile);
editScripts.append(miner.getAstEditScripts());
patchesSourceCode.append(miner.getPatchesSourceCode());
sizes.append(miner.getSizes());
buggyTrees.append(miner.getBuggyTrees());
parser.parseFixPatterns(prevFile, revFile, diffentryFile);
editScripts.append(parser.getAstEditScripts());
patchesSourceCode.append(parser.getPatchesSourceCode());
sizes.append(parser.getSizes());
buggyTrees.append(parser.getBuggyTrees());
log.info("Finish of parsing file: " + revFile.getPath());
counter ++;
if (counter % 1000 == 0) {
@@ -3,6 +3,7 @@ package edu.lu.uni.serval.config;
public class Configuration {
private static final String ROOT_PATH = "../";
public static final int HUNK_SIZE = 7;
public static final String BUGGY_TREE_TOKEN = "BUGGY_TREE###";
public static final String PATCH_TOKEN = "PATCH###";
@@ -0,0 +1,43 @@
package edu.lu.uni.serval.diffentry;
public class DiffEntryHunk {
private int bugLineStartNum;
private int fixLineStartNum;
private int bugRange;
private int fixRange;
private String hunk;
public DiffEntryHunk(int bugLineStartNum, int fixLineStartNum, int bugRange, int fixRange) {
super();
this.bugLineStartNum = bugLineStartNum;
this.fixLineStartNum = fixLineStartNum;
this.bugRange = bugRange;
this.fixRange = fixRange;
}
public int getBugLineStartNum() {
return bugLineStartNum;
}
public int getFixLineStartNum() {
return fixLineStartNum;
}
public int getBugRange() {
return bugRange;
}
public int getFixRange() {
return fixRange;
}
public String getHunk() {
return hunk;
}
public void setHunk(String hunk) {
this.hunk = hunk;
}
}
@@ -0,0 +1,80 @@
package edu.lu.uni.serval.diffentry;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import edu.lu.uni.serval.utils.FileHelper;
public class DiffEntryReader {
public List<DiffEntryHunk> readHunks(File diffentryFile) {
List<DiffEntryHunk> diffentryHunks = new ArrayList<>();
String content = FileHelper.readFile(diffentryFile);
BufferedReader reader = null;
try {
reader = new BufferedReader(new StringReader(content));
String line = null;
int startLine = 0;
int range = 0;
int startLine2 = 0;
int range2 = 0;
StringBuilder hunk = new StringBuilder();
while ((line = reader.readLine()) != null) {
if (RegExp.filterSignal(line.trim())) {
if (hunk.length() > 0) {
if ((range < 7 && range2 < 7) || range == 0 || range2 == 0) { // filter out big hunks
DiffEntryHunk diffEntryHunk = new DiffEntryHunk(startLine, startLine2, range, range2);
diffEntryHunk.setHunk(hunk.toString());
diffentryHunks.add(diffEntryHunk);
}
hunk.setLength(0);
}
int plusIndex = line.indexOf("+");
String lineNum = line.substring(4, plusIndex);
String[] nums = lineNum.split(",");
startLine = Integer.parseInt(nums[0].trim());
if (nums.length == 2) {
range = Integer.parseInt(nums[1].trim());
}
String lineNum2 = line.substring(plusIndex) .trim();
lineNum2 = lineNum2.substring(1, lineNum2.length() - 2);
String[] nums2 = lineNum2.split(",");
startLine2 = Integer.parseInt(nums2[0].trim());
if (nums2.length != 2) {
range2 = Integer.parseInt(nums2[1].trim());
}
continue;
}
hunk.append(line + "\n");
}
if (range < 7 && range2 < 7) { // filter out big hunks
DiffEntryHunk diffEntryHunk = new DiffEntryHunk(startLine, startLine2, range, range2);
diffEntryHunk.setHunk(hunk.toString());
diffentryHunks.add(diffEntryHunk);
}
hunk.setLength(0);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
reader = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return diffentryHunks;
}
}
@@ -0,0 +1,20 @@
package edu.lu.uni.serval.diffentry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegExp {
private static final String REGULAR_EXPRESSION = "^@@\\s\\-\\d+,*\\d*\\s\\+\\d+,*\\d*\\s@@$"; //@@ -21,0 +22,2 @@
private static Pattern pattern = Pattern.compile(REGULAR_EXPRESSION);
public static boolean filterSignal(String string) {
boolean flag = false;
Matcher res = pattern.matcher(string);
if (res.matches()) {
flag = true;
}
return flag;
}
}
@@ -0,0 +1,250 @@
package edu.lu.uni.serval.gumtree.regroup;
import java.util.ArrayList;
import java.util.List;
public class ActionFilter {
private List<String> methodNames = new ArrayList<>();
private List<String> variableNames = new ArrayList<>();
/**
* Filter out the modify actions of changing method names, method parameters, variable names and field names in declaration part.
*
* @param actionSets
* @return
*/
public List<HierarchicalActionSet> filterOutUselessActions(List<HierarchicalActionSet> actionSets) {
// Filter out modifications of variable names and method names.
List<HierarchicalActionSet> uselessActions = findoutUselessActions(actionSets);
actionSets.removeAll(uselessActions);
uselessActions.clear();
// Filter out non-UPD modifications, and modifications of variable names and method names.
uselessActions = findoutUselessActionSets(actionSets, true);
actionSets.removeAll(uselessActions);
return actionSets;
}
private List<HierarchicalActionSet> findoutUselessActionSets(List<HierarchicalActionSet> actionSets, boolean isRoot) {
List<HierarchicalActionSet> uselessActions = new ArrayList<>();
FindActionSet: {
for (HierarchicalActionSet actionSet : actionSets) {
if (!isRoot) {
String actionStr = actionSet.getActionString();
if (actionStr.startsWith("UPD MethodInvocation") || actionStr.startsWith("INS MethodInvocation") || actionStr.startsWith("DEL MethodInvocation")) {
String label = actionSet.getAction().getNode().getLabel();
for (String methodName : methodNames) {
if (actionSet.getActionString().startsWith("UPD MethodInvocation@@" + methodName + "(")
|| actionSet.getActionString().startsWith("INS MethodInvocation@@" + methodName + "(")
|| actionSet.getActionString().startsWith("DEL MethodInvocation@@" + methodName + "(")
|| label.contains("." + methodName + "(")) {
addToUselessActions(actionSet, uselessActions);
break FindActionSet;
}
}
} else if (actionStr.startsWith("UPD SimpleName") || actionStr.startsWith("INS SimpleName") || actionStr.startsWith("DEL SimpleName")) {
String label = actionSet.getAction().getNode().getLabel();
for (String variableName : variableNames) {
if (label.equals(variableName) || label.equals("Name:" + variableName)) {
addToUselessActions(actionSet, uselessActions);
break FindActionSet;
}
}
} else if (actionStr.startsWith("INS StringLiteral") || actionStr.startsWith("DEL StringLiteral") || actionStr.startsWith("MOV StringLiteral")) {
addToUselessActions(actionSet, uselessActions);
break FindActionSet;
}
List<HierarchicalActionSet> uselessActionSets = findoutUselessActionSets(actionSet.getSubActions(), false);
if (uselessActionSets.size() > 0) {
uselessActions.addAll(uselessActionSets);
break;
}
} else {
if (!actionSet.getAstNodeType().endsWith("Statement") || !"FieldDeclaration".equals(actionSet.getAstNodeType())) {
uselessActions.add(actionSet);
} else {
uselessActions.addAll(findoutUselessActionSets(actionSet.getSubActions(), false));
}
}
}
}
return uselessActions;
}
private void addToUselessActions(HierarchicalActionSet actionSet, List<HierarchicalActionSet> uselessActions) {
while (actionSet.getParent() != null) {
actionSet = actionSet.getParent();
}
if (!uselessActions.contains(actionSet)) {
uselessActions.add(actionSet);
}
}
/**
* Identify the the modify actions of changing method names, method parameters, variable names and field names in declaration part.
*
* @param actionSets
* @return
*/
private List<HierarchicalActionSet> findoutUselessActions(List<HierarchicalActionSet> actionSets) {
List<HierarchicalActionSet> uselessActions = new ArrayList<>();
for (HierarchicalActionSet actionSet : actionSets) {
String actionType = actionSet.getAstNodeType();
if (actionType.equals("MethodDeclaration")) {
addToUselessActions(actionSet, uselessActions);// INS, DEL: useful?, UPD, except the modifier actions
if (!actionSet.getActionString().startsWith("MOV ")) {
String label = actionSet.getNode().getLabel();
String methodName = label.substring(label.indexOf("MethodName:"));
methodName = methodName.substring(11, methodName.indexOf(","));
methodNames.add(methodName); // "MethodName:***"
// UPD, DEL, INS parameters.
List<HierarchicalActionSet> subActionSets = actionSet.getSubActions();
for (HierarchicalActionSet subActionSet : subActionSets) {
if (subActionSet.getAstNodeType().equals("SingleVariableDeclaration")) {
List<HierarchicalActionSet> subActionSets2 = subActionSet.getSubActions(); // <Type, identifier>
if (subActionSets2.size() == 0) {
String actSetStr = subActionSet.getActionString();
int index1 = actSetStr.indexOf("@@");
int index2 = 0;
if (actSetStr.startsWith("DEL")) {
index2 = actSetStr.indexOf("@AT@");
} else {
index2 = actSetStr.indexOf("@TO@");;
}
actSetStr = actSetStr.substring(index1, index2).trim();
String variableName = actSetStr.substring(actSetStr.lastIndexOf(" "));
variableNames.add(variableName); // "SimpleName:" + variableName TODO: effect range
} else {
HierarchicalActionSet actSet = subActionSets2.get(subActionSets2.size() - 1);
String actStr = actSet.getActionString();
if (actStr.startsWith("UPD SimpleName") || actStr.startsWith("INS SimpleName") || actStr.startsWith("DEL SimpleName")) {
String variableName = actSet.getNode().getLabel();
variableNames.add(variableName); // "SimpleName:" + variableName TODO: effect range
}
}
}
}
}
} else if (actionType.equals("FieldDeclaration") || actionType.equals("VariableDeclarationStatement")) {
// UPD VariableDeclarationFragment
if (!actionSet.getActionString().startsWith("MOV ")) {
List<HierarchicalActionSet> subActionSets = actionSet.getSubActions();
if (subActionSets.size() > 0) {
for (HierarchicalActionSet subActionSet : subActionSets) { // VariableDeclarationFragments
if (identifyUpdateVDF(subActionSet)) {
addToUselessActions(actionSet, uselessActions);
}
}
}
}
} else if (actionType.equals("TryStatement")) {
if (actionSet.getActionString().startsWith("UPD ")) {
List<HierarchicalActionSet> subActionSets = actionSet.getSubActions();
if (subActionSets.size() > 0) {
for (HierarchicalActionSet subActionSet : subActionSets) {
if (subActionSet.getActionString().startsWith("UPD VariableDeclarationExpression")) {
List<HierarchicalActionSet> subActionSets2 = subActionSet.getSubActions(); // VariableDeclarationFragments
for (HierarchicalActionSet subActionSet2 : subActionSets2) {
if (identifyUpdateVDF(subActionSet2)) {
addToUselessActions(actionSet, uselessActions);
}
}
} else {
break;
}
}
}
}
} else if (actionType.equals("EnhancedForStatement")) { // SingleVariableDeclaration
if (!actionSet.getActionString().startsWith("MOV ")) {
List<HierarchicalActionSet> subActionSets = actionSet.getSubActions();
if (subActionSets.size() > 0) {
HierarchicalActionSet subActionSet = subActionSets.get(0);
if (subActionSet.getActionString().startsWith("UPD SingleVariableDeclaration")) {
List<HierarchicalActionSet> subActionSets2 = subActionSet.getSubActions();
for (HierarchicalActionSet subActionSet2 : subActionSets2) { // Type or Identifier
if (subActionSet2.getActionString().startsWith("UPD SimpleName")) {
String variableName = subActionSet2.getNode().getLabel();
variableNames.add(variableName); // "SimpleName:" + variableName TODO: effect range
addToUselessActions(actionSet, uselessActions);
}
}
}
}
}
} else if (actionType.equals("SingleVariableDeclaration")) {
if (!actionSet.getActionString().startsWith("MOV ")) {
List<HierarchicalActionSet> subActionSets2 = actionSet.getSubActions(); // <Type, identifier>
if (subActionSets2.size() == 0) {
String actSetStr = actionSet.getActionString();
int index1 = actSetStr.indexOf("@@");
int index2 = 0;
if (actSetStr.startsWith("DEL")) {
index2 = actSetStr.indexOf("@AT@");
} else {
index2 = actSetStr.indexOf("@TO@");;
}
actSetStr = actSetStr.substring(index1, index2).trim();
String variableName = actSetStr.substring(actSetStr.lastIndexOf(" "));
variableNames.add(variableName); // "SimpleName:" + variableName TODO: effect range
addToUselessActions(actionSet, uselessActions);
} else {
HierarchicalActionSet actSet = subActionSets2.get(subActionSets2.size() - 1);
String actStr = actSet.getActionString();
if (actStr.startsWith("UPD SimpleName") || actStr.startsWith("INS SimpleName") || actStr.startsWith("DEL SimpleName")) {
String variableName = actSet.getNode().getLabel();
variableNames.add(variableName); // "SimpleName:" + variableName TODO: effect range
addToUselessActions(actionSet, uselessActions);
}
}
}
} else {
if (actionSet.getParent() != null) {
while (actionSet.getParent() != null) {
actionSet = actionSet.getParent();
}
if (uselessActions.contains(actionSet)) {
return uselessActions;
} else {
uselessActions.addAll(findoutUselessActions(actionSet.getSubActions()));
}
}
}
}
return uselessActions;
}
/**
* Identify the AST node of this ActionSet is VariableDeclarationFragment or not.
* And, whether the action is happened on the Variable name or not.
*
* @param actionSet
*/
private boolean identifyUpdateVDF(HierarchicalActionSet actionSet) {
String actStr = actionSet.getActionString();
if (actStr.startsWith("UPD VariableDeclarationFragment")
|| actStr.startsWith("INS VariableDeclarationFragment")
|| actStr.startsWith("DEL VariableDeclarationFragment")) {
List<HierarchicalActionSet> subActionSets = actionSet.getSubActions();
if (subActionSets == null || subActionSets.size() == 0) {
// modification of Dimension
return true;
}
HierarchicalActionSet actSet = subActionSets.get(0);
String actSetStr = actSet.getActionString();
if (actSetStr.startsWith("UPD SimpleName") || actSetStr.startsWith("INS SimpleName") || actSetStr.startsWith("DEL SimpleName")) {
String variableName = actSet.getNode().getLabel();
variableNames.add(variableName); // "SimpleName:" + variableName TODO: effect range
return true;
}
}
return false;
}
}
@@ -0,0 +1,227 @@
package edu.lu.uni.serval.gumtree.regroup;
import java.util.ArrayList;
import java.util.List;
import com.github.gumtreediff.actions.model.Action;
import com.github.gumtreediff.tree.ITree;
/**
* Hierarchical-level results of GumTree results
*
* @author kui.liu
*
*/
public class HierarchicalActionSet implements Comparable<HierarchicalActionSet> {
private String astNodeType;
private Action action;
private Action parentAction;
private String actionString;
private int startPosition;
private int length;
private int bugStartLineNum;
private int bugEndLineNum;
private int fixStartLineNum;
private int fixEndLineNum;
private HierarchicalActionSet parent = null;
private List<HierarchicalActionSet> subActions = new ArrayList<>();
private ITree node;
private SimpleTree abstractSimpleTree = null; // semi-source code tree. and AST node type tree
private SimpleTree abstractIdentifierTree = null; // abstract identifier tree
private SimpleTree simpleTree = null; // source code tree and AST node type tree
private SimpleTree originalTree = null; // source code tree.
public ITree getNode() {
return node;
}
public void setNode(ITree node) {
this.node = node;
}
public String getAstNodeType() {
return astNodeType;
}
public Action getAction() {
return action;
}
public void setAction(Action action) {
this.action = action;
}
public Action getParentAction() {
return parentAction;
}
public void setParentAction(Action parentAction) {
this.parentAction = parentAction;
}
public String getActionString() {
return actionString;
}
public void setActionString(String actionString) {
this.actionString = actionString;
int atIndex = actionString.indexOf("@AT@") + 4;
int lengthIndex = actionString.indexOf("@LENGTH@");
if (lengthIndex == -1) {
this.startPosition = Integer.parseInt(actionString.substring(atIndex).trim());
this.length = 0;
} else {
this.startPosition = Integer.parseInt(actionString.substring(atIndex, lengthIndex).trim());
this.length = Integer.parseInt(actionString.substring(lengthIndex + 8).trim());
}
String nodeType = actionString.substring(0, actionString.indexOf("@@"));
nodeType = nodeType.substring(nodeType.indexOf(" ") + 1);
this.astNodeType = nodeType;
}
public int getStartPosition() {
return startPosition;
}
public int getLength() {
return length;
}
public int getBugStartLineNum() {
return bugStartLineNum;
}
public void setBugStartLineNum(int bugStartLineNum) {
this.bugStartLineNum = bugStartLineNum;
}
public int getBugEndLineNum() {
return bugEndLineNum;
}
public void setBugEndLineNum(int bugEndLineNum) {
this.bugEndLineNum = bugEndLineNum;
}
public int getFixStartLineNum() {
return fixStartLineNum;
}
public void setFixStartLineNum(int fixStartLineNum) {
this.fixStartLineNum = fixStartLineNum;
}
public int getFixEndLineNum() {
return fixEndLineNum;
}
public void setFixEndLineNum(int fixEndLineNum) {
this.fixEndLineNum = fixEndLineNum;
}
public HierarchicalActionSet getParent() {
return parent;
}
public void setParent(HierarchicalActionSet parent) {
this.parent = parent;
}
public List<HierarchicalActionSet> getSubActions() {
return subActions;
}
public void setSubActions(List<HierarchicalActionSet> subActions) {
this.subActions = subActions;
}
public SimpleTree getAbstractSimpleTree() {
return abstractSimpleTree;
}
public void setAbstractSimpleTree(SimpleTree simpleTree) {
this.abstractSimpleTree = simpleTree;
}
public SimpleTree getAbstractIdentifierTree() {
return abstractIdentifierTree;
}
public void setAbstractIdentifierTree(SimpleTree abstractIdentifierTree) {
this.abstractIdentifierTree = abstractIdentifierTree;
}
public SimpleTree getSimpleTree() {
return simpleTree;
}
public void setSimpleTree(SimpleTree rawTokenTree) {
this.simpleTree = rawTokenTree;
}
public SimpleTree getOriginalTree() {
return originalTree;
}
public void setOriginalTree(SimpleTree originalTree) {
this.originalTree = originalTree;
}
@Override
public int compareTo(HierarchicalActionSet o) {
return this.action.compareTo(o.action);
}
private List<String> strList = new ArrayList<>();
@Override
public String toString() {
String str = actionString;
if (strList.size() == 0) {
strList.add(str);
for (HierarchicalActionSet actionSet : subActions) {
actionSet.toString();
List<String> strList1 = actionSet.strList;
for (String str1 : strList1) {
strList.add("----" + str1);
}
}
}
str = "";
for (String str1 : strList) {
str += str1 + "\n";
}
return str;
}
public String toASTNodeLevelAction() {
if (strList.size() == 0) {
toString();
}
String astNodeStr = "";
for (String str : strList) {
astNodeStr += str.substring(0, str.indexOf("@@")) + "\n";
}
return astNodeStr;
}
public String toRawCodeLevelAction() {
if (strList.size() == 0) {
toString();
}
String astNodeStr = "";
for (String str : strList) {
str = str.substring(0, str.indexOf(" @AT@")) + "\n";
int index1 = str.indexOf(" ") + 1;
int index2 = str.indexOf("@@") + 2;
astNodeStr += str.substring(0, index1) + str.substring(index2);
}
return astNodeStr;
}
}
@@ -0,0 +1,173 @@
package edu.lu.uni.serval.gumtree.regroup;
import java.util.ArrayList;
import java.util.List;
import com.github.gumtreediff.actions.model.Action;
import com.github.gumtreediff.actions.model.Addition;
import com.github.gumtreediff.actions.model.Insert;
import com.github.gumtreediff.actions.model.Move;
import com.github.gumtreediff.tree.ITree;
import edu.lu.uni.serval.gumtree.utils.ASTNodeMap;
import edu.lu.uni.serval.utils.ListSorter;
/**
* Regroup GumTree results to a hierarchical construction.
*
* @author kui.liu
*
*/
public class HierarchicalRegrouper {
public List<HierarchicalActionSet> regroupGumTreeResults(List<Action> actionsArgu) {
/*
* First, sort actions by their positions.
*/
List<Action> actions = new ListSorter<Action>(actionsArgu).sortAscending();
if (actions == null) {
actions = actionsArgu;
}
/*
* Second, group actions by their positions.
*/
List<HierarchicalActionSet> actionSets = new ArrayList<>();
HierarchicalActionSet actionSet = null;
for(Action act : actions){
Action parentAct = findParentAction(act, actions);
if (parentAct == null) {
actionSet = createActionSet(act, parentAct);
actionSets.add(actionSet);
} else {
if (!addToAactionSet(act, parentAct, actionSets)) {
// The index of the parent action in the actions' list is larger than the index of this action.
actionSet = createActionSet(act, parentAct);
actionSets.add(actionSet);
}
}
}
/*
* Third, add the subActionSet to its parent ActionSet.
*/
List<HierarchicalActionSet> reActionSets = new ArrayList<>();
for (HierarchicalActionSet actSet : actionSets) {
Action parentAct = actSet.getParentAction();
if (parentAct != null) {
addToActionSets(actSet, parentAct, actionSets);
} else {
reActionSets.add(actSet);
}
}
return reActionSets;
}
private HierarchicalActionSet createActionSet(Action act, Action parentAct) {
HierarchicalActionSet actionSet = new HierarchicalActionSet();
actionSet.setAction(act);
actionSet.setActionString(parseAction(act.toString()));
actionSet.setParentAction(parentAct);
actionSet.setNode(act.getNode());
actionSet.setParent(null);
return actionSet;
}
private String parseAction(String actStr1) {
// UPD 25@@!a from !a to isTrue(a) at 69
String[] actStrArrays = actStr1.split("@@");
String actStr = "";
int length = actStrArrays.length;
for (int i =0; i < length - 1; i ++) {
String actStrFrag = actStrArrays[i];
int index = actStrFrag.lastIndexOf(" ") + 1;
String nodeType = actStrFrag.substring(index);
if (!"".equals(nodeType)) {
try {
nodeType = ASTNodeMap.map.get(Integer.parseInt(nodeType));
} catch (NumberFormatException e) {
nodeType = actStrFrag.substring(index);
}
}
actStrFrag = actStrFrag.substring(0, index) + nodeType + "@@";
actStr += actStrFrag;
}
actStr += actStrArrays[length - 1];
return actStr;
}
private void addToActionSets(HierarchicalActionSet actionSet, Action parentAct, List<HierarchicalActionSet> actionSets) {
for (HierarchicalActionSet actSet : actionSets) {
if (actSet.equals(actionSet)) continue;
if (actSet.getAction().equals(parentAct)) { // actSet is the parent of actionSet.
actionSet.setParent(actSet);
actSet.getSubActions().add(actionSet);
ListSorter<HierarchicalActionSet> sorter = new ListSorter<HierarchicalActionSet>(actSet.getSubActions());
actSet.setSubActions(sorter.sortAscending());
break;
} else {
addToActionSets(actionSet, parentAct, actSet.getSubActions());
}
}
}
private boolean addToAactionSet(Action act, Action parentAct, List<HierarchicalActionSet> actionSets) {
ITree parentTree = parentAct.getNode();
for(HierarchicalActionSet actionSet : actionSets) {
Action action = actionSet.getAction();
ITree tree = action.getNode();
if (tree.equals(parentTree)) { // actionSet is the parent of actSet.
if (action instanceof Move && !(act instanceof Move)) {
continue;
}
HierarchicalActionSet actSet = createActionSet(act, actionSet.getAction());
actSet.setParent(actionSet);
actionSet.getSubActions().add(actSet);
return true;
} else {
if ((!(act instanceof Insert) && !(action instanceof Insert))
|| (act instanceof Insert && action instanceof Insert)) {
int startPosition = act.getPosition();
int length = act.getLength();
int startP = action.getPosition();
int leng = action.getLength();
if (!(startP <= startPosition) || !(length <= leng)) {
continue;
} else if (startP > startPosition + length) {
break;
}
}
List<HierarchicalActionSet> subActionSets = actionSet.getSubActions();
if (subActionSets.size() > 0) {
boolean added = addToAactionSet(act, parentAct, subActionSets);
if (added) {
return true;
} else {
continue;
}
}
}
}
return false;
}
private Action findParentAction(Action action, List<Action> actions) {
ITree parent = action.getNode().getParent();
if (action instanceof Addition) {
parent = ((Addition) action).getParent();
}
for (Action act : actions) {
if (act.getNode().equals(parent)) {
if (act instanceof Move && !(action instanceof Move)) {
continue;
}
return act;
}
}
return null;
}
}
@@ -0,0 +1,326 @@
package edu.lu.uni.serval.gumtree.regroup;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.core.dom.CompilationUnit;
import com.github.gumtreediff.actions.model.Move;
import com.github.gumtreediff.actions.model.Update;
import com.github.gumtreediff.tree.ITree;
import edu.lu.uni.serval.FixPatternParser.CUCreator;
import edu.lu.uni.serval.diffentry.DiffEntryHunk;
public class HunkActionFilter {
/**
* Filter out the modify actions, which are not in the DiffEntry hunks.
*
* @param hunks
* @param actionSets
* @return
*/
public List<HierarchicalActionSet> filterActionsByDiffEntryHunk(List<DiffEntryHunk> hunks,
List<HierarchicalActionSet> actionSets, File revFile, File prevFile) {
List<HierarchicalActionSet> uselessActions = new ArrayList<>();
CUCreator cuCreator = new CUCreator();
CompilationUnit prevUnit = cuCreator.createCompilationUnit(prevFile);
CompilationUnit revUnit = cuCreator.createCompilationUnit(revFile);
if (prevUnit == null || revUnit == null) {
return uselessActions;
}
for (HierarchicalActionSet actionSet : actionSets) {
// position of buggy statements
int startPosition = 0;
int endPosition = 0;
int startLine = 0;
int endLine = 0;
// position of fixed statements
int startPosition2 = 0;
int endPosition2 = 0;
int startLine2 = 0;
int endLine2 = 0;
String actionStr = actionSet.getActionString();
if (actionStr.startsWith("INS")) {
startPosition2 = actionSet.getStartPosition();
endPosition2 = startPosition2 + actionSet.getLength();
List<Move> firstAndLastMov = getFirstAndLastMoveAction(actionSet);
if (firstAndLastMov != null) {
startPosition = firstAndLastMov.get(0).getNode().getPos();
ITree lastTree = firstAndLastMov.get(1).getNode();
endPosition = lastTree.getPos() + lastTree.getLength();
}
} else {
startPosition = actionSet.getStartPosition(); // range of actions
endPosition = startPosition + actionSet.getLength();
if (actionStr.startsWith("UPD")) {
Update update = (Update) actionSet.getAction();
ITree newNode = update.getNewNode();
startPosition2 = newNode.getPos();
endPosition2 = startPosition2 + newNode.getLength();
}
}
startLine = prevUnit.getLineNumber(startPosition);
endLine = prevUnit.getLineNumber(endPosition);
startLine2 = revUnit.getLineNumber(startPosition2);
endLine2 = revUnit.getLineNumber(endPosition2);
for (DiffEntryHunk hunk : hunks) {
int bugStartLine = hunk.getBugLineStartNum();
int bugRange = hunk.getBugRange();
int fixStartLine = hunk.getFixLineStartNum();
int fixRange = hunk.getFixRange();
if (actionStr.startsWith("INS")) {
if (fixStartLine + fixRange < startLine2) {
continue;
}
if (endLine2 < fixStartLine ) {
uselessActions.add(actionSet);
}
break;
} else {
if (bugStartLine + bugRange < startLine) {
continue;
}
if (endLine < bugStartLine ) {
uselessActions.add(actionSet);
}
break;
}
}
actionSet.setBugStartLineNum(startLine);
actionSet.setBugEndLineNum(endLine);
actionSet.setFixStartLineNum(startLine2);
actionSet.setFixEndLineNum(endLine2);
}
actionSets.removeAll(uselessActions);
uselessActions.clear();
return actionSets;
}
/**
* Filter out the modify actions, which are not in the DiffEntry hunks.
*
* @param hunks
* @param actionSets
* @return
*/
public List<HunkFixPattern> filterActionsByDiffEntryHunk2(List<DiffEntryHunk> hunks,
List<HierarchicalActionSet> actionSets, File revFile, File prevFile) {
List<HunkFixPattern> allHunkFixPatterns = new ArrayList<>();
CUCreator cuCreator = new CUCreator();
CompilationUnit prevUnit = cuCreator.createCompilationUnit(prevFile);
CompilationUnit revUnit = cuCreator.createCompilationUnit(revFile);
if (prevUnit == null || revUnit == null) {
return allHunkFixPatterns;
}
int i = 0;
int size = actionSets.size();
for (DiffEntryHunk hunk : hunks) {
int bugStartLine = hunk.getBugLineStartNum();
int bugRange = hunk.getBugRange();
int fixStartLine = hunk.getFixLineStartNum();
int fixRange = hunk.getFixRange();
for (; i < size; i ++) {
// position of buggy statements
int startPosition = 0;
int endPosition = 0;
int startLine = 0;
int endLine = 0;
// position of fixed statements
int startPosition2 = 0;
int endPosition2 = 0;
int startLine2 = 0;
int endLine2 = 0;
HierarchicalActionSet actionSet = actionSets.get(i);
String actionStr = actionSet.getActionString();
ITree parentITree = null;
List<HierarchicalActionSet> hunkActionSets = new ArrayList<>();
if (actionStr.startsWith("INS")) {
startPosition2 = actionSet.getStartPosition();
endPosition2 = startPosition2 + actionSet.getLength();
List<Move> firstAndLastMov = getFirstAndLastMoveAction(actionSet);
if (firstAndLastMov != null) {
startPosition = firstAndLastMov.get(0).getNode().getPos();
ITree lastTree = firstAndLastMov.get(1).getNode();
endPosition = lastTree.getPos() + lastTree.getLength();
}
} else {
startPosition = actionSet.getStartPosition(); // range of actions
endPosition = startPosition + actionSet.getLength();
if (actionStr.startsWith("UPD")) {
Update update = (Update) actionSet.getAction();
ITree newNode = update.getNewNode();
startPosition2 = newNode.getPos();
endPosition2 = startPosition2 + newNode.getLength();
String astNodeType = actionSet.getAstNodeType();
if ("EnhancedForStatement".equals(astNodeType) || "ForStatement".equals(astNodeType)
|| "DoStatement".equals(astNodeType) || "WhileStatement".equals(astNodeType)
|| "LabeledStatement".equals(astNodeType) || "SynchronizedStatement".equals(astNodeType)
|| "IfStatement".equals(astNodeType) || "TryStatement".equals(astNodeType)) {
List<ITree> children = update.getNode().getChildren();
endPosition = getEndPosition(children);
List<ITree> newChildren = newNode.getChildren();
endPosition2 = getEndPosition(newChildren);
if (endPosition == 0) {
endPosition = startPosition + actionSet.getLength();
}
if (endPosition2 == 0) {
endPosition2 = startPosition2 + newNode.getLength();
}
}
}
}
startLine = prevUnit.getLineNumber(startPosition);
endLine = prevUnit.getLineNumber(endPosition);
startLine2 = revUnit.getLineNumber(startPosition2);
endLine2 = revUnit.getLineNumber(endPosition2);
actionSet.setBugStartLineNum(startLine);
actionSet.setBugEndLineNum(endLine);
actionSet.setFixStartLineNum(startLine2);
actionSet.setFixEndLineNum(endLine2);
if (actionStr.startsWith("INS")) {
if (fixStartLine + fixRange < startLine2) {
addHunkActionSets(hunkActionSets, allHunkFixPatterns, hunk);
break;
}
if (endLine2 >= fixStartLine ) {
ITree parent = addToHunkActionSets(actionSet, hunkActionSets, allHunkFixPatterns, startLine, startLine2, endLine, endLine2, parentITree, hunk);
if (parent != null) {
if (parent != parentITree) {
hunkActionSets = new ArrayList<>();
}
hunkActionSets.add(actionSet);
} else if (hunkActionSets.size() > 0) {
hunkActionSets = new ArrayList<>();
}
parentITree = parent;
}
} else { // UPD, DEL, MOV
if (bugStartLine + bugRange < startLine) {
addHunkActionSets(hunkActionSets, allHunkFixPatterns, hunk);
break;
}
if (endLine >= bugStartLine ) {
ITree parent = addToHunkActionSets(actionSet, hunkActionSets, allHunkFixPatterns, startLine, startLine2, endLine, endLine2, parentITree, hunk);
if (parent != null) {
if (parent != parentITree) {
hunkActionSets = new ArrayList<>();
}
hunkActionSets.add(actionSet);
} else if (hunkActionSets.size() > 0) {
hunkActionSets = new ArrayList<>();
}
parentITree = parent;
}
}
addHunkActionSets(hunkActionSets, allHunkFixPatterns, hunk);
}
}
return allHunkFixPatterns;
}
private int getEndPosition(List<ITree> children) {
int endPosition = 0;
for (ITree child : children) {
if (child.getLabel().endsWith("Body")) {
endPosition = child.getPos() - 1;
break;
}
}
return endPosition;
}
private void addHunkActionSets(List<HierarchicalActionSet> hunkActionSets, List<HunkFixPattern> allHunkFixPatterns, DiffEntryHunk hunk) {
if (hunkActionSets.size() > 0) {
HunkFixPattern hunkFixPattern = new HunkFixPattern(hunk, hunkActionSets);
allHunkFixPatterns.add(hunkFixPattern);
}
}
private ITree addToHunkActionSets(HierarchicalActionSet actionSet, List<HierarchicalActionSet> hunkActionSets, List<HunkFixPattern> allHunkFixPatterns,
int startLine, int startLine2, int endLine, int endLine2, ITree parentITree, DiffEntryHunk hunk) {
String astNodeType = actionSet.getAstNodeType();
if ("FieldDeclaration".equals(astNodeType)) {
addHunkActionSets(hunkActionSets, allHunkFixPatterns, hunk);
hunkActionSets = new ArrayList<>();
hunkActionSets.add(actionSet);
HunkFixPattern hunkFixPattern = new HunkFixPattern(hunk, hunkActionSets);
allHunkFixPatterns.add(hunkFixPattern);
return null;
} else {
ITree currentParent = actionSet.getNode().getParent();
if (parentITree == null) {
parentITree = currentParent;
} else {
if (!parentITree.equals(currentParent)) {
HunkFixPattern hunkFixPattern = new HunkFixPattern(hunk, hunkActionSets);
allHunkFixPatterns.add(hunkFixPattern);
parentITree = currentParent;
}
}
return parentITree;
}
}
private List<Move> getFirstAndLastMoveAction(HierarchicalActionSet gumTreeResult) {
List<Move> firstAndLastMoveActions = new ArrayList<>();
List<HierarchicalActionSet> actions = gumTreeResult.getSubActions();
if (actions.size() == 0) {
return null;
}
Move firstMoveAction = null;
Move lastMoveAction = null;
while (actions.size() > 0) {
List<HierarchicalActionSet> subActions = new ArrayList<>();
for (HierarchicalActionSet action : actions) {
subActions.addAll(action.getSubActions());
if (action.toString().startsWith("MOV")) {
if (firstMoveAction == null) {
firstMoveAction = (Move) action.getAction();
lastMoveAction = (Move) action.getAction();
} else {
int startPosition = action.getStartPosition();
int length = action.getLength();
int startPositionFirst = firstMoveAction.getPosition();
int startPositionLast = lastMoveAction.getPosition();
int lengthLast = lastMoveAction.getNode().getLength();
if (startPosition < startPositionFirst || (startPosition == startPositionFirst && length > firstMoveAction.getLength())) {
firstMoveAction = (Move) action.getAction();
}
if ((startPosition + length) > (startPositionLast + lengthLast)) {
lastMoveAction = (Move) action.getAction();
}
}
}
}
actions.clear();
actions.addAll(subActions);
}
if (firstMoveAction == null) {
return null;
}
firstAndLastMoveActions.add(firstMoveAction);
firstAndLastMoveActions.add(lastMoveAction);
return firstAndLastMoveActions;
}
}
@@ -0,0 +1,27 @@
package edu.lu.uni.serval.gumtree.regroup;
import java.util.List;
import edu.lu.uni.serval.diffentry.DiffEntryHunk;
public class HunkFixPattern {
private DiffEntryHunk hunk;
private List<HierarchicalActionSet> hunkActionSets;
public HunkFixPattern(DiffEntryHunk hunk, List<HierarchicalActionSet> hunkActionSets) {
super();
this.hunk = hunk;
this.hunkActionSets = hunkActionSets;
}
public DiffEntryHunk getHunk() {
return hunk;
}
public List<HierarchicalActionSet> getHunkActionSets() {
return hunkActionSets;
}
}
@@ -0,0 +1,68 @@
package edu.lu.uni.serval.gumtree.regroup;
import java.util.ArrayList;
import java.util.List;
public class SimpleTree {
private String nodeType;
private String label;
private SimpleTree parent;
private List<SimpleTree> children = new ArrayList<>();
public String getNodeType() {
return nodeType;
}
public void setNodeType(String nodeType) {
this.nodeType = nodeType;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public SimpleTree getParent() {
return parent;
}
public void setParent(SimpleTree parent) {
this.parent = parent;
}
public List<SimpleTree> getChildren() {
return children;
}
public void setChildren(List<SimpleTree> children) {
this.children = children;
}
private List<String> strList = new ArrayList<>();
@Override
public String toString() {
String str = this.nodeType + "@@" + this.label;
if (strList.size() == 0) {
strList.add(str);
for (SimpleTree child : children) {
child.toString();
List<String> strList1 = child.strList;
for (String str1 : strList1) {
strList.add("------" + str1);
}
}
}
str = "";
for (String str1 : strList) {
str += str1 + "\n";
}
return str;
}
}
@@ -0,0 +1,662 @@
package edu.lu.uni.serval.gumtree.regroup;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.github.gumtreediff.actions.model.Action;
import com.github.gumtreediff.tree.ITree;
import edu.lu.uni.serval.gumtree.utils.ASTNodeMap;
import edu.lu.uni.serval.utils.ListSorter;
/**
* Simplify the ITree of source code into a simple tree.
*
* @author kui.liu
*
*/
public class SimplifyTree {
private static final String ABSTRACT_TYPE = "T";
private static final String ABSTRACT_NAME = "N";
private static final String ABSTRACT_METHOD = "m";
private static final String ABSTRACT_VARIABLE = "v";
private Map<String, String> abstractTypeIdentifiers = new HashMap<>();
private Map<String, String> abstractMethodIdentifiers = new HashMap<>();
private Map<String, String> abstractNameIdentifiers = new HashMap<>();
private Map<String, String> abstractVariableIdentifiers = new HashMap<>();
/**
* Convert ITree to a source code simple tree, an abstract identifier simple tree, and a semi-source code simple tree.
*
* @param actionSet
*/
public void abstractTree(HierarchicalActionSet actionSet) {
SimpleTree sourceCodeSimpleTree = null; // source code tree and AST node type tree
SimpleTree abstractIdentifierTree = null; // abstract identifier tree
SimpleTree abstractSimpleTree = null; // semi-source code tree. and AST node type tree
SimpleTree simpleTree = null; // source code tree with canonical variable names.
if (actionSet.getActionString().startsWith("INS")) {
List<Action> allMoveActions = getAllMoveActions(actionSet);
if (allMoveActions != null) {
List<Action> actions = new ArrayList<>();
for (Action action : allMoveActions) {
boolean hasParent = false;
ITree parent = action.getNode().getParent();
for (Action act : allMoveActions) {
if (act == action) continue;
ITree actNode = act.getNode();
if (actNode.equals(parent)) {
hasParent = true;
break;
}
}
if (!hasParent) {
actions.add(action);
}
}
sourceCodeSimpleTree = sourceCodeTree(actions);
simpleTree = canonicalizeSourceCodeTree(actions, null);
}
} else {
ITree tree = actionSet.getNode();
String astNodeType = actionSet.getAstNodeType();
if ("EnhancedForStatement".equals(astNodeType) || "ForStatement".equals(astNodeType)
|| "DoStatement".equals(astNodeType) || "WhileStatement".equals(astNodeType)
|| "LabeledStatement".equals(astNodeType) || "SynchronizedStatement".equals(astNodeType)
|| "IfStatement".equals(astNodeType) || "TryStatement".equals(astNodeType)) {
// delete the body block.
List<ITree> children = tree.getChildren();
List<ITree> newChildren = new ArrayList<>();
for (ITree child : children) {
if (!child.getLabel().endsWith("Body")) {
newChildren.add(child);
}
}
tree.setChildren(newChildren);
}
sourceCodeSimpleTree = originalSourceCodeTree(tree, null);
// abstractIdentifierTree = abstractIdentifierTree(actionSet, tree, null);
// abstractSimpleTree = semiSourceCodeTree(actionSet, tree, null);
simpleTree = canonicalizeSourceCodeTree(tree, null);
}
// actionSet.setAbstractSimpleTree(abstractSimpleTree);
// actionSet.setAbstractIdentifierTree(abstractIdentifierTree);
// actionSet.setSimpleTree(sourceCodeSimpleTree);
actionSet.setSimpleTree(simpleTree);
actionSet.setOriginalTree(sourceCodeSimpleTree);
}
private SimpleTree canonicalizeSourceCodeTree(List<Action> actions, SimpleTree parent) {
SimpleTree simpleTree = new SimpleTree();
simpleTree.setLabel("Block");
simpleTree.setNodeType("Block");
simpleTree.setParent(parent);
List<SimpleTree> children = new ArrayList<>();
for (Action action : actions) {
ITree node = action.getNode();
children.add(canonicalizeSourceCodeTree(node, simpleTree));
}
simpleTree.setChildren(children);
return simpleTree;
}
private SimpleTree canonicalizeSourceCodeTree(ITree tree, SimpleTree parent) {
SimpleTree simpleTree = new SimpleTree();
String label = tree.getLabel();
String astNode = ASTNodeMap.map.get(tree.getType());
List<ITree> children = tree.getChildren();
if (children.size() > 0) {
simpleTree.setNodeType(astNode);
if (astNode.endsWith("Type")) {
simpleTree.setLabel(canonicalizeTypeStr(label).replaceAll(" ", ""));
} else {
List<SimpleTree> subTrees = new ArrayList<>();
for (ITree child : children) {
subTrees.add(canonicalizeSourceCodeTree(child, simpleTree));
}
simpleTree.setChildren(subTrees);
simpleTree.setLabel(astNode);
}
} else {
if (astNode.endsWith("Name")) {
// variableName, methodName, QualifiedName
if (label.startsWith("MethodName:")) { // <MethodName, name>
label = label.substring(11);
simpleTree.setNodeType("MethodName");
simpleTree.setLabel(label);
} else if (label.startsWith("Name:")) {
label = label.substring(5);
String firstChar = label.substring(0, 1);
if (firstChar.equals(firstChar.toUpperCase())) {
simpleTree.setNodeType("Name");
simpleTree.setLabel(label);
} else {// variableName: <VariableName, canonicalName>
simpleTree.setNodeType("VariableName");
simpleTree.setLabel(canonicalVariableName(label, tree));
}
} else {// variableName: <VariableName, canonicalName>
simpleTree.setNodeType("VariableName");
simpleTree.setLabel(canonicalVariableName(label, tree));
}
} else {
simpleTree.setNodeType(astNode);
simpleTree.setLabel(label.replaceAll(" ", ""));
}
}
simpleTree.setParent(parent);
return simpleTree;
}
private String canonicalVariableName(String label, ITree tree) {
ITree parent = tree.getParent();
if (parent == null) {
return label;
} else {
String matchStr = null;
int parentType = parent.getType();
if (parentType == 44) { // SingleVariableDeclaration
matchStr = matchSingleVariableDeclaration(parent, label);
} else if (parentType == 23 || parentType == 58 || parentType == 60) {
//FieldDeclaration, VariableDeclarationExpression, VariableDeclarationStatement
matchStr = matchVariableDeclarationExpression(parent, label);
} else if (parentType == 31) { // MethodDeclaration
List<ITree> children = parent.getChildren();
int index = children.indexOf(tree);
for (int i = index - 1; i >=0; i --) {
ITree child = children.get(i);
int childType = child.getType();
if (childType == 60) { // VariableDeclarationStatement
matchStr = matchVariableDeclarationExpression(child, label);
} else if (childType == 44) { // SingleVariableDeclaration
matchStr = matchSingleVariableDeclaration(child, label);
} else if (childType ==70 || childType == 24 ||childType == 12 || childType == 54) {
matchStr = matchStatements(childType, child, label);
}
if (matchStr != null) break;
}
} else if (parentType ==70 || parentType == 24 ||parentType == 12 || parentType == 54) {
// EnhancedForStatement, ForStatement, CatchClause, TryStatement
matchStr = matchStatements(parentType, parent, label);
} else if (parentType == 55) { // TypeDeclaration: Class Declaration
List<ITree> children = parent.getChildren();
for (ITree child : children) {
if (child.getType() == 23) { // FieldDeclaration
matchStr = matchVariableDeclarationExpression(child, label);
}
}
}
if (matchStr != null) {
return matchStr;
} else {
return canonicalVariableName(label, parent);
}
}
}
private String matchStatements(int typeInt, ITree tree, String label) {
String matchStr = null;
if (typeInt == 70) { // EnhancedForStatement
matchStr = matchSingleVariableDeclaration(tree.getChild(0), label);
} else if (typeInt == 24) { // ForStatement
List<ITree> children = tree.getChildren();
for (ITree child : children) {
if (child.getType() == 58) {
matchStr = matchVariableDeclarationExpression(child, label);
if (matchStr != null) break;
} else {
break;
}
}
} else if (typeInt == 12) { // CatchClause
matchStr = matchSingleVariableDeclaration(tree.getChild(0), label);
} else if (typeInt == 54) { // TryStatement
List<ITree> children = tree.getChildren();
for (ITree child : children) {
if (child.getType() == 58) { //VariableDeclarationExpression
matchStr = matchVariableDeclarationExpression(tree, label);
if (matchStr != null) break;
} else {
break;
}
}
}
return null;
}
private String matchVariableDeclarationExpression(ITree variable, String label) {
List<ITree> children = variable.getChildren();
ITree type = null;
for (int i = 0, size = children.size(); i < size; i ++) {
ITree child = children.get(i);
if (child.getType() == 59) {// VariableDeclarationFragment
if (type == null) {
type = children.get(i - 1);
}
ITree simpleName = child.getChild(0);
if (simpleName.getLabel().equals(label)) {
String typeStr = canonicalizeTypeStr(type.getLabel());
label = typeStr.toLowerCase() + "Var";
return label;
}
}
}
return null;
}
private String matchSingleVariableDeclaration(ITree singleVariable, String label) {
List<ITree> children = singleVariable.getChildren();
for (int i = 0, size = children.size(); i < size; i ++) {
ITree child = children.get(i);
if (child.getType() == 42) { // SimpleName
if (child.getLabel().equals(label)) {
ITree type = children.get(i - 1);
String typeStr = canonicalizeTypeStr(type.getLabel());
label = typeStr.toLowerCase() + "Var";
return label;
}
break;
}
}
return null;
}
private String canonicalizeTypeStr(String label) {
String typeStr = label;
int index1 = typeStr.indexOf("<");
if (index1 != -1) {
typeStr = typeStr.substring(0, index1);
}
index1 = typeStr.lastIndexOf(".");
if (index1 != -1) {
typeStr = typeStr.substring(index1 + 1);
}
return typeStr;
}
// public static String addPrefixByType(Type type) {
// String newName = "";
// if (type instanceof PrimitiveType) {
// // byte,short,char,int,long,float,double,boolean,void
// newName = type.toString().toLowerCase();
// } else if (type instanceof ArrayType) {
// // Type [ ]
// ArrayType at = (ArrayType) type;
// type = at.getElementType();
// if (type instanceof SimpleType || type instanceof PrimitiveType) {
// newName = getNewName(type);
// } else {
// newName = addPrefixByType(type);
// }
// } else if (type instanceof SimpleType) {
// // TypeName
// if (type.toString().equals("Integer")) {
// newName = "int";
// } else {
// newName = getNewName(type);
// }
// } else if (type instanceof QualifiedType) {
// // Type.SimpleName
// newName = ((QualifiedType) type).getName().toString().toLowerCase();
// } else if (type instanceof ParameterizedType) {
// // Type < Type { , Type } > 泛型
// ParameterizedType t = (ParameterizedType) type;
// newName = getNewName(t.getType());
// } else if (type instanceof WildcardType) {
// newName = "object";
// }
// return newName;
// }
//
// private static String getNewName(Type type) {
// String newName = "";
// String typeName = type.toString();
// int dot = typeName.lastIndexOf(".");
// if (dot > 0) {
// newName = typeName.substring(dot + 1).toString().toLowerCase();
// } else {
// newName = typeName.toString().toLowerCase();
// }
// return newName;
// }
/**
* Convert the Move actions of an INS action into a simple tree with AST nodes and leaf labels.
*
* @param actions
* @return
*/
private SimpleTree sourceCodeTree(List<Action> actions) {
if (actions.size() > 0) {
SimpleTree simpleTree = new SimpleTree();
simpleTree.setNodeType("Block");
simpleTree.setLabel("Block");
simpleTree.setParent(null);
List<SimpleTree> subTrees = new ArrayList<>();
for (Action action : actions) {
ITree node = action.getNode();
subTrees.add(sourceCodeTree(node, simpleTree));
}
simpleTree.setChildren(subTrees);
return simpleTree;
}
return null;
}
/**
* Convert a Move action into a simple tree with AST nodes and leaf labels.
*
* @param tree
* @param parent
* @return
*/
private SimpleTree sourceCodeTree(ITree tree, SimpleTree parent) {
SimpleTree simpleTree = new SimpleTree();
String astNode = ASTNodeMap.map.get(tree.getType());
do {
if (astNode.endsWith("Statement") || astNode.equals("FieldDeclaration")) break;
tree = tree.getParent();
astNode = ASTNodeMap.map.get(tree.getType());// FIXME if the ASTNode is a method declaration or class declaration?
} while (!astNode.endsWith("Statement") && !astNode.equals("FieldDeclaration"));
String label = tree.getLabel();
List<ITree> children = tree.getChildren();
if (children.size() > 0) {
List<SimpleTree> subTrees = new ArrayList<>();
for (ITree child : children) {
subTrees.add(sourceCodeTree(child, simpleTree));
}
simpleTree.setChildren(subTrees);
simpleTree.setLabel(astNode);
} else {
simpleTree.setLabel(label);
}
simpleTree.setNodeType(astNode);
simpleTree.setParent(parent);
return simpleTree;
}
/**
* Convert an UPD/DEL/MOV action into a simple tree with AST nodes and leaf labels.
*
* @param tree
* @param parent
* @return
*/
private SimpleTree originalSourceCodeTree(ITree tree, SimpleTree parent) {
SimpleTree simpleTree = new SimpleTree();
String label = tree.getLabel();
String astNode = ASTNodeMap.map.get(tree.getType());
simpleTree.setNodeType(astNode);
List<ITree> children = tree.getChildren();
if (children.size() > 0) {
List<SimpleTree> subTrees = new ArrayList<>();
for (ITree child : children) {
subTrees.add(originalSourceCodeTree(child, simpleTree));
}
simpleTree.setChildren(subTrees);
simpleTree.setLabel(astNode);
} else {
simpleTree.setLabel(label);
}
simpleTree.setParent(parent);
return simpleTree;
}
/**
* Convert an UPD/DEL/MOV action into a simple tree with abstract identifiers of AST nodes and abstract identifiers of leaf labels.
*
* @param actionSet
* @param tree
* @param parent
* @return
*/
private SimpleTree abstractIdentifierTree(ITree tree, SimpleTree parent) {
SimpleTree simpleTree = new SimpleTree();
String label = tree.getLabel();
String astNode = ASTNodeMap.map.get(tree.getType());
simpleTree.setNodeType(astNode);
List<ITree> children = tree.getChildren();
if (children.size() > 0) {
if (astNode.endsWith("Type")) {
simpleTree.setNodeType("Type");
simpleTree.setLabel(getAbstractLabel(abstractTypeIdentifiers, label, ABSTRACT_TYPE)); // abstract Type identifier
} else {
List<SimpleTree> subTrees = new ArrayList<>();
for (ITree child : children) {
subTrees.add(abstractIdentifierTree(child, simpleTree));
}
simpleTree.setChildren(subTrees);
simpleTree.setLabel(astNode);
}
} else {
if (astNode.endsWith("Type")) {
simpleTree.setNodeType("Type");
if (astNode.equals("WildcardType")) {
simpleTree.setLabel("?");
} else {
simpleTree.setLabel(getAbstractLabel(abstractTypeIdentifiers, label, ABSTRACT_TYPE)); // abstract Type identifier
}
} else if (astNode.endsWith("Name")) {
// variableName, methodName, QualifiedName
if (label.startsWith("MethodName:")) { // <Method, name>
label = label.substring(11);
simpleTree.setNodeType("Method");
simpleTree.setLabel(getAbstractLabel(abstractMethodIdentifiers, label, ABSTRACT_METHOD)); // abstract method identifier
} else if (label.startsWith("Name:")) {
label = label.substring(5);
String firstChar = label.substring(0, 1);
if (firstChar.equals(firstChar.toUpperCase())) {
simpleTree.setNodeType("Name");
simpleTree.setLabel(getAbstractLabel(abstractNameIdentifiers, label, ABSTRACT_NAME)); // abstract Name identifier
} else {// variableName: <Variable, var>
simpleTree.setNodeType("Variable");
simpleTree.setLabel(getAbstractLabel(abstractVariableIdentifiers, label, ABSTRACT_VARIABLE));// abstract Variable identifier
}
} else {// variableName: <Variable, var>
simpleTree.setNodeType("Variable");
simpleTree.setLabel(getAbstractLabel(abstractVariableIdentifiers, label, ABSTRACT_VARIABLE));// abstract Variable identifier
}
} else if (astNode.equals("BooleanLiteral") || astNode.equals("CharacterLiteral") || astNode.equals("NullLiteral")
|| astNode.equals("NumberLiteral") || astNode.equals("StringLiteral") || astNode.equals("ThisExpression")
|| astNode.equals("Modifier") || astNode.equals("Operator")) {
simpleTree.setNodeType(astNode);
simpleTree.setLabel(label);
}
}
simpleTree.setParent(parent);
return simpleTree;
}
/**
* Convert an UPD/DEL/MOV action into a semi-source code simple tree by abstracting the non-buggy code.
*
* @param actionSet
* @param tree
* @param parent
* @return
*/
private SimpleTree semiSourceCodeTree(HierarchicalActionSet actionSet, ITree tree, SimpleTree parent) {
SimpleTree simpleTree = new SimpleTree();
simpleTree.setParent(parent);
// deep first
abstractBuggyTreeDeepFirst(actionSet, tree, simpleTree);
return simpleTree;
}
private void abstractBuggyTreeDeepFirst(HierarchicalActionSet actionSet, ITree tree, SimpleTree simpleTree) {
List<ITree> children = tree.getChildren();
HierarchicalActionSet modifyAction = findHierarchicalActionSet(tree.getPos(), tree.getLength(), actionSet);
String label = tree.getLabel();
String astNode = ASTNodeMap.map.get(tree.getType());
if (isExpressionType(astNode)) {
if (modifyAction == null || !modifyAction.getActionString().contains("@@" + label)) {
simpleTree.setNodeType("Expression");
simpleTree.setLabel("EXP"); // astNode
}
} else {
if (astNode.endsWith("Type")) { // <Type, ?> TODO: sub Type
simpleTree.setNodeType("Type");
// simpleTree.setLabel("?");
if (astNode.equals("WildcardType")) {
simpleTree.setLabel("?");
} else { // ArrayType, PrimitiveType, SimpleType, ParameterizedType, QualifiedType, WildcardType, UnionType,NameQualifiedType, IntersectionType
simpleTree.setLabel(astNode + "@@" + label);
}
} else if (astNode.endsWith("Name")) { // variableName, methodName, QualifiedName
if (label.startsWith("MethodName:")) { // <Method, name>
label = label.substring(11);
simpleTree.setNodeType("Method");
simpleTree.setLabel(label);
} else if (label.startsWith("Name:")) {
label = label.substring(5);
String firstChar = label.substring(0, 1);
if (firstChar.equals(firstChar.toUpperCase())) {
simpleTree.setNodeType("Name");
simpleTree.setLabel(label); // <Name, name>
} else {// variableName: <Variable, var>
simpleTree.setNodeType("Variable");
simpleTree.setLabel(getAbstractLabel(abstractVariableIdentifiers, label, ABSTRACT_VARIABLE));
}
} else {// variableName: <Variable, var>
simpleTree.setNodeType("Variable");
simpleTree.setLabel(getAbstractLabel(abstractVariableIdentifiers, label, ABSTRACT_VARIABLE));
}
} else if (astNode.equals("BooleanLiteral") ||astNode.equals("CharacterLiteral") || astNode.equals("ThisExpression")
|| astNode.equals("NullLiteral") || astNode.equals("NumberLiteral") || astNode.equals("StringLiteral")
|| astNode.equals("Modifier") || astNode.equals("Operator")) {
simpleTree.setNodeType(astNode);
simpleTree.setLabel(label);
} else {
simpleTree.setNodeType(astNode);
simpleTree.setLabel(astNode);
}
}
List<SimpleTree> simpleChildren = new ArrayList<>();
if (children != null && !astNode.endsWith("Type")) {
for (ITree child : children) {
simpleChildren.add(semiSourceCodeTree(actionSet, child, simpleTree));
}
}
simpleTree.setChildren(simpleChildren);
}
private List<Action> getAllMoveActions(HierarchicalActionSet actionSet) {
String astNodeType = actionSet.getAstNodeType();
if ("EnhancedForStatement".equals(astNodeType) || "ForStatement".equals(astNodeType)
|| "DoStatement".equals(astNodeType) || "WhileStatement".equals(astNodeType)
|| "LabeledStatement".equals(astNodeType) || "SynchronizedStatement".equals(astNodeType)
|| "IfStatement".equals(astNodeType) || "TryStatement".equals(astNodeType)) {
List<Action> allMoveActions = getAllMoveActions2(actionSet);
if (allMoveActions != null && allMoveActions.size() > 0) {
ListSorter<Action> sorter = new ListSorter<Action>(allMoveActions);
allMoveActions = sorter.sortAscending();
return allMoveActions;
} else {// FIXME: pure INS actions.
return null;
}
} else {// FIXME: pure INS actions.
return null;
}
/**
* Variables, non-new and used in the inserted statements, could be selected to localize buggy code
*/
}
private List<Action> getAllMoveActions2(HierarchicalActionSet actionSet) {
List<Action> allMoveActions = new ArrayList<>();
List<HierarchicalActionSet> actions = actionSet.getSubActions();
if (actions.size() == 0) {
return null;
}
while (actions.size() > 0) {
List<HierarchicalActionSet> subActions = new ArrayList<>();
for (HierarchicalActionSet action : actions) {
subActions.addAll(action.getSubActions());
if (action.toString().startsWith("MOV")) {
allMoveActions.add(action.getAction());
}
}
actions.clear();
actions.addAll(subActions);
}
return allMoveActions;
}
private String getAbstractLabel(Map<String, String> map, String label, String nameType) {
if (map.containsKey(label)) {
return map.get(label);
} else {
String name = nameType + map.size();
map.put(label, name);
return name;
}
}
private boolean isExpressionType(String astNode) {
if (astNode.equals("ArrayAccess") || astNode.equals("ArrayCreation") ||
astNode.equals("ArrayInitializer") || astNode.equals("Assignment") || astNode.equals("CastExpression") ||
astNode.equals("ClassInstanceCreation") || astNode.equals("ConditionalExpression") || astNode.equals("CreationReference") ||
astNode.equals("ExpressionMethodReference") || astNode.equals("FieldAccess") || astNode.equals("InfixExpression") ||
astNode.equals("InstanceofExpression") || astNode.equals("LambdaExpression") || astNode.equals("MethodInvocation") ||
astNode.equals("MethodReference") || astNode.equals("ParenthesizedExpression") || astNode.equals("PostfixExpression") ||
astNode.equals("PrefixExpression") || astNode.equals("SuperFieldAccess") || astNode.equals("SuperMethodInvocation") ||
astNode.equals("SuperMethodReference") || astNode.equals("TypeLiteral") || astNode.equals("TypeMethodReference")
|| astNode.equals("VariableDeclarationExpression") ) {
return true;
}
return false;
}
private HierarchicalActionSet findHierarchicalActionSet(int position, int length, HierarchicalActionSet actionSet) {
if (actionSet.getStartPosition() == position && actionSet.getLength() == length && !actionSet.getActionString().startsWith("INS")) {
return actionSet;
} else {
for (HierarchicalActionSet subActionSet : actionSet.getSubActions()) {
HierarchicalActionSet actSet = findHierarchicalActionSet(position, length, subActionSet);
if (actSet != null) {
return actSet;
}
}
}
return null;
}
public Map<String, String> getAbstractTypeIdentifiers() {
return abstractTypeIdentifiers;
}
public Map<String, String> getAbstractMethodIdentifiers() {
return abstractMethodIdentifiers;
}
public Map<String, String> getAbstractNameIdentifiers() {
return abstractNameIdentifiers;
}
public Map<String, String> getAbstractVariableIdentifiers() {
return abstractVariableIdentifiers;
}
}
@@ -0,0 +1,140 @@
package edu.lu.uni.serval.gumtree.regroup;
import java.util.ArrayList;
import java.util.List;
import com.github.gumtreediff.tree.ITree;
import edu.lu.uni.serval.gumtree.utils.ASTNodeMap;
/**
* A traveler to travel a tree-constructed object.
*
* @author kui.liu
*
*/
public class Traveler {
public List<List<String>> list = new ArrayList<>();
/**
* Get all action string by traveling HierarchicalActionSet in a deep-first way.
*
* @param actionSet
* @param astNodeTypeActionQueue
*/
public void travelActionSetDeepFirstToASTNodeQueue(HierarchicalActionSet actionSet, List<String> astNodeTypeActionQueue) {
if (actionSet == null) {
System.err.println("Null Action set!");
} else {
if (astNodeTypeActionQueue == null) {
astNodeTypeActionQueue = new ArrayList<>();
}
String actionStr = actionSet.getActionString();
actionStr = actionStr.substring(0, actionStr.indexOf("@@"));
astNodeTypeActionQueue.add(actionStr); // RawToken: TODO
if (actionStr.startsWith("DEL")) {
list.add(astNodeTypeActionQueue); // FIXME BUG: Change AST node type 1 to AST node type 2. Solve method: a list is one pattern.
} else {
List<HierarchicalActionSet> subActionSet = actionSet.getSubActions();
int size = subActionSet.size();
if (size > 0) {
for (HierarchicalActionSet subAction : subActionSet) {
List<String> astNodeTypeActionQueue_ = new ArrayList<>();
astNodeTypeActionQueue_.addAll(astNodeTypeActionQueue);
travelActionSetDeepFirstToASTNodeQueue(subAction, astNodeTypeActionQueue_);
}
} else {
list.add(astNodeTypeActionQueue);
}
}
}
}
/**
* Get all AST node types of a root tree by traveling the root tree in a deep-first way.
*
* @param root
* @return
*/
public static List<String> travelTreeDeepFirstToASTNodeQueue(ITree root) {
if (root == null) {
System.err.println("Null tree!");
return null;
}
List<String> astNodeTypeQueue = new ArrayList<>();
astNodeTypeQueue.add(ASTNodeMap.map.get(root.getType())); // RawToken: root.getLabel();
List<ITree> childrenTreeList = root.getChildren();
if (childrenTreeList != null && childrenTreeList.size() > 0) {
for (ITree childTree : childrenTreeList) {
astNodeTypeQueue.addAll(travelTreeDeepFirstToASTNodeQueue(childTree));
}
}
return astNodeTypeQueue;
}
/**
* Get all AST node types of a root tree by traveling the root tree in a breadth-first way.
*
* @param root
* @return
*/
public static List<String> travelTreeBreadthFirstToASTNodeQueue(ITree root) {
if (root == null) {
System.err.println("Null tree.");
return null;
}
List<String> astNodeTypeQueue = new ArrayList<>();
astNodeTypeQueue.add(ASTNodeMap.map.get(root.getType())); // RawToken: root.getLabel();
List<ITree> treeList = new ArrayList<>();
treeList.add(root);
while (!treeList.isEmpty()) {
List<ITree> childrenTreeList = new ArrayList<>();
for (ITree tree : treeList) {
astNodeTypeQueue.addAll(travelTreeBreadthFirstToASTNodeQueue(tree));
childrenTreeList.addAll(tree.getChildren());
}
treeList.clear();
treeList.addAll(childrenTreeList);
}
return astNodeTypeQueue;
}
/**
* Convert a root ITree into a SimpleTree by traveling the root tree in a deep-first way.
*
* SimpleTree node label is root.toShortString().
*
* @param root
* @param parent
* @return
*/
public static SimpleTree travelITreeDeepFirstToSimpleTree(ITree root, SimpleTree parent) {
if (root == null) {
System.err.println("Null tree!");
return null;
}
SimpleTree simpleTree = new SimpleTree();
simpleTree.setLabel(root.toShortString());
simpleTree.setParent(parent);
List<SimpleTree> children = new ArrayList<>();
List<ITree> childrenTreeList = root.getChildren();
if (childrenTreeList != null && childrenTreeList.size() > 0) {
for (ITree childTree : childrenTreeList) {
children.add(travelITreeDeepFirstToSimpleTree(childTree, simpleTree));
}
}
simpleTree.setChildren(children);
return simpleTree;
}
}
@@ -0,0 +1,109 @@
package edu.lu.uni.serval.gumtree.utils;
import java.util.HashMap;
import java.util.Map;
public class ASTNodeMap {
public static Map<Integer, String> map;
static {
map = new HashMap<Integer, String>();
map.put(-3, "Instanceof");
map.put(-2, "New");
map.put(-1, "Operator");
map.put(0, "ASTNode");
map.put(1, "AnonymousClassDeclaration");
map.put(2, "ArrayAccess");
map.put(3, "ArrayCreation");
map.put(4, "ArrayInitializer");
map.put(5, "ArrayType");
map.put(6, "AssertStatement");
map.put(7, "Assignment");
map.put(8, "Block");
map.put(9, "BooleanLiteral");
map.put(10, "BreakStatement");
map.put(11, "CastExpression");
map.put(12, "CatchClause");
map.put(13, "CharacterLiteral");
map.put(14, "ClassInstanceCreation");
map.put(15, "CompilationUnit");
map.put(16, "ConditionalExpression");
map.put(17, "ConstructorInvocation");
map.put(18, "ContinueStatement");
map.put(19, "DoStatement");
map.put(20, "EmptyStatement");
map.put(21, "ExpressionStatement");
map.put(22, "FieldAccess");
map.put(23, "FieldDeclaration");
map.put(24, "ForStatement");
map.put(25, "IfStatement");
map.put(26, "ImportDeclaration");
map.put(27, "InfixExpression");
map.put(28, "Initializer");
map.put(29, "Javadoc");
map.put(30, "LabeledStatement");
map.put(31, "MethodDeclaration");
map.put(32, "MethodInvocation");
map.put(33, "NullLiteral");
map.put(34, "NumberLiteral");
map.put(35, "PackageDeclaration");
map.put(36, "ParenthesizedExpression");
map.put(37, "PostfixExpression");
map.put(38, "PrefixExpression");
map.put(39, "PrimitiveType");
map.put(40, "QualifiedName");
map.put(41, "ReturnStatement");
map.put(42, "SimpleName");
map.put(43, "SimpleType");
map.put(44, "SingleVariableDeclaration");
map.put(45, "StringLiteral");
map.put(46, "SuperConstructorInvocation");
map.put(47, "SuperFieldAccess");
map.put(48, "SuperMethodInvocation");
map.put(49, "SwitchCase");
map.put(50, "SwitchStatement");
map.put(51, "SynchronizedStatement");
map.put(52, "ThisExpression");
map.put(53, "ThrowStatement");
map.put(54, "TryStatement");
map.put(55, "TypeDeclaration");
map.put(56, "TypeDeclarationStatement");
map.put(57, "TypeLiteral");
map.put(58, "VariableDeclarationExpression");
map.put(59, "VariableDeclarationFragment");
map.put(60, "VariableDeclarationStatement");
map.put(61, "WhileStatement");
map.put(62, "InstanceofExpression");
map.put(63, "LineComment");
map.put(64, "BlockComment");
map.put(65, "TagElement");
map.put(66, "TextElement");
map.put(67, "MemberRef");
map.put(68, "MethodRef");
map.put(69, "MethodRefParameter");
map.put(70, "EnhancedForStatement");
map.put(71, "EnumDeclaration");
map.put(72, "EnumConstantDeclaration");
map.put(73, "TypeParameter");
map.put(74, "ParameterizedType");
map.put(75, "QualifiedType");
map.put(76, "WildcardType");
map.put(77, "NormalAnnotation");
map.put(78, "MarkerAnnotation");
map.put(79, "SingleMemberAnnotation");
map.put(80, "MemberValuePair");
map.put(81, "AnnotationTypeDeclaration");
map.put(82, "AnnotationTypeMemberDeclaration");
map.put(83, "Modifier");
map.put(84, "UnionType");
map.put(85, "Dimension");
map.put(86, "LambdaExpression");
map.put(87, "IntersectionType");
map.put(88, "NameQualifiedType");
map.put(89, "CreationReference");
map.put(90, "ExpressionMethodReference");
map.put(91, "SuperMethhodReference");
map.put(92, "TypeMethodReference");
}
}