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

refactoring equals #674

Merged
merged 4 commits into from
May 30, 2016
Merged
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
124 changes: 124 additions & 0 deletions src/main/java/spoon/generating/CtBiScannerGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/**
* Copyright (C) 2006-2015 INRIA and contributors
* Spoon - http://spoon.gforge.inria.fr/
*
* This software is governed by the CeCILL-C License under French law and
* abiding by the rules of distribution of free software. You can use, modify
* and/or redistribute the software under the terms of the CeCILL-C license as
* circulated by CEA, CNRS and INRIA at http://www.cecill.info.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package spoon.generating;

import spoon.processing.AbstractProcessor;
import spoon.reflect.code.CtExpression;
import spoon.reflect.code.CtInvocation;
import spoon.reflect.code.CtLocalVariable;
import spoon.reflect.code.CtVariableAccess;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.CtPackage;
import spoon.reflect.declaration.CtType;
import spoon.reflect.declaration.ModifierKind;
import spoon.reflect.factory.Factory;
import spoon.reflect.reference.CtTypeReference;
import spoon.reflect.visitor.CtScanner;
import spoon.reflect.visitor.ReferenceFilter;

import java.util.List;

public class CtBiScannerGenerator extends AbstractProcessor<CtType<?>> {
private static final String TARGET_BISCANNER_PACKAGE = "spoon.reflect.visitor";
private static final String GENERATING_BISCANNER_PACKAGE = "spoon.generating.scanner";
private static final String GENERATING_BISCANNER = GENERATING_BISCANNER_PACKAGE + ".CtBiScannerTemplate";

@Override
public boolean isToBeProcessed(CtType<?> candidate) {
return CtScanner.class.getName().equals(candidate.getQualifiedName()) && super.isToBeProcessed(candidate);
}

@Override
public void process(CtType<?> element) {
final CtLocalVariable<?> peekElement = getFactory().Class()
.get(GENERATING_BISCANNER_PACKAGE + ".PeekElementTemplate")
.getMethod("statement")
.getBody().getStatement(0);
final CtClass<Object> target = createBiScanner();

new CtScanner() {
@Override
public <T> void visitCtMethod(CtMethod<T> element) {
if (!element.getSimpleName().startsWith("visitCt")) {
return;
}

Factory factory = element.getFactory();
CtMethod<T> clone = factory.Core().clone(element);

// Peek element from Stack.
final CtLocalVariable<?> peek = factory.Core().clone(peekElement);
final CtTypeReference type = factory.Core().clone(clone.getParameters().get(0).getType());
type.getActualTypeArguments().clear();
peek.getDefaultExpression().addTypeCast(type);
peek.setType(type);
clone.getBody().insertBegin(peek);

for (int i = 2; i < clone.getBody().getStatements().size() - 1; i++) {
final CtInvocation targetInvocation = (CtInvocation) ((CtInvocation) clone.getBody().getStatement(i)).getArguments().get(0);
if ("getValue".equals(targetInvocation.getExecutable().getSimpleName()) && "CtLiteral".equals(targetInvocation.getExecutable().getDeclaringType().getSimpleName())) {
clone.getBody().getStatement(i--).delete();
continue;
}
CtInvocation replace = (CtInvocation) factory.Core().clone(clone.getBody().getStatement(i));

// Changes to biScan method.
replace.getExecutable().setSimpleName("biScan");

// Creates other inv.
final CtVariableAccess<?> otherRead = factory.Code().createVariableRead(peek.getReference(), false);
replace.addArgument(factory.Code().createInvocation(otherRead, ((CtInvocation) replace.getArguments().get(0)).getExecutable()));

if ("Map".equals(targetInvocation.getExecutable().getType().getSimpleName())) {
((CtExpression) replace.getArguments().get(0)).replace(factory.Code().createInvocation(targetInvocation, factory.Executable().createReference("List Map#values()")));
replace.getArguments().add(1, factory.Code().createInvocation((CtExpression) replace.getArguments().get(1), factory.Executable().createReference("List Map#values()")));
replace.getArguments().remove(2);
}

clone.getBody().getStatement(i).replace(replace);
}

target.addMethod(clone);
}
}.scan(getFactory().Class().get(CtScanner.class));
}

private CtClass<Object> createBiScanner() {
final CtPackage aPackage = getFactory().Package().getOrCreate(TARGET_BISCANNER_PACKAGE);
final CtClass<Object> target = getFactory().Class().get(GENERATING_BISCANNER);
target.setSimpleName("CtBiScannerDefault");
target.addModifier(ModifierKind.PUBLIC);
aPackage.addType(target);
final List<CtTypeReference> references = target.getReferences(new ReferenceFilter<CtTypeReference>() {
@Override
public boolean matches(CtTypeReference reference) {
return reference != null && GENERATING_BISCANNER.equals(reference.getQualifiedName());
}

@Override
public Class<CtTypeReference> getType() {
return CtTypeReference.class;
}
});
for (CtTypeReference reference : references) {
reference.setSimpleName("CtBiScannerDefault");
reference.setPackage(aPackage.getReference());
}
return target;
}
}
96 changes: 96 additions & 0 deletions src/main/java/spoon/generating/EqualsVisitorGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/**
* Copyright (C) 2006-2015 INRIA and contributors
* Spoon - http://spoon.gforge.inria.fr/
*
* This software is governed by the CeCILL-C License under French law and
* abiding by the rules of distribution of free software. You can use, modify
* and/or redistribute the software under the terms of the CeCILL-C license as
* circulated by CEA, CNRS and INRIA at http://www.cecill.info.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package spoon.generating;

import spoon.processing.AbstractManualProcessor;
import spoon.reflect.code.CtInvocation;
import spoon.reflect.declaration.CtAnnotation;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.CtPackage;
import spoon.reflect.declaration.ModifierKind;
import spoon.reflect.factory.Factory;
import spoon.reflect.reference.CtTypeReference;
import spoon.reflect.visitor.CtAbstractBiScanner;
import spoon.reflect.visitor.CtBiScannerDefault;
import spoon.reflect.visitor.CtScanner;
import spoon.reflect.visitor.ReferenceFilter;
import spoon.support.visitor.equals.IgnoredByEquals;

import java.util.List;

public class EqualsVisitorGenerator extends AbstractManualProcessor {
private static final String TARGET_EQUALS_PACKAGE = "spoon.support.visitor.equals";
private static final String GENERATING_EQUALS_PACKAGE = "spoon.generating.equals";
private static final String GENERATING_EQUALS = GENERATING_EQUALS_PACKAGE + ".EqualsVisitorTemplate";

@Override
public void process() {
final CtClass<Object> target = createEqualsVisitor();
new CtScanner() {
@Override
public <T> void visitCtMethod(CtMethod<T> element) {
if (!element.getSimpleName().startsWith("visitCt")) {
return;
}

Factory factory = element.getFactory();
CtMethod<T> clone = factory.Core().clone(element);

final CtAnnotation<?> ignoredAnnotation = factory.Core().createAnnotation();
ignoredAnnotation.setAnnotationType(factory.Type().createReference(IgnoredByEquals.class));

for (int i = 2; i < clone.getBody().getStatements().size() - 1; i++) {
final CtInvocation targetInvocation = (CtInvocation) ((CtInvocation) clone.getBody().getStatement(i)).getArguments().get(0);
if (targetInvocation.getExecutable().getExecutableDeclaration().getAnnotations().contains(ignoredAnnotation)) {
clone.getBody().getStatement(i--).delete();
continue;
}
CtInvocation replace = (CtInvocation) factory.Core().clone(clone.getBody().getStatement(i));
clone.getBody().getStatement(i).replace(replace);
}

target.addMethod(clone);
}
}.scan(getFactory().Class().get(CtBiScannerDefault.class));
}

private CtClass<Object> createEqualsVisitor() {
final CtPackage aPackage = getFactory().Package().getOrCreate(TARGET_EQUALS_PACKAGE);
final CtClass<Object> target = getFactory().Class().get(GENERATING_EQUALS);
target.setSimpleName("EqualsVisitor");
target.addModifier(ModifierKind.PUBLIC);
target.setSuperclass(getFactory().Type().createReference(CtAbstractBiScanner.class));
aPackage.addType(target);
final List<CtTypeReference> references = target.getReferences(new ReferenceFilter<CtTypeReference>() {
@Override
public boolean matches(CtTypeReference reference) {
return reference != null && GENERATING_EQUALS.equals(reference.getQualifiedName());
}

@Override
public Class<CtTypeReference> getType() {
return CtTypeReference.class;
}
});
for (CtTypeReference reference : references) {
reference.setSimpleName("EqualsVisitor");
reference.setPackage(aPackage.getReference());
}
return target;
}
}
44 changes: 44 additions & 0 deletions src/main/java/spoon/generating/equals/EqualsVisitorTemplate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* Copyright (C) 2006-2015 INRIA and contributors
* Spoon - http://spoon.gforge.inria.fr/
*
* This software is governed by the CeCILL-C License under French law and
* abiding by the rules of distribution of free software. You can use, modify
* and/or redistribute the software under the terms of the CeCILL-C license as
* circulated by CEA, CNRS and INRIA at http://www.cecill.info.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package spoon.generating.equals;

import spoon.reflect.declaration.CtElement;
import spoon.reflect.visitor.CtBiScannerDefault;
import spoon.support.visitor.equals.EqualsChecker;

/**
* Used to check equality between an element and another one.
*
* This class is generated automatically by the processor {@link spoon.generating.EqualsVisitorGenerator}.
*/
class EqualsVisitorTemplate extends CtBiScannerDefault {
public static boolean equals(CtElement element, CtElement other) {
return !new EqualsVisitorTemplate().biScan(element, other);
}

private final EqualsChecker checker = new EqualsChecker();

@Override
protected void enter(CtElement e) {
super.enter(e);
checker.setOther(stack.peek());
checker.scan(e);
if (checker.isNotEqual()) {
fail();
}
}
}
32 changes: 32 additions & 0 deletions src/main/java/spoon/generating/scanner/CtBiScannerTemplate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Copyright (C) 2006-2015 INRIA and contributors
* Spoon - http://spoon.gforge.inria.fr/
*
* This software is governed by the CeCILL-C License under French law and
* abiding by the rules of distribution of free software. You can use, modify
* and/or redistribute the software under the terms of the CeCILL-C license as
* circulated by CEA, CNRS and INRIA at http://www.cecill.info.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package spoon.generating.scanner;

