/******************************************************************************* * Copyright (c) 2000, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Jesper Steen Moller - bug 341232 *******************************************************************************/ package org.eclipse.jdt.internal.debug.eval.ast.engine; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Stack; import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.ISourceRange; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.Signature; import org.eclipse.jdt.core.SourceRange; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration; import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; import org.eclipse.jdt.core.dom.ArrayAccess; import org.eclipse.jdt.core.dom.ArrayCreation; import org.eclipse.jdt.core.dom.ArrayInitializer; import org.eclipse.jdt.core.dom.ArrayType; import org.eclipse.jdt.core.dom.AssertStatement; import org.eclipse.jdt.core.dom.Assignment; import org.eclipse.jdt.core.dom.Block; import org.eclipse.jdt.core.dom.BlockComment; import org.eclipse.jdt.core.dom.BodyDeclaration; import org.eclipse.jdt.core.dom.BooleanLiteral; import org.eclipse.jdt.core.dom.BreakStatement; import org.eclipse.jdt.core.dom.CastExpression; import org.eclipse.jdt.core.dom.CatchClause; import org.eclipse.jdt.core.dom.CharacterLiteral; import org.eclipse.jdt.core.dom.ClassInstanceCreation; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.ConditionalExpression; import org.eclipse.jdt.core.dom.ConstructorInvocation; import org.eclipse.jdt.core.dom.ContinueStatement; import org.eclipse.jdt.core.dom.DoStatement; import org.eclipse.jdt.core.dom.EmptyStatement; import org.eclipse.jdt.core.dom.EnhancedForStatement; import org.eclipse.jdt.core.dom.EnumConstantDeclaration; import org.eclipse.jdt.core.dom.EnumDeclaration; import org.eclipse.jdt.core.dom.ExpressionStatement; import org.eclipse.jdt.core.dom.FieldAccess; import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.ForStatement; import org.eclipse.jdt.core.dom.IfStatement; import org.eclipse.jdt.core.dom.ImportDeclaration; import org.eclipse.jdt.core.dom.InfixExpression; import org.eclipse.jdt.core.dom.Initializer; import org.eclipse.jdt.core.dom.InstanceofExpression; import org.eclipse.jdt.core.dom.Javadoc; import org.eclipse.jdt.core.dom.LabeledStatement; import org.eclipse.jdt.core.dom.LineComment; import org.eclipse.jdt.core.dom.MarkerAnnotation; import org.eclipse.jdt.core.dom.MemberRef; import org.eclipse.jdt.core.dom.MemberValuePair; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.MethodRef; import org.eclipse.jdt.core.dom.MethodRefParameter; import org.eclipse.jdt.core.dom.Modifier; import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.NormalAnnotation; import org.eclipse.jdt.core.dom.NullLiteral; import org.eclipse.jdt.core.dom.NumberLiteral; import org.eclipse.jdt.core.dom.PackageDeclaration; import org.eclipse.jdt.core.dom.ParameterizedType; import org.eclipse.jdt.core.dom.ParenthesizedExpression; import org.eclipse.jdt.core.dom.PostfixExpression; import org.eclipse.jdt.core.dom.PrefixExpression; import org.eclipse.jdt.core.dom.PrimitiveType; import org.eclipse.jdt.core.dom.QualifiedName; import org.eclipse.jdt.core.dom.QualifiedType; import org.eclipse.jdt.core.dom.ReturnStatement; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SimpleType; import org.eclipse.jdt.core.dom.SingleMemberAnnotation; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.StringLiteral; import org.eclipse.jdt.core.dom.SuperConstructorInvocation; import org.eclipse.jdt.core.dom.SuperFieldAccess; import org.eclipse.jdt.core.dom.SuperMethodInvocation; import org.eclipse.jdt.core.dom.SwitchCase; import org.eclipse.jdt.core.dom.SwitchStatement; import org.eclipse.jdt.core.dom.SynchronizedStatement; import org.eclipse.jdt.core.dom.TagElement; import org.eclipse.jdt.core.dom.TextElement; import org.eclipse.jdt.core.dom.ThisExpression; import org.eclipse.jdt.core.dom.ThrowStatement; import org.eclipse.jdt.core.dom.TryStatement; import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.TypeDeclarationStatement; import org.eclipse.jdt.core.dom.TypeLiteral; import org.eclipse.jdt.core.dom.TypeParameter; import org.eclipse.jdt.core.dom.UnionType; import org.eclipse.jdt.core.dom.VariableDeclarationExpression; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.dom.VariableDeclarationStatement; import org.eclipse.jdt.core.dom.WhileStatement; import org.eclipse.jdt.core.dom.WildcardType; import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; public class SourceBasedSourceGenerator extends ASTVisitor { private static final String RUN_METHOD_NAME = "___run"; //$NON-NLS-1$ private static final String EVAL_METHOD_NAME = "___eval"; //$NON-NLS-1$ private static final String EVAL_FIELD_NAME = "___field"; //$NON-NLS-1$ private String[] fLocalVariableTypeNames; private String[] fLocalVariableNames; private String fCodeSnippet; private boolean fRightTypeFound; private boolean fCreateInAStaticMethod; private boolean fEvaluateNextEndTypeDeclaration; private String fError; private IType fType; private int fLine; private StringBuffer fSource; private String fLastTypeName; private String fCompilationUnitName; private int fSnippetStartPosition; private int fRunMethodStartOffset; private int fRunMethodLength; /** * Level of source code to generate (major, minor). For example 1 and 4 * indicates 1.4. */ private int fSourceMajorLevel; private int fSourceMinorLevel; private Stack<Map<String, String>> fTypeParameterStack = new Stack<>(); private Map<String, String> fMatchingTypeParameters = null; private CompilationUnit fCompilationUnit; { fTypeParameterStack.push(Collections.<String,String>emptyMap()); } /** * if the <code>createInAnInstanceMethod</code> flag is set, the method * created which contains the code snippet is an no-static method, even if * <code>position</code> is in a static method. * * @param type * the root {@link IType} * @param sourcePosition * the reference position in the type's source * @param createInAStaticMethod * if the source should be generated * @param localTypesNames * the array of local type names * @param localVariables * the listing of local variable names * @param codeSnippet * the code snippet * @param sourceLevel * the desired source level */ public SourceBasedSourceGenerator(IType type, int line, boolean createInAStaticMethod, String[] localTypesNames, String[] localVariables, String codeSnippet, String sourceLevel) { fRightTypeFound = false; fType = type; fLine = line; fLocalVariableTypeNames = localTypesNames; fLocalVariableNames = localVariables; fCodeSnippet = codeSnippet; fCreateInAStaticMethod = createInAStaticMethod; int index = sourceLevel.indexOf('.'); String num = sourceLevel.substring(0, index); fSourceMajorLevel = Integer.valueOf(num).intValue(); num = sourceLevel.substring(index + 1); fSourceMinorLevel = Integer.valueOf(num).intValue(); } /** * Returns the generated source or <code>null</code> if no source can be * generated. * * @return returns the backing source from the generator */ public String getSource() { if (fSource == null) { return null; } return fSource.toString(); } public String getCompilationUnitName() { return fCompilationUnitName; } public int getSnippetStart() { return fSnippetStartPosition; } public int getRunMethodStart() { return fSnippetStartPosition - fRunMethodStartOffset; } public int getRunMethodLength() { return fRunMethodLength; } private boolean rightTypeFound() { return fRightTypeFound; } private void setRightTypeFound(boolean value) { fRightTypeFound = value; } public boolean hasError() { return fError != null; } public void setError(String errorDesc) { fError = errorDesc; } public String getError() { return fError; } private StringBuffer buildRunMethod(List<BodyDeclaration> bodyDeclarations) { StringBuffer buffer = new StringBuffer(); if (fCreateInAStaticMethod) { buffer.append("static "); //$NON-NLS-1$ } adddTypeParameters(buffer); buffer.append("void "); //$NON-NLS-1$ buffer.append(getUniqueMethodName(RUN_METHOD_NAME, bodyDeclarations)); buffer.append('('); for (int i = 0, length = fLocalVariableNames.length; i < length; i++) { buffer.append(getDotName(fLocalVariableTypeNames[i])); buffer.append(' '); buffer.append(fLocalVariableNames[i]); if (i + 1 < length) buffer.append(", "); //$NON-NLS-1$ } buffer.append(") throws Throwable {"); //$NON-NLS-1$ buffer.append('\n'); fSnippetStartPosition = buffer.length() - 2; fRunMethodStartOffset = fSnippetStartPosition; String codeSnippet = new String(fCodeSnippet).trim(); buffer.append(codeSnippet); buffer.append('\n'); buffer.append('}').append('\n'); fRunMethodLength = buffer.length(); return buffer; } private String getDotName(String typeName) { return typeName.replace('$', '.'); } /** * Adds generic type parameters as needed to the given buffer * * @param buffer * @since 3.8.0 */ void adddTypeParameters(StringBuffer buffer) { if (isSourceLevelGreaterOrEqual(1, 5)) { Collection<String> activeTypeParameters = (fMatchingTypeParameters != null ? fMatchingTypeParameters : fTypeParameterStack.peek()).values(); if (!activeTypeParameters.isEmpty()) { Iterator<String> iterator = activeTypeParameters.iterator(); buffer.append(Signature.C_GENERIC_START); while (iterator.hasNext()) { String name = iterator.next(); buffer.append(name); if (iterator.hasNext()) { buffer.append(", "); //$NON-NLS-1$ } } buffer.append(Signature.C_GENERIC_END); buffer.append(' '); } } } /** * Returns if the specified {@link ASTNode} has the 'correct' parent type to * match the current type name context * * @param node * the {@link ASTNode} to check source ranges for * @return true if the parent type of the given node matches the current * type name context, false otherwise */ private boolean isRightType(ASTNode node) { try { switch(node.getNodeType()) { case ASTNode.ANNOTATION_TYPE_DECLARATION: case ASTNode.ENUM_DECLARATION: case ASTNode.TYPE_DECLARATION: { AbstractTypeDeclaration decl = (AbstractTypeDeclaration) node; SimpleName name = decl.getName(); ISourceRange range = new SourceRange(name.getStartPosition(), name.getLength()); return fType.getNameRange().equals(range); } case ASTNode.ANONYMOUS_CLASS_DECLARATION: { return isRightType(node.getParent()); } case ASTNode.CLASS_INSTANCE_CREATION: { ClassInstanceCreation decl = (ClassInstanceCreation) node; Type type = decl.getType(); ISourceRange name = fType.getNameRange(); return name.getOffset() >= type.getStartPosition() && name.getOffset()+name.getLength() <= type.getStartPosition()+type.getLength(); } } } catch(JavaModelException jme) { JDIDebugPlugin.log(jme); } return false; } private StringBuffer buildTypeBody(StringBuffer buffer, List<BodyDeclaration> list) { StringBuffer source = new StringBuffer(); source.append('{').append('\n'); if (buffer != null) { fSnippetStartPosition += source.length(); } source.append(buildBody(buffer, list)); source.append('}').append('\n'); return source; } private StringBuffer buildEnumBody(StringBuffer buffer, List<EnumConstantDeclaration> constantDeclarations, List<BodyDeclaration> bodyDeclarations) { StringBuffer source = new StringBuffer(); source.append('{').append('\n'); if (constantDeclarations.isEmpty()) { source.append(';').append('\n'); } else { for (Iterator<EnumConstantDeclaration> iter = constantDeclarations.iterator(); iter .hasNext();) { source.append(iter.next().getName() .getIdentifier()); if (iter.hasNext()) { source.append(','); } else { source.append(';'); } source.append('\n'); } } if (buffer != null) { fSnippetStartPosition += source.length(); } source.append(buildBody(buffer, bodyDeclarations)); source.append('}').append('\n'); return source; } /** * Builds up the given buffer with the source from each of * {@link BodyDeclaration}s in the given list * * @param buffer * the buffer to clone and append to * @param list * the list of {@link BodyDeclaration}s * @return the new source buffer */ private StringBuffer buildBody(StringBuffer buffer, List<BodyDeclaration> list) { StringBuffer source = new StringBuffer(); if (buffer != null) { fSnippetStartPosition += source.length(); source.append(buffer.toString()); } for (Iterator<BodyDeclaration> iterator = list.iterator(); iterator.hasNext();) { BodyDeclaration bodyDeclaration = iterator.next(); if (bodyDeclaration instanceof FieldDeclaration) { source.append(buildFieldDeclaration((FieldDeclaration) bodyDeclaration)); } else if (bodyDeclaration instanceof MethodDeclaration) { source.append(buildMethodDeclaration((MethodDeclaration) bodyDeclaration)); } else if (bodyDeclaration instanceof TypeDeclaration) { TypeDeclaration typeDeclaration = (TypeDeclaration) bodyDeclaration; if (!typeDeclaration.getName().getIdentifier() .equals(fLastTypeName)) { source.append(buildTypeDeclaration(null, typeDeclaration)); } } else if (bodyDeclaration instanceof EnumDeclaration) { EnumDeclaration enumDeclaration = (EnumDeclaration) bodyDeclaration; if (!enumDeclaration.getName().getIdentifier() .equals(fLastTypeName)) { source.append(buildEnumDeclaration(null, enumDeclaration)); } } } return source; } private StringBuffer buildFieldDeclaration(FieldDeclaration fieldDeclaration) { StringBuffer source = new StringBuffer(); source.append(Flags.toString(fieldDeclaration.getModifiers())); source.append(' '); source.append(getDotName(getTypeName(fieldDeclaration.getType()))); source.append(' '); boolean first = true; for (Iterator<VariableDeclarationFragment> iterator = fieldDeclaration.fragments().iterator(); iterator .hasNext();) { VariableDeclarationFragment variableDeclarationFragment = iterator .next(); if (first) { first = false; } else { source.append(','); } source.append(variableDeclarationFragment.getName().getIdentifier()); for (int i = 0, dim = variableDeclarationFragment .getExtraDimensions(); i < dim; i++) { source.append('[').append(']'); } } source.append(';').append('\n'); return source; } private StringBuffer buildMethodDeclaration( MethodDeclaration methodDeclaration) { StringBuffer source = new StringBuffer(); int modifiers = methodDeclaration.getModifiers(); source.append(Flags.toString(modifiers)); source.append(' '); appendTypeParameters(source, methodDeclaration.typeParameters()); boolean isConstructor = methodDeclaration.isConstructor(); if (!isConstructor) { source.append(getDotName(getTypeName(methodDeclaration .getReturnType2()))); source.append(' '); } source.append(methodDeclaration.getName().getIdentifier()); source.append(' ').append('('); boolean first = true; for (Iterator<SingleVariableDeclaration> iterator = methodDeclaration.parameters().iterator(); iterator .hasNext();) { SingleVariableDeclaration singleVariableDeclaration = iterator .next(); if (first) { first = false; } else { source.append(','); } source.append(getDotName(getTypeName(singleVariableDeclaration .getType()))); if (singleVariableDeclaration.isVarargs()) { source.append("..."); //$NON-NLS-1$ } source.append(' '); source.append(singleVariableDeclaration.getName().getIdentifier()); appendExtraDimensions(source, singleVariableDeclaration.getExtraDimensions()); } source.append(')'); appendExtraDimensions(source, methodDeclaration.getExtraDimensions()); first = true; for (Iterator<Name> iterator = methodDeclaration.thrownExceptions() .iterator(); iterator.hasNext();) { Name name = iterator.next(); if (first) { first = false; source.append(" throws "); //$NON-NLS-1$ } else { source.append(','); } source.append(getQualifiedIdentifier(name)); } if (Flags.isAbstract(modifiers) || Flags.isNative(modifiers)) { // No body for abstract and native methods source.append(";\n"); //$NON-NLS-1$ } else { source.append('{').append('\n'); if (!isConstructor) { source.append(getReturnExpression(methodDeclaration .getReturnType2())); } source.append('}').append('\n'); } return source; } private void appendExtraDimensions(StringBuffer source, int extraDimension) { if (extraDimension > 0) { source.append(' '); for (int i = 0; i < extraDimension; i++) { source.append("[]"); //$NON-NLS-1$ } } } private StringBuffer buildEnumDeclaration(StringBuffer buffer, EnumDeclaration enumDeclaration) { StringBuffer source = new StringBuffer(); source.append(Flags.toString(enumDeclaration.getModifiers())); source.append(" enum "); //$NON-NLS-1$ source.append(enumDeclaration.getName().getIdentifier()); Iterator<Type> iterator = enumDeclaration.superInterfaceTypes().iterator(); if (iterator.hasNext()) { source.append(" implements "); //$NON-NLS-1$ source.append(getTypeName(iterator.next())); while (iterator.hasNext()) { source.append(','); source.append(getTypeName(iterator.next())); } } if (buffer != null) { fSnippetStartPosition += source.length(); } source.append(buildEnumBody(buffer, enumDeclaration.enumConstants(), enumDeclaration.bodyDeclarations())); return source; } private StringBuffer buildTypeDeclaration(StringBuffer buffer, TypeDeclaration typeDeclaration) { StringBuffer source = new StringBuffer(); source.append(Flags.toString(typeDeclaration.getModifiers())); if (typeDeclaration.isInterface()) { source.append(" interface "); //$NON-NLS-1$ } else { source.append(" class "); //$NON-NLS-1$ } source.append(typeDeclaration.getName().getIdentifier()); List<TypeParameter> typeParameters = typeDeclaration.typeParameters(); if (!typeParameters.isEmpty() && isSourceLevelGreaterOrEqual(1, 5)) { source.append('<'); Iterator<TypeParameter> iter = typeParameters.iterator(); TypeParameter typeParameter = iter.next(); source.append(typeParameter.getName().getIdentifier()); List<Type> typeBounds = typeParameter.typeBounds(); if (!typeBounds.isEmpty()) { source.append(" extends "); //$NON-NLS-1$ Iterator<Type> iter2 = typeBounds.iterator(); source.append(getTypeName(iter2.next())); while (iter2.hasNext()) { source.append('&'); source.append(getTypeName(iter2.next())); } } while (iter.hasNext()) { source.append(','); typeParameter = iter.next(); source.append(typeParameter.getName().getIdentifier()); typeBounds = typeParameter.typeBounds(); if (!typeBounds.isEmpty()) { source.append(" extends "); //$NON-NLS-1$ Iterator<Type> iter2 = typeBounds.iterator(); source.append(getTypeName(iter2.next())); while (iter2.hasNext()) { source.append('&'); source.append(getTypeName(iter2.next())); } } } source.append('>'); } Type superClass = typeDeclaration.getSuperclassType(); if (superClass != null) { source.append(" extends "); //$NON-NLS-1$ source.append(getTypeName(superClass)); } Iterator<Type> iter = typeDeclaration.superInterfaceTypes().iterator(); if (iter.hasNext()) { if (typeDeclaration.isInterface()) { source.append(" extends "); //$NON-NLS-1$ } else { source.append(" implements "); //$NON-NLS-1$ } source.append(getTypeName(iter.next())); while (iter.hasNext()) { source.append(','); source.append(getTypeName(iter.next())); } } if (buffer != null) { fSnippetStartPosition += source.length(); } source.append(buildTypeBody(buffer, typeDeclaration.bodyDeclarations())); return source; } private StringBuffer buildCompilationUnit(StringBuffer buffer, CompilationUnit compilationUnit) { StringBuffer source = new StringBuffer(); PackageDeclaration packageDeclaration = compilationUnit.getPackage(); if (packageDeclaration != null) { source.append("package "); //$NON-NLS-1$ source.append(getQualifiedIdentifier(packageDeclaration.getName())); source.append(";\n"); //$NON-NLS-1$ } for (Iterator<ImportDeclaration> iterator = compilationUnit.imports().iterator(); iterator .hasNext();) { ImportDeclaration importDeclaration = iterator .next(); source.append("import "); //$NON-NLS-1$ if (importDeclaration.isStatic()) { source.append("static "); //$NON-NLS-1$ } source.append(getQualifiedIdentifier(importDeclaration.getName())); if (importDeclaration.isOnDemand()) { source.append(".*"); //$NON-NLS-1$ } source.append(";\n"); //$NON-NLS-1$ } fSnippetStartPosition += source.length(); source.append(buffer); for (Iterator<TypeDeclaration> iterator = compilationUnit.types().iterator(); iterator .hasNext();) { AbstractTypeDeclaration typeDeclaration = iterator.next(); if (Flags.isPublic(typeDeclaration.getModifiers())) { fCompilationUnitName = typeDeclaration.getName() .getIdentifier(); } if (!fLastTypeName .equals(typeDeclaration.getName().getIdentifier())) { if (typeDeclaration instanceof TypeDeclaration) { source.append(buildTypeDeclaration(null, (TypeDeclaration) typeDeclaration)); } else if (typeDeclaration instanceof EnumDeclaration) { source.append(buildEnumDeclaration(null, (EnumDeclaration) typeDeclaration)); } } } if (fCompilationUnitName == null) { // If no public class was found, the compilation unit // name doesn't matter. fCompilationUnitName = "Eval"; //$NON-NLS-1$ } return source; } /** * Returns a method name that will be unique in the generated source. The * generated name is baseName plus as many '_' characters as necessary to * not duplicate an existing method name. * * @param methodName * the method name to look for * @param bodyDeclarations * the listing of {@link BodyDeclaration}s to search through * @return the unique method name */ private String getUniqueMethodName(String methodName, List<BodyDeclaration> bodyDeclarations) { Iterator<BodyDeclaration> iter = bodyDeclarations.iterator(); BodyDeclaration bodyDeclaration; MethodDeclaration method; String foundName; while (iter.hasNext()) { bodyDeclaration = iter.next(); if (bodyDeclaration instanceof MethodDeclaration) { method = (MethodDeclaration) bodyDeclaration; foundName = method.getName().getIdentifier(); if (foundName.startsWith(methodName)) { methodName = foundName + '_'; } } } return methodName; } /** * Returns a field name that will be unique in the generated source. The * generated name is baseName plus as many '_' characters as necessary to * not duplicate an existing method name. * * @param fieldName * the name of the field to look for * @param bodyDeclarations * the list of {@link BodyDeclaration}s to search through * @return the unique field name */ private String getUniqueFieldName(String fieldName, List<BodyDeclaration> bodyDeclarations) { Iterator<BodyDeclaration> iter = bodyDeclarations.iterator(); BodyDeclaration bodyDeclaration; FieldDeclaration fieldDeclaration; String foundName; while (iter.hasNext()) { bodyDeclaration = iter.next(); if (bodyDeclaration instanceof FieldDeclaration) { fieldDeclaration = (FieldDeclaration) bodyDeclaration; for (Iterator<VariableDeclarationFragment> iterator = fieldDeclaration.fragments() .iterator(); iterator.hasNext();) { foundName = iterator.next() .getName().getIdentifier(); if (foundName.startsWith(fieldName)) { fieldName = foundName + '_'; } } } } return fieldName; } private String getQualifiedIdentifier(Name name) { String typeName = ""; //$NON-NLS-1$ while (name.isQualifiedName()) { QualifiedName qualifiedName = (QualifiedName) name; typeName = "." + qualifiedName.getName().getIdentifier() + typeName; //$NON-NLS-1$ name = qualifiedName.getQualifier(); } if (name.isSimpleName()) { typeName = ((SimpleName) name).getIdentifier() + typeName; } else { return null; } return typeName; } public String getTypeName(Type type) { if (type.isSimpleType()) { String name = getQualifiedIdentifier(((SimpleType) type).getName()); if (!isSourceLevelGreaterOrEqual(1, 5) && fTypeParameterStack.peek().containsKey(name)) { return "Object"; //$NON-NLS-1$ } return name; } else if (type.isArrayType()) { return getTypeName(((ArrayType) type).getComponentType()) + "[]"; //$NON-NLS-1$ } else if (type.isPrimitiveType()) { return ((PrimitiveType) type).getPrimitiveTypeCode().toString(); } else if (type.isQualifiedType()) { QualifiedType qualifiedType = (QualifiedType) type; return getTypeName(qualifiedType.getQualifier()) + '.' + qualifiedType.getName().getIdentifier(); } else if (type.isParameterizedType()) { ParameterizedType parameterizedType = (ParameterizedType) type; StringBuffer buff = new StringBuffer( getTypeName(parameterizedType.getType())); Iterator<Type> iter = parameterizedType.typeArguments().iterator(); if (iter.hasNext() && isSourceLevelGreaterOrEqual(1, 5)) { buff.append('<'); buff.append(getTypeName(iter.next())); while (iter.hasNext()) { buff.append(','); buff.append(getTypeName(iter.next())); } buff.append('>'); } return buff.toString(); } else if (type.isWildcardType()) { WildcardType wildcardType = (WildcardType) type; StringBuffer buff = new StringBuffer("?"); //$NON-NLS-1$ Type bound = wildcardType.getBound(); if (bound != null) { buff.append(wildcardType.isUpperBound() ? " extends " : " super "); //$NON-NLS-1$ //$NON-NLS-2$ buff.append(getTypeName(bound)); } return buff.toString(); } return null; } public String getReturnExpression(Type type) { if (type.isSimpleType() || type.isArrayType() || type.isQualifiedType() || type.isWildcardType() || type.isParameterizedType()) { return "return null;"; //$NON-NLS-1$ } else if (type.isPrimitiveType()) { String typeName = ((PrimitiveType) type).getPrimitiveTypeCode() .toString(); char char0 = typeName.charAt(0); if (char0 == 'v') { return ""; //$NON-NLS-1$ } char char1 = typeName.charAt(1); if (char0 == 'b' && char1 == 'o') { return "return false;"; //$NON-NLS-1$ } return "return 0;"; //$NON-NLS-1$ } return null; } // ---------------------- /** * @see ASTVisitor#endVisit(ClassInstanceCreation) */ @Override public void endVisit(ClassInstanceCreation node) { if (hasError()) { return; } AnonymousClassDeclaration anonymousClassDeclaration = node .getAnonymousClassDeclaration(); if (anonymousClassDeclaration != null) { if (!rightTypeFound() && isRightType(node)) { setRightTypeFound(true); fSource = buildRunMethod(anonymousClassDeclaration .bodyDeclarations()); fEvaluateNextEndTypeDeclaration = true; } if (rightTypeFound()) { List<BodyDeclaration> bodyDeclarations = anonymousClassDeclaration .bodyDeclarations(); StringBuffer source = buildTypeBody(fSource, bodyDeclarations); ASTNode parent = node.getParent(); while (!(parent instanceof MethodDeclaration || parent instanceof FieldDeclaration || parent instanceof Initializer) && parent != null) { parent = parent.getParent(); } fSource = new StringBuffer(); if (parent instanceof Initializer) { buildAnonymousEvalMethod(true, bodyDeclarations, getTypeName(node.getType()), source); } else if (parent instanceof MethodDeclaration) { MethodDeclaration enclosingMethodDeclaration = (MethodDeclaration) parent; buildAnonymousEvalMethod( Flags.isStatic(enclosingMethodDeclaration .getModifiers()), bodyDeclarations, getTypeName(node.getType()), source); } else if (parent instanceof FieldDeclaration) { FieldDeclaration enclosingFieldDeclaration = (FieldDeclaration) parent; if (Flags .isStatic(enclosingFieldDeclaration.getModifiers())) { fSource.append("static "); //$NON-NLS-1$ } Type type = getParentType(enclosingFieldDeclaration .getType()); fSource.append(getQualifiedIdentifier(((SimpleType) type) .getName())); fSource.append(' '); fSource.append(getUniqueFieldName(EVAL_FIELD_NAME, bodyDeclarations)); fSource.append(" = new "); //$NON-NLS-1$ fSource.append(getTypeName(node.getType())); fSource.append("()"); //$NON-NLS-1$ fSnippetStartPosition += fSource.length(); fSource.append(source); fSource.append(";\n"); //$NON-NLS-1$ } fLastTypeName = ""; //$NON-NLS-1$ } } } /** * Create a <code>void ____eval()</code> method considering the given * {@link BodyDeclaration}s, type name and existing body source when an * anonymous {@link ClassInstanceCreation} is visited. <br> * <br> * This method adds the new <code>___eval</code> method source to the root * {@link #fSource} variable directly * * @param isstatic * if the keyword <code>static</code> should be added to the * method source * @param bodydecls * the existing listing of {@link BodyDeclaration}s to consider * when creating the <code>___eval</code> method name * @param typename * the raw type name of the type to instantiate in the * <code>___eval</code> method * @param body * the existing body of source to append to the remainder of the * new method * @since 3.7 */ void buildAnonymousEvalMethod(boolean isstatic, List<BodyDeclaration> bodydecls, String typename, StringBuffer body) { if (isstatic) { fSource.append("static "); //$NON-NLS-1$ } adddTypeParameters(fSource); fSource.append("void "); //$NON-NLS-1$ fSource.append(getUniqueMethodName(EVAL_METHOD_NAME, bodydecls)); fSource.append("() {\n"); //$NON-NLS-1$ fSource.append("new "); //$NON-NLS-1$ fSource.append(typename); fSource.append("()"); //$NON-NLS-1$ fSnippetStartPosition += fSource.length(); fSource.append(body); fSource.append(";}\n"); //$NON-NLS-1$ } /** * Recursively finds the parent {@link Type} from the given type, in the * cases where the type is an {@link ArrayType} or a * {@link ParameterizedType} * * @param type * the {@link Type} * @return the parent {@link Type} */ private Type getParentType(Type type) { if (type instanceof ArrayType) { return getParentType(((ArrayType) type).getComponentType()); } if (type instanceof ParameterizedType) { return getParentType(((ParameterizedType) type).getType()); } return type; } /** * @see ASTVisitor#endVisit(CompilationUnit) */ @Override public void endVisit(CompilationUnit node) { if (hasError()) { return; } if (!rightTypeFound()) { // if the right type hasn't been found fSource = null; return; } fSource = buildCompilationUnit(fSource, node); } /* * (non-Javadoc) * * @see * org.eclipse.jdt.core.dom.ASTVisitor#endVisit(org.eclipse.jdt.core.dom * .EnumDeclaration) */ @Override public void endVisit(EnumDeclaration node) { if (hasError()) { return; } if (!rightTypeFound() && isRightType(node)) { setRightTypeFound(true); fSource = buildRunMethod(node.bodyDeclarations()); fEvaluateNextEndTypeDeclaration = true; } if (!fEvaluateNextEndTypeDeclaration) { fEvaluateNextEndTypeDeclaration = true; return; } if (rightTypeFound()) { StringBuffer source = buildEnumDeclaration(fSource, node); if (node.isLocalTypeDeclaration()) { // enclose in a method if necessary ASTNode parent = node.getParent(); while (!(parent instanceof MethodDeclaration)) { parent = parent.getParent(); } MethodDeclaration enclosingMethodDeclaration = (MethodDeclaration) parent; fSource = new StringBuffer(); if (Flags.isStatic(enclosingMethodDeclaration.getModifiers())) { fSource.append("static "); //$NON-NLS-1$ } fSource.append("void ___eval() {\n"); //$NON-NLS-1$ fSnippetStartPosition += fSource.length(); fSource.append(source); fSource.append("}\n"); //$NON-NLS-1$ fLastTypeName = ""; //$NON-NLS-1$ } else { fSource = source; fLastTypeName = node.getName().getIdentifier(); } } } /* (non-Javadoc) * @see org.eclipse.jdt.core.dom.ASTVisitor#endVisit(org.eclipse.jdt.core.dom.MethodDeclaration) */ @Override public void endVisit(MethodDeclaration node) { fTypeParameterStack.pop(); } /** * @see ASTVisitor#endVisit(TypeDeclaration) */ @Override public void endVisit(TypeDeclaration node) { if (hasError()) { fTypeParameterStack.pop(); return; } if (!rightTypeFound() && isRightType(node)) { setRightTypeFound(true); fSource = buildRunMethod(node.bodyDeclarations()); fEvaluateNextEndTypeDeclaration = true; } if (!fEvaluateNextEndTypeDeclaration) { fEvaluateNextEndTypeDeclaration = true; fTypeParameterStack.pop(); return; } if (rightTypeFound()) { StringBuffer source = buildTypeDeclaration(fSource, node); if (node.isLocalTypeDeclaration()) { // enclose in a method if nessecary ASTNode parent = node.getParent(); while (!(parent instanceof MethodDeclaration)) { parent = parent.getParent(); } MethodDeclaration enclosingMethodDeclaration = (MethodDeclaration) parent; fSource = new StringBuffer(); if (Flags.isStatic(enclosingMethodDeclaration.getModifiers())) { fSource.append("static "); //$NON-NLS-1$ } fSource.append("void ___eval() {\n"); //$NON-NLS-1$ fSnippetStartPosition += fSource.length(); fSource.append(source); fSource.append("}\n"); //$NON-NLS-1$ fLastTypeName = ""; //$NON-NLS-1$ } else { fSource = source; fLastTypeName = node.getName().getIdentifier(); } } fTypeParameterStack.pop(); } /* * (non-Javadoc) * * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. * AnnotationTypeDeclaration) */ @Override public boolean visit(AnnotationTypeDeclaration node) { return false; } /* * (non-Javadoc) * * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. * AnnotationTypeMemberDeclaration) */ @Override public boolean visit(AnnotationTypeMemberDeclaration node) { return false; } /** * @see ASTVisitor#visit(AnonymousClassDeclaration) */ @Override public boolean visit(AnonymousClassDeclaration node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(ArrayAccess) */ @Override public boolean visit(ArrayAccess node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(ArrayCreation) */ @Override public boolean visit(ArrayCreation node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(ArrayInitializer) */ @Override public boolean visit(ArrayInitializer node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(ArrayType) */ @Override public boolean visit(ArrayType node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(AssertStatement) */ @Override public boolean visit(AssertStatement node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(Assignment) */ @Override public boolean visit(Assignment node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(Block) */ @Override public boolean visit(Block node) { if (rightTypeFound()) { return false; } return true; } /* * (non-Javadoc) * * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. * BlockComment) */ @Override public boolean visit(BlockComment node) { return false; } /** * @see ASTVisitor#visit(BooleanLiteral) */ @Override public boolean visit(BooleanLiteral node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(BreakStatement) */ @Override public boolean visit(BreakStatement node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(CastExpression) */ @Override public boolean visit(CastExpression node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(CatchClause) */ @Override public boolean visit(CatchClause node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(CharacterLiteral) */ @Override public boolean visit(CharacterLiteral node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(ClassInstanceCreation) */ @Override public boolean visit(ClassInstanceCreation node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(CompilationUnit) */ @Override public boolean visit(CompilationUnit node) { fCompilationUnit = node; if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(ConditionalExpression) */ @Override public boolean visit(ConditionalExpression node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(ConstructorInvocation) */ @Override public boolean visit(ConstructorInvocation node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(ContinueStatement) */ @Override public boolean visit(ContinueStatement node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(DoStatement) */ @Override public boolean visit(DoStatement node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(EmptyStatement) */ @Override public boolean visit(EmptyStatement node) { if (rightTypeFound()) { return false; } return true; } /* * (non-Javadoc) * * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. * EnhancedForStatement) */ @Override public boolean visit(EnhancedForStatement node) { if (rightTypeFound()) { return false; } return true; } /* * (non-Javadoc) * * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. * EnumConstantDeclaration) */ @Override public boolean visit(EnumConstantDeclaration node) { if (rightTypeFound()) { return false; } return true; } /* * (non-Javadoc) * * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. * EnumDeclaration) */ @Override public boolean visit(EnumDeclaration node) { if (rightTypeFound()) { fEvaluateNextEndTypeDeclaration = false; return false; } return true; } /** * @see ASTVisitor#visit(ExpressionStatement) */ @Override public boolean visit(ExpressionStatement node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(FieldAccess) */ @Override public boolean visit(FieldAccess node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(FieldDeclaration) */ @Override public boolean visit(FieldDeclaration node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(ForStatement) */ @Override public boolean visit(ForStatement node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(IfStatement) */ @Override public boolean visit(IfStatement node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(ImportDeclaration) */ @Override public boolean visit(ImportDeclaration node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(InfixExpression) */ @Override public boolean visit(InfixExpression node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(Initializer) */ @Override public boolean visit(Initializer node) { if (rightTypeFound()) { return false; } return true; } /* * (non-Javadoc) * * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. * InstanceofExpression) */ @Override public boolean visit(InstanceofExpression node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(Javadoc) */ @Override public boolean visit(Javadoc node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(LabeledStatement) */ @Override public boolean visit(LabeledStatement node) { if (rightTypeFound()) { return false; } return true; } /* * (non-Javadoc) * * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. * LineComment) */ @Override public boolean visit(LineComment node) { return false; } /* * (non-Javadoc) * * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. * MarkerAnnotation) */ @Override public boolean visit(MarkerAnnotation node) { return false; } /* * (non-Javadoc) * * @see * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MemberRef * ) */ @Override public boolean visit(MemberRef node) { return false; } /* * (non-Javadoc) * * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. * MemberValuePair) */ @Override public boolean visit(MemberValuePair node) { return false; } /** * @see ASTVisitor#visit(MethodDeclaration) */ @Override public boolean visit(MethodDeclaration node) { int firstLine = fCompilationUnit.getLineNumber(node.getStartPosition()); int lastLine = fCompilationUnit.getLineNumber(node.getStartPosition() + node.getLength()); List<TypeParameter> typeParameters = node.typeParameters(); pushTypeParameters(typeParameters); if (isRightType(node.getParent()) && firstLine <= fLine && fLine <= lastLine) { fMatchingTypeParameters = fTypeParameterStack.peek(); } if (rightTypeFound()) { return false; } return true; } private void pushTypeParameters(List<TypeParameter> typeParameters) { if (!typeParameters.isEmpty()) { HashMap<String,String> newTypeParameters = new HashMap<>(fTypeParameterStack.peek()); Iterator<TypeParameter> iterator = typeParameters.iterator(); while (iterator.hasNext()) { TypeParameter typeParameter = iterator.next(); String boundName = typeParameter.getName().getIdentifier(); newTypeParameters.put(boundName, typeParameter.toString()); } fTypeParameterStack.push(newTypeParameters); // Push the new "scope" } else { fTypeParameterStack.push(fTypeParameterStack.peek()); // Push the same } } /** * @see ASTVisitor#visit(MethodInvocation) */ @Override public boolean visit(MethodInvocation node) { if (rightTypeFound()) { return false; } return true; } /* * (non-Javadoc) * * @see * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodRef * ) */ @Override public boolean visit(MethodRef node) { return false; } /* * (non-Javadoc) * * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. * MethodRefParameter) */ @Override public boolean visit(MethodRefParameter node) { return false; } /* * (non-Javadoc) * * @see * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Modifier * ) */ @Override public boolean visit(Modifier node) { return false; } /* * (non-Javadoc) * * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. * NormalAnnotation) */ @Override public boolean visit(NormalAnnotation node) { return false; } /** * @see ASTVisitor#visit(NullLiteral) */ @Override public boolean visit(NullLiteral node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(NumberLiteral) */ @Override public boolean visit(NumberLiteral node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(PackageDeclaration) */ @Override public boolean visit(PackageDeclaration node) { if (rightTypeFound()) { return false; } return true; } /* * (non-Javadoc) * * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. * ParameterizedType) */ @Override public boolean visit(ParameterizedType node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(ParenthesizedExpression) */ @Override public boolean visit(ParenthesizedExpression node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(PostfixExpression) */ @Override public boolean visit(PostfixExpression node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(PrefixExpression) */ @Override public boolean visit(PrefixExpression node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(PrimitiveType) */ @Override public boolean visit(PrimitiveType node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(QualifiedName) */ @Override public boolean visit(QualifiedName node) { if (rightTypeFound()) { return false; } return true; } /* * (non-Javadoc) * * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. * QualifiedType) */ @Override public boolean visit(QualifiedType node) { return false; } /** * @see ASTVisitor#visit(ReturnStatement) */ @Override public boolean visit(ReturnStatement node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(SimpleName) */ @Override public boolean visit(SimpleName node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(SimpleType) */ @Override public boolean visit(SimpleType node) { if (rightTypeFound()) { return false; } return true; } /* * (non-Javadoc) * * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. * SingleMemberAnnotation) */ @Override public boolean visit(SingleMemberAnnotation node) { return false; } /** * @see ASTVisitor#visit(SingleVariableDeclaration) */ @Override public boolean visit(SingleVariableDeclaration node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(StringLiteral) */ @Override public boolean visit(StringLiteral node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(SuperConstructorInvocation) */ @Override public boolean visit(SuperConstructorInvocation node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(SuperFieldAccess) */ @Override public boolean visit(SuperFieldAccess node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(SuperMethodInvocation) */ @Override public boolean visit(SuperMethodInvocation node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(SwitchCase) */ @Override public boolean visit(SwitchCase node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(SwitchStatement) */ @Override public boolean visit(SwitchStatement node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(SynchronizedStatement) */ @Override public boolean visit(SynchronizedStatement node) { if (rightTypeFound()) { return false; } return true; } /* * (non-Javadoc) * * @see * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TagElement * ) */ @Override public boolean visit(TagElement node) { return false; } /* * (non-Javadoc) * * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. * TextElement) */ @Override public boolean visit(TextElement node) { return false; } /** * @see ASTVisitor#visit(ThisExpression) */ @Override public boolean visit(ThisExpression node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(ThrowStatement) */ @Override public boolean visit(ThrowStatement node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(TryStatement) */ @Override public boolean visit(TryStatement node) { if (rightTypeFound()) { return false; } return true; } /* * (non-Javadoc) * * @see * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.UnionType * ) */ @Override public boolean visit(UnionType node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(TypeDeclaration) */ @Override public boolean visit(TypeDeclaration node) { List<TypeParameter> typeParameters = node.typeParameters(); pushTypeParameters(typeParameters); if (rightTypeFound()) { fEvaluateNextEndTypeDeclaration = false; return false; } return true; } /** * @see ASTVisitor#visit(TypeDeclarationStatement) */ @Override public boolean visit(TypeDeclarationStatement node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(TypeLiteral) */ @Override public boolean visit(TypeLiteral node) { if (rightTypeFound()) { return false; } return true; } /* * (non-Javadoc) * * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. * TypeParameter) */ @Override public boolean visit(TypeParameter node) { return false; } /** * @see ASTVisitor#visit(VariableDeclarationExpression) */ @Override public boolean visit(VariableDeclarationExpression node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(VariableDeclarationFragment) */ @Override public boolean visit(VariableDeclarationFragment node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(VariableDeclarationStatement) */ @Override public boolean visit(VariableDeclarationStatement node) { if (rightTypeFound()) { return false; } return true; } /** * @see ASTVisitor#visit(WhileStatement) */ @Override public boolean visit(WhileStatement node) { if (rightTypeFound()) { return false; } return true; } /* * (non-Javadoc) * * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. * WildcardType) */ @Override public boolean visit(WildcardType node) { return false; } /** * Returns whether the source to be generated is greater than or equal to * the given source level. * * @param major * major level - e.g. 1 from 1.4 * @param minor * minor level - e.g. 4 from 1.4 * @return <code>true</code> if the given major / minor version is less than * or equal to the backing source level */ public boolean isSourceLevelGreaterOrEqual(int major, int minor) { return (fSourceMajorLevel > major) || (fSourceMajorLevel == major && fSourceMinorLevel >= minor); } /** * Appends type parameters to source. * * @param source * the current buffer of source to append to * @param typeParameters * the list of {@link TypeParameter}s to add */ private void appendTypeParameters(StringBuffer source, List<TypeParameter> typeParameters) { if (!typeParameters.isEmpty() && isSourceLevelGreaterOrEqual(1, 5)) { source.append('<'); Iterator<TypeParameter> iter = typeParameters.iterator(); TypeParameter typeParameter = iter.next(); source.append(typeParameter.getName().getIdentifier()); List<Type> typeBounds = typeParameter.typeBounds(); if (!typeBounds.isEmpty()) { source.append(" extends "); //$NON-NLS-1$ Iterator<Type> iter2 = typeBounds.iterator(); source.append(getTypeName(iter2.next())); while (iter2.hasNext()) { source.append('&'); source.append(getTypeName(iter2.next())); } } while (iter.hasNext()) { source.append(','); typeParameter = iter.next(); source.append(typeParameter.getName().getIdentifier()); typeBounds = typeParameter.typeBounds(); if (!typeBounds.isEmpty()) { source.append(" extends "); //$NON-NLS-1$ Iterator<Type> iter2 = typeBounds.iterator(); source.append(getTypeName(iter2.next())); while (iter2.hasNext()) { source.append('&'); source.append(getTypeName(iter2.next())); } } } source.append('>'); source.append(' '); } } }