use of org.eclipse.ceylon.model.typechecker.model.TypeDeclaration in project ceylon by eclipse.
the class AnnotationVisitor method checkAnnotationConstructor.
private void checkAnnotationConstructor(Tree.AnyMethod that, Function a) {
Tree.Type type = that.getType();
if (type != null) {
Type t = type.getTypeModel();
if (t != null) {
TypeDeclaration td = t.getDeclaration();
if (td != null) {
if (td.isAnnotation()) {
Unit unit = that.getUnit();
TypeDeclaration annotationDec = unit.getAnnotationDeclaration();
if (t.isNothing()) {
that.addError("annotation constructor may not return 'Nothing'");
}
if (!td.inherits(annotationDec)) {
that.addError("annotation constructor must return a subtype of 'Annotation'");
}
if (!unit.getPackage().isLanguagePackage()) {
boolean langPackage = td.getUnit().getPackage().isLanguagePackage();
String typeName = td.getName();
if (langPackage && (typeName.equals("Shared") || typeName.equals("Abstract") || typeName.equals("Default") || typeName.equals("Formal") || typeName.equals("Actual") || typeName.equals("Final") || typeName.equals("Variable") || typeName.equals("Late") || typeName.equals("Native") || typeName.equals("Deprecated") || typeName.equals("Annotation"))) {
type.addError("annotation constructor may not return modifier annotation type");
}
}
} else {
type.addError("annotation constructor must return an annotation type");
}
}
}
}
List<Tree.ParameterList> pls = that.getParameterLists();
if (pls.size() == 1) {
for (Tree.Parameter pn : pls.get(0).getParameters()) {
checkAnnotationParameter(a, pn);
}
} else {
that.addError("annotation constructor must have exactly one parameter list");
}
if (that instanceof Tree.MethodDefinition) {
Tree.MethodDefinition md = (Tree.MethodDefinition) that;
Tree.Block block = md.getBlock();
if (block != null) {
List<Tree.Statement> list = getExecutableStatements(block);
if (list.size() == 1) {
Tree.Statement s = list.get(0);
if (s instanceof Tree.Return) {
Tree.Return r = (Tree.Return) s;
Tree.Expression e = r.getExpression();
checkAnnotationInstantiation(a, e, "annotation constructor must return a newly-instantiated annotation");
} else {
s.addError("annotation constructor body must return an annotation instance");
}
} else {
block.addError("annotation constructor body must have exactly one statement");
}
}
} else {
Tree.MethodDeclaration md = (Tree.MethodDeclaration) that;
Tree.SpecifierExpression se = md.getSpecifierExpression();
if (se != null) {
checkAnnotationInstantiation(a, se.getExpression(), "annotation constructor must return a newly-instantiated annotation");
}
}
}
use of org.eclipse.ceylon.model.typechecker.model.TypeDeclaration in project ceylon by eclipse.
the class AnnotationVisitor method checkAnnotations.
private void checkAnnotations(Tree.AnnotationList annotationList, Type declarationType, Type modelType, Node that) {
Unit unit = annotationList.getUnit();
List<Tree.Annotation> annotations = annotationList.getAnnotations();
for (Tree.Annotation annotation : annotations) {
Type t = annotation.getTypeModel();
if (t != null) {
TypeDeclaration cad = unit.getConstrainedAnnotationDeclaration();
Type cat = t.getSupertype(cad);
if (cat != null) {
// check *Ceylon* annotation constraints
List<Type> args = cat.getTypeArgumentList();
if (args.size() > 2) {
Type constraint = args.get(2);
checkAssignable(declarationType, constraint, annotation, "annotated program element does not satisfy annotation constraint");
}
if (args.size() > 3) {
Type constraint = args.get(3);
if (!constraint.isAnything()) {
checkAssignable(modelType, constraint, annotation, "annotated program element does not satisfy annotation constraint");
}
}
}
EnumSet<AnnotationTarget> target = null;
Tree.Primary primary = annotation.getPrimary();
if (primary instanceof Tree.MemberOrTypeExpression) {
Declaration ac = ((Tree.MemberOrTypeExpression) primary).getDeclaration();
if (ac instanceof TypedDeclaration) {
target = ((TypedDeclaration) ac).getAnnotationTargets();
}
}
if (target != null) {
// check the *Java* annotation constraints
boolean ok = false;
if (that instanceof Tree.PackageDescriptor) {
if (target.contains(PACKAGE)) {
ok = true;
}
}
if (that instanceof Tree.InterfaceDefinition) {
if (target.contains(TYPE)) {
ok = true;
}
}
if (that instanceof Tree.ClassDefinition) {
Tree.ClassDefinition c = (Tree.ClassDefinition) that;
boolean initializer = c.getParameterList() != null;
if (target.contains(TYPE)) {
// it always goes on the class,
// not on the constructor
ok = true;
}
if (target.contains(CONSTRUCTOR) && initializer) {
// it goes on the constructor
ok = true;
}
if (target.contains(ANNOTATION_TYPE) && c.getDeclarationModel().isAnnotation()) {
// it goes on the annotation type
ok = true;
}
}
if (that instanceof Tree.ObjectDefinition) {
if (target.contains(FIELD)) {
ok = true;
}
}
if (that instanceof Tree.Constructor || that instanceof Tree.Enumerated) {
if (target.contains(CONSTRUCTOR)) {
ok = true;
}
}
if (that instanceof Tree.MethodDefinition || that instanceof Tree.MethodDeclaration || that instanceof Tree.AttributeGetterDefinition || that instanceof Tree.AttributeSetterDefinition) {
if (target.contains(METHOD)) {
// it goes on the method, getter,
// or setter, unambiguously
ok = true;
}
}
if (that instanceof Tree.AttributeDeclaration) {
Tree.AttributeDeclaration ad = (Tree.AttributeDeclaration) that;
Value model = ad.getDeclarationModel();
boolean parameter = model.isParameter();
boolean classMember = model.isClassMember();
boolean toplevel = model.isToplevel();
boolean local = !toplevel && !model.isClassOrInterfaceMember();
if (target.contains(PARAMETER) && parameter) {
// in this case there is a parameter,
// so the annotation *never* goes on
// the field, getter, nor setter
ok = true;
}
Tree.SpecifierOrInitializerExpression se = ad.getSpecifierOrInitializerExpression();
if (se instanceof Tree.LazySpecifierExpression || model.isFormal()) {
if (target.contains(METHOD)) {
// there is no field, so it
// goes on the getter
ok = true;
}
} else {
// if it's cannot go on the field
if (classMember || toplevel) {
if (target.contains(FIELD)) {
ok = true;
} else if (target.contains(METHOD)) {
ok = true;
}
}
if (target.contains(LOCAL_VARIABLE) && !parameter && local) {
ok = true;
}
}
}
if (!ok) {
StringBuilder message = new StringBuilder();
for (AnnotationTarget at : target) {
if (message.length() > 0) {
message.append(", ");
}
message.append(at);
}
annotation.addError("annotated program element does not satisfy annotation constraint: the annotation is declared 'target {" + message + "}'");
}
}
}
}
TypeDeclaration od = unit.getOptionalAnnotationDeclaration();
for (int i = 0; i < annotations.size(); i++) {
Tree.Annotation ann = annotations.get(i);
Type t = ann.getTypeModel();
if (t != null) {
TypeDeclaration td = t.getDeclaration();
// this implicitly excludes Java annotations but they are checked in the backend for duplicates
if (td.inherits(od)) {
for (int j = 0; j < i; j++) {
Tree.Annotation other = annotations.get(j);
Type ot = other.getTypeModel();
if (ot != null) {
TypeDeclaration otd = ot.getDeclaration();
if (otd.equals(td)) {
ann.addError("duplicate annotation: there are multiple annotations of type '" + td.getName() + "'");
break;
}
}
}
}
}
}
}
use of org.eclipse.ceylon.model.typechecker.model.TypeDeclaration in project ceylon by eclipse.
the class ExpressionVisitor method handleStaticReferenceImplicitTypeArguments.
/**
* Validate the type arguments to the qualifying type
* in a static reference when no type arguments are
* given explicitly.
*
* This is called later than usual because the type args
* might be inferrable from an invocation of the whole
* static reference.
*
* @param that the static reference
*/
private void handleStaticReferenceImplicitTypeArguments(Tree.QualifiedMemberOrTypeExpression that) {
Declaration member = that.getDeclaration();
Tree.TypeArguments tas = that.getTypeArguments();
// without type arguments to the qualifying type
if (isStaticReference(that)) {
if (member != null && !explicitTypeArguments(member, tas)) {
that.addError("type arguments could not be inferred: '" + member.getName(unit) + "' is generic");
}
// the reference to the qualifying type
Tree.StaticMemberOrTypeExpression smte = (Tree.StaticMemberOrTypeExpression) that.getPrimary();
// we have to get the type args from the tree
// here because the calling code doesn't know
// them (it is walking the qualifying reference)
Tree.TypeArguments typeArgs = smte.getTypeArguments();
TypeDeclaration type = (TypeDeclaration) smte.getDeclaration();
if (type != null && !explicitTypeArguments(type, typeArgs) && typeArgs.getTypeModels() == null) {
// nothing inferred
Declaration declaration = smte.getDeclaration();
smte.addError("missing type arguments to generic type qualifying static reference: '" + declaration.getName(unit) + "' declares type parameters " + typeParameterList(declaration));
}
}
Tree.Primary primary = that.getPrimary();
if (!that.getDirectlyInvoked() && (member.isStatic() || isConstructor(member)) && primary instanceof Tree.StaticMemberOrTypeExpression) {
Tree.StaticMemberOrTypeExpression smte = (Tree.StaticMemberOrTypeExpression) primary;
Declaration qualifyingType = smte.getDeclaration();
Tree.TypeArguments qtas = smte.getTypeArguments();
if (qualifyingType != null && qualifyingType.isParameterized() && !qualifyingType.isJava() && !explicitTypeArguments(qualifyingType, qtas)) {
if (explicitTypeArguments(member, tas)) {
Type functionType = genericFunctionType(qualifyingType, that.getScope(), member, that.getTarget(), unit);
that.setTypeModel(functionType);
checkNotJvm(that, "type functions are not supported on the JVM: '" + qualifyingType.getName(unit) + "' is generic (specify explicit type arguments)");
} else {
that.addError("missing explicit type arguments to generic qualifying type: '" + qualifyingType.getName(unit) + "' declares type parameters " + typeParameterList(qualifyingType));
}
}
}
}
use of org.eclipse.ceylon.model.typechecker.model.TypeDeclaration in project ceylon by eclipse.
the class ExpressionVisitor method getDeclaration.
private TypeDeclaration getDeclaration(Tree.QualifiedMemberOrTypeExpression that, Type pt) {
TypeDeclaration td;
if (that.getStaticMethodReference()) {
Tree.MemberOrTypeExpression primary = (Tree.MemberOrTypeExpression) that.getPrimary();
td = (TypeDeclaration) primary.getDeclaration();
td = td == null ? new UnknownType(unit) : td;
} else {
td = unwrap(pt, that).getDeclaration();
}
if (td != null && td.isNativeImplementation()) {
TypeDeclaration header = (TypeDeclaration) getNativeHeader(td);
if (header != null) {
td = header;
}
}
return td;
}
use of org.eclipse.ceylon.model.typechecker.model.TypeDeclaration in project ceylon by eclipse.
the class ExpressionVisitor method enterConstructorDelegation.
private TypeDeclaration enterConstructorDelegation(Constructor c) {
TypeDeclaration occ = constructorClass;
Type et = c.getExtendedType();
constructorClass = et == null ? null : et.getDeclaration();
return occ;
}
Aggregations