import spoon.reflect.visitor.CtAbstractBiScanner;

/**
* This visitor implements a deep-search scan on the model for 2 elements.
*
* Ensures that all children nodes are visited once, a visit means three method
* calls, one call to "enter", one call to "exit" and one call to biScan.
*
* This class is generated automatically by the processor {@link spoon.generating.CtBiScannerGenerator}.
*
* Is used by EqualsVisitor.
*/
abstract class CtBiScannerTemplate extends CtAbstractBiScanner {
}
28 changes: 28 additions & 0 deletions src/main/java/spoon/generating/scanner/PeekElementTemplate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Copyright (C) 2006-2015 INRIA and contributors
* Spoon - http://spoon.gforge.inria.fr/
*
* This software is governed by the CeCILL-C License under French law and
* abiding by the rules of distribution of free software. You can use, modify
* and/or redistribute the software under the terms of the CeCILL-C license as
* circulated by CEA, CNRS and INRIA at http://www.cecill.info.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package spoon.generating.scanner;

import spoon.reflect.declaration.CtElement;

import java.util.Stack;

class PeekElementTemplate {
Stack<CtElement> stack;
public void statement() {
CtElement other = stack.peek();
}
}
2 changes: 2 additions & 0 deletions src/main/java/spoon/reflect/declaration/CtElement.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import spoon.reflect.visitor.Filter;
import spoon.reflect.visitor.ReferenceFilter;
import spoon.reflect.visitor.Root;
import spoon.support.visitor.equals.IgnoredByEquals;

import java.lang.annotation.Annotation;
import java.util.List;
Expand Down Expand Up @@ -266,6 +267,7 @@ <E extends CtElement> List<E> getAnnotatedChildren(
* The list of comments
* @return the list of comment
*/
@IgnoredByEquals
List<CtComment> getComments();

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
*/
package spoon.reflect.reference;

import spoon.support.visitor.equals.IgnoredByEquals;

import java.util.List;

/**
Expand All @@ -25,6 +27,7 @@ public interface CtActualTypeContainer {
/**
* Gets the type arguments.
*/
@IgnoredByEquals
List<CtTypeReference<?>> getActualTypeArguments();

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package spoon.reflect.reference;

import spoon.reflect.declaration.CtExecutable;
import spoon.support.visitor.equals.IgnoredByEquals;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
Expand Down Expand Up @@ -75,6 +76,7 @@ public interface CtExecutableReference<T> extends CtReference, CtGenericElementR
/**
* Gets the return type of the executable (may be null in noclasspath mode).
*/
@IgnoredByEquals
CtTypeReference<T> getType();

/**
Expand Down
Loading