| /******************************************************************************* |
| * Copyright (c) 2005, 2007 BEA Systems, Inc. |
| * 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: |
| * tyeung@bea.com - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.apt.core.internal.declaration; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import org.eclipse.jdt.apt.core.internal.declaration.EclipseMirrorObject.MirrorKind; |
| import org.eclipse.jdt.apt.core.internal.env.BaseProcessorEnv; |
| import org.eclipse.jdt.apt.core.internal.util.Factory; |
| import org.eclipse.jdt.core.dom.IMethodBinding; |
| import org.eclipse.jdt.core.dom.ITypeBinding; |
| import org.eclipse.jdt.core.dom.Name; |
| import org.eclipse.jdt.core.dom.SingleVariableDeclaration; |
| import org.eclipse.jdt.core.dom.TypeParameter; |
| |
| import com.sun.mirror.declaration.ParameterDeclaration; |
| import com.sun.mirror.declaration.TypeDeclaration; |
| import com.sun.mirror.declaration.TypeParameterDeclaration; |
| import com.sun.mirror.type.ReferenceType; |
| |
| class ExecutableUtil { |
| |
| /** |
| * @param executable must be a constructor, method or annotation element. |
| * @return the formal type parameters of the executable. |
| */ |
| static Collection<TypeParameterDeclaration> getFormalTypeParameters( |
| EclipseDeclarationImpl executable, |
| BaseProcessorEnv env) |
| { |
| // the dom ast does not provide type parameter list for annotation element |
| // that incorrectly includes them in the text |
| if(executable == null || executable.kind() == MirrorKind.ANNOTATION_ELEMENT) |
| return Collections.emptyList(); |
| if( executable.kind() != MirrorKind.METHOD && executable.kind() != MirrorKind.CONSTRUCTOR) |
| throw new IllegalArgumentException("Executable is not a method " + //$NON-NLS-1$ |
| executable.getClass().getName()); |
| |
| if( executable.isFromSource() ){ |
| final org.eclipse.jdt.core.dom.MethodDeclaration methodAstNode = |
| (org.eclipse.jdt.core.dom.MethodDeclaration)executable.getAstNode(); |
| |
| // Synthetic methods will have no ast node |
| if (methodAstNode == null) |
| return Collections.emptyList(); |
| @SuppressWarnings("unchecked") |
| final List<TypeParameter> typeParams = methodAstNode.typeParameters(); |
| final List<TypeParameterDeclaration> result = new ArrayList<TypeParameterDeclaration>(); |
| for(TypeParameter typeParam : typeParams){ |
| final ITypeBinding typeBinding = typeParam.resolveBinding(); |
| if( typeBinding == null ){ |
| throw new UnsupportedOperationException("cannot create a type parameter declaration without a binding"); //$NON-NLS-1$ |
| } |
| else{ |
| final TypeParameterDeclaration typeParamDecl = |
| (TypeParameterDeclaration)Factory.createDeclaration(typeBinding, env); |
| if( typeParamDecl != null ) |
| result.add(typeParamDecl); |
| } |
| } |
| return result; |
| } |
| else{ // binary |
| if( !executable.isBindingBased() ) |
| throw new IllegalStateException("binary executable without binding."); //$NON-NLS-1$ |
| final IMethodBinding methodBinding = ((ExecutableDeclarationImpl)executable).getDeclarationBinding(); |
| final ITypeBinding[] typeParams = methodBinding.getTypeParameters(); |
| if( typeParams == null || typeParams.length == 0 ) |
| return Collections.emptyList(); |
| final List<TypeParameterDeclaration> result = new ArrayList<TypeParameterDeclaration>(); |
| for( ITypeBinding typeVar : typeParams ){ |
| final TypeParameterDeclaration typeParamDecl = |
| (TypeParameterDeclaration)Factory.createDeclaration(typeVar, env); |
| if( typeParamDecl != null ) |
| result.add(typeParamDecl); |
| } |
| return result; |
| |
| } |
| } |
| |
| /** |
| * @param executable must be a constructor, method or annotation element. |
| * @return the list formal parameters of the executable. |
| */ |
| static Collection<ParameterDeclaration> getParameters( |
| final EclipseDeclarationImpl executable, |
| final BaseProcessorEnv env) |
| { |
| // the dom ast does not provide parameter list for annotation element |
| // that incorrectly includes them in the text |
| if(executable == null || executable.kind() == MirrorKind.ANNOTATION_ELEMENT) |
| return Collections.emptyList(); |
| if( executable.kind() != MirrorKind.METHOD && executable.kind() != MirrorKind.CONSTRUCTOR) |
| throw new IllegalArgumentException("Executable is not a method " + //$NON-NLS-1$ |
| executable.getClass().getName()); |
| |
| if( executable.isFromSource() ){ |
| // We always need to look into the ast to make sure the complete list of |
| // parameters are returned since parameters with unresolved type will not |
| // show up in the method binding |
| final org.eclipse.jdt.core.dom.MethodDeclaration methodAstNode = |
| (org.eclipse.jdt.core.dom.MethodDeclaration)executable.getAstNode(); |
| |
| // Synthetic methods will have no ast node |
| if (methodAstNode == null) |
| return Collections.emptyList(); |
| |
| @SuppressWarnings("unchecked") |
| final List<SingleVariableDeclaration> params = methodAstNode.parameters(); |
| if( params == null || params.size() == 0 ) |
| return Collections.emptyList(); |
| final List<ParameterDeclaration> result = new ArrayList<ParameterDeclaration>(params.size()); |
| for( int i=0, size=params.size(); i<size; i++ ){ |
| final SingleVariableDeclaration varDecl = params.get(i); |
| final ParameterDeclaration param = |
| Factory.createParameterDeclaration(varDecl, executable.getResource(), env); |
| result.add(param); |
| } |
| return result; |
| } |
| else{ |
| if( !executable.isBindingBased() ) |
| throw new IllegalStateException("binary executable without binding."); //$NON-NLS-1$ |
| // it is binary, since we don't support the class file format, will rely on the |
| // binding and hope that it's complete. |
| final ExecutableDeclarationImpl impl = (ExecutableDeclarationImpl)executable; |
| final IMethodBinding methodBinding = impl.getDeclarationBinding(); |
| final ITypeBinding[] paramTypes = methodBinding.getParameterTypes(); |
| if( paramTypes == null || paramTypes.length == 0 ) |
| return Collections.emptyList(); |
| final List<ParameterDeclaration> result = new ArrayList<ParameterDeclaration>(paramTypes.length); |
| |
| for( int i=0; i<paramTypes.length; i++ ){ |
| final ITypeBinding type = paramTypes[i]; |
| final ParameterDeclaration param = Factory.createParameterDeclaration(impl, i, type, env); |
| result.add(param); |
| } |
| |
| return result; |
| |
| } |
| } |
| |
| /** |
| * @param executable must be a constructor, method or annotation element. |
| * @return the list thrown types of the executable. |
| */ |
| static Collection<ReferenceType> getThrownTypes( |
| final EclipseDeclarationImpl executable, |
| final BaseProcessorEnv env) |
| { |
| if(executable == null || executable.kind() == MirrorKind.ANNOTATION_ELEMENT) |
| return Collections.emptyList(); |
| if( executable.kind() != MirrorKind.METHOD && executable.kind() != MirrorKind.CONSTRUCTOR) |
| throw new IllegalArgumentException("Executable is not a method " + //$NON-NLS-1$ |
| executable.getClass().getName()); |
| if( executable.isFromSource()){ |
| // We always need to look into the ast to make sure the complete list of |
| // parameters are returned since parameters with unresolved type will not |
| // show up in the method binding |
| final org.eclipse.jdt.core.dom.MethodDeclaration methodAstNode = |
| (org.eclipse.jdt.core.dom.MethodDeclaration)executable.getAstNode(); |
| |
| // If this method is synthetic, there will be no AST node |
| if (methodAstNode == null) |
| return Collections.emptyList(); |
| |
| @SuppressWarnings("unchecked") |
| final List<Name> exceptions = methodAstNode.thrownExceptions(); |
| if(exceptions == null || exceptions.size() == 0 ) |
| return Collections.emptyList(); |
| final List<ReferenceType> results = new ArrayList<ReferenceType>(4); |
| for(Name exception : exceptions ){ |
| final ITypeBinding eType = exception.resolveTypeBinding(); |
| final ReferenceType refType; |
| if( eType == null ) |
| refType = Factory.createErrorClassType(exception.toString()); |
| else |
| refType = Factory.createReferenceType(eType, env); |
| results.add(refType); |
| } |
| |
| return results; |
| } |
| else{ |
| if( !executable.isBindingBased() ) |
| throw new IllegalStateException("binary executable without binding."); //$NON-NLS-1$ |
| final ExecutableDeclarationImpl impl = (ExecutableDeclarationImpl)executable; |
| final IMethodBinding methodBinding = impl.getDeclarationBinding(); |
| final ITypeBinding[] exceptions = methodBinding.getExceptionTypes(); |
| final List<ReferenceType> results = new ArrayList<ReferenceType>(4); |
| for( ITypeBinding exception : exceptions ){ |
| final TypeDeclaration mirrorDecl = Factory.createReferenceType(exception, env); |
| if( mirrorDecl != null) |
| results.add((ReferenceType)mirrorDecl); |
| } |
| return results; |
| } |
| } |
| } |