/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.devtools.j2objc.util;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.devtools.j2objc.Options;
import com.google.devtools.j2objc.types.GeneratedElement;
import com.google.devtools.j2objc.types.GeneratedExecutableElement;
import com.google.devtools.j2objc.types.GeneratedTypeElement;
import com.google.devtools.j2objc.types.GeneratedVariableElement;
import com.google.devtools.j2objc.types.LambdaTypeElement;
import com.google.j2objc.annotations.Property;
import com.google.j2objc.annotations.RetainedWith;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Symbol;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Pattern;
import javax.annotation.ParametersAreNonnullByDefault;
import javax.lang.model.AnnotatedConstruct;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import javax.lang.model.element.NestingKind;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
/**
* Utility methods for working with elements.
*/
public final class ElementUtil {
// Flags defined in JVM spec, table 4.1. These constants are also defined in
// java.lang.reflect.Modifier, but aren't public.
public static final int ACC_BRIDGE = 0x40;
public static final int ACC_VARARGS = 0x80;
public static final int ACC_SYNTHETIC = 0x1000;
public static final int ACC_ANNOTATION = 0x2000;
public static final int ACC_ENUM = 0x4000;
// Not defined in JVM spec, but used by reflection support.
public static final int ACC_ANONYMOUS = 0x8000;
// Class files can only use the lower 16 bits.
public static final int ACC_FLAG_MASK = 0xFFFF;
private static final Set<Modifier> VISIBILITY_MODIFIERS = EnumSet.of(
Modifier.PUBLIC, Modifier.PROTECTED, Modifier.PRIVATE);
private static final String LAZY_INIT = "com.google.errorprone.annotations.concurrent.LazyInit";
private final Elements javacElements;
private final Map<Element, TypeMirror> elementTypeMap = new HashMap<>();
private static final Map<Integer, Set<Modifier>> modifierSets = new HashMap<>();
public ElementUtil(Elements javacElements) {
this.javacElements = javacElements;
}
public static String getName(Element element) {
// Always return qualified package names.
Name name = element.getKind() == ElementKind.PACKAGE
? ((PackageElement) element).getQualifiedName() : element.getSimpleName();
return name.toString();
}
public static String getQualifiedName(TypeElement element) {
return element.getQualifiedName().toString();
}
public static boolean isStatic(Element element) {
return hasModifier(element, Modifier.STATIC);
}
public static boolean isDefault(Element element) {
// Indirectly check whether Modifier.DEFAULT exists, since it was
// added in Java 8.
try {
Modifier m = Modifier.valueOf("DEFAULT");
return hasModifier(element, m);
} catch (IllegalArgumentException e) {
return false;
}
}
public static boolean isFinal(Element element) {
return hasModifier(element, Modifier.FINAL);
}
public static boolean isPublic(Element element) {
return hasModifier(element, Modifier.PUBLIC);
}
public static boolean isPrivate(Element element) {
return hasModifier(element, Modifier.PRIVATE);
}
public static boolean isVolatile(VariableElement element) {
return hasModifier(element, Modifier.VOLATILE)
// Upgrade reference type fields marked with error prone's LazyInit because this indicates
// an intentional racy init.
|| (!element.asType().getKind().isPrimitive()
&& hasQualifiedNamedAnnotation(element, LAZY_INIT));
}
public static boolean isTopLevel(TypeElement type) {
return type.getNestingKind() == NestingKind.TOP_LEVEL;
}
public static boolean isAnonymous(TypeElement type) {
return type.getNestingKind() == NestingKind.ANONYMOUS;
}
public static boolean isLocal(TypeElement type) {
NestingKind nestingKind = type.getNestingKind();
return nestingKind == NestingKind.ANONYMOUS || nestingKind == NestingKind.LOCAL;
}
public static boolean isLambda(TypeElement type) {
return type instanceof LambdaTypeElement;
}
public static boolean isInterface(Element type) {
return type.getKind() == ElementKind.INTERFACE;
}
public static boolean isAnnotationType(Element type) {
return type.getKind() == ElementKind.ANNOTATION_TYPE;
}
public static boolean isEnum(Element e) {
return e.getKind() == ElementKind.ENUM;
}
public static boolean isEnumConstant(Element e) {
return e.getKind() == ElementKind.ENUM_CONSTANT;
}
public static boolean isPackage(Element e) {
return e.getKind() == ElementKind.PACKAGE;
}
public static boolean isTypeElement(Element e) {
ElementKind kind = e.getKind();
return kind.isClass() || kind.isInterface();
}
public static boolean isExecutableElement(Element e) {
ElementKind kind = e.getKind();
return kind == ElementKind.CONSTRUCTOR || kind == ElementKind.METHOD;
}
public static boolean isTypeParameterElement(Element e) {
return e.getKind() == ElementKind.TYPE_PARAMETER;
}
public static boolean isAnnotationMember(ExecutableElement e) {
return isAnnotationType(getDeclaringClass(e));
}
//TODO(malvania): For elements inside static blocks, this method returns a "TypeElement" of a
// static block, which does not work with getBinaryName(TypeElement) (one proven example)
public static TypeElement getDeclaringClass(Element element) {
do {
element = element.getEnclosingElement();
} while (element != null && !isTypeElement(element));
return (TypeElement) element;
}
public static TypeElement getSuperclass(TypeElement element) {
TypeMirror supertype = element.getSuperclass();
return supertype != null ? TypeUtil.asTypeElement(supertype) : null;
}
public static List<TypeElement> getInterfaces(TypeElement element) {
return Lists.newArrayList(Iterables.transform(
element.getInterfaces(), i -> TypeUtil.asTypeElement(i)));
}
public static boolean isPrimitiveConstant(VariableElement element) {
return isFinal(element) && element.asType().getKind().isPrimitive()
&& element.getConstantValue() != null
// Exclude local variables declared final.
&& element.getKind().isField();
}
public static boolean isConstant(VariableElement element) {
Object constantValue = element.getConstantValue();
return constantValue != null
&& (element.asType().getKind().isPrimitive()
|| (constantValue instanceof String
&& UnicodeUtils.hasValidCppCharacters((String) constantValue)));
}
public static boolean isStringConstant(VariableElement element) {
Object constantValue = element.getConstantValue();
return constantValue != null && constantValue instanceof String
&& UnicodeUtils.hasValidCppCharacters((String) constantValue);
}
/**
* Returns whether this variable will be declared in global scope in ObjC.
*/
public static boolean isGlobalVar(VariableElement element) {
return isStatic(element) || isPrimitiveConstant(element);
}
/**
* Returns whether this variable will be an ObjC instance variable.
*/
public static boolean isInstanceVar(VariableElement element) {
return element.getKind() == ElementKind.FIELD && !isGlobalVar(element);
}
public static boolean isNonnull(VariableElement element) {
return element instanceof GeneratedVariableElement
&& ((GeneratedVariableElement) element).isNonnull();
}
public static String getTypeQualifiers(VariableElement element) {
return element instanceof GeneratedVariableElement
? ((GeneratedVariableElement) element).getTypeQualifiers() : null;
}
public static boolean isAbstract(Element element) {
return hasModifier(element, Modifier.ABSTRACT);
}
public static boolean isNative(Element element) {
return hasModifier(element, Modifier.NATIVE);
}
public static boolean isSynchronized(Element element) {
return hasModifier(element, Modifier.SYNCHRONIZED);
}
public static boolean isSynthetic(int modifiers) {
return (modifiers & ACC_SYNTHETIC) != 0;
}
public static boolean isSynthetic(Element e) {
if (e instanceof GeneratedElement) {
return ((GeneratedElement) e).isSynthetic();
}
if (e instanceof Symbol) {
return (((Symbol) e).flags() & Flags.SYNTHETIC) > 0;
}
return false;
}
public static String getHeader(TypeElement e) {
return e instanceof GeneratedTypeElement ? ((GeneratedTypeElement) e).getHeader() : null;
}
public static boolean isIosType(TypeElement e) {
return e instanceof GeneratedTypeElement && ((GeneratedTypeElement) e).isIosType();
}
public static String getSelector(ExecutableElement e) {
if (e instanceof GeneratedExecutableElement) {
return ((GeneratedExecutableElement) e).getSelector();
}
return null;
}
public static boolean isPackageInfo(TypeElement type) {
return type.getSimpleName().toString().equals(NameTable.PACKAGE_INFO_CLASS_NAME);
}
/**
* Tests if this type element is private to it's source file. A public type declared
* within a private type is considered private.
*/
public static boolean isPrivateInnerType(TypeElement type) {
switch (type.getNestingKind()) {
case ANONYMOUS:
case LOCAL:
return true;
case MEMBER:
return isPrivate(type) || isPrivateInnerType((TypeElement) type.getEnclosingElement());
case TOP_LEVEL:
return isPrivate(type);
}
throw new AssertionError("Unknown NestingKind");
}
/**
* Determines if a type element can access fields and methods from an outer class.
*/
public static boolean hasOuterContext(TypeElement type) {
switch (type.getNestingKind()) {
case ANONYMOUS:
case LOCAL:
return !isStatic(type.getEnclosingElement());
case MEMBER:
return !isStatic(type);
case TOP_LEVEL:
return false;
}
throw new AssertionError("Unknown NestingKind");
}
private static boolean hasModifier(Element element, Modifier modifier) {
return element.getModifiers().contains(modifier);
}
public static boolean isVariable(Element element) {
ElementKind kind = element.getKind();
return kind == ElementKind.FIELD || kind == ElementKind.LOCAL_VARIABLE
|| kind == ElementKind.PARAMETER || kind == ElementKind.EXCEPTION_PARAMETER
|| kind == ElementKind.RESOURCE_VARIABLE || kind == ElementKind.ENUM_CONSTANT;
}
public static boolean isField(Element element) {
return element.getKind() == ElementKind.FIELD;
}
public static boolean isParameter(Element element) {
return element.getKind() == ElementKind.PARAMETER;
}
public static boolean isLocalVariable(Element element) {
return element.getKind() == ElementKind.LOCAL_VARIABLE;
}
public static boolean isMethod(Element element) {
return element.getKind() == ElementKind.METHOD;
}
public static boolean isConstructor(Element element) {
return element.getKind() == ElementKind.CONSTRUCTOR;
}
public static boolean isInstanceMethod(Element element) {
return isMethod(element) && !isStatic(element);
}
public static boolean isWeakReference(VariableElement var) {
return hasNamedAnnotation(var, "Weak")
|| hasWeakPropertyAttribute(var)
|| (var instanceof GeneratedVariableElement && ((GeneratedVariableElement) var).isWeak());
}
public boolean isWeakOuterType(TypeElement type) {
if (type instanceof LambdaTypeElement) {
return ((LambdaTypeElement) type).isWeakOuter();
} else if (isAnonymous(type)) {
// TODO(kstanger): remove this block when javac conversion is complete.
// For anonymous classes we must check for a TYPE_USE annotation on the supertype used in the
// declaration. For example:
// Runnable r = new @WeakOuter Runnable() { ... };
TypeMirror superclass = type.getSuperclass();
if (superclass != null && hasNamedAnnotation(superclass, "WeakOuter")) {
return true;
}
for (TypeMirror intrface : type.getInterfaces()) {
if (hasNamedAnnotation(intrface, "WeakOuter")) {
return true;
}
}
if (elementTypeMap.containsKey(type)) {
return hasNamedAnnotation(elementTypeMap.get(type), "WeakOuter");
}
return hasNamedAnnotation(type.asType(), "WeakOuter");
} else {
return hasNamedAnnotation(type, "WeakOuter");
}
}
private static boolean hasWeakPropertyAttribute(VariableElement var) {
AnnotationMirror annotation = getAnnotation(var, Property.class);
return annotation != null && parsePropertyAttribute(annotation).contains("weak");
}
/**
* Returns the attributes of a Property annotation.
*/
public static Set<String> parsePropertyAttribute(AnnotationMirror annotation) {
assert getName(annotation.getAnnotationType().asElement()).equals("Property");
String attributesStr = (String) getAnnotationValue(annotation, "value");
Set<String> attributes = new HashSet<>();
if (attributesStr != null) {
attributes.addAll(Arrays.asList(attributesStr.split(",\\s*")));
attributes.remove(""); // Clear any empty strings.
}
return attributes;
}
public static boolean isRetainedWithField(VariableElement varElement) {
return hasAnnotation(varElement, RetainedWith.class);
}
public static <T extends Element> Iterable<T> filterEnclosedElements(
Element elem, Class<T> resultClass, ElementKind... kinds) {
List<ElementKind> kindsList = Arrays.asList(kinds);
return Iterables.transform(Iterables.filter(
elem.getEnclosedElements(), e -> kindsList.contains(e.getKind())), resultClass::cast);
}
public static Iterable<ExecutableElement> getMethods(TypeElement e) {
return filterEnclosedElements(e, ExecutableElement.class, ElementKind.METHOD);
}
public static Iterable<ExecutableElement> getConstructors(TypeElement e) {
return filterEnclosedElements(e, ExecutableElement.class, ElementKind.CONSTRUCTOR);
}
public static List<ExecutableElement> getExecutables(TypeElement e) {
return Lists.newArrayList(filterEnclosedElements(
e, ExecutableElement.class, ElementKind.CONSTRUCTOR, ElementKind.METHOD));
}
public static List<VariableElement> getDeclaredFields(Element e) {
return Lists.newArrayList(filterEnclosedElements(e, VariableElement.class, ElementKind.FIELD));
}
public static Iterable<TypeElement> getDeclaredTypes(TypeElement e) {
return filterEnclosedElements(
e, TypeElement.class, ElementKind.ANNOTATION_TYPE, ElementKind.ENUM, ElementKind.CLASS,
ElementKind.INTERFACE);
}
private static boolean paramsMatch(ExecutableElement method, String[] paramTypes) {
List<? extends VariableElement> params = method.getParameters();
int size = params.size();
if (size != paramTypes.length) {
return false;
}
for (int i = 0; i < size; i++) {
if (!TypeUtil.getQualifiedName(params.get(i).asType()).equals(paramTypes[i])) {
return false;
}
}
return true;
}
public static ExecutableElement findMethod(TypeElement type, String name, String... paramTypes) {
return Iterables.getFirst(Iterables.filter(
filterEnclosedElements(type, ExecutableElement.class, ElementKind.METHOD),
method -> getName(method).equals(name) && paramsMatch(method, paramTypes)), null);
}
public static Iterable<TypeMirror> asTypes(Iterable<? extends Element> elements) {
return Iterables.transform(elements, elem -> elem.asType());
}
public boolean overrides(
ExecutableElement overrider, ExecutableElement overridden, TypeElement type) {
return javacElements.overrides(overrider, overridden, type);
}
public static PackageElement getPackage(Element e) {
while (e != null && !isPackage(e)) {
e = e.getEnclosingElement();
}
return (PackageElement) e;
}
public String getBinaryName(TypeElement e) {
if (e instanceof GeneratedTypeElement) {
TypeElement declaringClass = getDeclaringClass(e);
if (declaringClass != null) {
return getBinaryName(declaringClass) + '$' + getName(e);
} else {
return getQualifiedName(e);
}
}
return javacElements.getBinaryName(e).toString();
}
Map<? extends ExecutableElement, ? extends AnnotationValue>
getElementValuesWithDefaults(AnnotationMirror a) {
return javacElements.getElementValuesWithDefaults(a);
}
public static Set<Modifier> getVisibilityModifiers(Element e) {
return Sets.intersection(e.getModifiers(), VISIBILITY_MODIFIERS);
}
public static Set<Modifier> toModifierSet(int modifiers) {
Set<Modifier> set = modifierSets.get(modifiers);
if (set == null) {
set = EnumSet.noneOf(Modifier.class);
if ((modifiers & java.lang.reflect.Modifier.PUBLIC) > 0) {
set.add(Modifier.PUBLIC);
}
if ((modifiers & java.lang.reflect.Modifier.PRIVATE) > 0) {
set.add(Modifier.PRIVATE);
}
if ((modifiers & java.lang.reflect.Modifier.PROTECTED) > 0) {
set.add(Modifier.PROTECTED);
}
if ((modifiers & java.lang.reflect.Modifier.STATIC) > 0) {
set.add(Modifier.STATIC);
}
if ((modifiers & java.lang.reflect.Modifier.FINAL) > 0) {
set.add(Modifier.FINAL);
}
if ((modifiers & java.lang.reflect.Modifier.SYNCHRONIZED) > 0) {
set.add(Modifier.SYNCHRONIZED);
}
if ((modifiers & java.lang.reflect.Modifier.VOLATILE) > 0) {
set.add(Modifier.VOLATILE);
}
if ((modifiers & java.lang.reflect.Modifier.TRANSIENT) > 0) {
set.add(Modifier.TRANSIENT);
}
if ((modifiers & java.lang.reflect.Modifier.NATIVE) > 0) {
set.add(Modifier.NATIVE);
}
if ((modifiers & java.lang.reflect.Modifier.ABSTRACT) > 0) {
set.add(Modifier.ABSTRACT);
}
if ((modifiers & java.lang.reflect.Modifier.STRICT) > 0) {
set.add(Modifier.STRICTFP);
}
// Indirectly check whether Modifier.DEFAULT exists, since it was
// added in Java 8.
if ((modifiers & org.eclipse.jdt.core.dom.Modifier.DEFAULT) > 0) {
try {
Modifier m = Modifier.valueOf("DEFAULT");
set.add(m);
} catch (IllegalArgumentException e) {
// Can only add DEFAULT modifier in Java 8.
}
}
modifierSets.put(modifiers, set);
}
return set;
}
public static int fromModifierSet(Set<Modifier> set) {
int modifiers = 0;
if (set.contains(Modifier.PUBLIC)) {
modifiers |= java.lang.reflect.Modifier.PUBLIC;
}
if (set.contains(Modifier.PRIVATE)) {
modifiers |= java.lang.reflect.Modifier.PRIVATE;
}
if (set.contains(Modifier.PROTECTED)) {
modifiers |= java.lang.reflect.Modifier.PROTECTED;
}
if (set.contains(Modifier.STATIC)) {
modifiers |= java.lang.reflect.Modifier.STATIC;
}
if (set.contains(Modifier.FINAL)) {
modifiers |= java.lang.reflect.Modifier.FINAL;
}
if (set.contains(Modifier.SYNCHRONIZED)) {
modifiers |= java.lang.reflect.Modifier.SYNCHRONIZED;
}
if (set.contains(Modifier.VOLATILE)) {
modifiers |= java.lang.reflect.Modifier.VOLATILE;
}
if (set.contains(Modifier.TRANSIENT)) {
modifiers |= java.lang.reflect.Modifier.TRANSIENT;
}
if (set.contains(Modifier.NATIVE)) {
modifiers |= java.lang.reflect.Modifier.NATIVE;
}
if (set.contains(Modifier.ABSTRACT)) {
modifiers |= java.lang.reflect.Modifier.ABSTRACT;
}
if (set.contains(Modifier.STRICTFP)) {
modifiers |= java.lang.reflect.Modifier.STRICT;
}
// Indirectly check whether Modifier.DEFAULT exists, since it was
// added in Java 8.
try {
Modifier m = Modifier.valueOf("DEFAULT");
if (set.contains(m)) {
modifiers |= org.eclipse.jdt.core.dom.Modifier.DEFAULT;
}
} catch (IllegalArgumentException e) {
// Can only add DEFAULT modifier in Java 8.
}
return modifiers;
}
public static boolean isRuntimeAnnotation(AnnotationMirror mirror) {
return isRuntimeAnnotation(mirror.getAnnotationType().asElement());
}
public static boolean isRuntimeAnnotation(Element e) {
if (e.getKind() != ElementKind.ANNOTATION_TYPE) {
return false;
}
for (AnnotationMirror ann : e.getAnnotationMirrors()) {
String annotationName = ann.getAnnotationType().asElement().getSimpleName().toString();
if (annotationName.equals("Retention")) {
for (AnnotationValue value : ann.getElementValues().values()) {
// Retention's value is a RetentionPolicy enum constant.
VariableElement v = (VariableElement) value.getValue();
return v.getSimpleName().toString().equals("RUNTIME");
}
}
}
return false;
}
public static AnnotationMirror getAnnotation(Element element, Class<?> annotationClass) {
return getQualifiedNamedAnnotation(element, annotationClass.getName());
}
public static boolean hasAnnotation(Element element, Class<?> annotationClass) {
return getAnnotation(element, annotationClass) != null;
}
/**
* Less strict version of the above where we don't care about the annotation's package.
*/
public static boolean hasNamedAnnotation(AnnotatedConstruct ac, String name) {
for (AnnotationMirror annotation : ac.getAnnotationMirrors()) {
if (getName(annotation.getAnnotationType().asElement()).equals(name)) {
return true;
}
}
return false;
}
public static boolean hasQualifiedNamedAnnotation(Element element, String name) {
return getQualifiedNamedAnnotation(element, name) != null;
}
public static AnnotationMirror getQualifiedNamedAnnotation(Element element, String name) {
for (AnnotationMirror annotation : element.getAnnotationMirrors()) {
if (getQualifiedName((TypeElement) annotation.getAnnotationType().asElement()).equals(name)) {
return annotation;
}
}
return null;
}
/**
* Return true if a binding has a named "Nullable" annotation. Package names aren't
* checked because different nullable annotations are defined by several different
* Java frameworks.
*/
public static boolean hasNullableAnnotation(Element element) {
return hasNamedAnnotation(element, "Nullable");
}
/**
* Return true if a binding has a named "Nonnull" annotation. Package names aren't
* checked because different nonnull annotations are defined in several Java
* frameworks, with varying but similar names.
*/
public static boolean hasNonnullAnnotation(Element element) {
Pattern p = Pattern.compile("No[nt][Nn]ull");
for (AnnotationMirror annotation : element.getAnnotationMirrors()) {
if (p.matcher(annotation.getAnnotationType().asElement().getSimpleName()).matches()) {
return true;
}
}
return false;
}
public static Object getAnnotationValue(AnnotationMirror annotation, String name) {
for (Entry<? extends ExecutableElement, ? extends AnnotationValue> entry
: annotation.getElementValues().entrySet()) {
if (entry.getKey().getSimpleName().toString().equals(name)) {
return entry.getValue().getValue();
}
}
return null;
}
/**
* Returns an alphabetically sorted list of an annotation type's members.
* This is necessary since an annotation's values can be specified in any
* order, but the annotation's constructor needs to be invoked using its
* declaration order.
*/
public static List<ExecutableElement> getSortedAnnotationMembers(TypeElement annotation) {
List<ExecutableElement> members = Lists.newArrayList(getMethods(annotation));
Collections.sort(members, (m1, m2) -> getName(m1).compareTo(getName(m2)));
return members;
}
public boolean areParametersNonnullByDefault(TypeElement typeElement, Options options) {
if (ElementUtil.hasAnnotation(typeElement, ParametersAreNonnullByDefault.class)) {
return true;
}
PackageElement pkg = getPackage(typeElement);
String pkgName = pkg.getQualifiedName().toString();
return options.getPackageInfoLookup().hasParametersAreNonnullByDefault(pkgName);
}
/**
* Returns true if there's a SuppressedWarning annotation with the specified warning.
* The SuppressWarnings annotation can be inherited from the owning method or class,
* but does not have package scope.
*/
@SuppressWarnings("unchecked")
public static boolean suppressesWarning(String warning, Element element) {
if (element == null || isPackage(element)) {
return false;
}
AnnotationMirror annotation = getAnnotation(element, SuppressWarnings.class);
if (annotation != null) {
for (AnnotationValue elem
: (List<? extends AnnotationValue>) getAnnotationValue(annotation, "value")) {
if (warning.equals(elem.getValue())) {
return true;
}
}
}
return suppressesWarning(warning, element.getEnclosingElement());
}
/**
* Maps an Element to a TypeMirror. element.asType() is the preferred mapping,
* but sometimes type information is lost. For example, an anonymous class with
* a type use annotation has the annotation in the node's type, but not in the
* node's element.asType().
*/
public void mapElementType(Element element, TypeMirror type) {
elementTypeMap.put(element, type);
}
/**
* Returns the associated type mirror for an element.
*/
public TypeMirror getType(Element element) {
return elementTypeMap.containsKey(element) ? elementTypeMap.get(element) : element.asType();
}
/**
* Returns whether an element is marked as always being non-null. Field, method,
* and parameter elements can be defined as non-null with a Nonnull annotation.
* Method parameters can also be defined as non-null by annotating the owning
* package or type element with the ParametersNonnullByDefault annotation.
*/
public static boolean isNonnull(Element element, boolean parametersNonnullByDefault) {
return hasNonnullAnnotation(element)
|| (isParameter(element)
&& parametersNonnullByDefault
&& !((VariableElement) element).asType().getKind().isPrimitive());
}
}