use of org.checkerframework.checker.guieffect.qual.SafeEffect in project checker-framework by typetools.
the class GuiEffectTypeFactory method getDeclaredEffect.
/**
* Calling context annotations
*
* <p>To make anon-inner-classes work, I need to climb the inheritance DAG, until I:
*
* <ul>
* <li>find the class/interface that declares this calling method (an anon inner class is a
* separate class that implements an interface)
* <li>check whether *that* declaration specifies @UI on either the type or method
* </ul>
*
* A method has the UI effect when:
*
* <ol>
* <li>A method is UI if annotated @UIEffect
* <li>A method is UI if the enclosing class is annotated @UI or @UIType and the method is not
* annotated @AlwaysSafe
* <li>A method is UI if the corresponding method in the super-class/interface is UI, and this
* method is not annotated @AlwaysSafe, and this method resides in an anonymous inner
* class (named classes still require a package/class/method annotation to make it UI,
* only anon inner classes have this inheritance-by-default)
* <ul>
* <li>A method must be *annotated* UI if the method it overrides is *annotated* UI
* <li>A method must be *annotated* UI if it overrides a UI method and the enclosing
* class is not UI
* </ul>
* <li>It is an error if a method is UI but the same method in a super-type is not UI
* <li>It is an error if two super-types specify the same method, where one type says it's UI
* and one says it's not (it's possible to simply enforce the weaker (safe) effect, but
* this seems more principled, it's easier --- backwards-compatible --- to change our
* minds about this later)
* </ol>
*/
public Effect getDeclaredEffect(ExecutableElement methodElt) {
if (debugSpew) {
System.err.println("begin mayHaveUIEffect(" + methodElt + ")");
}
AnnotationMirror targetUIP = getDeclAnnotation(methodElt, UIEffect.class);
AnnotationMirror targetSafeP = getDeclAnnotation(methodElt, SafeEffect.class);
AnnotationMirror targetPolyP = getDeclAnnotation(methodElt, PolyUIEffect.class);
TypeElement targetClassElt = (TypeElement) methodElt.getEnclosingElement();
if (debugSpew) {
System.err.println("targetClassElt found");
}
// Short-circuit if the method is explicitly annotated
if (targetSafeP != null) {
if (debugSpew) {
System.err.println("Method marked @SafeEffect");
}
return new Effect(SafeEffect.class);
} else if (targetUIP != null) {
if (debugSpew) {
System.err.println("Method marked @UIEffect");
}
return new Effect(UIEffect.class);
} else if (targetPolyP != null) {
if (debugSpew) {
System.err.println("Method marked @PolyUIEffect");
}
return new Effect(PolyUIEffect.class);
}
if (isUIType(targetClassElt)) {
// Already checked, no explicit @SafeEffect annotation
return new Effect(UIEffect.class);
}
// developer to be explicit.
if (isAnonymousType(targetClassElt)) {
// Refine this for polymorphic parents
boolean canInheritParentEffects = true;
DeclaredType directSuper = (DeclaredType) targetClassElt.getSuperclass();
TypeElement superElt = (TypeElement) directSuper.asElement();
// Anonymous subtypes of polymorphic classes other than object can't inherit
if (getDeclAnnotation(superElt, PolyUIType.class) != null && !TypesUtils.isObject(directSuper)) {
canInheritParentEffects = false;
} else {
for (TypeMirror ifaceM : targetClassElt.getInterfaces()) {
DeclaredType iface = (DeclaredType) ifaceM;
TypeElement ifaceElt = (TypeElement) iface.asElement();
if (getDeclAnnotation(ifaceElt, PolyUIType.class) != null) {
canInheritParentEffects = false;
}
}
}
if (canInheritParentEffects) {
Effect.EffectRange r = findInheritedEffectRange(targetClassElt, methodElt);
return (r != null ? Effect.min(r.min, r.max) : new Effect(SafeEffect.class));
}
}
return new Effect(SafeEffect.class);
}
use of org.checkerframework.checker.guieffect.qual.SafeEffect in project checker-framework by typetools.
the class GuiEffectTypeFactory method getComputedEffectAtCallsite.
/**
* Get the effect of a method call at its callsite, acknowledging polymorphic instantiation
* using type use annotations.
*
* @param node The method invocation as an AST node.
* @param callerReceiver The type of the receiver object if available. Used to resolve direct
* calls like "super()"
* @param methodElt The element of the callee method.
* @return The computed effect (SafeEffect or UIEffect) for the method call.
*/
public Effect getComputedEffectAtCallsite(MethodInvocationTree node, AnnotatedTypeMirror.AnnotatedDeclaredType callerReceiver, ExecutableElement methodElt) {
Effect targetEffect = getDeclaredEffect(methodElt);
if (targetEffect.isPoly()) {
AnnotatedTypeMirror srcType = null;
if (node.getMethodSelect().getKind() == Tree.Kind.MEMBER_SELECT) {
ExpressionTree src = ((MemberSelectTree) node.getMethodSelect()).getExpression();
srcType = getAnnotatedType(src);
} else if (node.getMethodSelect().getKind() == Tree.Kind.IDENTIFIER) {
// Tree.Kind.IDENTIFIER, e.g. a direct call like "super()"
if (callerReceiver == null) {
// Not enought information provided to instantiate this type-polymorphic effects
return targetEffect;
}
srcType = callerReceiver;
} else {
ErrorReporter.errorAbort("Unexpected getMethodSelect() kind at callsite " + node);
}
// Instantiate type-polymorphic effects
if (srcType.hasAnnotation(AlwaysSafe.class)) {
targetEffect = new Effect(SafeEffect.class);
} else if (srcType.hasAnnotation(UI.class)) {
targetEffect = new Effect(UIEffect.class);
}
// Poly substitution would be a noop.
}
return targetEffect;
}
Aggregations