| /******************************************************************************* |
| * 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(' '); |
| } |
| } |
| } |