Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: Test for duplicate imports #3267 and fqn bug #3369

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
import spoon.reflect.reference.CtWildcardReference;
import spoon.reflect.visitor.PrintingContext.Writable;
import spoon.reflect.visitor.printer.CommentOffset;
import spoon.support.util.ModelList;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
Expand Down Expand Up @@ -1083,7 +1084,7 @@ public void visitCtCompilationUnit(CtCompilationUnit compilationUnit) {
break;
case TYPE_DECLARATION:
scan(compilationUnit.getPackageDeclaration());
for (CtImport imprt : compilationUnit.getImports()) {
for (CtImport imprt : getImports(compilationUnit)) {
scan(imprt);
printer.writeln();
}
Expand All @@ -1100,6 +1101,10 @@ public void visitCtCompilationUnit(CtCompilationUnit compilationUnit) {
}
}

protected ModelList<CtImport> getImports(CtCompilationUnit compilationUnit) {
return compilationUnit.getImports();
}

@Override
public void visitCtPackageDeclaration(CtPackageDeclaration packageDeclaration) {
CtPackageReference ctPackage = packageDeclaration.getReference();
Expand Down Expand Up @@ -1615,7 +1620,7 @@ public void visitCtPackage(CtPackage ctPackage) {
if (!ctPackage.isUnnamedPackage()) {
elementPrinterHelper.writePackageLine(ctPackage.getQualifiedName());
}
elementPrinterHelper.writeImports(ctPackage.getPosition().getCompilationUnit().getImports());
elementPrinterHelper.writeImports(getImports(ctPackage.getPosition().getCompilationUnit()));
}

@Override
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/spoon/support/sniper/SniperJavaPrettyPrinter.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,17 @@
import spoon.reflect.cu.position.NoSourcePosition;
import spoon.reflect.declaration.CtCompilationUnit;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtImport;
import spoon.reflect.declaration.CtPackage;
import spoon.reflect.declaration.CtType;
import spoon.reflect.path.CtRole;
import spoon.reflect.reference.CtPackageReference;
import spoon.reflect.visitor.DefaultJavaPrettyPrinter;
import spoon.reflect.visitor.Filter;
import spoon.reflect.visitor.PrettyPrinter;
import spoon.reflect.visitor.TokenWriter;
import spoon.support.Experimental;
import spoon.support.comparator.CtLineElementComparator;
import spoon.support.modelobs.ChangeCollector;
import spoon.support.sniper.internal.ChangeResolver;
import spoon.support.sniper.internal.CollectionSourceFragment;
Expand All @@ -42,6 +47,7 @@
import spoon.support.sniper.internal.TokenPrinterEvent;
import spoon.support.sniper.internal.TokenType;
import spoon.support.sniper.internal.TokenWriterProxy;
import spoon.support.util.ModelList;

/**
* {@link PrettyPrinter} implementation, which copies as much as possible from the origin sources
Expand Down Expand Up @@ -442,4 +448,14 @@ private SourceFragmentPrinter popSourceFragmentContext() {
c.onFinished();
return c;
}

// fix #3267
// in sniper mode, we must visit the order in the same order
// as the source code
protected ModelList<CtImport> getImports(CtCompilationUnit compilationUnit) {
ModelList<CtImport> imports = super.getImports(compilationUnit);
imports.sort(new CtLineElementComparator());
return imports;
}

}
33 changes: 33 additions & 0 deletions src/test/java/spoon/leafactorci/Cases/VariableDeclared.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package spoon.leafactorci.Cases;

import spoon.leafactorci.engine.CaseOfInterest;
import spoon.leafactorci.engine.DetectionPhaseContext;
import spoon.reflect.declaration.CtVariable;


public class VariableDeclared extends CaseOfInterest {
final public CtVariable variable;

private VariableDeclared(CtVariable variable, DetectionPhaseContext context) {
super(context);
this.variable = variable;
}

public static VariableDeclared detect(DetectionPhaseContext context) {
if (context.statement instanceof CtVariable) {
CtVariable variable = (CtVariable) context.statement;
return new VariableDeclared(variable, context);
}
return null;
}

@Override
public String toString() {
return "VariableDeclared{" +
"variable=" + variable +
", index=" + index +
", statementIndex=" + statementIndex +
", statement=" + statement +
'}';
}
}
32 changes: 32 additions & 0 deletions src/test/java/spoon/leafactorci/Cases/VariableReassigned.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package spoon.leafactorci.Cases;

import spoon.leafactorci.engine.CaseOfInterest;
import spoon.leafactorci.engine.DetectionPhaseContext;
import spoon.reflect.code.CtAssignment;

public class VariableReassigned extends CaseOfInterest {
final public CtAssignment assignment;

private VariableReassigned(CtAssignment assignment, DetectionPhaseContext context) {
super(context);
this.assignment = assignment;
}

public static VariableReassigned detect(DetectionPhaseContext context) {
if (context.statement instanceof CtAssignment) {
CtAssignment assignment = (CtAssignment) context.statement;
return new VariableReassigned(assignment, context);
}
return null;
}

@Override
public String toString() {
return "VariableReassigned{" +
"assignment=" + assignment +
", index=" + index +
", statementIndex=" + statementIndex +
", statement=" + statement +
'}';
}
}
48 changes: 48 additions & 0 deletions src/test/java/spoon/leafactorci/Cases/VariableUsed.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package spoon.leafactorci.Cases;

import spoon.leafactorci.engine.CaseOfInterest;
import spoon.leafactorci.engine.DetectionPhaseContext;
import spoon.reflect.code.CtVariableAccess;
import spoon.reflect.code.CtVariableRead;
import spoon.reflect.declaration.CtElement;


import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class VariableUsed extends CaseOfInterest {
final public List<CtVariableAccess> variableAccesses;

private VariableUsed(List<CtVariableAccess> variableAccesses, DetectionPhaseContext context) {
super(context);
this.variableAccesses = variableAccesses;
}

public static VariableUsed detect(DetectionPhaseContext context) {
List<CtVariableAccess> variableAccesses = new ArrayList<>();
Stack<CtElement> stack = new Stack<>();
stack.add(context.statement);
do {
CtElement current = stack.pop();
if (current instanceof CtVariableRead) {
variableAccesses.add((CtVariableAccess) current);
}
stack.addAll(current.getDirectChildren());
} while(!stack.isEmpty());
if(variableAccesses.size() == 0) {
return null;
}
return new VariableUsed(variableAccesses, context);
}

@Override
public String toString() {
return "VariableUsed{" +
"variableAccesses=" + variableAccesses +
", index=" + index +
", statementIndex=" + statementIndex +
", statement=" + statement +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package spoon.leafactorci.DrawAllocationCases;

import spoon.leafactorci.engine.CaseOfInterest;
import spoon.leafactorci.engine.DetectionPhaseContext;
import spoon.reflect.code.*;
import spoon.reflect.declaration.CtVariable;
import spoon.reflect.reference.CtTypeReference;
import spoon.reflect.reference.CtVariableReference;

import java.util.List;

public class ObjectAllocation extends CaseOfInterest {
final public CtVariableReference variable; // The variable that is being assigned
final public CtConstructorCall constructorCall;

private ObjectAllocation(CtVariableReference variable,
CtConstructorCall constructorCall,
DetectionPhaseContext context) {
super(context);
this.variable = variable;
this.constructorCall = constructorCall;
}

public static boolean isClearable(CtTypeReference type) {
return type.getSimpleName().startsWith("Collection") || type.getSimpleName().startsWith("java.util.List")
|| type.getSimpleName().startsWith("List") || type.getSimpleName().startsWith("java.util.List")
|| type.getSimpleName().startsWith("ArrayList") || type.getSimpleName().startsWith("java.util.ArrayList")
|| type.getSimpleName().startsWith("LinkedList") || type.getSimpleName().startsWith("java.util.LinkedList")
|| type.getSimpleName().startsWith("Vector") || type.getSimpleName().startsWith("java.util.Vector")
|| type.getSimpleName().startsWith("Stack") || type.getSimpleName().startsWith("java.util.Stack")
|| type.getSimpleName().startsWith("Set") || type.getSimpleName().startsWith("java.util.Set")
|| type.getSimpleName().startsWith("HashSet") || type.getSimpleName().startsWith("java.util.HashSet")
|| type.getSimpleName().startsWith("LinkedHashSet") || type.getSimpleName().startsWith("java.util.LinkedHashSet")
|| type.getSimpleName().startsWith("SortedSet") || type.getSimpleName().startsWith("java.util.SortedSet")
|| type.getSimpleName().startsWith("NavigableSet") || type.getSimpleName().startsWith("java.util.NavigableSet")
|| type.getSimpleName().startsWith("TreeSet") || type.getSimpleName().startsWith("java.util.TreeSet")
|| type.getSimpleName().startsWith("EnumSet") || type.getSimpleName().startsWith("java.util.EnumSet")
|| type.getSimpleName().startsWith("Queue") || type.getSimpleName().startsWith("java.util.Queue")
|| type.getSimpleName().startsWith("PriorityQueue") || type.getSimpleName().startsWith("java.util.PriorityQueue")
|| type.getSimpleName().startsWith("Deque") || type.getSimpleName().startsWith("java.util.Deque")
|| type.getSimpleName().startsWith("ArrayDeque") || type.getSimpleName().startsWith("java.util.ArrayDeque")
|| type.getSimpleName().startsWith("Map") || type.getSimpleName().startsWith("java.util.Map")
|| type.getSimpleName().startsWith("HashMap") || type.getSimpleName().startsWith("java.util.HashMap")
|| type.getSimpleName().startsWith("SortedMap") || type.getSimpleName().startsWith("java.util.SortedMap")
|| type.getSimpleName().startsWith("NavigableMap") || type.getSimpleName().startsWith("java.util.NavigableMap")
|| type.getSimpleName().startsWith("TreeMap") || type.getSimpleName().startsWith("java.util.TreeMap");
}

public static ObjectAllocation detect(DetectionPhaseContext context) {
CtExpression assignmentExpression;
CtVariableReference variableReference;
if(context.statement instanceof CtVariable) {
assignmentExpression = ((CtVariable)context.statement).getDefaultExpression();
variableReference = ((CtVariable)context.statement).getReference();
} else if (context.statement instanceof CtAssignment) {
CtAssignment assignment = (CtAssignment)context.statement;
assignmentExpression = assignment.getAssignment();
CtExpression assignedExpression = assignment.getAssigned();
if(!(assignedExpression instanceof CtVariableWrite)) {
return null;
}
variableReference = ((CtVariableWrite) assignedExpression).getVariable();
} else {
return null;
}

CtConstructorCall constructorCall;
if(assignmentExpression instanceof CtConstructorCall) {
constructorCall = (CtConstructorCall) assignmentExpression;
} else {
return null;
}

// Remove allocation that depend on other variables
List<CtExpression<?>> expressionList = constructorCall.getArguments();
for(CtExpression expression : expressionList) {
if(expression instanceof CtVariableRead) {
return null;
}
}

return new ObjectAllocation(variableReference, constructorCall, context);
}

@Override
public String toString() {
return "ObjectAllocation{" +
"variable=" + variable +
", index=" + index +
", statementIndex=" + statementIndex +
", statement=" + statement +
'}';
}
}
83 changes: 83 additions & 0 deletions src/test/java/spoon/leafactorci/RecycleCases/VariableLost.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package spoon.leafactorci.RecycleCases;

import spoon.leafactorci.engine.CaseOfInterest;
import spoon.leafactorci.engine.DetectionPhaseContext;
import spoon.leafactorci.engine.RefactoringRule;
import spoon.reflect.code.*;
import spoon.reflect.declaration.CtElement;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Stack;

public class VariableLost extends CaseOfInterest {
final public List<CtVariableAccess> variableAccesses;

private VariableLost(List<CtVariableAccess> variableAccesses, DetectionPhaseContext context) {
super(context);
this.variableAccesses = variableAccesses;
}

private static boolean isInsideLambda(CtElement current, DetectionPhaseContext context) {
CtLambda result = RefactoringRule.getClosestTypeParent(current, CtLambda.class, Arrays.asList(new CtElement[] {context.block}));
return result != null;
}

private static boolean isInsideReturn(CtElement current, DetectionPhaseContext context) {
CtReturn result = RefactoringRule.getClosestTypeParent(current, CtReturn.class, Arrays.asList(new CtElement[] {context.block}));
return result != null && result.getReturnedExpression() == current;
}

private static boolean isInsideInvocation(CtElement current, DetectionPhaseContext context) {
CtInvocation result = RefactoringRule.getClosestTypeParent(current, CtInvocation.class, Arrays.asList(new CtElement[] {context.block}));
return result != null && result.getArguments().contains(current);
}

private static boolean isInsideBlock(CtElement current, DetectionPhaseContext context) {
CtBlock result = RefactoringRule.getClosestTypeParent(current, CtBlock.class, Arrays.asList(new CtElement[] {context.block}));
return result != null;
}

public static VariableLost detect(DetectionPhaseContext context) {
List<CtVariableAccess> variableAccesses = new ArrayList<>();
Stack<CtElement> stack = new Stack<>();
stack.add(context.statement);
do {
CtElement current = stack.pop();
if (current instanceof CtVariableRead) {
boolean wasLost = isInsideLambda(current, context)
|| isInsideReturn(current, context)
|| isInsideInvocation(current, context);

if(current.getParent() instanceof CtLocalVariable
&& ((CtLocalVariable) current.getParent()).getDefaultExpression() == current) {
wasLost = true;
}

if(wasLost) {
variableAccesses.add((CtVariableAccess) current);
}
}
if (current instanceof CtVariableWrite && current.getParent() instanceof CtAssignment
&& isInsideBlock(current, context)) {
variableAccesses.add((CtVariableAccess) current);
}
stack.addAll(current.getDirectChildren());
} while(!stack.isEmpty());
if(variableAccesses.size() == 0) {
return null;
}
return new VariableLost(variableAccesses, context);
}

@Override
public String toString() {
return "VariableLost{" +
"variableAccesses=" + variableAccesses +
", index=" + index +
", statementIndex=" + statementIndex +
", statement=" + statement +
'}';
}
}
Loading