blob: ee6fcae59b680ad4878e5894b02e32de5afca3dd [file] [log] [blame]
/*******************************************************************************
* 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.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.jdt.apt.core.internal.env.BaseProcessorEnv;
import org.eclipse.jdt.apt.core.internal.util.Factory;
import org.eclipse.jdt.apt.core.internal.util.SourcePositionImpl;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.IAnnotationBinding;
import org.eclipse.jdt.core.dom.IMemberValuePairBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import com.sun.mirror.declaration.AnnotationMirror;
import com.sun.mirror.declaration.AnnotationTypeElementDeclaration;
import com.sun.mirror.declaration.AnnotationValue;
import com.sun.mirror.type.AnnotationType;
import com.sun.mirror.util.SourcePosition;
/**
* Annotation instance from source.
*/
public class AnnotationMirrorImpl implements AnnotationMirror, EclipseMirrorObject
{
/**The ast node that correspond to the annotation.*/
private final IAnnotationBinding _domAnnotation;
private final BaseProcessorEnv _env;
/** the declaration that is annotated by this annotation or the annotation element declaration
* if this is (part of) a default value*/
private final EclipseDeclarationImpl _annotated;
public AnnotationMirrorImpl(IAnnotationBinding annotationAstNode, EclipseDeclarationImpl decl, BaseProcessorEnv env)
{
_domAnnotation = annotationAstNode;
_env = env;
_annotated = decl;
assert _domAnnotation != null : "annotation node missing."; //$NON-NLS-1$
assert _annotated != null : "missing the declaration that is annotated with this annotation."; //$NON-NLS-1$
}
public AnnotationType getAnnotationType()
{
final ITypeBinding binding = _domAnnotation.getAnnotationType();
if( binding == null ){
final ASTNode node = _annotated.getCompilationUnit().findDeclaringNode(_domAnnotation);
String name = ""; //$NON-NLS-1$
if( node != null && node instanceof Annotation ){
final Name typeNameNode = ((Annotation)node).getTypeName();
if( typeNameNode != null )
name = typeNameNode.toString();
}
return Factory.createErrorAnnotationType(name);
}
else
return (AnnotationType)Factory.createReferenceType(binding, _env);
}
public Map<AnnotationTypeElementDeclaration, AnnotationValue> getElementValues()
{
final IMemberValuePairBinding[] pairs = _domAnnotation.getDeclaredMemberValuePairs();
if (pairs.length == 0) {
return Collections.emptyMap();
}
final Map<AnnotationTypeElementDeclaration, AnnotationValue> result =
new LinkedHashMap<AnnotationTypeElementDeclaration, AnnotationValue>(pairs.length * 4 / 3 + 1 );
for( IMemberValuePairBinding pair : pairs ){
final String name = pair.getName();
if( name == null ) continue;
IMethodBinding elementMethod = pair.getMethodBinding();
if( elementMethod != null ){
final EclipseDeclarationImpl mirrorDecl = Factory.createDeclaration(elementMethod, _env);
if( mirrorDecl != null && mirrorDecl.kind() == EclipseMirrorObject.MirrorKind.ANNOTATION_ELEMENT )
{
final AnnotationTypeElementDeclaration elementDecl =
(AnnotationTypeElementDeclaration)mirrorDecl;
final AnnotationValue annoValue =
Factory.createAnnotationMemberValue(pair.getValue(), name, this, _env, elementDecl.getReturnType());
if( annoValue != null )
result.put( elementDecl, annoValue);
}
}
}
return result;
}
public SourcePosition getPosition()
{
if( isFromSource() ){
final CompilationUnit unit = _annotated.getCompilationUnit();
final org.eclipse.jdt.core.dom.Annotation annotation = getAstNode();
if( annotation == null ) return null;
org.eclipse.jdt.core.dom.ASTNode astNode = annotation.getTypeName();
if( astNode == null )
astNode = annotation;
final int offset = astNode.getStartPosition();
return new SourcePositionImpl(astNode.getStartPosition(),
astNode.getLength(),
unit.getLineNumber(offset),
unit.getColumnNumber(offset),
_annotated);
}
return null;
}
public String toString()
{
return _domAnnotation.toString();
}
/**
* @return the type(s) of the member value named <code>membername</code>.
* If the value is a class literal, then return the type binding corresponding to the type requested.
* Otherwise, return the type of the expression.
* If the value is an array initialization, then the type of each of the initialization expresion will
* be returned. Return null if no match is found.
*/
public ITypeBinding[] getMemberValueTypeBinding(String membername)
{
if( membername == null ) return null;
final IMemberValuePairBinding[] declaredPairs = _domAnnotation.getDeclaredMemberValuePairs();
for( IMemberValuePairBinding pair : declaredPairs ){
if( membername.equals(pair.getName()) ){
final Object value = pair.getValue();
return getValueTypeBinding(value, pair.getMethodBinding().getReturnType());
}
}
// didn't find it in the ast, check the default values.
final IMethodBinding binding = getMethodBinding(membername);
if(binding == null ) return null;
final Object defaultValue = binding.getDefaultValue();
if( defaultValue != null )
return getValueTypeBinding(defaultValue, binding.getReturnType() );
else
return null;
}
private ITypeBinding[] getValueTypeBinding(Object value, final ITypeBinding resolvedType)
{
if( value == null ) return null;
if( resolvedType.isPrimitive() || resolvedType.isAnnotation() || value instanceof String )
return new ITypeBinding[]{ resolvedType };
else if( resolvedType.isArray() ){
final Object[] elements = (Object[])value;
final ITypeBinding[] result = new ITypeBinding[elements.length];
final ITypeBinding leafType = resolvedType.getElementType();
for(int i=0, len = elements.length; i<len; i++ ){
final ITypeBinding[] t = getValueTypeBinding(elements[i], leafType);
result[i] = t == null ? null : t[0];
}
return result;
}
else if( value instanceof IVariableBinding )
return new ITypeBinding[]{ ( (IVariableBinding)value ).getDeclaringClass() };
else if( value instanceof ITypeBinding )
return new ITypeBinding[]{ (ITypeBinding)value };
else
throw new IllegalStateException("value = " + value + " resolvedType = " + resolvedType ); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* @param memberName the name of the member
* @return the value of the given member
*/
public Object getValue(final String memberName)
{
if( memberName == null ) return null;
final IMemberValuePairBinding[] declaredPairs = _domAnnotation.getDeclaredMemberValuePairs();
for( IMemberValuePairBinding pair : declaredPairs ){
if( memberName.equals(pair.getName()) ){
return pair.getValue();
}
}
// didn't find it in the ast, check the default values.
final IMethodBinding binding = getMethodBinding(memberName);
if(binding == null ) return null;
return binding.getDefaultValue();
}
/**
* @return the method binding that matches the given name from the annotation type
* referenced by this annotation.
*/
public IMethodBinding getMethodBinding(final String memberName)
{
if( memberName == null ) return null;
final ITypeBinding typeBinding = _domAnnotation.getAnnotationType();
if( typeBinding == null ) return null;
final IMethodBinding[] methods = typeBinding.getDeclaredMethods();
for( IMethodBinding method : methods ){
if( memberName.equals(method.getName()) )
return method;
}
return null;
}
public IAnnotationBinding getResolvedAnnotaion(){return _domAnnotation; }
public MirrorKind kind(){ return MirrorKind.ANNOTATION_MIRROR; }
boolean isFromSource()
{
return _annotated.isFromSource();
}
org.eclipse.jdt.core.dom.Annotation getAstNode()
{
if( isFromSource() ){
final CompilationUnit unit = _annotated.getCompilationUnit();
final ASTNode node = unit.findDeclaringNode(_domAnnotation);
if( node instanceof org.eclipse.jdt.core.dom.Annotation )
return (org.eclipse.jdt.core.dom.Annotation)node;
}
return null;
}
@SuppressWarnings("unchecked")
ASTNode getASTNodeForElement(String name)
{
if( name == null ) return null;
final org.eclipse.jdt.core.dom.Annotation anno = getAstNode();
if( anno != null ){
if( anno.isSingleMemberAnnotation() ){
if( "value".equals(name) ) //$NON-NLS-1$
return ((SingleMemberAnnotation)anno).getValue();
}
else if( anno.isNormalAnnotation() ){
final List<MemberValuePair> pairs = ((NormalAnnotation)anno).values();
for( MemberValuePair pair : pairs )
{
final String pairName = pair.getName() == null ? null : pair.getName().toString();
if( name.equals(pairName) )
return pair.getValue();
}
}
}
// marker annotation or no match.
return null;
}
CompilationUnit getCompilationUnit() { return _annotated.getCompilationUnit(); }
public BaseProcessorEnv getEnvironment(){ return _env; }
public IFile getResource()
{ return _annotated.getResource(); }
public EclipseDeclarationImpl getAnnotatedDeclaration(){ return _annotated; }
public boolean equals(Object obj){
if( obj instanceof AnnotationMirrorImpl ){
return ((AnnotationMirrorImpl)obj)._domAnnotation == _domAnnotation;
}
return false;
}
public int hashCode(){
return _domAnnotation.hashCode();
}
}