Skip to content

Commit

Permalink
Migrate isWeakReference logic from BindingUtil to ElementUtil.
Browse files Browse the repository at this point in the history
	Change on 2016/11/23 by kstanger <kstanger@google.com>

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=140026535
  • Loading branch information
kstanger authored and Keith Stanger committed Dec 1, 2016
1 parent 1fa859c commit f1648c7
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 63 deletions.
Expand Up @@ -23,7 +23,6 @@
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
import com.google.devtools.j2objc.jdt.BindingConverter;
import com.google.devtools.j2objc.util.BindingUtil;
import com.google.devtools.j2objc.util.ElementUtil;
import java.util.Collection;
import java.util.Iterator;
Expand Down Expand Up @@ -85,15 +84,16 @@ private void addEdge(Edge e) {
private void addFieldEdges() {
for (ITypeBinding type : allTypes.values()) {
for (IVariableBinding field : type.getDeclaredFields()) {
VariableElement fieldE = BindingConverter.getVariableElement(field);
ITypeBinding fieldType = getElementType(field.getType());
if (!whitelist.containsField(field)
&& !whitelist.containsType(fieldType)
&& !fieldType.isPrimitive()
&& !Modifier.isStatic(field.getModifiers())
// Exclude self-referential fields. (likely linked DS or delegate pattern)
&& !type.isAssignmentCompatible(fieldType)
&& !BindingUtil.isWeakReference(field)
&& !BindingUtil.isRetainedWithField(field)) {
&& !ElementUtil.isWeakReference(fieldE)
&& !ElementUtil.isRetainedWithField(fieldE)) {
addEdge(Edge.newFieldEdge(type, field));
}
}
Expand Down Expand Up @@ -162,8 +162,7 @@ private void addOuterClassEdges() {
Element element = BindingConverter.getElement(type.getTypeDeclaration());
if (ElementUtil.isTypeElement(element)
&& captureFields.hasOuterReference((TypeElement) element)
&& !BindingUtil.hasNamedAnnotation(type, "WeakOuter")
&& !BindingUtil.isWeakOuterAnonymousClass(type)) {
&& !ElementUtil.isWeakOuterType((TypeElement) element)) {
ITypeBinding declaringType = type.getDeclaringClass();
if (declaringType != null && !whitelist.containsType(declaringType)
&& !whitelist.hasOuterForType(type)) {
Expand All @@ -183,7 +182,7 @@ private void addAnonymousClassCaptureEdges() {
capturedVarElement);
ITypeBinding targetType = getElementType(capturedVarBinding.getType());
if (!targetType.isPrimitive() && !whitelist.containsType(targetType)
&& !BindingUtil.isWeakReference(capturedVarBinding)) {
&& !ElementUtil.isWeakReference(capturedVarElement)) {
addEdge(Edge.newCaptureEdge(type, capturedVarBinding));
}
}
Expand Down
Expand Up @@ -21,6 +21,7 @@
import javax.lang.model.type.TypeMirror;
import org.eclipse.jdt.core.dom.IAnnotationBinding;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;

abstract class JdtTypeMirror implements TypeMirror {

Expand All @@ -33,8 +34,10 @@ abstract class JdtTypeMirror implements TypeMirror {
@Override
public List<? extends AnnotationMirror> getAnnotationMirrors() {
List<AnnotationMirror> mirrors = new ArrayList<>();
for (IAnnotationBinding annotation : binding.getAnnotations()) {
mirrors.add(new JdtAnnotationMirror(annotation));
if (binding instanceof ITypeBinding) {
for (IAnnotationBinding annotation : ((ITypeBinding) binding).getTypeAnnotations()) {
mirrors.add(new JdtAnnotationMirror(annotation));
}
}
return mirrors;
}
Expand Down
Expand Up @@ -15,7 +15,6 @@
package com.google.devtools.j2objc.util;

import com.google.devtools.j2objc.types.GeneratedTypeElement;
import com.google.j2objc.annotations.Property;
import com.google.j2objc.annotations.RetainedWith;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
Expand Down Expand Up @@ -534,48 +533,6 @@ public static Object getAnnotationValue(IAnnotationBinding annotation, String na
return null;
}

/**
* Checks to see if this is an anonymous class annotated with @WeakOuter.
* Because this is an anonymous class, we can't annotate its declaration
* so we annotate the instantiation instead: (i.e. new @WeakOuter Interface() { ... },
* or new @WeakOuter SomeClass() { ... }).
* In order to detect if a particular anonymous class is annotated in this way, we
* check the type annotations of the interface it implements and its superclass.
*/
public static boolean isWeakOuterAnonymousClass(ITypeBinding type) {
ITypeBinding[] interfaces = type.getInterfaces();
if (interfaces.length > 0) {
if (hasNamedTypeAnnotation(interfaces[0], "WeakOuter")) {
return true;
}
}
ITypeBinding superclass = type.getSuperclass();
if (superclass != null) {
if (hasNamedTypeAnnotation(superclass, "WeakOuter")) {
return true;
}
}
return false;
}

public static boolean isWeakReference(IVariableBinding var) {
if (var.getName().startsWith("this$") && isWeakOuterAnonymousClass(var.getDeclaringClass())) {
return true;
}
return hasNamedAnnotation(var, "Weak")
|| hasWeakPropertyAttribute(var)
|| (var.getName().startsWith("this$")
&& hasNamedAnnotation(var.getDeclaringClass(), "WeakOuter"));
}

static boolean hasWeakPropertyAttribute(IVariableBinding var) {
IAnnotationBinding propertyAnnotation = getAnnotation(var, Property.class);
if (propertyAnnotation == null) {
return false;
}
return parseAttributeString(propertyAnnotation).contains("weak");
}

public static boolean isRetainedWithField(IVariableBinding var) {
return hasAnnotation(var, RetainedWith.class);
}
Expand Down
Expand Up @@ -24,19 +24,22 @@
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;
Expand All @@ -51,7 +54,6 @@
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;

/**
* Utility methods for working with elements.
Expand Down Expand Up @@ -353,16 +355,48 @@ public static boolean isInstanceMethod(Element element) {
return isMethod(element) && !isStatic(element);
}

public static boolean isWeakReference(VariableElement varElement) {
IVariableBinding var = (IVariableBinding) BindingConverter.unwrapElement(varElement);
if (var.getName().startsWith("this$")
&& BindingUtil.isWeakOuterAnonymousClass(var.getDeclaringClass())) {
return true;
public static boolean isWeakReference(VariableElement var) {
return hasNamedAnnotation(var, "Weak")
|| hasWeakPropertyAttribute(var)
|| (getName(var).startsWith("this$")
&& isWeakOuterType(ElementUtil.getDeclaringClass(var)));
}

public static boolean isWeakOuterType(TypeElement type) {
if (isAnonymous(type)) {
// 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;
}
}
return false;
} else {
return hasNamedAnnotation(type, "WeakOuter");
}
return BindingUtil.hasNamedAnnotation(var, "Weak")
|| BindingUtil.hasWeakPropertyAttribute(var)
|| (var.getName().startsWith("this$")
&& BindingUtil.hasNamedAnnotation(var.getDeclaringClass(), "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<>();
attributes.addAll(Arrays.asList(attributesStr.split(",\\s*")));
attributes.remove(""); // Clear any empty strings.
return attributes;
}

public static boolean isRetainedWithField(VariableElement varElement) {
Expand Down Expand Up @@ -582,8 +616,8 @@ public static boolean hasAnnotation(Element element, Class<?> annotationClass) {
/**
* Less strict version of the above where we don't care about the annotation's package.
*/
public static boolean hasNamedAnnotation(Element element, String annotationName) {
for (AnnotationMirror annotation : element.getAnnotationMirrors()) {
public static boolean hasNamedAnnotation(AnnotatedConstruct ac, String annotationName) {
for (AnnotationMirror annotation : ac.getAnnotationMirrors()) {
Name annotationTypeName = annotation.getAnnotationType().asElement().getSimpleName();
if (annotationTypeName.toString().equals(annotationName)) {
return true;
Expand Down

0 comments on commit f1648c7

Please sign in to comment.