/**
* Copyright (C) 2006-2017 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.support.compiler.jdt;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
import org.eclipse.jdt.internal.compiler.ast.CaseStatement;
import org.eclipse.jdt.internal.compiler.ast.CastExpression;
import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.ForStatement;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.StringLiteralConcatenation;
import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.ast.UnionTypeReference;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import spoon.reflect.code.CtBlock;
import spoon.reflect.code.CtLoop;
import spoon.reflect.code.CtStatement;
import spoon.reflect.code.CtExpression;
import spoon.reflect.code.CtTargetedExpression;
import spoon.reflect.code.CtTypeAccess;
import spoon.reflect.code.CtArrayWrite;
import spoon.reflect.code.CtArrayRead;
import spoon.reflect.code.CtArrayAccess;
import spoon.reflect.code.CtAssert;
import spoon.reflect.code.CtAssignment;
import spoon.reflect.code.CtBinaryOperator;
import spoon.reflect.code.CtCase;
import spoon.reflect.code.CtCatch;
import spoon.reflect.code.CtCatchVariable;
import spoon.reflect.code.CtDo;
import spoon.reflect.code.CtFor;
import spoon.reflect.code.CtForEach;
import spoon.reflect.code.CtWhile;
import spoon.reflect.code.CtConditional;
import spoon.reflect.code.CtIf;
import spoon.reflect.code.CtSuperAccess;
import spoon.reflect.code.CtInvocation;
import spoon.reflect.code.CtConstructorCall;
import spoon.reflect.code.CtNewArray;
import spoon.reflect.code.CtNewClass;
import spoon.reflect.code.CtLambda;
import spoon.reflect.code.CtExecutableReferenceExpression;
import spoon.reflect.code.CtReturn;
import spoon.reflect.code.CtSwitch;
import spoon.reflect.code.CtSynchronized;
import spoon.reflect.code.CtThrow;
import spoon.reflect.code.CtTry;
import spoon.reflect.code.CtTryWithResource;
import spoon.reflect.code.CtUnaryOperator;
import spoon.reflect.code.BinaryOperatorKind;
import spoon.reflect.code.CtThisAccess;
import spoon.reflect.code.CtLocalVariable;
import spoon.reflect.cu.SourcePosition;
import spoon.reflect.declaration.CtAnnotation;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtExecutable;
import spoon.reflect.declaration.CtTypedElement;
import spoon.reflect.declaration.CtFormalTypeDeclarer;
import spoon.reflect.declaration.CtType;
import spoon.reflect.declaration.CtParameter;
import spoon.reflect.declaration.CtVariable;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.CtEnum;
import spoon.reflect.declaration.CtAnnotationMethod;
import spoon.reflect.declaration.CtAnonymousExecutable;
import spoon.reflect.declaration.CtField;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtPackage;
import spoon.reflect.declaration.CtEnumValue;
import spoon.reflect.declaration.CtConstructor;
import spoon.reflect.declaration.CtTypeParameter;
import spoon.reflect.declaration.CtAnnotatedElementType;
import spoon.reflect.reference.CtArrayTypeReference;
import spoon.reflect.reference.CtIntersectionTypeReference;
import spoon.reflect.reference.CtTypeParameterReference;
import spoon.reflect.reference.CtTypeReference;
import spoon.reflect.visitor.CtInheritanceScanner;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SuppressWarnings("unchecked")
public class ParentExiter extends CtInheritanceScanner {
private final JDTTreeBuilder jdtTreeBuilder;
private CtElement child;
private ASTNode childJDT;
private Map<CtTypedElement<?>, List<CtTypeReference<? extends java.lang.annotation.Annotation>>> annotationsMap = new HashMap<>();
/**
* @param jdtTreeBuilder
*/
ParentExiter(JDTTreeBuilder jdtTreeBuilder) {
this.jdtTreeBuilder = jdtTreeBuilder;
}
public void setChild(CtElement child) {
this.child = child;
}
public void setChild(ASTNode child) {
this.childJDT = child;
}
@Override
public void scanCtElement(CtElement e) {
if (child instanceof CtAnnotation && this.jdtTreeBuilder.getContextBuilder().annotationValueName.isEmpty()) {
e.addAnnotation((CtAnnotation<?>) child);
if (e instanceof CtTypedElement && JDTTreeBuilderQuery.hasAnnotationWithType((Annotation) childJDT, CtAnnotatedElementType.TYPE_USE)) {
List<CtTypeReference<? extends java.lang.annotation.Annotation>> annotations = new ArrayList<>();
if (!annotationsMap.containsKey(e)) {
annotationsMap.put((CtTypedElement<?>) e, annotations);
} else {
annotations = annotationsMap.get(e);
}
annotations.add(((CtAnnotation) child).getType());
annotationsMap.put((CtTypedElement<?>) e, annotations);
}
return;
}
}
private void substituteAnnotation(CtTypedElement ele) {
if (annotationsMap.containsKey(ele)) {
List<CtTypeReference<? extends java.lang.annotation.Annotation>> annotations = annotationsMap.get(ele);
for (CtTypeReference<? extends java.lang.annotation.Annotation> annotation : annotations) {
final CtAnnotation<? extends java.lang.annotation.Annotation> targetAnnotation = ele.getAnnotation(annotation);
ele.removeAnnotation(targetAnnotation);
if (!ele.getType().getAnnotations().contains(targetAnnotation)) {
ele.getType().addAnnotation(targetAnnotation);
}
}
annotationsMap.remove(ele);
}
}
@Override
public <R> void scanCtExecutable(CtExecutable<R> e) {
if (child instanceof CtTypeAccess) {
e.addThrownType(((CtTypeAccess) child).getAccessedType());
return;
} else if (child instanceof CtParameter) {
e.addParameter((CtParameter<?>) child);
return;
} else if (child instanceof CtBlock && !(e instanceof CtMethod || e instanceof CtConstructor)) {
e.setBody((CtBlock<R>) child);
return;
}
super.scanCtExecutable(e);
}
@Override
public void scanCtFormalTypeDeclarer(CtFormalTypeDeclarer e) {
if (childJDT instanceof TypeParameter && child instanceof CtTypeParameter) {
e.addFormalCtTypeParameter((CtTypeParameter) child);
}
return;
}
@Override
public void scanCtLoop(CtLoop loop) {
if (loop.getBody() == null && child instanceof CtStatement) {
CtStatement child = (CtStatement) this.child;
if (!(this.child instanceof CtBlock)) {
child = jdtTreeBuilder.getFactory().Code().createCtBlock(child);
child.setImplicit(true);
}
loop.setBody(child);
}
super.scanCtLoop(loop);
}
@Override
public <T, E extends CtExpression<?>> void scanCtTargetedExpression(CtTargetedExpression<T, E> targetedExpression) {
if (child instanceof CtExpression) {
targetedExpression.setTarget((E) child);
return;
}
super.scanCtTargetedExpression(targetedExpression);
}
@Override
public <T> void scanCtType(CtType<T> type) {
if (child instanceof CtType && !(child instanceof CtTypeParameter)) {
if (type.getTypeMembers().contains(child)) {
type.removeTypeMember((CtType) child);
}
type.addNestedType((CtType<?>) child);
return;
} else if (child instanceof CtEnumValue && type instanceof CtEnum) {
((CtEnum) type).addEnumValue((CtEnumValue) child);
} else if (child instanceof CtField) {
type.addField((CtField<?>) child);
return;
} else if (child instanceof CtConstructor) {
return;
}
if (child instanceof CtMethod) {
type.addMethod((CtMethod<?>) child);
return;
}
super.scanCtType(type);
}
@Override
public <T> void scanCtVariable(CtVariable<T> v) {
if (childJDT instanceof TypeReference && child instanceof CtTypeAccess) {
v.setType(((CtTypeAccess) child).getAccessedType());
substituteAnnotation((CtTypedElement) v);
return;
} else if (child instanceof CtExpression && hasChildEqualsToDefaultValue(v)) {
v.setDefaultExpression((CtExpression<T>) child);
return;
}
super.scanCtVariable(v);
}
private <T> boolean hasChildEqualsToDefaultValue(CtVariable<T> ctVariable) {
if (jdtTreeBuilder.getContextBuilder().stack.peek().node instanceof AnnotationMethodDeclaration) {
final AnnotationMethodDeclaration parent = (AnnotationMethodDeclaration) jdtTreeBuilder.getContextBuilder().stack.peek().node;
// Default value is equals to the jdt child.
return parent.defaultValue != null && getFinalExpressionFromCast(parent.defaultValue).equals(childJDT)
// Return type not yet initialized.
&& !child.equals(ctVariable.getDefaultExpression());
}
final AbstractVariableDeclaration parent = (AbstractVariableDeclaration) jdtTreeBuilder.getContextBuilder().stack.peek().node;
// Default value is equals to the jdt child.
return parent.initialization != null && getFinalExpressionFromCast(parent.initialization).equals(childJDT)
// Return type not yet initialized.
&& !child.equals(ctVariable.getDefaultExpression());
}
@Override
public <A extends java.lang.annotation.Annotation> void visitCtAnnotation(CtAnnotation<A> annotation) {
if (child instanceof CtExpression) {
annotation.addValue(this.jdtTreeBuilder.getContextBuilder().annotationValueName.peek(), child);
}
super.visitCtAnnotation(annotation);
}
@Override
public <T> void visitCtConstructor(CtConstructor<T> e) {
if (e.getBody() == null && child instanceof CtBlock) {
e.setBody((CtBlock) child);
return;
} else if (child instanceof CtStatement) {
visitCtBlock(e.getBody());
return;
}
super.visitCtConstructor(e);
}
@Override
public <T> void visitCtMethod(CtMethod<T> e) {
if (e.getBody() == null && child instanceof CtBlock) {
e.setBody((CtBlock) child);
return;
} else if (child instanceof CtStatement) {
visitCtBlock(e.getBody());
return;
} else if (child instanceof CtTypeAccess && hasChildEqualsToType(e)) {
e.setType(((CtTypeAccess) child).getAccessedType());
substituteAnnotation(e);
return;
}
super.visitCtMethod(e);
}
private <T> boolean hasChildEqualsToType(CtMethod<T> ctMethod) {
final MethodDeclaration parent = (MethodDeclaration) jdtTreeBuilder.getContextBuilder().stack.peek().node;
// Return type is equals to the jdt child.
return parent.returnType != null && parent.returnType.equals(childJDT)
// Return type not yet initialized.
&& !child.equals(ctMethod.getType());
}
@Override
public <T> void visitCtAnnotationMethod(CtAnnotationMethod<T> annotationMethod) {
if (child instanceof CtExpression && hasChildEqualsToDefaultValue(annotationMethod)) {
annotationMethod.setDefaultExpression((CtExpression) child);
return;
}
super.visitCtAnnotationMethod(annotationMethod);
}
private <T> boolean hasChildEqualsToDefaultValue(CtAnnotationMethod<T> ctAnnotationMethod) {
final AnnotationMethodDeclaration parent = (AnnotationMethodDeclaration) jdtTreeBuilder.getContextBuilder().stack.peek().node;
// Default value is equals to the jdt child.
return parent.defaultValue != null && parent.defaultValue.equals(childJDT)
// Default value not yet initialized.
&& !child.equals(ctAnnotationMethod.getDefaultExpression());
}
@Override
public void visitCtAnonymousExecutable(CtAnonymousExecutable e) {
if (child instanceof CtBlock) {
e.setBody((CtBlock) child);
return;
}
super.visitCtAnonymousExecutable(e);
}
@Override
public <T> void visitCtArrayRead(CtArrayRead<T> arrayRead) {
if (visitArrayAccess(arrayRead)) {
super.visitCtArrayRead(arrayRead);
}
}
@Override
public <T> void visitCtArrayWrite(CtArrayWrite<T> arrayWrite) {
if (visitArrayAccess(arrayWrite)) {
super.visitCtArrayWrite(arrayWrite);
}
}
private <T, E extends CtExpression<?>> boolean visitArrayAccess(CtArrayAccess<T, E> arrayAccess) {
if (child instanceof CtExpression) {
if (arrayAccess.getTarget() == null) {
arrayAccess.setTarget((E) child);
return false;
} else {
arrayAccess.setIndexExpression((CtExpression<Integer>) child);
return false;
}
}
return true;
}
@Override
public <T> void visitCtAssert(CtAssert<T> asserted) {
if (child instanceof CtExpression) {
if (asserted.getAssertExpression() == null) {
asserted.setAssertExpression((CtExpression<Boolean>) child);
return;
} else {
asserted.setExpression((CtExpression<T>) child);
return;
}
}
super.visitCtAssert(asserted);
}
@Override
public <T, A extends T> void visitCtAssignment(CtAssignment<T, A> assignement) {
if (child instanceof CtExpression) {
if (assignement.getAssigned() == null) {
assignement.setAssigned((CtExpression<T>) child);
return;
} else if (assignement.getAssignment() == null) {
assignement.setAssignment((CtExpression<A>) child);
return;
}
}
super.visitCtAssignment(assignement);
}
@Override
public <T> void visitCtBinaryOperator(CtBinaryOperator<T> operator) {
if (child instanceof CtExpression) {
if (operator.getLeftHandOperand() == null) {
operator.setLeftHandOperand((CtExpression<?>) child);
return;
} else if (operator.getRightHandOperand() == null) {
operator.setRightHandOperand((CtExpression<?>) child);
return;
} else if (jdtTreeBuilder.getContextBuilder().stack.peek().node instanceof StringLiteralConcatenation) {
CtBinaryOperator<?> op = operator.getFactory().Core().createBinaryOperator();
op.setKind(BinaryOperatorKind.PLUS);
op.setLeftHandOperand(operator.getRightHandOperand());
op.setRightHandOperand((CtExpression<?>) child);
operator.setRightHandOperand(op);
int[] lineSeparatorPositions = this.jdtTreeBuilder.getContextBuilder().compilationunitdeclaration.compilationResult.lineSeparatorPositions;
SourcePosition leftPosition = op.getLeftHandOperand().getPosition();
SourcePosition rightPosition = op.getRightHandOperand().getPosition();
op.setPosition(op.getFactory().createSourcePosition(leftPosition.getCompilationUnit(), leftPosition.getSourceStart(), rightPosition.getSourceEnd(), lineSeparatorPositions));
return;
}
}
super.visitCtBinaryOperator(operator);
}
@Override
public <R> void visitCtBlock(CtBlock<R> block) {
if (child instanceof CtStatement) {
block.addStatement((CtStatement) child);
return;
}
super.visitCtBlock(block);
}
@Override
public <E> void visitCtCase(CtCase<E> caseStatement) {
final ASTNode node = jdtTreeBuilder.getContextBuilder().stack.peek().node;
if (node instanceof CaseStatement && ((CaseStatement) node).constantExpression != null && caseStatement.getCaseExpression() == null && child instanceof CtExpression) {
caseStatement.setCaseExpression((CtExpression<E>) child);
return;
} else if (child instanceof CtStatement) {
caseStatement.addStatement((CtStatement) child);
return;
}
super.visitCtCase(caseStatement);
}
@Override
public void visitCtCatch(CtCatch catchBlock) {
if (child instanceof CtBlock) {
catchBlock.setBody((CtBlock<?>) child);
return;
} else if (child instanceof CtCatchVariable) {
catchBlock.setParameter((CtCatchVariable<? extends Throwable>) child);
return;
}
super.visitCtCatch(catchBlock);
}
@Override
public <T> void visitCtCatchVariable(CtCatchVariable<T> e) {
if (jdtTreeBuilder.getContextBuilder().stack.peekFirst().node instanceof UnionTypeReference) {
e.addMultiType((CtTypeReference<?>) child);
return;
}
super.visitCtCatchVariable(e);
}
@Override
public <T> void visitCtClass(CtClass<T> ctClass) {
if (child instanceof CtConstructor) {
CtConstructor<T> c = (CtConstructor<T>) child;
ctClass.addConstructor(c);
if (c.getPosition() != null && c.getPosition().getSourceStart() == -1) {
c.setImplicit(true);
}
}
if (child instanceof CtAnonymousExecutable) {
ctClass.addAnonymousExecutable((CtAnonymousExecutable) child);
}
super.visitCtClass(ctClass);
}
@Override
public void visitCtTypeParameter(CtTypeParameter typeParameter) {
if (childJDT instanceof TypeReference && child instanceof CtTypeAccess) {
if (typeParameter.getSuperclass() == null) {
typeParameter.setSuperclass(((CtTypeAccess) child).getAccessedType());
} else if (typeParameter.getSuperclass() instanceof CtIntersectionTypeReference) {
typeParameter.getSuperclass().asCtIntersectionTypeReference().addBound(((CtTypeAccess) child).getAccessedType());
} else {
final List<CtTypeReference<?>> refs = new ArrayList<>();
refs.add(typeParameter.getSuperclass());
refs.add(((CtTypeAccess) child).getAccessedType());
typeParameter.setSuperclass(jdtTreeBuilder.getFactory().Type().createIntersectionTypeReferenceWithBounds(refs));
}
return;
}
super.visitCtTypeParameter(typeParameter);
}
@Override
public <T> void visitCtConditional(CtConditional<T> conditional) {
if (child instanceof CtExpression) {
if (conditional.getCondition() == null) {
conditional.setCondition((CtExpression<Boolean>) child);
} else if (conditional.getThenExpression() == null) {
conditional.setThenExpression((CtExpression<T>) child);
} else if (conditional.getElseExpression() == null) {
conditional.setElseExpression((CtExpression<T>) child);
}
}
super.visitCtConditional(conditional);
}
@Override
public void visitCtDo(CtDo doLoop) {
if (doLoop.getBody() != null && child instanceof CtExpression && doLoop.getLoopingExpression() == null) {
doLoop.setLoopingExpression((CtExpression<Boolean>) child);
return;
}
super.visitCtDo(doLoop);
}
@Override
public void visitCtFor(CtFor forLoop) {
if (isContainedInForInit() && child instanceof CtStatement) {
forLoop.addForInit((CtStatement) child);
return;
} else if (isContainedInForUpdate() && child instanceof CtStatement) {
forLoop.addForUpdate((CtStatement) child);
return;
} else if (forLoop.getExpression() == null && child instanceof CtExpression) {
forLoop.setExpression((CtExpression<Boolean>) child);
return;
}
super.visitCtFor(forLoop);
}
private boolean isContainedInForInit() {
if (!(jdtTreeBuilder.getContextBuilder().stack.peek().node instanceof ForStatement)) {
return false;
}
final ForStatement parent = (ForStatement) jdtTreeBuilder.getContextBuilder().stack.peek().node;
if (parent.initializations == null) {
return false;
}
for (Statement initialization : parent.initializations) {
if (initialization != null && initialization.equals(childJDT)) {
return true;
}
}
return false;
}
private boolean isContainedInForUpdate() {
if (!(jdtTreeBuilder.getContextBuilder().stack.peek().node instanceof ForStatement)) {
return false;
}
final ForStatement parent = (ForStatement) jdtTreeBuilder.getContextBuilder().stack.peek().node;
if (parent.increments == null) {
return false;
}
for (Statement increment : parent.increments) {
if (increment != null && increment.equals(childJDT)) {
return true;
}
}
return false;
}
@Override
public void visitCtForEach(CtForEach foreach) {
if (foreach.getVariable() == null && child instanceof CtVariable) {
foreach.setVariable((CtLocalVariable<?>) child);
return;
} else if (foreach.getExpression() == null && child instanceof CtExpression) {
foreach.setExpression((CtExpression<?>) child);
return;
}
super.visitCtForEach(foreach);
}
@Override
public void visitCtWhile(CtWhile whileLoop) {
if (whileLoop.getLoopingExpression() == null && child instanceof CtExpression) {
whileLoop.setLoopingExpression((CtExpression<Boolean>) child);
return;
}
super.visitCtWhile(whileLoop);
}
@Override
public void visitCtIf(CtIf ifElement) {
if (ifElement.getCondition() == null && child instanceof CtExpression) {
ifElement.setCondition((CtExpression<Boolean>) child);
return;
} else if (child instanceof CtStatement) {
CtStatement child = (CtStatement) this.child;
if (!(this.child instanceof CtBlock)) {
child = jdtTreeBuilder.getFactory().Code().createCtBlock(child);
child.setImplicit(true);
}
if (ifElement.getThenStatement() == null) {
ifElement.setThenStatement(child);
return;
} else if (ifElement.getElseStatement() == null) {
ifElement.setElseStatement(child);
return;
}
}
super.visitCtIf(ifElement);
}
@Override
public <T> void visitCtSuperAccess(CtSuperAccess<T> superAccess) {
if (child instanceof CtTypeAccess<?>) {
superAccess.setTarget((CtTypeAccess<?>) child);
return;
}
super.visitCtSuperAccess(superAccess);
}
@Override
public <T> void visitCtInvocation(CtInvocation<T> invocation) {
if (childJDT instanceof TypeReference && child instanceof CtTypeAccess) {
invocation.getExecutable().addActualTypeArgument(((CtTypeAccess) child).getAccessedType());
return;
} else if (child instanceof CtExpression) {
if (hasChildEqualsToReceiver(invocation) || hasChildEqualsToQualification(invocation)) {
if (child instanceof CtThisAccess) {
final CtTypeReference<?> declaringType = invocation.getExecutable().getDeclaringType();
if (declaringType != null && invocation.getExecutable().isStatic() && child.isImplicit()) {
invocation.setTarget(jdtTreeBuilder.getFactory().Code().createTypeAccess(declaringType, declaringType.isAnonymous()));
} else {
invocation.setTarget((CtThisAccess<?>) child);
}
} else {
invocation.setTarget((CtExpression<?>) child);
}
} else {
invocation.addArgument((CtExpression<?>) child);
}
return;
}
super.visitCtInvocation(invocation);
}
private <T> boolean hasChildEqualsToQualification(CtInvocation<T> ctInvocation) {
if (!(jdtTreeBuilder.getContextBuilder().stack.peek().node instanceof ExplicitConstructorCall)) {
return false;
}
final ExplicitConstructorCall parent = (ExplicitConstructorCall) jdtTreeBuilder.getContextBuilder().stack.peek().node;
// qualification is equals to the jdt child.
return parent.qualification != null && getFinalExpressionFromCast(parent.qualification).equals(childJDT)
// qualification not yet initialized.
&& !child.equals(ctInvocation.getTarget());
}
private <T> boolean hasChildEqualsToReceiver(CtInvocation<T> ctInvocation) {
if (!(jdtTreeBuilder.getContextBuilder().stack.peek().node instanceof MessageSend)) {
return false;
}
final MessageSend parent = (MessageSend) jdtTreeBuilder.getContextBuilder().stack.peek().node;
// Receiver is equals to the jdt child.
return parent.receiver != null && getFinalExpressionFromCast(parent.receiver).equals(childJDT)
// Receiver not yet initialized.
&& !child.equals(ctInvocation.getTarget());
}
private Expression getFinalExpressionFromCast(Expression potentialCase) {
if (!(potentialCase instanceof CastExpression)) {
return potentialCase;
}
return getFinalExpressionFromCast(((CastExpression) potentialCase).expression);
}
@Override
public <T> void visitCtNewArray(CtNewArray<T> newArray) {
if (childJDT instanceof TypeReference && child instanceof CtTypeAccess) {
final ArrayAllocationExpression arrayAlloc = (ArrayAllocationExpression) jdtTreeBuilder.getContextBuilder().stack.peek().node;
newArray.setType((CtArrayTypeReference) jdtTreeBuilder.getFactory().Type().createArrayReference(((CtTypeAccess) child).getAccessedType(), arrayAlloc.dimensions.length));
} else if (child instanceof CtExpression) {
if (isContainedInDimensionExpression()) {
newArray.addDimensionExpression((CtExpression<Integer>) child);
} else if (child instanceof CtNewArray && childJDT instanceof ArrayInitializer && jdtTreeBuilder.getContextBuilder().stack.peek().node instanceof ArrayAllocationExpression) {
newArray.setElements(((CtNewArray) child).getElements());
} else {
newArray.addElement((CtExpression) child);
}
}
}
private boolean isContainedInDimensionExpression() {
if (!(jdtTreeBuilder.getContextBuilder().stack.peek().node instanceof ArrayAllocationExpression)) {
return false;
}
final ArrayAllocationExpression parent = (ArrayAllocationExpression) jdtTreeBuilder.getContextBuilder().stack.peek().node;
if (parent.dimensions == null) {
return false;
}
for (Expression dimension : parent.dimensions) {
if (dimension != null && getFinalExpressionFromCast(dimension).equals(childJDT)) {
return true;
}
}
return false;
}
@Override
public <T> void visitCtConstructorCall(CtConstructorCall<T> ctConstructorCall) {
if (child instanceof CtTypeAccess) {
if (hasChildEqualsToType(ctConstructorCall)) {
ctConstructorCall.getExecutable().setType(((CtTypeAccess) child).getAccessedType());
} else {
ctConstructorCall.addActualTypeArgument(((CtTypeAccess) child).getAccessedType());
}
return;
} else if (child instanceof CtExpression) {
if (hasChildEqualsToEnclosingInstance(ctConstructorCall)) {
ctConstructorCall.setTarget((CtExpression<?>) child);
} else {
ctConstructorCall.addArgument((CtExpression<?>) child);
}
return;
}
super.visitCtConstructorCall(ctConstructorCall);
}
private <T> boolean hasChildEqualsToEnclosingInstance(CtConstructorCall<T> ctConstructorCall) {
if (!(jdtTreeBuilder.getContextBuilder().stack.peek().node instanceof QualifiedAllocationExpression)) {
return false;
}
final QualifiedAllocationExpression parent = (QualifiedAllocationExpression) jdtTreeBuilder.getContextBuilder().stack.peek().node;
// Enclosing instance is equals to the jdt child.
return parent.enclosingInstance != null && getFinalExpressionFromCast(parent.enclosingInstance).equals(childJDT)
// Enclosing instance not yet initialized.
&& !child.equals(ctConstructorCall.getTarget());
}
private <T> boolean hasChildEqualsToType(CtConstructorCall<T> ctConstructorCall) {
final AllocationExpression parent = (AllocationExpression) jdtTreeBuilder.getContextBuilder().stack.peek().node;
// Type is equals to the jdt child.
return parent.type != null && parent.type.equals(childJDT);
}
@Override
public <T> void visitCtNewClass(CtNewClass<T> newClass) {
if (child instanceof CtClass) {
newClass.setAnonymousClass((CtClass<?>) child);
final QualifiedAllocationExpression node = (QualifiedAllocationExpression) jdtTreeBuilder.getContextBuilder().stack.peek().node;
final ReferenceBinding[] referenceBindings = node.resolvedType == null ? null : node.resolvedType.superInterfaces();
if (referenceBindings != null && referenceBindings.length > 0) {
((CtClass<?>) child).addSuperInterface(newClass.getType().clone());
} else if (newClass.getType() != null) {
((CtClass<?>) child).setSuperclass(newClass.getType().clone());
}
return;
}
super.visitCtNewClass(newClass);
}
@Override
public <T> void visitCtLambda(CtLambda<T> lambda) {
if (child instanceof CtParameter) {
lambda.addParameter((CtParameter<?>) child);
return;
} else if (child instanceof CtBlock) {
lambda.setBody((CtBlock) child);
return;
} else if (child instanceof CtExpression) {
lambda.setExpression((CtExpression<T>) child);
}
super.visitCtLambda(lambda);
}
@Override
public <T, E extends CtExpression<?>> void visitCtExecutableReferenceExpression(CtExecutableReferenceExpression<T, E> expression) {
if (child instanceof CtExpression) {
expression.setTarget((E) child);
}
super.visitCtExecutableReferenceExpression(expression);
}
@Override
public void visitCtPackage(CtPackage ctPackage) {
if (child instanceof CtType) {
if (ctPackage.getTypes().contains(child)) {
ctPackage.getTypes().remove(child);
}
ctPackage.getTypes().add((CtType<?>) child);
if (child.getPosition() != null && child.getPosition().getCompilationUnit() != null) {
child.getPosition().getCompilationUnit().getDeclaredTypes().add((CtType<?>) child);
}
return;
}
super.visitCtPackage(ctPackage);
}
@Override
public <R> void visitCtReturn(CtReturn<R> returnStatement) {
if (child instanceof CtExpression) {
returnStatement.setReturnedExpression((CtExpression<R>) child);
return;
}
super.visitCtReturn(returnStatement);
}
@Override
public <E> void visitCtSwitch(CtSwitch<E> switchStatement) {
if (switchStatement.getSelector() == null && child instanceof CtExpression) {
switchStatement.setSelector((CtExpression<E>) child);
return;
}
if (child instanceof CtCase) {
switchStatement.addCase((CtCase<E>) child);
return;
}
super.visitCtSwitch(switchStatement);
}
@Override
public void visitCtSynchronized(CtSynchronized synchro) {
if (synchro.getExpression() == null && child instanceof CtExpression) {
synchro.setExpression((CtExpression<?>) child);
return;
}
if (synchro.getBlock() == null && child instanceof CtBlock) {
synchro.setBlock((CtBlock<?>) child);
return;
}
super.visitCtSynchronized(synchro);
}
@Override
public void visitCtThrow(CtThrow throwStatement) {
if (throwStatement.getThrownExpression() == null && child instanceof CtExpression) {
throwStatement.setThrownExpression((CtExpression<? extends Throwable>) child);
return;
}
super.visitCtThrow(throwStatement);
}
@Override
public void visitCtTry(CtTry tryBlock) {
if (child instanceof CtBlock) {
final CtBlock<?> childBlock = (CtBlock<?>) this.child;
if (tryBlock.getCatchers().size() > 0 && tryBlock.getCatchers().get(tryBlock.getCatchers().size() - 1).getBody() == null) {
tryBlock.getCatchers().get(tryBlock.getCatchers().size() - 1).setBody(childBlock);
} else if (tryBlock.getBody() != null && tryBlock.getFinalizer() == null) {
tryBlock.setFinalizer(childBlock);
} else {
tryBlock.setBody(childBlock);
}
return;
} else if (child instanceof CtCatch) {
tryBlock.addCatcher((CtCatch) child);
return;
}
super.visitCtTry(tryBlock);
}
@Override
public void visitCtTryWithResource(CtTryWithResource tryWithResource) {
if (child instanceof CtLocalVariable) {
tryWithResource.addResource((CtLocalVariable<?>) child);
}
super.visitCtTryWithResource(tryWithResource);
}
@Override
public <T> void visitCtUnaryOperator(CtUnaryOperator<T> operator) {
if (operator.getOperand() == null && child instanceof CtExpression) {
operator.setOperand((CtExpression<T>) child);
return;
}
super.visitCtUnaryOperator(operator);
}
@Override
public void visitCtTypeParameterReference(CtTypeParameterReference e) {
if (childJDT instanceof TypeReference && child instanceof CtTypeAccess) {
e.addBound(((CtTypeAccess) child).getAccessedType());
}
super.visitCtTypeParameterReference(e);
}
}