com.redhat.ceylon.compiler.java.codegen.AnnotationUtil Maven / Gradle / Ivy
/*
* Copyright Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the authors tag. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License version 2.
*
* This particular file is subject to the "Classpath" exception as provided in the
* LICENSE file that accompanied this code.
*
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License,
* along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package com.redhat.ceylon.compiler.java.codegen;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import static com.redhat.ceylon.model.loader.model.OutputElement.*;
import com.redhat.ceylon.common.Backend;
import com.redhat.ceylon.compiler.typechecker.analyzer.Warning;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.Annotation;
import com.redhat.ceylon.model.loader.model.AnnotationProxyClass;
import com.redhat.ceylon.model.loader.model.AnnotationProxyMethod;
import com.redhat.ceylon.model.loader.model.AnnotationTarget;
import com.redhat.ceylon.model.loader.model.OutputElement;
import com.redhat.ceylon.model.typechecker.model.Declaration;
import com.redhat.ceylon.model.typechecker.model.Interface;
import com.redhat.ceylon.model.typechecker.model.ModelUtil;
import com.redhat.ceylon.model.typechecker.model.Type;
import com.redhat.ceylon.model.typechecker.model.TypeDeclaration;
import com.redhat.ceylon.model.typechecker.model.Value;
/**
*
* @author Stéphane Épardaud
*/
public class AnnotationUtil {
/**
* Returns the set of output program elements that the given annotation
* could be applied to. If the {@code errors} flag is true then add
* warnings/errors to the tree about ambigous/impossible targets.
*/
public static EnumSet interopAnnotationTargeting(EnumSet outputs,
Tree.Annotation annotation, boolean errors) {
Declaration annoCtor = ((Tree.BaseMemberExpression)annotation.getPrimary()).getDeclaration();
if (annoCtor instanceof AnnotationProxyMethod) {
AnnotationProxyMethod proxyCtor = (AnnotationProxyMethod)annoCtor;
AnnotationProxyClass annoClass = proxyCtor.getProxyClass();
EnumSet possibleTargets;
if (proxyCtor.getAnnotationTarget() != null) {
possibleTargets = EnumSet.of(proxyCtor.getAnnotationTarget());
} else {
possibleTargets = AnnotationTarget.outputTargets(annoClass);
}
EnumSet actualTargets = possibleTargets.clone();
actualTargets.retainAll(outputs);
if (actualTargets.size() > 1) {
if (errors) {
StringBuffer sb = new StringBuffer();
sb.append("ambiguous annotation target: ").append(annoCtor.getName());
sb.append(" could be applied to several targets, use one of ");
for (Iterator iterator = actualTargets.iterator(); iterator.hasNext();) {
OutputElement x = iterator.next();
sb.append(Naming.getDisambigAnnoCtorName((Interface)((AnnotationProxyMethod) annoCtor).getProxyClass().iface, x));
if (iterator.hasNext()) {
sb.append(", ");
}
}
sb.append(" to disambiguate");
annotation.addUsageWarning(Warning.ambiguousAnnotation, sb.toString(), Backend.Java);
}
return null;
} else if (actualTargets.size() == 0) {
if (errors) {
annotation.addError("no target for " + annoCtor.getName() +
" annotation: @Target of @interface " +
((AnnotationProxyClass)annoClass).iface.getName() +
" lists " + possibleTargets +
" but annotated element tranforms to " + outputs, Backend.Java);
}
}
return actualTargets;
} else {
return null;
}
}
public static EnumSet outputs(Tree.ObjectDefinition that) {
return EnumSet.of(TYPE, CONSTRUCTOR, FIELD, GETTER);
}
public static EnumSet outputs(Tree.AnyClass that) {
EnumSet result = EnumSet.of(TYPE);
if (!that.getDeclarationModel().hasConstructors()) {
result.add(CONSTRUCTOR);
}
if (that.getDeclarationModel().isAnnotation()) {
result.add(ANNOTATION_TYPE);
}
return result;
}
public static EnumSet outputs(Tree.PackageDescriptor annotated) {
return EnumSet.of(TYPE);
}
public static EnumSet outputs(Tree.ImportModule annotated) {
return EnumSet.of(FIELD);
}
public static EnumSet outputs(Tree.ModuleDescriptor annotated) {
return EnumSet.of(TYPE);
}
public static EnumSet outputs(Tree.TypeAliasDeclaration that) {
return EnumSet.of(TYPE);
}
public static EnumSet outputs(Tree.AnyInterface that) {
return EnumSet.of(TYPE);
}
public static EnumSet outputs(
Tree.Constructor annotated) {
return EnumSet.of(CONSTRUCTOR);
}
public static EnumSet outputs(
Tree.Enumerated annotated) {
return EnumSet.of(CONSTRUCTOR, FIELD, GETTER);
}
public static EnumSet outputs(Tree.AnyMethod that) {
return EnumSet.of(METHOD);
}
public static EnumSet outputs(Tree.AttributeGetterDefinition that) {
return EnumSet.of(GETTER);
}
public static EnumSet outputs(Tree.AttributeSetterDefinition that) {
return EnumSet.of(SETTER);
}
public static EnumSet outputs(Tree.AttributeDeclaration that) {
EnumSet result = EnumSet.noneOf(OutputElement.class);
Value declarationModel = that.getDeclarationModel();
if (declarationModel != null) {
if (declarationModel.isClassMember()) {
if (declarationModel.isParameter()) {
result.add(PARAMETER);
}
if (declarationModel.isShared() || declarationModel.isCaptured()) {
result.add(GETTER);
if (!(that.getSpecifierOrInitializerExpression() instanceof Tree.LazySpecifierExpression)) {
result.add(FIELD);
}
} else if (!declarationModel.isParameter()) {
result.add(LOCAL_VARIABLE);
}
} else if (declarationModel.isInterfaceMember()) {
result.add(GETTER);
} else if (declarationModel.isToplevel()) {
result.add(GETTER);
result.add(FIELD);
} else {
if (declarationModel.isParameter()) {
result.add(PARAMETER);
} else {
result.add(LOCAL_VARIABLE);
}
}
}
if (result.contains(GETTER)
&& (declarationModel.isVariable() || declarationModel.isLate())) {
result.add(SETTER);
}
return result;
}
public static void duplicateInteropAnnotation(EnumSet outputs, List annotations) {
for (int i=0; i mainTargets = interopAnnotationTargeting(outputs, ann, false);
if (t!=null && mainTargets != null) {
TypeDeclaration td = t.getDeclaration();
if (!ModelUtil.isCeylonDeclaration(td)) {
for (int j=0; j dupeTargets = interopAnnotationTargeting(outputs, other, false);
if(dupeTargets != null){
EnumSet sameTargets = intersection(mainTargets, dupeTargets);
if(!sameTargets.isEmpty()){
ann.addError("duplicate annotation: there are multiple annotations of type '" +
td.getName() + "' for targets: '"+sameTargets+"'");
break;
}
}
}
}
}
}
}
}
}
private static EnumSet intersection(EnumSet mainTargets, EnumSet dupeTargets) {
EnumSet intersect = EnumSet.copyOf(mainTargets);
intersect.retainAll(dupeTargets);
return intersect;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy