/** * 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.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Argument; import org.eclipse.jdt.internal.compiler.ast.FieldReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; import org.eclipse.jdt.internal.compiler.ast.ReferenceExpression; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.MissingTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; import org.eclipse.jdt.internal.compiler.lookup.ProblemBinding; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; import spoon.reflect.code.CtCatchVariable; import spoon.reflect.code.CtExecutableReferenceExpression; import spoon.reflect.code.CtExpression; import spoon.reflect.code.CtFieldAccess; import spoon.reflect.code.CtLambda; import spoon.reflect.code.CtTypeAccess; import spoon.reflect.code.CtVariableAccess; import spoon.reflect.declaration.CtClass; import spoon.reflect.declaration.CtConstructor; import spoon.reflect.declaration.CtExecutable; import spoon.reflect.declaration.CtField; import spoon.reflect.declaration.CtParameter; import spoon.reflect.declaration.CtType; import spoon.reflect.declaration.CtVariable; import spoon.reflect.declaration.ModifierKind; import spoon.reflect.factory.CoreFactory; import spoon.reflect.factory.ExecutableFactory; import spoon.reflect.factory.TypeFactory; import spoon.reflect.reference.CtArrayTypeReference; import spoon.reflect.reference.CtExecutableReference; import spoon.reflect.reference.CtFieldReference; import spoon.reflect.reference.CtParameterReference; import spoon.reflect.reference.CtReference; import spoon.reflect.reference.CtTypeReference; import spoon.reflect.reference.CtVariableReference; import java.util.ArrayList; import java.util.List; import java.util.Set; import static spoon.support.compiler.jdt.JDTTreeBuilderQuery.getModifiers; import static spoon.support.compiler.jdt.JDTTreeBuilderQuery.isLhsAssignment; public class JDTTreeBuilderHelper { private final JDTTreeBuilder jdtTreeBuilder; JDTTreeBuilderHelper(JDTTreeBuilder jdtTreeBuilder) { this.jdtTreeBuilder = jdtTreeBuilder; } /** * Computes the anonymous simple name from its fully qualified type name. * * @param anonymousQualifiedName * Qualified name which contains the anonymous name. * @return Anonymous simple name. */ static String computeAnonymousName(char[] anonymousQualifiedName) { final String poolName = CharOperation.charToString(anonymousQualifiedName); return poolName.substring(poolName.lastIndexOf(CtType.INNERTTYPE_SEPARATOR) + 1, poolName.length()); } /** * Creates a qualified type name from a two-dimensional array. * * @param typeName * two-dimensional array which represents the qualified name expected. * @return Qualified name. */ static String createQualifiedTypeName(char[][] typeName) { String s = ""; for (int i = 0; i < typeName.length - 1; i++) { s += CharOperation.charToString(typeName[i]) + "."; } s += CharOperation.charToString(typeName[typeName.length - 1]); return s; } /** * Creates a catch variable from a type reference. * * @param typeReference * Correspond to the exception type declared in the catch. * @return a catch variable. */ CtCatchVariable<Throwable> createCatchVariable(TypeReference typeReference) { final Argument jdtCatch = (Argument) jdtTreeBuilder.getContextBuilder().stack.peekFirst().node; final Set<ModifierKind> modifiers = getModifiers(jdtCatch.modifiers); return jdtTreeBuilder.getFactory().Code().createCatchVariable(// jdtTreeBuilder.getReferencesBuilder().<Throwable>getTypeReference(typeReference.resolvedType), // CharOperation.charToString(jdtCatch.name), // modifiers.toArray(new ModifierKind[modifiers.size()])); } /** * Creates variable access from a {@link CtVariableReference}. Think to move this method * in the {@link spoon.reflect.factory.CodeFactory} if you think that is a good idea. */ public <T> CtVariableAccess<T> createVariableAccess(CtVariableReference<T> variableReference, boolean isReadAccess) { CtVariableAccess<T> variableAccess; if (isReadAccess) { variableAccess = jdtTreeBuilder.getFactory().Core().createVariableWrite(); } else { variableAccess = jdtTreeBuilder.getFactory().Core().createVariableRead(); } return variableAccess.setVariable(variableReference); } /** * Creates a variable access from its single name. * * @param singleNameReference * Used to build a variable reference which will be contained in the variable access. * @return a variable access. */ <T> CtVariableAccess<T> createVariableAccess(SingleNameReference singleNameReference) { CtVariableAccess<T> va; if (isLhsAssignment(jdtTreeBuilder.getContextBuilder(), singleNameReference)) { va = jdtTreeBuilder.getFactory().Core().createVariableWrite(); } else { va = jdtTreeBuilder.getFactory().Core().createVariableRead(); } va.setVariable(jdtTreeBuilder.getReferencesBuilder().<T>getVariableReference((VariableBinding) singleNameReference.binding)); return va; } /** * Analyzes if {@code singleNameReference} points to a {@link CtVariable} visible in current * scope and, if existent, returns its corresponding {@link CtVariableAccess}. Returns * {@code null} if {@code singleNameReference} could not be resolved as variable access. Since * we are in noclasspath mode this function may also returns {@code null} if * {@code singleNameReference} points to a variable declared by an unknown class. * * @param singleNameReference * The potential variable access. * @return A {@link CtVariableAccess} if {@code singleNameReference} points to a variable * visible in current scope, {@code null} otherwise. */ <T> CtVariableAccess<T> createVariableAccessNoClasspath(SingleNameReference singleNameReference) { final TypeFactory typeFactory = jdtTreeBuilder.getFactory().Type(); final CoreFactory coreFactory = jdtTreeBuilder.getFactory().Core(); final ExecutableFactory executableFactory = jdtTreeBuilder.getFactory().Executable(); final ContextBuilder contextBuilder = jdtTreeBuilder.getContextBuilder(); final ReferenceBuilder referenceBuilder = jdtTreeBuilder.getReferencesBuilder(); final PositionBuilder positionBuilder = jdtTreeBuilder.getPositionBuilder(); final String name = CharOperation.charToString(singleNameReference.token); final CtVariable<T> variable = contextBuilder.getVariableDeclaration(name); if (variable == null) { return null; } final CtVariableReference<T> variableReference; final CtVariableAccess<T> variableAccess; if (variable instanceof CtParameter) { // create variable of concrete type to avoid type casting while calling methods final CtParameterReference<T> parameterReference = coreFactory.createParameterReference(); if (variable.getParent() instanceof CtLambda) { parameterReference.setDeclaringExecutable( referenceBuilder.getLambdaExecutableReference(singleNameReference)); } else { // Unfortunately, we can not use `variable.getReference()` here as some parent // references (in terms of Java objects) have not been set up yet. Thus, we need to // create the required parameter reference by our own. // Since the given parameter has not been declared in a lambda expression it must // have been declared by a method/constructor. final CtExecutable executable = (CtExecutable) variable.getParent(); // create list of executable's parameter types final List<CtTypeReference<?>> parameterTypesOfExecutable = new ArrayList<>(); @SuppressWarnings("unchecked") final List<CtParameter<?>> parametersOfExecutable = executable.getParameters(); for (CtParameter<?> parameter : parametersOfExecutable) { parameterTypesOfExecutable.add(parameter.getType() != null ? parameter.getType().clone() // it's the best match :( : typeFactory.OBJECT.clone() ); } // find executable's corresponding jdt element AbstractMethodDeclaration executableJDT = null; for (final ASTPair astPair : contextBuilder.stack) { if (astPair.element == executable) { executableJDT = (AbstractMethodDeclaration) astPair.node; } } assert executableJDT != null; // create a reference to executable's declaring class final CtTypeReference declaringReferenceOfExecutable = // `binding` may be null for anonymous classes which means we have to // create an 'empty' type reference since we have no further information // available executableJDT.binding == null ? coreFactory.createTypeReference() : referenceBuilder.getTypeReference( executableJDT.binding.declaringClass); // If executable is a constructor, `executable.getType()` returns null since the // parent is not available yet. Fortunately, however, the return type of a // constructor is its declaring class which, in our case, is already available with // declaringReferenceOfExecutable. CtTypeReference executableTypeReference = executable instanceof CtConstructor // IMPORTANT: Create a clone of the type reference (rt) if retrieved by // other AST elements as `executableFactory.createReference` (see below) // indirectly sets the parent of `rt` and, thus, may break the AST! ? declaringReferenceOfExecutable.clone() : executable.getType().clone(); // create a reference to the executable of the currently processed parameter // reference @SuppressWarnings("unchecked") final CtExecutableReference executableReference = executableFactory.createReference( declaringReferenceOfExecutable, executableTypeReference, executable.getSimpleName(), parameterTypesOfExecutable); // finally, we can set the executable reference... parameterReference.setDeclaringExecutable(executableReference); } variableReference = parameterReference; variableAccess = isLhsAssignment(contextBuilder, singleNameReference) ? coreFactory.<T>createVariableWrite() : coreFactory.<T>createVariableRead(); } else if (variable instanceof CtField) { variableReference = variable.getReference(); variableAccess = isLhsAssignment(contextBuilder, singleNameReference) ? coreFactory.<T>createFieldWrite() : coreFactory.<T>createFieldRead(); } else { // CtLocalVariable, CtCatchVariable, ... variableReference = variable.getReference(); variableAccess = isLhsAssignment(contextBuilder, singleNameReference) ? coreFactory.<T>createVariableWrite() : coreFactory.<T>createVariableRead(); } variableReference.setSimpleName(name); variableReference.setPosition(positionBuilder.buildPosition( singleNameReference.sourceStart(), singleNameReference.sourceEnd())); variableAccess.setVariable(variableReference); return variableAccess; } /** * Creates a variable or a field access from its qualified name. * * @param qualifiedNameReference * Used to build the variable access. See all sub methods of this class to understand its usage. * @return a variable access. */ <T> CtVariableAccess<T> createVariableAccess(QualifiedNameReference qualifiedNameReference) { long[] positions = qualifiedNameReference.sourcePositions; int sourceStart = qualifiedNameReference.sourceStart(); int sourceEnd = qualifiedNameReference.sourceEnd(); if (qualifiedNameReference.indexOfFirstFieldBinding < positions.length) { sourceEnd = (int) (positions[qualifiedNameReference.indexOfFirstFieldBinding] >>> 32) - 2; } CtVariableAccess<T> va; CtVariableReference<T> ref; boolean fromAssignment = isLhsAssignment(jdtTreeBuilder.getContextBuilder(), qualifiedNameReference); boolean isOtherBinding = qualifiedNameReference.otherBindings == null || qualifiedNameReference.otherBindings.length == 0; if (qualifiedNameReference.binding instanceof FieldBinding) { ref = jdtTreeBuilder.getReferencesBuilder().getVariableReference(qualifiedNameReference.fieldBinding()); ref.setPosition(jdtTreeBuilder.getPositionBuilder().buildPosition(sourceStart, sourceEnd)); va = createFieldAccess(ref, createTargetFieldAccess(qualifiedNameReference, (CtFieldReference<Object>) ref), isOtherBinding && fromAssignment); } else { ref = jdtTreeBuilder.getReferencesBuilder().getVariableReference((VariableBinding) qualifiedNameReference.binding); ref.setPosition(jdtTreeBuilder.getPositionBuilder().buildPosition(sourceStart, sourceEnd)); va = createVariableAccess(ref, isOtherBinding && fromAssignment); } ref.setPosition(jdtTreeBuilder.getPositionBuilder().buildPosition(sourceStart, sourceEnd)); if (qualifiedNameReference.otherBindings != null) { int i = 0; //positions index; va.setPosition(ref.getPosition()); sourceStart = (int) (positions[qualifiedNameReference.indexOfFirstFieldBinding - 1] >>> 32); for (FieldBinding b : qualifiedNameReference.otherBindings) { isOtherBinding = qualifiedNameReference.otherBindings.length == i + 1; CtFieldAccess<T> other = createFieldAccess(// jdtTreeBuilder.getReferencesBuilder().<T>getVariableReference(b, qualifiedNameReference.tokens[i + 1]), va, isOtherBinding && fromAssignment); //set source position of fa if (i + qualifiedNameReference.indexOfFirstFieldBinding >= qualifiedNameReference.otherBindings.length) { sourceEnd = qualifiedNameReference.sourceEnd(); } else { sourceEnd = (int) (positions[qualifiedNameReference.indexOfFirstFieldBinding + i + 1] >>> 32) - 2; } other.setPosition(jdtTreeBuilder.getPositionBuilder().buildPosition(sourceStart, sourceEnd)); va = other; i++; } } else if (!(qualifiedNameReference.binding instanceof FieldBinding) && qualifiedNameReference.tokens.length > 1) { sourceStart = (int) (positions[0] >>> 32); for (int i = 1; i < qualifiedNameReference.tokens.length; i++) { isOtherBinding = qualifiedNameReference.tokens.length == i + 1; CtFieldAccess<T> other = createFieldAccess(// jdtTreeBuilder.getReferencesBuilder().<T>getVariableReference(null, qualifiedNameReference.tokens[i]), va, isOtherBinding && fromAssignment); //set source position of va; sourceEnd = (int) (positions[i]); va.setPosition(jdtTreeBuilder.getPositionBuilder().buildPosition(sourceStart, sourceEnd)); va = other; } } va.setPosition(jdtTreeBuilder.getPositionBuilder().buildPosition(qualifiedNameReference.sourceStart(), qualifiedNameReference.sourceEnd())); return va; } /** * Creates variable access from a {@link CtVariableReference}. Think to move this method * in the {@link spoon.reflect.factory.CodeFactory} if you think that is a good idea. */ public <T> CtFieldAccess<T> createFieldAccess(CtVariableReference<T> variableReference, CtExpression<?> target, boolean isReadAccess) { CtFieldAccess<T> fieldAccess; if (isReadAccess) { fieldAccess = jdtTreeBuilder.getFactory().Core().createFieldWrite(); } else { fieldAccess = jdtTreeBuilder.getFactory().Core().createFieldRead(); } fieldAccess.setVariable(variableReference); fieldAccess.setTarget(target); return fieldAccess; } /** * Creates a field access from its single name. * * @param singleNameReference * Used to build a variable reference and a target which will be contained in the field access. * @return a field access. */ <T> CtFieldAccess<T> createFieldAccess(SingleNameReference singleNameReference) { CtFieldAccess<T> va; if (isLhsAssignment(jdtTreeBuilder.getContextBuilder(), singleNameReference)) { va = jdtTreeBuilder.getFactory().Core().createFieldWrite(); } else { va = jdtTreeBuilder.getFactory().Core().createFieldRead(); } va.setVariable(jdtTreeBuilder.getReferencesBuilder().<T>getVariableReference(singleNameReference.fieldBinding().original())); if (va.getVariable() != null) { final CtFieldReference<T> ref = va.getVariable(); if (ref.isStatic() && !ref.getDeclaringType().isAnonymous()) { va.setTarget(jdtTreeBuilder.getFactory().Code().createTypeAccess(ref.getDeclaringType())); } else if (!ref.isStatic()) { va.setTarget(jdtTreeBuilder.getFactory().Code().createThisAccess(jdtTreeBuilder.getReferencesBuilder().getTypeReference(singleNameReference.actualReceiverType), true)); } } return va; } /** * In no classpath mode, when we build a field access, we have a binding typed by ProblemBinding. * This binding doesn't contain all information but we can get some of them. * * @param singleNameReference * Used to get the problem binding of the field access and the name of the declaring type. * @return a field access. */ <T> CtFieldAccess<T> createFieldAccessNoClasspath(SingleNameReference singleNameReference) { CtFieldAccess<T> va; if (isLhsAssignment(jdtTreeBuilder.getContextBuilder(), singleNameReference)) { va = jdtTreeBuilder.getFactory().Core().createFieldWrite(); } else { va = jdtTreeBuilder.getFactory().Core().createFieldRead(); } va.setVariable(jdtTreeBuilder.getReferencesBuilder().<T>getVariableReference((ProblemBinding) singleNameReference.binding)); final CtReference declaring = jdtTreeBuilder.getReferencesBuilder().getDeclaringReferenceFromImports(singleNameReference.token); if (declaring instanceof CtTypeReference && va.getVariable() != null) { final CtTypeReference<Object> declaringRef = (CtTypeReference<Object>) declaring; va.setTarget(jdtTreeBuilder.getFactory().Code().createTypeAccess(declaringRef)); va.getVariable().setDeclaringType(declaringRef); va.getVariable().setStatic(true); } return va; } /** * In no classpath mode, when we build a field access, we have a binding typed by ProblemBinding. * We try to get all information we can get from this binding. * * @param qualifiedNameReference * Used to get the problem binding of the field access and the name of the declaring type. * @return a field access. */ <T> CtFieldAccess<T> createFieldAccessNoClasspath(QualifiedNameReference qualifiedNameReference) { boolean fromAssignment = isLhsAssignment(jdtTreeBuilder.getContextBuilder(), qualifiedNameReference); CtFieldAccess<T> fieldAccess = createFieldAccess(jdtTreeBuilder.getReferencesBuilder().<T>getVariableReference((ProblemBinding) qualifiedNameReference.binding), null, fromAssignment); // In no classpath mode and with qualified name, the type given by JDT is wrong... final char[][] declaringClass = CharOperation.subarray(qualifiedNameReference.tokens, 0, qualifiedNameReference.tokens.length - 1); final MissingTypeBinding declaringType = jdtTreeBuilder.getContextBuilder().compilationunitdeclaration.scope.environment.createMissingType(null, declaringClass); final CtTypeReference<T> declaringRef = jdtTreeBuilder.getReferencesBuilder().getTypeReference(declaringType); fieldAccess.getVariable().setDeclaringType(declaringRef); fieldAccess.getVariable().setStatic(true); fieldAccess.setTarget(jdtTreeBuilder.getFactory().Code().createTypeAccess(declaringRef)); // In no classpath mode and with qualified name, the binding don't have a good name. fieldAccess.getVariable() .setSimpleName(createQualifiedTypeName(CharOperation.subarray(qualifiedNameReference.tokens, qualifiedNameReference.tokens.length - 1, qualifiedNameReference.tokens.length))); return fieldAccess; } /** * Creates a field access from a field reference. * * @param fieldReference * Used to build the spoon variable reference and the type of the field access. * @return a field access. */ <T> CtFieldAccess<T> createFieldAccess(FieldReference fieldReference) { CtFieldAccess<T> fieldAccess; if (isLhsAssignment(jdtTreeBuilder.getContextBuilder(), fieldReference)) { fieldAccess = jdtTreeBuilder.getFactory().Core().createFieldWrite(); } else { fieldAccess = jdtTreeBuilder.getFactory().Core().createFieldRead(); } fieldAccess.setVariable(jdtTreeBuilder.getReferencesBuilder().<T>getVariableReference(fieldReference.binding, fieldReference.token)); fieldAccess.setType(jdtTreeBuilder.getReferencesBuilder().<T>getTypeReference(fieldReference.resolvedType)); return fieldAccess; } /** * Creates a type access from its qualified name and with a field reference. * * @param qualifiedNameReference * Used to update the field reference if necessary. * @param fieldReference * Used to get its declaring class and to put it in the type access. * @return a type access. */ CtTypeAccess<?> createTypeAccess(QualifiedNameReference qualifiedNameReference, CtFieldReference<?> fieldReference) { final TypeBinding receiverType = qualifiedNameReference.actualReceiverType; if (receiverType != null) { final CtTypeReference<Object> qualifiedRef = jdtTreeBuilder.getReferencesBuilder().getQualifiedTypeReference(// qualifiedNameReference.tokens, receiverType, qualifiedNameReference.fieldBinding().declaringClass.enclosingType(), new JDTTreeBuilder.OnAccessListener() { @Override public boolean onAccess(char[][] tokens, int index) { return !CharOperation.equals(tokens[index + 1], tokens[tokens.length - 1]); } }); if (qualifiedRef != null) { fieldReference.setDeclaringType(qualifiedRef); } else { fieldReference.setDeclaringType(jdtTreeBuilder.getReferencesBuilder().getTypeReference(receiverType)); } } CtTypeAccess<?> typeAccess = jdtTreeBuilder.getFactory().Code().createTypeAccess(fieldReference.getDeclaringType()); if (qualifiedNameReference.indexOfFirstFieldBinding > 1) { // the array sourcePositions contains the position of each element of the qualifiedNameReference // the last element contains the position of the field long[] positions = qualifiedNameReference.sourcePositions; typeAccess.setPosition( jdtTreeBuilder.getPositionBuilder().buildPosition(qualifiedNameReference.sourceStart(), (int) (positions[qualifiedNameReference.indexOfFirstFieldBinding - 1] >>> 32) - 2)); } else { typeAccess.setImplicit(qualifiedNameReference.isImplicitThis()); } return typeAccess; } /** * Creates a type access from its qualified name. * * @param qualifiedNameReference * Used to get the declaring class of this type. This qualified type should have a type as target. * @return a type access. */ <T> CtTypeAccess<T> createTypeAccessNoClasspath(QualifiedNameReference qualifiedNameReference) { CtTypeReference<T> typeReference; if (qualifiedNameReference.binding instanceof ProblemBinding) { typeReference = jdtTreeBuilder.getFactory().Type().<T>createReference(CharOperation.toString(qualifiedNameReference.tokens)); } else if (qualifiedNameReference.binding instanceof FieldBinding) { final ReferenceBinding declaringClass = ((FieldBinding) qualifiedNameReference.binding).declaringClass; typeReference = jdtTreeBuilder.getReferencesBuilder().<T>getTypeReference(declaringClass); } else { // TODO try to determine package/class boundary by upper case char[][] packageName = CharOperation.subarray(qualifiedNameReference.tokens, 0, qualifiedNameReference.tokens.length - 1); char[][] className = CharOperation.subarray(qualifiedNameReference.tokens, qualifiedNameReference.tokens.length - 1, qualifiedNameReference.tokens.length); if (packageName.length > 0) { final PackageBinding aPackage = jdtTreeBuilder.getContextBuilder().compilationunitdeclaration.scope.environment.createPackage(packageName); final MissingTypeBinding declaringType = jdtTreeBuilder.getContextBuilder().compilationunitdeclaration.scope.environment.createMissingType(aPackage, className); typeReference = jdtTreeBuilder.getReferencesBuilder().getTypeReference(declaringType); } else { typeReference = jdtTreeBuilder.getFactory().Type().createReference(qualifiedNameReference.toString()); } } final CtTypeAccess<T> typeAccess = jdtTreeBuilder.getFactory().Code().createTypeAccess(typeReference); int sourceStart = qualifiedNameReference.sourceStart(); int sourceEnd = qualifiedNameReference.sourceEnd(); typeAccess.setPosition(jdtTreeBuilder.getPositionBuilder().buildPosition(sourceStart, sourceEnd)); return typeAccess; } /** * Creates a type access from its single name. * * @param singleNameReference * Used to get the simple name of the type. * @return a type access. */ <T> CtTypeAccess<T> createTypeAccessNoClasspath(SingleNameReference singleNameReference) { final CtTypeReference<T> typeReference = jdtTreeBuilder.getFactory().Core().createTypeReference(); if (singleNameReference.binding == null) { typeReference.setSimpleName(CharOperation.charToString(singleNameReference.token)); } else { typeReference.setSimpleName(CharOperation.charToString(singleNameReference.binding.readableName())); } jdtTreeBuilder.getReferencesBuilder().setPackageOrDeclaringType(typeReference, jdtTreeBuilder.getReferencesBuilder().getDeclaringReferenceFromImports(singleNameReference.token)); return jdtTreeBuilder.getFactory().Code().createTypeAccess(typeReference); } /** * Creates the target of a field access. * * @param qualifiedNameReference * Used to get the declaring class of the target. * @param ref * Used in a static context. * @return an expression. */ CtExpression<?> createTargetFieldAccess(QualifiedNameReference qualifiedNameReference, CtFieldReference<Object> ref) { CtExpression<?> target = null; if (JDTTreeBuilderQuery.isValidProblemBindingField(qualifiedNameReference)) { target = createTypeAccessNoClasspath(qualifiedNameReference); } else if (ref.isStatic()) { target = createTypeAccess(qualifiedNameReference, ref); } else if (!ref.isStatic() && !ref.getDeclaringType().isAnonymous()) { target = jdtTreeBuilder.getFactory().Code().createThisAccess(jdtTreeBuilder.getReferencesBuilder().<Object>getTypeReference(qualifiedNameReference.actualReceiverType), true); } return target; } /** * Creates a parameter. If the argument have a type == null, we get the type from its binding. A type == null is possible when * this type is implicit like in a lambda where you don't need to specify the type of parameters. * * @param argument * Used to get the name of the parameter, the modifiers, know if it is a var args parameter. * @return a parameter. */ <T> CtParameter<T> createParameter(Argument argument) { CtParameter<T> p = jdtTreeBuilder.getFactory().Core().createParameter(); p.setSimpleName(CharOperation.charToString(argument.name)); p.setVarArgs(argument.isVarArgs()); p.setModifiers(getModifiers(argument.modifiers)); if (argument.binding != null && argument.binding.type != null && argument.type == null) { p.setType(jdtTreeBuilder.getReferencesBuilder().<T>getTypeReference(argument.binding.type)); p.getType().setImplicit(argument.type == null); if (p.getType() instanceof CtArrayTypeReference) { ((CtArrayTypeReference) p.getType()).getComponentType().setImplicit(argument.type == null); } } return p; } /** * Creates an executable reference expression. * * @param referenceExpression * Used to get the executable reference. * @return an executable reference expression. */ <T, E extends CtExpression<?>> CtExecutableReferenceExpression<T, E> createExecutableReferenceExpression(ReferenceExpression referenceExpression) { CtExecutableReferenceExpression<T, E> executableRef = jdtTreeBuilder.getFactory().Core().createExecutableReferenceExpression(); CtExecutableReference<T> executableReference = jdtTreeBuilder.getReferencesBuilder().getExecutableReference(referenceExpression.binding); if (executableReference == null) { // No classpath mode. executableReference = jdtTreeBuilder.getFactory().Core().createExecutableReference(); executableReference.setSimpleName(CharOperation.charToString(referenceExpression.selector)); executableReference.setDeclaringType(jdtTreeBuilder.getReferencesBuilder().getTypeReference(referenceExpression.lhs.resolvedType)); } final CtTypeReference<T> declaringType = (CtTypeReference<T>) executableReference.getDeclaringType(); executableReference.setType(declaringType == null ? null : declaringType.clone()); executableRef.setExecutable(executableReference); return executableRef; } /** * Creates a class, an enum, an interface or a annotation type. * * @return a type. */ CtType<?> createType(TypeDeclaration typeDeclaration) { CtType<?> type; if ((typeDeclaration.modifiers & ClassFileConstants.AccAnnotation) != 0) { type = jdtTreeBuilder.getFactory().Core().<java.lang.annotation.Annotation>createAnnotationType(); } else if ((typeDeclaration.modifiers & ClassFileConstants.AccEnum) != 0) { type = jdtTreeBuilder.getFactory().Core().createEnum(); } else if ((typeDeclaration.modifiers & ClassFileConstants.AccInterface) != 0) { type = jdtTreeBuilder.getFactory().Core().createInterface(); } else { type = jdtTreeBuilder.getFactory().Core().createClass(); } jdtTreeBuilder.getContextBuilder().enter(type, typeDeclaration); if (typeDeclaration.superInterfaces != null) { for (TypeReference ref : typeDeclaration.superInterfaces) { final CtTypeReference superInterface = jdtTreeBuilder.references.buildTypeReference(ref, null); type.addSuperInterface(superInterface); } } if (type instanceof CtClass) { if (typeDeclaration.superclass != null) { ((CtClass) type).setSuperclass(jdtTreeBuilder.references.buildTypeReference(typeDeclaration.superclass, typeDeclaration.scope)); } if (typeDeclaration.binding.isAnonymousType() || (typeDeclaration.binding instanceof LocalTypeBinding && typeDeclaration.binding.enclosingMethod() != null)) { type.setSimpleName(computeAnonymousName(typeDeclaration.binding.constantPoolName())); } else { type.setSimpleName(new String(typeDeclaration.name)); } } else { type.setSimpleName(new String(typeDeclaration.name)); } // Setting modifiers type.setModifiers(getModifiers(typeDeclaration.modifiers)); return type; } }