Skip to content

Commit

Permalink
Refactoring folding (#81)
Browse files Browse the repository at this point in the history
* Implement basic refactorings' folding

* Add a nice hint with refactoring description

* Extract commit id from diff request

* Process only Move Method refactorings

* Checkstyle fix

* Extract to abstract

* Implement some

* Fix checkstyle

* Make class not abstract

* Check type in findMethod

* Add isChanged to RefactoringInfo

* Add changes detection to MoveOperationHandler

* Fix tests for RefactoringInfo

* Remove name from refactoring info (#74)

* Remove name from RefactoringInfo

* Do some small fixes

* Remove unused properties

* Return regex matching to correctLines

* Mine at git table commit selection (#75)

* Set buildSeachableOptions.enabled false in build.gradle

* Release 2021.1

* Update intellij version to 0.7.2

* Mine at git table commit selection

* Add comment

Co-authored-by: Zarina Kurbatova <zarina.kurbatova@gmail.com>

* Add new changes detection in Pull Up and Push Down refactorings

* Refactoring folding. Prototype of new architecture (#76)

* Move folding to new package and classes

* Prototype folding architecture

* Fix tests for RefactoringInfo

* Move Finder to PsiUtils

* Implement findClass with FindElementProcessor

* Rename MoveOperationHandler to MoveOperationFoldingHandler

* Add new FoldingHandlers

* Fix hint for extract and inline refactorings

* Implement hints grouping

* Simplify findClassJava

* Remove redundant comment

* Simplify findMethodJava

* Reorder methods in PsiUtils

* Remove blank lines between imports

* Add javadocs

* Fix NPE in deleted files

* Fix move operation hint text

* Fix move operation hint text

* Fix checkstyle

* Implement new version of positions detection

* Small optimizations for info serializing

* Remove unused folding positions

* Add new supported refactoring

* Add javadocs

* Style fixes

* Update serialization tests

* Add filename to Extract/Inline and move refactorings

Co-authored-by: Zarina Kurbatova <zarina.kurbatova@gmail.com>

* Remove 'with renaming'

* Fix Nullability in RefactoringFolder

* Fix path in move hint text

* If moving managed in single file trying to display qualified names without packages

* List refactoring destinations separated by commas

* Add () to method names

* Style fixes

* Fix and extract functionSimpleName

* Removed duplicate paths in extract and inline hints

* Minor refactoring

* Fix typos

* Fix descriptor setters/getters names

* Make FoldingBuilder constructor private

* Encapsulate invariant that hint text is not null

* Add hint text caching

* Remove incorrect folds from pull requests

* Minor refactoring

Co-authored-by: Zarina Kurbatova <zarina.kurbatova@gmail.com>
  • Loading branch information
e2e4b6b7 and onewhl authored May 28, 2021
1 parent f5d33fe commit f23177b
Show file tree
Hide file tree
Showing 21 changed files with 887 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,17 @@ public enum RefactoringType {
MODIFY_PARAMETER_ANNOTATION("Modify Parameter Annotation", new ModifyParameterAnnotationHandler()),
ADD_PARAMETER("Add Parameter", new AddParameterHandler()),
REMOVE_PARAMETER("Remove Parameter", new RemoveParameterHandler()),
REORDER_PARAMETER("Reorder Parameter", new ReorderParameterHandler());
REORDER_PARAMETER("Reorder Parameter", new ReorderParameterHandler()),
RENAME_AND_CHANGE_ATTRIBUTE_TYPE("Rename and Change Attribute Type", null),
RENAME_AND_CHANGE_PARAMETER_TYPE("Rename and Change Parameter Type", null),
RENAME_AND_CHANGE_VARIABLE_TYPE("Rename and Change Variable Type", null);

String name;
Handler handler;

// Caching
public static final RefactoringType[] values = RefactoringType.values();

RefactoringType(String name, Handler handler) {
this.name = name;
this.handler = handler;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@ public enum Group {
VARIABLE,
INTERFACE,
ABSTRACT,
PACKAGE
PACKAGE;

public static final Group[] values = Group.values();
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.jetbrains.research.refactorinsight.data.diff.MoreSidedDiffRequestGenerator;
import org.jetbrains.research.refactorinsight.data.diff.ThreeSidedDiffRequestGenerator;
import org.jetbrains.research.refactorinsight.data.diff.TwoSidedDiffRequestGenerator;
import org.jetbrains.research.refactorinsight.folding.FoldingDescriptor;
import org.jetbrains.research.refactorinsight.utils.StringUtils;

/**
Expand All @@ -38,15 +39,16 @@ public class RefactoringInfo {

private transient RefactoringEntry entry;
private transient String groupId;
private transient RefactoringType type;
private transient List<Pair<String, Boolean>> moreSidedLeftPaths = new ArrayList<>();

private DiffRequestGenerator requestGenerator = new TwoSidedDiffRequestGenerator();
private String name;

private final String[][] uiStrings = new String[3][2];
private final String[] paths = new String[3];
// Optional data for foldable refactorings
private final FoldingDescriptor[] foldingPositions = new FoldingDescriptor[3];

private RefactoringType type;
private Group group;

private Set<String> includes = new HashSet<>();
Expand All @@ -55,6 +57,9 @@ public class RefactoringInfo {
private boolean threeSided = false;
private boolean moreSided = false;

// Optional data for move refactorings
private boolean changed = true;

/**
* Deserializes an {@link RefactoringInfo} instance from string.
*
Expand All @@ -63,9 +68,9 @@ public class RefactoringInfo {
*/
public static RefactoringInfo fromString(String value) {
String regex = delimiter(INFO, true);
String[] tokens = value.split(regex, 16);
String[] tokens = value.split(regex, 20);
RefactoringInfo info = new RefactoringInfo()
.setName(tokens[0])
.setType(RefactoringType.values[Integer.parseInt(tokens[0])])
.setNameBefore(StringUtils.deSanitize(tokens[1]))
.setNameAfter(StringUtils.deSanitize(tokens[2]))
.setElementBefore(StringUtils.deSanitize(tokens[3]))
Expand All @@ -75,20 +80,24 @@ public static RefactoringInfo fromString(String value) {
.setLeftPath(StringUtils.deSanitize(tokens[7]))
.setMidPath(StringUtils.deSanitize(tokens[8]))
.setRightPath(StringUtils.deSanitize(tokens[9]))
.setGroup(Group.valueOf(tokens[10]))
.setGroup(Group.values[Integer.parseInt(tokens[10])])
.setThreeSided(tokens[11].equals("t"))
.setHidden(tokens[12].equals("t"))
.setMoreSided(tokens[13].equals("t"))
.setChanged(tokens[14].equals("t"))
.setFoldingDescriptorBefore(FoldingDescriptor.fromString(tokens[16]))
.setFoldingDescriptorMid(FoldingDescriptor.fromString(tokens[17]))
.setFoldingDescriptorAfter(FoldingDescriptor.fromString(tokens[18]))
.setIncludes(new HashSet<>(
tokens[15].isEmpty() ? List.of() : Arrays.asList(tokens[15].split(regex))));
tokens[19].isEmpty() ? List.of() : Arrays.asList(tokens[19].split(regex))));

DiffRequestGenerator diffGenerator;
if (info.isMoreSided()) {
diffGenerator = MoreSidedDiffRequestGenerator.fromString(tokens[14]);
diffGenerator = MoreSidedDiffRequestGenerator.fromString(tokens[15]);
} else if (info.isThreeSided()) {
diffGenerator = ThreeSidedDiffRequestGenerator.fromString(tokens[14]);
diffGenerator = ThreeSidedDiffRequestGenerator.fromString(tokens[15]);
} else {
diffGenerator = TwoSidedDiffRequestGenerator.fromString(tokens[14]);
diffGenerator = TwoSidedDiffRequestGenerator.fromString(tokens[15]);
}

return info.setRequestGenerator(diffGenerator);
Expand All @@ -105,18 +114,22 @@ public SimpleDiffRequest generate(DiffContent[] contents) {
*/
public String toString() {
return String.join(delimiter(INFO),
name,
String.valueOf(type.ordinal()),
Stream.concat(
Arrays.stream(uiStrings).flatMap(Arrays::stream),
Arrays.stream(paths))
.map(s -> s == null ? "" : s)
.map(StringUtils::sanitize)
.collect(Collectors.joining(delimiter(INFO))),
group.toString(),
threeSided ? "t" : "f",
hidden ? "t" : "f",
moreSided ? "t" : "f",
String.valueOf(group.ordinal()),
threeSided ? "t" : "",
hidden ? "t" : "",
moreSided ? "t" : "",
changed ? "t" : "",
requestGenerator.toString(),
Arrays.stream(foldingPositions)
.map(fp -> fp == null ? "" : fp.toString())
.collect(Collectors.joining(delimiter(INFO))),
String.join(delimiter(INFO), includes)
);
}
Expand Down Expand Up @@ -157,10 +170,11 @@ public void addToHistory(Map<String, Set<RefactoringInfo>> map) {
((MoreSidedDiffRequestGenerator) requestGenerator).getClassNames()
.forEach(name -> {
Set<RefactoringInfo> infos = map.getOrDefault(name, new HashSet<>());
RefactoringInfo info = new RefactoringInfo().setGroup(group)
RefactoringInfo info = new RefactoringInfo()
.setGroup(group)
.setNameBefore(getNameBefore())
.setNameAfter(getNameAfter())
.setName(getName())
.setType(type)
.setIncludes(includes)
.setHidden(hidden)
.setRequestGenerator(requestGenerator)
Expand Down Expand Up @@ -362,12 +376,7 @@ public RefactoringInfo setType(RefactoringType type) {
}

public String getName() {
return name;
}

public RefactoringInfo setName(String name) {
this.name = name;
return this;
return type.getName();
}

public boolean isHidden() {
Expand Down Expand Up @@ -484,7 +493,6 @@ public boolean equals(Object o) {
&& Objects.equals(this.getDetailsAfter(), that.getDetailsAfter())
&& Objects.equals(this.getDetailsBefore(), that.getDetailsBefore())
&& Objects.equals(this.getElementBefore(), that.getElementBefore())
&& this.name.equals(that.getName())
&& this.type == that.getType()
&& this.group == that.getGroup();
}
Expand All @@ -508,11 +516,11 @@ public RefactoringInfo setGroup(Group group) {
public void correctLines(String before, String mid, String after) {
boolean skipAnnotationsLeft = true;
boolean skipAnnotationsRight = true;
if (name.matches("Add\\s(\\w)*\\sAnnotation")) {
if (type.getName().matches("Add\\s(\\w)*\\sAnnotation")) {
skipAnnotationsRight = false;
} else if (name.matches("Remove\\s(\\w)*\\sAnnotation")) {
} else if (type.getName().matches("Remove\\s(\\w)*\\sAnnotation")) {
skipAnnotationsLeft = false;
} else if (name.matches("Modify\\s(\\w)*\\sAnnotation")) {
} else if (type.getName().matches("Modify\\s(\\w)*\\sAnnotation")) {
skipAnnotationsLeft = skipAnnotationsRight = false;
}
requestGenerator.correct(before, mid, after, skipAnnotationsLeft, true, skipAnnotationsRight);
Expand All @@ -523,5 +531,40 @@ public void correctMoreSidedLines(List<String> befores, String after) {
true, false, true);
}

public boolean isChanged() {
return changed;
}

public RefactoringInfo setChanged(boolean changed) {
this.changed = changed;
return this;
}

public FoldingDescriptor getFoldingDescriptorBefore() {
return foldingPositions[0];
}

public RefactoringInfo setFoldingDescriptorBefore(FoldingDescriptor positions) {
foldingPositions[0] = positions;
return this;
}

public FoldingDescriptor getFoldingDescriptorMid() {
return foldingPositions[1];
}

public RefactoringInfo setFoldingDescriptorMid(FoldingDescriptor positions) {
foldingPositions[1] = positions;
return this;
}

public FoldingDescriptor getFoldingDescriptorAfter() {
return foldingPositions[2];
}

public RefactoringInfo setFoldingDescriptorAfter(FoldingDescriptor positions) {
foldingPositions[2] = positions;
return this;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ public abstract class Handler {
public RefactoringInfo handle(Refactoring refactoring, RefactoringEntry entry) {
RefactoringInfo info = new RefactoringInfo()
.setType(RefactoringType.valueOf(refactoring.getRefactoringType().name()))
.setName(refactoring.getName())
.setEntry(entry);
return specify(refactoring, info);
}
Expand All @@ -36,7 +35,6 @@ public RefactoringInfo handle(org.jetbrains.research.kotlinrminer.api.Refactorin
RefactoringEntry entry) {
RefactoringInfo info = new RefactoringInfo()
.setType(RefactoringType.valueOf(refactoring.getRefactoringType().name()))
.setName(refactoring.getName())
.setEntry(entry);
return specify(refactoring, info);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.jetbrains.research.refactorinsight.data.RefactoringInfo;
import org.jetbrains.research.refactorinsight.data.RefactoringLine;
import org.jetbrains.research.refactorinsight.data.types.Handler;
import org.jetbrains.research.refactorinsight.folding.FoldingBuilder;
import org.jetbrains.research.refactorinsight.utils.StringUtils;
import org.refactoringminer.api.Refactoring;
import org.refactoringminer.api.RefactoringType;
Expand All @@ -20,6 +21,8 @@ public class ExtractOperationHandler extends Handler {
public RefactoringInfo specify(Refactoring refactoring, RefactoringInfo info) {
ExtractOperationRefactoring ref = (ExtractOperationRefactoring) refactoring;

info.setFoldingDescriptorMid(FoldingBuilder.fromMethod(ref.getExtractedOperation()));

String classNameBefore = ref.getSourceOperationBeforeExtraction().getClassName();
String classNameAfter = ref.getExtractedOperation().getClassName();
List<String> parameterTypeList = new ArrayList<>();
Expand Down Expand Up @@ -94,12 +97,15 @@ public RefactoringInfo specify(org.jetbrains.research.kotlinrminer.api.Refactori
org.jetbrains.research.kotlinrminer.diff.refactoring.ExtractOperationRefactoring ref =
(org.jetbrains.research.kotlinrminer.diff.refactoring.ExtractOperationRefactoring) refactoring;

info.setFoldingDescriptorMid(FoldingBuilder.fromMethod(ref.getExtractedOperation()));

String classNameBefore = ref.getSourceOperationBeforeExtraction().getClassName();
String classNameAfter = ref.getExtractedOperation().getClassName();
List<String> parameterTypeList = new ArrayList<>();
for (UMLType type : ref.getExtractedOperation().getParameterTypeList()) {
parameterTypeList.add(type.toString());
}

String extractedMethod = StringUtils
.calculateSignatureWithoutClassName(ref.getExtractedOperation().getName(), parameterTypeList);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.jetbrains.research.refactorinsight.data.RefactoringInfo;
import org.jetbrains.research.refactorinsight.data.RefactoringLine;
import org.jetbrains.research.refactorinsight.data.types.Handler;
import org.jetbrains.research.refactorinsight.folding.FoldingBuilder;
import org.jetbrains.research.refactorinsight.utils.StringUtils;
import org.refactoringminer.api.Refactoring;

Expand All @@ -15,6 +16,8 @@ public class InlineOperationHandler extends Handler {
public RefactoringInfo specify(Refactoring refactoring, RefactoringInfo info) {
InlineOperationRefactoring ref = (InlineOperationRefactoring) refactoring;

info.setFoldingDescriptorMid(FoldingBuilder.fromMethod(ref.getInlinedOperation()));

ref.getInlinedOperationInvocations().forEach(c ->
info.addMarking(new CodeRange(c.codeRange()), new CodeRange(ref.getInlinedCodeRangeInTargetOperation()), true));
String classNameBefore = ref.getTargetOperationBeforeInline().getClassName();
Expand Down Expand Up @@ -47,6 +50,8 @@ public RefactoringInfo specify(org.jetbrains.research.kotlinrminer.api.Refactori
org.jetbrains.research.kotlinrminer.diff.refactoring.InlineOperationRefactoring ref =
(org.jetbrains.research.kotlinrminer.diff.refactoring.InlineOperationRefactoring) refactoring;

info.setFoldingDescriptorMid(FoldingBuilder.fromMethod(ref.getInlinedOperation()));

ref.getInlinedOperationInvocations().forEach(c ->
info.addMarking(new CodeRange(c.codeRange()), new CodeRange(ref.getInlinedCodeRangeInTargetOperation()), true));
String classNameBefore = ref.getTargetOperationBeforeInline().getClassName();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,37 @@
package org.jetbrains.research.refactorinsight.data.types.methods;

import gr.uom.java.xmi.decomposition.AbstractStatement;
import gr.uom.java.xmi.diff.MoveOperationRefactoring;
import org.jetbrains.research.refactorinsight.adapters.CodeRange;
import org.jetbrains.research.refactorinsight.adapters.RefactoringType;
import org.jetbrains.research.refactorinsight.data.Group;
import org.jetbrains.research.refactorinsight.data.RefactoringInfo;
import org.jetbrains.research.refactorinsight.data.RefactoringLine;
import org.jetbrains.research.refactorinsight.data.types.Handler;
import org.jetbrains.research.refactorinsight.folding.FoldingBuilder;
import org.jetbrains.research.refactorinsight.utils.StringUtils;
import org.jetbrains.research.refactorinsight.utils.Utils;
import org.refactoringminer.api.Refactoring;

import java.util.List;

public class MoveOperationHandler extends Handler {

@Override
public RefactoringInfo specify(Refactoring refactoring, RefactoringInfo info) {
final MoveOperationRefactoring ref = (MoveOperationRefactoring) refactoring;

info.setFoldingDescriptorBefore(FoldingBuilder.fromMethod(ref.getOriginalOperation()));
info.setFoldingDescriptorAfter(FoldingBuilder.fromMethod(ref.getMovedOperation()));

if (info.getType() != RefactoringType.MOVE_AND_RENAME_OPERATION) {
List<AbstractStatement> statementsBefore =
ref.getOriginalOperation().getBody().getCompositeStatement().getStatements();
List<AbstractStatement> statementsAfter =
ref.getMovedOperation().getBody().getCompositeStatement().getStatements();
info.setChanged(!Utils.isStatementsEqualJava(statementsBefore, statementsAfter));
}

String classBefore = ref.getOriginalOperation().getClassName();
String classAfter = ref.getMovedOperation().getClassName();

Expand All @@ -41,6 +58,17 @@ public RefactoringInfo specify(org.jetbrains.research.kotlinrminer.api.Refactori
final org.jetbrains.research.kotlinrminer.diff.refactoring.MoveOperationRefactoring ref =
(org.jetbrains.research.kotlinrminer.diff.refactoring.MoveOperationRefactoring) refactoring;

info.setFoldingDescriptorBefore(FoldingBuilder.fromMethod(ref.getOriginalOperation()));
info.setFoldingDescriptorAfter(FoldingBuilder.fromMethod(ref.getMovedOperation()));

if (info.getType() != RefactoringType.MOVE_AND_RENAME_OPERATION) {
List<org.jetbrains.research.kotlinrminer.decomposition.AbstractStatement> statementsBefore =
ref.getOriginalOperation().getBody().getCompositeStatement().getStatements();
List<org.jetbrains.research.kotlinrminer.decomposition.AbstractStatement> statementsAfter =
ref.getMovedOperation().getBody().getCompositeStatement().getStatements();
info.setChanged(!Utils.isStatementsEqualKotlin(statementsBefore, statementsAfter));
}

String classBefore = ref.getOriginalOperation().getClassName();
String classAfter = ref.getMovedOperation().getClassName();

Expand Down
Loading

0 comments on commit f23177b

Please sign in to comment.