// TODO: Annotations and non-annotation deprecation
// We matched these methods based on descriptor (=type & params) and name
// but the thrown exceptions and access type may still be different
// and if it is, we want that highlighted
MethodDefRow mdrA = null;
MethodDefRow mdrB = null;
if (methodA.getAccessFlags() == methodB.getAccessFlags()
&& methodA.getExceptions().equals(methodB.getExceptions())) {
// everything is equal, just add one line
MethodDefRow mdr = new MethodDefRow(cfA, methodA, true, methodA.getAttributes().getCode() != null);
mdrA = mdr;
mdrB = mdr;
this.rowsAll.add(mdr);
} else {
mdrA = new MethodDefRow(cfA, methodA, true, methodA.getAttributes().getCode() != null);
rowsA.add(mdrA);
mdrB = new MethodDefRow(cfB, methodB, true, methodB.getAttributes().getCode() != null);
rowsB.add(mdrB);
rowsAll.add(mdrA);
rowsAll.add(mdrB);
}
Attributes attrA = methodA.getAttributes();
Attributes attrB = methodB.getAttributes();
CodeAttribute codeAttrA = attrA.getCode();
CodeAttribute codeAttrB = attrB.getCode();
LineNumberTableAttribute lnAttrA = null;
LineNumberTableAttribute lnAttrB = null;
LocalVariableTableAttribute lvsA = null;
LocalVariableTableAttribute lvsB = null;
if (codeAttrA != null && codeAttrB != null) {
// TODO: deal with the case where only one is null
// ie, one method has code, the other doesn't
if (codeAttrA.getAttributes() != null) {
lnAttrA = codeAttrA.getAttributes().getLineNumberTable();
lvsA = codeAttrA.getAttributes().getLocalVariableTable();
}
if (codeAttrB.getAttributes() != null) {
lnAttrB = codeAttrB.getAttributes().getLineNumberTable();
lvsB = codeAttrB.getAttributes().getLocalVariableTable();
}
Code codeA = codeAttrA.getCode();
Code codeB = codeAttrB.getCode();
DecompilationContext dcA = codeA.createDecompilationContext();
DecompilationContext dcB = codeB.createDecompilationContext();
List<Instruction> instructionsA = codeA.getInstructions();
List<Instruction> instructionsB = codeB.getInstructions();
dcA.setPosition(0);
dcB.setPosition(0);
List<EditorRow> methodRowsA = getMethodRows(instructionsA, codeA, mdrA, lnAttrA, lvsA, dcA, cfA);
List<EditorRow> methodRowsB = getMethodRows(instructionsB, codeB, mdrB, lnAttrB, lvsB, dcB, cfB);
// find out the equal instructions at the beginning of the block
int startEqCount = 0;
while (true) {
if (startEqCount == methodRowsA.size()) break;
if (startEqCount == methodRowsB.size()) break;
EditorRow erA = methodRowsA.get(startEqCount);
EditorRow erB = methodRowsB.get(startEqCount);
boolean equal = rowsAreEqual(erA, erB);
if (!equal) break;
startEqCount++;
}
for (int i=0; i < startEqCount; i++) {
this.rowsAll.add(methodRowsA.get(0));
methodRowsA.remove(0);
methodRowsB.remove(0);
}
// find out the equal instructions at the end of each code block
int endEqCount = 0;
while (true) {
if (endEqCount == methodRowsA.size()) break;
if (endEqCount == methodRowsB.size()) break;
EditorRow erA = methodRowsA.get((methodRowsA.size()-1)-endEqCount);
EditorRow erB = methodRowsB.get((methodRowsB.size()-1)-endEqCount);
boolean equal = rowsAreEqual(erA, erB);
if (!equal) break;
endEqCount++;
}
List<EditorRow> equalRowsAtTheEnd = new ArrayList<EditorRow>();
for (int i=0; i < endEqCount; i++) {
equalRowsAtTheEnd.add(methodRowsA.get(methodRowsA.size()-1));
methodRowsA.remove(methodRowsA.size()-1);
methodRowsB.remove(methodRowsB.size()-1);
}
int m = methodRowsA.size();
int n = methodRowsB.size();
int[][] C = new int[m+1][n+1];
lcs(C, methodRowsA, methodRowsB);
List<EditorRow> common = new ArrayList<EditorRow>();
bt(C, methodRowsA, methodRowsB, m, n, common);
for (EditorRow commonRow : common) {
// rows from set A before the next common row
while (!rowsAreEqual(methodRowsA.get(0), commonRow)) {
this.rowsAll.add(methodRowsA.get(0));
this.rowsA.add(methodRowsA.get(0));
methodRowsA.remove(0);
}
// rows from set B before the next common row
while (!rowsAreEqual(methodRowsB.get(0), commonRow)) {
this.rowsAll.add(methodRowsB.get(0));
this.rowsB.add(methodRowsB.get(0));
methodRowsB.remove(0);
}
this.rowsAll.add(commonRow);
methodRowsA.remove(0);
methodRowsB.remove(0);
}
this.rowsA.addAll(methodRowsA);
this.rowsAll.addAll(methodRowsA);
this.rowsB.addAll(methodRowsB);
this.rowsAll.addAll(methodRowsB);
this.rowsAll.addAll(equalRowsAtTheEnd);
this.rowsAll.add(new MethodDefRow(cfA, methodA, false, true));
}
}