Skip to content

Commit

Permalink
Support the replacement of string literal concatenation with text block
Browse files Browse the repository at this point in the history
TestVM.java → BstFunctionsTest.java
#715
  • Loading branch information
tsantalis committed May 17, 2024
1 parent 93f5a85 commit 719e8e2
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 2 deletions.
6 changes: 6 additions & 0 deletions src/main/java/gr/uom/java/xmi/decomposition/LeafMapping.java
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,12 @@ else if(headZeros2 > headZeros1) {
}
}
if(equalNumberOfAssertions && this.getFragment1().isAssertCall() && this.getFragment2().isAssertCall() && o.getFragment1().isAssertCall() && o.getFragment2().isAssertCall()) {
if(distance1 < distance2 && thisReplacementTypes.size() < otherReplacementTypes.size()) {
return Double.compare(distance1, distance2);
}
else if(distance1 > distance2 && thisReplacementTypes.size() > otherReplacementTypes.size()) {
return Double.compare(distance1, distance2);
}
int indexDiff1 = Math.abs(this.getFragment1().getIndex() - this.getFragment2().getIndex());
int indexDiff2 = Math.abs(o.getFragment1().getIndex() - o.getFragment2().getIndex());
if(indexDiff1 != indexDiff2) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1288,7 +1288,13 @@ protected static boolean commonConcat(String s1, String s2, Map<String, String>
boolean arrayCreation1 = creationCoveringTheEntireStatement1 != null && creationCoveringTheEntireStatement1.isArray();
boolean arrayCreation2 = creationCoveringTheEntireStatement2 != null && creationCoveringTheEntireStatement2.isArray();
if(!arrayCreation1 && !arrayCreation2 && !containsMethodSignatureOfAnonymousClass(s1) && !containsMethodSignatureOfAnonymousClass(s2)) {
if(s1.contains(JAVA.STRING_CONCATENATION) && s2.contains(JAVA.STRING_CONCATENATION)) {
if(s1.contains(JAVA.STRING_CONCATENATION) && s2.contains(JAVA.STRING_CONCATENATION) && statement1.getTextBlocks().size() == 0 && statement2.getTextBlocks().size() > 0) {
boolean result = stringConcatTextBlock(s1, s2, info, statement1, statement2, container1, container2);
if(result) {
return true;
}
}
else if(s1.contains(JAVA.STRING_CONCATENATION) && s2.contains(JAVA.STRING_CONCATENATION)) {
Set<String> tokens1 = new LinkedHashSet<String>(Arrays.asList(SPLIT_CONCAT_STRING_PATTERN.split(s1)));
Set<String> tokens2 = new LinkedHashSet<String>(Arrays.asList(SPLIT_CONCAT_STRING_PATTERN.split(s2)));
Set<String> intersection = new LinkedHashSet<String>();
Expand Down Expand Up @@ -1371,6 +1377,12 @@ else if(token1.endsWith(")" + JAVA.STATEMENT_TERMINATION) && token2.endsWith(JAV
return true;
}
}
else if(s1.contains(JAVA.STRING_CONCATENATION) && !s2.contains(JAVA.STRING_CONCATENATION) && statement1.getTextBlocks().size() == 0 && statement2.getTextBlocks().size() > 0) {
boolean result = stringConcatTextBlock(s1, s2, info, statement1, statement2, container1, container2);
if(result) {
return true;
}
}
else if(s1.contains(JAVA.STRING_CONCATENATION) && !s2.contains(JAVA.STRING_CONCATENATION) && noCommaS1(s1, statement1, statement2) && s2.contains(",")) {
List<String> tokens1 = Arrays.asList(SPLIT_CONCAT_STRING_PATTERN.split(s1));
List<String> tokens2 = Arrays.asList(SPLIT_COMMA_PATTERN.split(s2));
Expand Down Expand Up @@ -1570,6 +1582,12 @@ else if(s1.contains(",") && s1.contains("(") && s1.contains(")") && !s2.contains
}
}
}
else if(statement1.getStringLiterals().size() > 0 && statement1.getTextBlocks().size() == 0 && statement2.getTextBlocks().size() > 0) {
boolean result = stringConcatTextBlock(s1, s2, info, statement1, statement2, container1, container2);
if(result) {
return true;
}
}
List<String> arguments1 = null;
AbstractCall invocation1 = null;
if(creationCoveringTheEntireStatement1 != null) {
Expand Down Expand Up @@ -1690,6 +1708,57 @@ else if(StringDistance.editDistance(concatenatedString, arg2) < tokens1.size())
return false;
}

private static boolean stringConcatTextBlock(String s1, String s2, ReplacementInfo info,
AbstractCodeFragment statement1, AbstractCodeFragment statement2, VariableDeclarationContainer container1,
VariableDeclarationContainer container2) {
StringBuilder sb = new StringBuilder();
for(LeafExpression leaf1 : statement1.getStringLiterals()) {
String literal = leaf1.getString();
sb.append(literal.substring(1, literal.length()-1));
}
String concatenated = sb.toString().replaceAll("\\s+","").replace("\\\"", "\"");
for(LeafExpression leaf2 : statement2.getTextBlocks()) {
String literal = leaf2.getString();
//remove 3 opening/closing double quotes
String s = literal.substring(3, literal.length()-3);
String lines[] = s.split("\\r?\\n");
Set<String> comments = new LinkedHashSet<String>();
for(String line : lines) {
if(line.contains("%")) {
String comment = line.substring(line.indexOf("%"), line.length());
comments.add(comment);
}
}
for(String comment : comments) {
s = s.replace(comment, "");
}
String formatted = s.replaceAll("\\s+","");
if(formatted.equals(concatenated)) {
IntersectionReplacement r = new IntersectionReplacement(s1, s2, ReplacementType.CONCATENATION);
for(LeafExpression leaf1 : statement1.getStringLiterals()) {
LeafMapping leafMapping = new LeafMapping(leaf1, leaf2, container1, container2);
r.addSubExpressionMapping(leafMapping);
}
info.getReplacements().add(r);
return true;
}
else {
int distance = StringDistance.editDistance(concatenated, formatted);
double normalized = (double)distance/(double)Math.max(concatenated.length(), formatted.length());
if(normalized < 0.1) {
IntersectionReplacement r = new IntersectionReplacement(s1, s2, ReplacementType.CONCATENATION);
for(LeafExpression leaf1 : statement1.getStringLiterals()) {
LeafMapping leafMapping = new LeafMapping(leaf1, leaf2, container1, container2);
r.addSubExpressionMapping(leafMapping);
}
info.getReplacements().add(r);
return true;
}
}
}
return false;
}

private static boolean noCommaS1(String s1, AbstractCodeFragment statement1, AbstractCodeFragment statement2) {
if(!s1.contains(",")) {
return true;
Expand Down
1 change: 1 addition & 0 deletions src/main/java/gr/uom/java/xmi/decomposition/Visitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,7 @@ public boolean visit(ConstructorInvocation node) {
private void processArgument(Expression argument) {
if(argument instanceof SuperMethodInvocation ||
argument instanceof Name ||
argument instanceof TextBlock ||
argument instanceof StringLiteral ||
argument instanceof BooleanLiteral ||
argument instanceof NumberLiteral ||
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/gr/uom/java/xmi/diff/UMLClassBaseDiff.java
Original file line number Diff line number Diff line change
Expand Up @@ -1661,12 +1661,15 @@ private void updateMapperSet(TreeSet<UMLOperationBodyMapper> mapperSet, UMLOpera
List<AbstractCodeMapping> totalMappings = new ArrayList<AbstractCodeMapping>(operationBodyMapper.getMappings());
int mappings = operationBodyMapper.mappingsWithoutBlocks();
if(mappings > 0 || (delegatesToAnotherRemovedOperation(removedOperation) && addedOperation.getBody() != null && addedOperation.stringRepresentation().size() > 3) || (removedOperation.getName().equals(addedOperation.getName()) && removedOperation.getBody() != null && addedOperation.getBody() != null)) {
boolean zeroNonMapped = operationBodyMapper.getNonMappedLeavesT1().size() == 0 && operationBodyMapper.getNonMappedLeavesT2().size() == 0 &&
operationBodyMapper.getNonMappedInnerNodesT1().size() == 0 && operationBodyMapper.getNonMappedInnerNodesT2().size() == 0 &&
removedOperation.hasTestAnnotation() && addedOperation.hasTestAnnotation();
int absoluteDifferenceInPosition = computeAbsoluteDifferenceInPositionWithinClass(removedOperation, addedOperation);
if(exactMappings(operationBodyMapper) || (operationBodyMapper.allMappingsHaveSameDepthAndIndex() && !removedOperation.hasTestAnnotation() && !addedOperation.hasTestAnnotation())) {
mapperSet.add(operationBodyMapper);
}
else if(mappedElementsMoreThanNonMappedT1AndT2(mappings, operationBodyMapper) &&
absoluteDifferenceInPosition <= differenceInPosition &&
(absoluteDifferenceInPosition <= differenceInPosition || zeroNonMapped) &&
compatibleSignatures(removedOperation, addedOperation, absoluteDifferenceInPosition) &&
removedOperation.testMethodCheck(addedOperation)) {
isPartOfMethodMovedFromDeletedMethod(removedOperation, addedOperation, operationBodyMapper);
Expand Down

0 comments on commit 719e8e2

Please sign in to comment.