blob: 0ff313140a66774ecaca533969d159522a5060f4 [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.tests.annotations.apitest;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import org.eclipse.jdt.apt.tests.annotations.BaseFactory;
import org.eclipse.jdt.apt.tests.annotations.BaseProcessor;
import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.apt.Messager;
import com.sun.mirror.declaration.AnnotationMirror;
import com.sun.mirror.declaration.AnnotationTypeDeclaration;
import com.sun.mirror.declaration.AnnotationTypeElementDeclaration;
import com.sun.mirror.declaration.AnnotationValue;
import com.sun.mirror.declaration.Declaration;
import com.sun.mirror.declaration.FieldDeclaration;
import com.sun.mirror.declaration.MethodDeclaration;
import com.sun.mirror.declaration.TypeDeclaration;
import com.sun.mirror.declaration.TypeParameterDeclaration;
import com.sun.mirror.type.DeclaredType;
import com.sun.mirror.type.TypeMirror;
import com.sun.mirror.util.Types;
public class APIAnnotationProcessorFactory extends BaseFactory {
public APIAnnotationProcessorFactory(){
super(Common.class.getName(), SubtypeOf.class.getName(), AssignableTo.class.getName());
}
public AnnotationProcessor getProcessorFor(
Set<AnnotationTypeDeclaration> decls,
AnnotationProcessorEnvironment env) {
return new APIAnnotationProcessor(env);
}
public static class APIAnnotationProcessor extends BaseProcessor{
private Messager _msgr;
private Types _types;
public APIAnnotationProcessor(AnnotationProcessorEnvironment env){
super(env);
}
public void process() {
_msgr = _env.getMessager();
_types = _env.getTypeUtils();
checkCommon();
checkSubtypeOf();
checkAssignableTo();
}
/**
* validate instances of the Common annotation
*/
private void checkCommon()
{
final AnnotationTypeDeclaration commonAnnoType =
(AnnotationTypeDeclaration)_env.getTypeDeclaration(Common.class.getName());
final Collection<Declaration> decls =
_env.getDeclarationsAnnotatedWith(commonAnnoType);
for( Declaration decl : decls ){
if(decl instanceof FieldDeclaration ){
final FieldDeclaration field = (FieldDeclaration)decl;
final TypeMirror type = field.getType();
if( type instanceof DeclaredType ){
final TypeMirror collectionType =
_env.getTypeUtils().getDeclaredType(_env.getTypeDeclaration(Collection.class.getName()));
final Collection<TypeMirror> typeVars =
((DeclaredType)type).getActualTypeArguments();
if(typeVars.size() == 1 ){
TypeMirror typeVar = typeVars.iterator().next();
boolean assignable = _env.getTypeUtils().isAssignable(typeVar, collectionType);
if( assignable )
_msgr.printError(typeVar + " is assignable to " + collectionType );
else
_msgr.printError(typeVar + " is not assignable to " + collectionType );
}
}
}else if(decl instanceof TypeDeclaration){
final TypeDeclaration typeDecl = (TypeDeclaration)decl;
final Collection<TypeParameterDeclaration> typeParams =
typeDecl.getFormalTypeParameters();
for(TypeParameterDeclaration typeParam : typeParams){
Declaration owner = typeParam.getOwner();
_msgr.printError("Type parameter '" + typeParam + "' belongs to " + owner.getClass().getName() + " " + owner.getSimpleName() );
}
}
else if( decl instanceof MethodDeclaration ){
final MethodDeclaration methodDecl = (MethodDeclaration)decl;
final Collection<TypeParameterDeclaration> typeParams =
methodDecl.getFormalTypeParameters();
for(TypeParameterDeclaration typeParam : typeParams){
Declaration owner = typeParam.getOwner();
_msgr.printError("Type parameter '" + typeParam + "' belongs to " + owner.getClass().getName() + " " + owner.getSimpleName() );
}
}
}
}
/**
* Validate all the fields annotated with @SubtypeOf, in order to test
* the Types.subtypeOf() method.
* We ignore anything but fields, out of laziness.
*/
private void checkSubtypeOf() {
final AnnotationTypeDeclaration annoType =
(AnnotationTypeDeclaration)_env.getTypeDeclaration(SubtypeOf.class.getName());
final Collection<Declaration> decls =
_env.getDeclarationsAnnotatedWith(annoType);
for( Declaration decl : decls ){
if(decl instanceof FieldDeclaration ) {
AnnotationMirror mirror = findMirror(decl, annoType);
if (mirror == null) {
return;
}
TypeMirror valueType = getTypeValue(mirror);
final FieldDeclaration field = (FieldDeclaration)decl;
final TypeMirror fieldType = field.getType();
boolean isSubtype = _types.isSubtype(fieldType, valueType);
if( isSubtype )
_msgr.printError(fieldType + " is a subtype of " + valueType );
else
_msgr.printError(fieldType + " is not a subtype of " + valueType );
}
}
}
/**
* Validate all the fields annotated with @AssignableTo.
* We ignore anything but fields, out of laziness.
*/
private void checkAssignableTo() {
final AnnotationTypeDeclaration annoType =
(AnnotationTypeDeclaration)_env.getTypeDeclaration(AssignableTo.class.getName());
final Collection<Declaration> decls =
_env.getDeclarationsAnnotatedWith(annoType);
for( Declaration decl : decls ){
if(decl instanceof FieldDeclaration ) {
AnnotationMirror mirror = findMirror(decl, annoType);
if (mirror == null) {
return;
}
TypeMirror valueType = getTypeValue(mirror);
final FieldDeclaration field = (FieldDeclaration)decl;
final TypeMirror fieldType = field.getType();
boolean isAssignableTo = _types.isAssignable(fieldType, valueType);
if( isAssignableTo )
_msgr.printError(fieldType + " is assignable to " + valueType );
else
_msgr.printError(fieldType + " is not assignable to " + valueType );
}
}
}
/**
* @return a mirror for the instance of the specified annotation on the specified
* declaration, or null if one is not present.
*/
private AnnotationMirror findMirror(Declaration decl, AnnotationTypeDeclaration at) {
for (AnnotationMirror mirror : decl.getAnnotationMirrors()) {
if (mirror.getAnnotationType().equals(at)) {
return mirror;
}
}
return null;
}
/**
* @return the value() of an annotation instance <code>mirror</code>, if it is a
* class value, or null if not.
*/
private TypeMirror getTypeValue(AnnotationMirror mirror) {
Map<AnnotationTypeElementDeclaration, AnnotationValue> values = mirror.getElementValues();
for (Entry<AnnotationTypeElementDeclaration, AnnotationValue> entry : values.entrySet()) {
if ("value".equals(entry.getKey().getSimpleName())) {
if (entry.getValue().getValue() instanceof TypeMirror)
return (TypeMirror)entry.getValue().getValue();
else
return null;
}
}
return null;
}
}
}