<NME> JreRetainedWith.h
<BEF> // 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.

//
//  JreRetainedWith.h
//  JreEmulation
//
//  Created by Keith Stanger on Mar. 18, 2016.
//
// INTERNAL ONLY. For use by JRE emulation code.

#ifndef JRE_RETAINED_WITH_H_
#define JRE_RETAINED_WITH_H_

#import <Foundation/Foundation.h>

// Called by @RetainedWith assignment functions. Caller must ensure that value
// has a retain count at least two.
FOUNDATION_EXPORT void JreRetainedWithInitialize(id parent, id value);

// Checks the previous value of a @RetainedWith assignment, possibly returning
// it to normal behavior.
FOUNDATION_EXPORT void JreRetainedWithHandlePreviousValue(id parent, id value);

// Called during dealloc of the parent and before releasing the child.
FOUNDATION_EXPORT void JreRetainedWithHandleDealloc(id parent, id child);

#endif // JRE_RETAINED_WITH_H_

#define RETAINED_WITH_CHILD(PARENT_REF) \
  RETAINED_WITH_CHILD_NUM_REFS(PARENT_REF, 1)

#endif // JRE_RETAINED_WITH_H_

<MSG> Handle @RetainedWith annotation in cycle_finder.
Adds RetainedWith behavior to JRE map types.

	Change on 2016/05/31 by kstanger <kstanger@google.com>

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=123645390

<DFF> @@ -34,4 +34,25 @@ FOUNDATION_EXPORT void JreRetainedWithCheckPreviousValue(id parent, id value);
 // Called during dealloc of the parent and before releasing the child.
 FOUNDATION_EXPORT void JreRetainedWithHandleDealloc(id parent, id child);
 
+// Internal only macro that hacks the @RetainedWith behavior to a child class
+// without needing to use class swizzling or associated objects. Must be
+// combined with @Weak or @WeakOuter on the parent reference.
+#define RETAINED_WITH_CHILD(PARENT_REF) \
+  - (id)retain { \
+    @synchronized (self) { \
+      if ([self retainCount] == 1) { \
+        [PARENT_REF retain]; \
+      } \
+      return [super retain]; \
+    } \
+  } \
+  - (oneway void)release { \
+    @synchronized (self) { \
+      if ([self retainCount] == 2) { \
+        [PARENT_REF autorelease]; \
+      } \
+      [super release]; \
+    } \
+  }
+
 #endif // JRE_RETAINED_WITH_H_

{'commit': 'diff --git a/cycle_finder/src/main/java/com/google/devtools/cyclefinder/ReferenceGraph.java b/cycle_finder/src/main/java/com/google/devtools/cyclefinder/ReferenceGraph.java\nindex b495eb397..58802e6b8 100644\n--- a/cycle_finder/src/main/java/com/google/devtools/cyclefinder/ReferenceGraph.java\n+++ b/cycle_finder/src/main/java/com/google/devtools/cyclefinder/ReferenceGraph.java\n@@ -90,7 +90,8 @@ public class ReferenceGraph {\n             && !Modifier.isStatic(field.getModifiers())\n             // Exclude self-referential fields. (likely linked DS or delegate pattern)\n             && !type.isAssignmentCompatible(fieldType)\n-            && !BindingUtil.isWeakReference(field)) {\n+            && !BindingUtil.isWeakReference(field)\n+            && !BindingUtil.isRetainedWithField(field)) {\n           addEdge(Edge.newFieldEdge(type, field));\n         }\n       }\ndiff --git a/cycle_finder/src/test/java/com/google/devtools/cyclefinder/CycleFinderTest.java b/cycle_finder/src/test/java/com/google/devtools/cyclefinder/CycleFinderTest.java\nindex f4c56354e..ef6720f03 100644\n--- a/cycle_finder/src/test/java/com/google/devtools/cyclefinder/CycleFinderTest.java\n+++ b/cycle_finder/src/test/java/com/google/devtools/cyclefinder/CycleFinderTest.java\n@@ -73,6 +73,14 @@ public class CycleFinderTest extends TestCase {\n     assertNoCycles();\n   }\n \n+  public void testRetainedWithField() throws Exception {\n+    addSourceFile("A.java",\n+        "import com.google.j2objc.annotations.RetainedWith; class A { @RetainedWith B b; }");\n+    addSourceFile("B.java", "class B { A a; }");\n+    findCycles();\n+    assertNoCycles();\n+  }\n+\n   public void testRecursiveWildcard() throws Exception {\n     addSourceFile("A.java", "class A<T> { A<? extends T> a; }");\n     addSourceFile("B.java", "class B<T> { B<? extends B<T>> b; }");\ndiff --git a/jre_emul/Classes/JreRetainedWith.h b/jre_emul/Classes/JreRetainedWith.h\nindex 50e194cdd..bb312a612 100644\n--- a/jre_emul/Classes/JreRetainedWith.h\n+++ b/jre_emul/Classes/JreRetainedWith.h\n@@ -34,4 +34,25 @@ FOUNDATION_EXPORT void JreRetainedWithCheckPreviousValue(id parent, id value);\n // Called during dealloc of the parent and before releasing the child.\n FOUNDATION_EXPORT void JreRetainedWithHandleDealloc(id parent, id child);\n \n+// Internal only macro that hacks the @RetainedWith behavior to a child class\n+// without needing to use class swizzling or associated objects. Must be\n+// combined with @Weak or @WeakOuter on the parent reference.\n+#define RETAINED_WITH_CHILD(PARENT_REF) \\\n+  - (id)retain { \\\n+    @synchronized (self) { \\\n+      if ([self retainCount] == 1) { \\\n+        [PARENT_REF retain]; \\\n+      } \\\n+      return [super retain]; \\\n+    } \\\n+  } \\\n+  - (oneway void)release { \\\n+    @synchronized (self) { \\\n+      if ([self retainCount] == 2) { \\\n+        [PARENT_REF autorelease]; \\\n+      } \\\n+      [super release]; \\\n+    } \\\n+  }\n+\n #endif // JRE_RETAINED_WITH_H_\ndiff --git a/jre_emul/Tests/com/google/j2objc/RetainedWithTest.java b/jre_emul/Tests/com/google/j2objc/RetainedWithTest.java\nindex 2dc41109b..f7b2be1a3 100644\n--- a/jre_emul/Tests/com/google/j2objc/RetainedWithTest.java\n+++ b/jre_emul/Tests/com/google/j2objc/RetainedWithTest.java\n@@ -20,9 +20,18 @@ import com.google.j2objc.annotations.RetainedWith;\n import junit.framework.TestCase;\n \n import java.util.ArrayList;\n+import java.util.Collection;\n+import java.util.EnumMap;\n+import java.util.HashMap;\n import java.util.HashSet;\n+import java.util.Hashtable;\n+import java.util.IdentityHashMap;\n import java.util.List;\n+import java.util.Map;\n import java.util.Set;\n+import java.util.TreeMap;\n+import java.util.WeakHashMap;\n+import java.util.concurrent.ConcurrentHashMap;\n \n /**\n  * Tests the {@link RetainedWith} annotation.\n@@ -151,4 +160,111 @@ public class RetainedWithTest extends TestCase {\n       assertTrue(finalizedObjects.contains(i));\n     }\n   }\n+\n+  abstract class MapFactory {\n+\n+    final Object key;\n+\n+    MapFactory(Object key) {\n+      this.key = key;\n+    }\n+\n+    public abstract Map newMap();\n+\n+    public Object getKey() {\n+      return key;\n+    }\n+  }\n+\n+  // We use this class as a value to insert in our maps so we can verity that the map has been\n+  // deallocated.\n+  static class ValueType {\n+    protected void finalize() {\n+      finalizedObjects.add(System.identityHashCode(this));\n+    }\n+  }\n+\n+  enum Color { RED, GREEN, BLUE }\n+\n+  Set keys;\n+  Collection values;\n+  Set<Map.Entry> entrySet;\n+\n+  @AutoreleasePool\n+  private void createMapChildren(MapFactory factory, List<Integer> objectCodes) {\n+    // Use separate maps for each of the views to ensure that each view type is strengthening its\n+    // reference to the map.\n+    Map m1 = factory.newMap();\n+    Map m2 = factory.newMap();\n+    Map m3 = factory.newMap();\n+    ValueType v = new ValueType();\n+    m1.put(factory.getKey(), v);\n+    m2.put(factory.getKey(), v);\n+    m3.put(factory.getKey(), v);\n+    keys = m1.keySet();\n+    values = m2.values();\n+    entrySet = m3.entrySet();\n+    objectCodes.add(System.identityHashCode(v));\n+  }\n+\n+  @AutoreleasePool\n+  private void checkMapChildren(MapFactory factory, List<Integer> objectCodes) {\n+    createMapChildren(factory, objectCodes);\n+    // Call some methods to make sure they still exist and can access the parent\n+    assertEquals(1, keys.size());\n+    assertEquals(1, values.size());\n+    assertEquals(1, entrySet.size());\n+    assertTrue(keys.contains(factory.getKey()));\n+    assertFalse(values.contains(new Object()));\n+    assertEquals(factory.getKey(), entrySet.iterator().next().getKey());\n+    keys = null;\n+    values = null;\n+    entrySet = null;\n+  }\n+\n+  public void runMapTest(MapFactory factory) {\n+    List<Integer> objectCodes = new ArrayList<Integer>();\n+    checkMapChildren(factory, objectCodes);\n+    for (Integer i : objectCodes) {\n+      assertTrue(finalizedObjects.contains(i));\n+    }\n+  }\n+\n+  public void testMapChildren() {\n+    runMapTest(new MapFactory(new Object()) {\n+      public Map newMap() {\n+        return new IdentityHashMap();\n+      }\n+    });\n+    runMapTest(new MapFactory(new Object()) {\n+      public Map newMap() {\n+        return new WeakHashMap();\n+      }\n+    });\n+    runMapTest(new MapFactory(Color.RED) {\n+      public Map newMap() {\n+        return new EnumMap(Color.class);\n+      }\n+    });\n+    runMapTest(new MapFactory(new Object()) {\n+      public Map newMap() {\n+        return new HashMap();\n+      }\n+    });\n+    runMapTest(new MapFactory(5) {\n+      public Map newMap() {\n+        return new TreeMap();\n+      }\n+    });\n+    runMapTest(new MapFactory(new Object()) {\n+      public Map newMap() {\n+        return new Hashtable();\n+      }\n+    });\n+    runMapTest(new MapFactory(new Object()) {\n+      public Map newMap() {\n+        return new ConcurrentHashMap();\n+      }\n+    });\n+  }\n }\ndiff --git a/jre_emul/android/libcore/luni/src/main/java/java/util/AbstractMap.java b/jre_emul/android/libcore/luni/src/main/java/java/util/AbstractMap.java\nindex 803b7e027..07892afb7 100644\n--- a/jre_emul/android/libcore/luni/src/main/java/java/util/AbstractMap.java\n+++ b/jre_emul/android/libcore/luni/src/main/java/java/util/AbstractMap.java\n@@ -21,6 +21,10 @@ import com.google.j2objc.annotations.WeakOuter;\n \n import java.io.Serializable;\n \n+/*-[\n+#include "JreRetainedWith.h"\n+]-*/\n+\n /**\n  * A base class for {@code Map} implementations.\n  *\n@@ -359,6 +363,8 @@ public abstract class AbstractMap<K, V> implements Map<K, V> {\n                         }\n                     };\n                 }\n+\n+                /*-[ RETAINED_WITH_CHILD(this$0_) ]-*/\n             }\n             keySet = new AbstractMapKeySet();\n         }\n@@ -496,6 +502,8 @@ public abstract class AbstractMap<K, V> implements Map<K, V> {\n                         }\n                     };\n                 }\n+\n+                /*-[ RETAINED_WITH_CHILD(this$0_) ]-*/\n             }\n             valuesCollection = new AbstractMapValuesCollection();\n         }\ndiff --git a/jre_emul/android/libcore/luni/src/main/java/java/util/EnumMap.java b/jre_emul/android/libcore/luni/src/main/java/java/util/EnumMap.java\nindex 41dfac61e..dea3a1c00 100644\n--- a/jre_emul/android/libcore/luni/src/main/java/java/util/EnumMap.java\n+++ b/jre_emul/android/libcore/luni/src/main/java/java/util/EnumMap.java\n@@ -24,6 +24,10 @@ import java.io.ObjectOutputStream;\n import java.io.Serializable;\n import java.lang.reflect.Array;\n \n+/*-[\n+#include "JreRetainedWith.h"\n+]-*/\n+\n /**\n  * An {@code Map} specialized for use with {@code Enum} types as keys.\n  */\n@@ -223,6 +227,8 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements\n         public int size() {\n             return enumMap.size();\n         }\n+\n+        /*-[ RETAINED_WITH_CHILD(enumMap_) ]-*/\n     }\n \n     private static class EnumMapValueCollection<KT extends Enum<KT>, VT>\n@@ -279,6 +285,8 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements\n         public int size() {\n             return enumMap.size();\n         }\n+\n+        /*-[ RETAINED_WITH_CHILD(enumMap_) ]-*/\n     }\n \n     private static class EnumMapEntryIterator<E, KT extends Enum<KT>, VT>\n@@ -382,6 +390,8 @@ public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements\n             }\n             return entryArray;\n         }\n+\n+        /*-[ RETAINED_WITH_CHILD(enumMap_) ]-*/\n     }\n \n     /**\ndiff --git a/jre_emul/android/libcore/luni/src/main/java/java/util/HashMap.java b/jre_emul/android/libcore/luni/src/main/java/java/util/HashMap.java\nindex d370d28d1..6b61ff8d5 100644\n--- a/jre_emul/android/libcore/luni/src/main/java/java/util/HashMap.java\n+++ b/jre_emul/android/libcore/luni/src/main/java/java/util/HashMap.java\n@@ -27,6 +27,10 @@ import java.io.ObjectStreamField;\n import java.io.Serializable;\n import libcore.util.Objects;\n \n+/*-[\n+#include "JreRetainedWith.h"\n+]-*/\n+\n /**\n  * HashMap is an implementation of {@link Map}. All optional operations are supported.\n  *\n@@ -949,6 +953,8 @@ public class HashMap<K, V> extends AbstractMap<K, V> implements Cloneable, Seria\n           }\n           return objCount;\n         }\n+\n+        RETAINED_WITH_CHILD(this$0_)\n         ]-*/\n     }\n \n@@ -981,6 +987,8 @@ public class HashMap<K, V> extends AbstractMap<K, V> implements Cloneable, Seria\n           }\n           return objCount;\n         }\n+\n+        RETAINED_WITH_CHILD(this$0_)\n         ]-*/\n     }\n \n@@ -1017,6 +1025,8 @@ public class HashMap<K, V> extends AbstractMap<K, V> implements Cloneable, Seria\n                                             count:(NSUInteger)len {\n           return [this$0_ enumerateEntriesWithState:state objects:stackbuf count:len];\n         }\n+\n+        RETAINED_WITH_CHILD(this$0_)\n         ]-*/\n     }\n \ndiff --git a/jre_emul/android/libcore/luni/src/main/java/java/util/Hashtable.java b/jre_emul/android/libcore/luni/src/main/java/java/util/Hashtable.java\nindex 492b1a47e..c1af8b83e 100644\n--- a/jre_emul/android/libcore/luni/src/main/java/java/util/Hashtable.java\n+++ b/jre_emul/android/libcore/luni/src/main/java/java/util/Hashtable.java\n@@ -26,6 +26,10 @@ import java.io.ObjectOutputStream;\n import java.io.ObjectStreamField;\n import java.io.Serializable;\n \n+/*-[\n+#include "JreRetainedWith.h"\n+]-*/\n+\n /**\n  * Hashtable is a synchronized implementation of {@link Map}. All optional operations are supported.\n  *\n@@ -961,6 +965,8 @@ public class Hashtable<K, V> extends Dictionary<K, V>\n                 return super.toArray(a);\n             }\n         }\n+\n+        /*-[ RETAINED_WITH_CHILD(this$0_) ]-*/\n     }\n \n     @WeakOuter\n@@ -997,6 +1003,8 @@ public class Hashtable<K, V> extends Dictionary<K, V>\n                 return super.toArray(a);\n             }\n         }\n+\n+        /*-[ RETAINED_WITH_CHILD(this$0_) ]-*/\n     }\n \n     @WeakOuter\n@@ -1060,6 +1068,8 @@ public class Hashtable<K, V> extends Dictionary<K, V>\n                 return super.toArray(a);\n             }\n         }\n+\n+        /*-[ RETAINED_WITH_CHILD(this$0_) ]-*/\n     }\n \n     private static final long serialVersionUID = 1421746759512286392L;\ndiff --git a/jre_emul/android/libcore/luni/src/main/java/java/util/IdentityHashMap.java b/jre_emul/android/libcore/luni/src/main/java/java/util/IdentityHashMap.java\nindex 3612bf293..3135349a1 100644\n--- a/jre_emul/android/libcore/luni/src/main/java/java/util/IdentityHashMap.java\n+++ b/jre_emul/android/libcore/luni/src/main/java/java/util/IdentityHashMap.java\n@@ -24,6 +24,10 @@ import java.io.ObjectInputStream;\n import java.io.ObjectOutputStream;\n import java.io.Serializable;\n \n+/*-[\n+#include "JreRetainedWith.h"\n+]-*/\n+\n /**\n  * IdentityHashMap is a variant on HashMap which tests equality by reference\n  * instead of equality by value. Basically, keys and values are compared for\n@@ -650,6 +654,8 @@ public class IdentityHashMap<K, V> extends AbstractMap<K, V> implements\n                         }\n                     }, IdentityHashMap.this);\n         }\n+\n+        /*-[ RETAINED_WITH_CHILD(this$0_) ]-*/\n     }\n \n     /**\n@@ -717,6 +723,8 @@ public class IdentityHashMap<K, V> extends AbstractMap<K, V> implements\n             }\n             return false;\n         }\n+\n+        /*-[ RETAINED_WITH_CHILD(this$0_) ]-*/\n     }\n \n     /**\ndiff --git a/jre_emul/android/libcore/luni/src/main/java/java/util/TreeMap.java b/jre_emul/android/libcore/luni/src/main/java/java/util/TreeMap.java\nindex 73217eb39..8fb84e10c 100644\n--- a/jre_emul/android/libcore/luni/src/main/java/java/util/TreeMap.java\n+++ b/jre_emul/android/libcore/luni/src/main/java/java/util/TreeMap.java\n@@ -29,6 +29,10 @@ import static java.util.TreeMap.Bound.*;\n import static java.util.TreeMap.Relation.*;\n import libcore.util.Objects;\n \n+/*-[\n+#include "JreRetainedWith.h"\n+]-*/\n+\n /**\n  * A map whose entries are sorted by their keys. All optional operations such as\n  * {@link #put} and {@link #remove} are supported.\n@@ -973,6 +977,8 @@ public class TreeMap<K, V> extends AbstractMap<K, V>\n           SetEndpoints(this$0_, state);\n           return EnumerateEntries(this$0_, state, stackbuf, len, 0, YES);\n         }\n+\n+        RETAINED_WITH_CHILD(this$0_)\n         ]-*/\n     }\n \n@@ -1091,6 +1097,8 @@ public class TreeMap<K, V> extends AbstractMap<K, V>\n           SetEndpoints(this$0_, state);\n           return EnumerateEntries(this$0_, state, stackbuf, len, 1, YES);\n         }\n+\n+        RETAINED_WITH_CHILD(this$0_)\n         ]-*/\n     }\n \n@@ -1115,6 +1123,8 @@ public class TreeMap<K, V> extends AbstractMap<K, V>\n           SetEndpoints(this$0_, state);\n           return EnumerateEntries(this$0_, state, stackbuf, len, 2, YES);\n         }\n+\n+        RETAINED_WITH_CHILD(this$0_)\n         ]-*/\n     }\n \ndiff --git a/jre_emul/android/libcore/luni/src/main/java/java/util/WeakHashMap.java b/jre_emul/android/libcore/luni/src/main/java/java/util/WeakHashMap.java\nindex 0a1f4fd07..5c6f0ce01 100644\n--- a/jre_emul/android/libcore/luni/src/main/java/java/util/WeakHashMap.java\n+++ b/jre_emul/android/libcore/luni/src/main/java/java/util/WeakHashMap.java\n@@ -22,6 +22,10 @@ import com.google.j2objc.annotations.WeakOuter;\n import java.lang.ref.ReferenceQueue;\n import java.lang.ref.WeakReference;\n \n+/*-[\n+#include "JreRetainedWith.h"\n+]-*/\n+\n /**\n  * WeakHashMap is an implementation of Map with keys which are WeakReferences. A\n  * key/value mapping is removed when the key is no longer referenced. All\n@@ -392,6 +396,8 @@ public class WeakHashMap<K, V> extends AbstractMap<K, V> implements Map<K, V> {\n                 }\n             });\n         }\n+\n+        /*-[ RETAINED_WITH_CHILD(this$0_) ]-*/\n     }\n \n     /**\n@@ -447,6 +453,8 @@ public class WeakHashMap<K, V> extends AbstractMap<K, V> implements Map<K, V> {\n                 }\n             });\n         }\n+\n+        /*-[ RETAINED_WITH_CHILD(this$0_) ]-*/\n     };\n \n     /**\ndiff --git a/jre_emul/android/libcore/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java b/jre_emul/android/libcore/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java\nindex 2ded7d3bb..5df2fc3df 100644\n--- a/jre_emul/android/libcore/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java\n+++ b/jre_emul/android/libcore/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java\n@@ -6,7 +6,7 @@\n \n package java.util.concurrent;\n \n-import com.google.j2objc.annotations.Weak;\n+import com.google.j2objc.annotations.RetainedWith;\n \n import java.io.ObjectStreamField;\n import java.io.Serializable;\n@@ -648,9 +648,9 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K, V>\n     private transient volatile CounterCell[] counterCells;\n \n     // views\n-    private transient KeySetView<K,V> keySet;\n-    private transient ValuesView<K,V> values;\n-    private transient EntrySetView<K,V> entrySet;\n+    @RetainedWith private transient KeySetView<K,V> keySet;\n+    @RetainedWith private transient ValuesView<K,V> values;\n+    @RetainedWith private transient EntrySetView<K,V> entrySet;\n \n \n     /* ---------------- Public operations -------------- */\n@@ -2779,7 +2779,7 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K, V>\n     abstract static class CollectionView<K,V,E>\n         implements Collection<E>, java.io.Serializable {\n         private static final long serialVersionUID = 7249069246763182397L;\n-        @Weak final ConcurrentHashMap<K,V> map;\n+        final ConcurrentHashMap<K,V> map;\n         CollectionView(ConcurrentHashMap<K,V> map)  { this.map = map; }\n \n         /**\ndiff --git a/jre_emul/cycle_whitelist.txt b/jre_emul/cycle_whitelist.txt\nindex 68834e835..82cd4ad4d 100644\n--- a/jre_emul/cycle_whitelist.txt\n+++ b/jre_emul/cycle_whitelist.txt\n@@ -12,6 +12,7 @@ FIELD java.net.NetworkInterface.children\n FIELD java.util.HashSet.backingMap\n FIELD java.util.TreeSet.backingMap\n \n+FIELD java.util.concurrent.ConcurrentHashMap.CollectionView.map\n FIELD java.util.concurrent.ConcurrentSkipListSet.m\n FIELD java.util.concurrent.ForkJoinWorkerThread.pool\n FIELD java.util.concurrent.Phaser.QNode.phaser\n', 'commit_subject': 'Handle @RetainedWith annotation in cycle_finder. Adds RetainedWith behavior to JRE map types.', 'repo_name': 'google/j2objc', 'committer': {'name': 'Keith Stanger', 'email': '49783279543e4289ca1f85c30d71c6f27f26fca0@vibe.wat.corp.google.com', 'time_sec': '1465393758', 'tz_offset': '-240', 'date': {'seconds': '1465393758'}}, 'commit_tree': '99a8695b83137908bb1f5e35b4a3b478307c12c1', 'commit_message': 'Handle @RetainedWith annotation in cycle_finder.\nAdds RetainedWith behavior to JRE map types.\n\n\tChange on 2016/05/31 by kstanger <kstanger@google.com>\n\n-------------\nCreated by MOE: https://github.com/google/moe\nMOE_MIGRATED_REVID=123645390\n', 'language_name': 'Shell', 'license': 'apache-2.0', 'hunks': '@@ -34,4 +34,25 @@ FOUNDATION_EXPORT void JreRetainedWithCheckPreviousValue(id parent, id value);\n // Called during dealloc of the parent and before releasing the child.\n FOUNDATION_EXPORT void JreRetainedWithHandleDealloc(id parent, id child);\n \n+// Internal only macro that hacks the @RetainedWith behavior to a child class\n+// without needing to use class swizzling or associated objects. Must be\n+// combined with @Weak or @WeakOuter on the parent reference.\n+#define RETAINED_WITH_CHILD(PARENT_REF) \\\n+  - (id)retain { \\\n+    @synchronized (self) { \\\n+      if ([self retainCount] == 1) { \\\n+        [PARENT_REF retain]; \\\n+      } \\\n+      return [super retain]; \\\n+    } \\\n+  } \\\n+  - (oneway void)release { \\\n+    @synchronized (self) { \\\n+      if ([self retainCount] == 2) { \\\n+        [PARENT_REF autorelease]; \\\n+      } \\\n+      [super release]; \\\n+    } \\\n+  }\n+\n #endif // JRE_RETAINED_WITH_H_\n', 'addition_count': 21, 'deletion_count': 0, 'src_file': 'a/jre_emul/Classes/JreRetainedWith.h', 'tgt_file': 'b/jre_emul/Classes/JreRetainedWith.h', 'file_extension': '.h', 'before_file': '// Licensed under the Apache License, Version 2.0 (the "License");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an "AS IS" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n//\n//  JreRetainedWith.h\n//  JreEmulation\n//\n//  Created by Keith Stanger on Mar. 18, 2016.\n//\n// INTERNAL ONLY. For use by JRE emulation code.\n\n#ifndef JRE_RETAINED_WITH_H_\n#define JRE_RETAINED_WITH_H_\n\n#import <Foundation/Foundation.h>\n\n// Called by @RetainedWith assignment functions. Caller must ensure that value\n// has a retain count at least two.\nFOUNDATION_EXPORT void JreRetainedWithInitialize(id parent, id value);\n\n// Checks the previous value of a @RetainedWith assignment, possibly returning\n// it to normal behavior.\nFOUNDATION_EXPORT void JreRetainedWithHandlePreviousValue(id parent, id value);\n\n// Called during dealloc of the parent and before releasing the child.\nFOUNDATION_EXPORT void JreRetainedWithHandleDealloc(id parent, id child);\n\n#endif // JRE_RETAINED_WITH_H_\n\n#define RETAINED_WITH_CHILD(PARENT_REF) \\\n  RETAINED_WITH_CHILD_NUM_REFS(PARENT_REF, 1)\n\n#endif // JRE_RETAINED_WITH_H_\n', 'message': 'Handle @RetainedWith annotation in cycle_finder.\nAdds RetainedWith behavior to JRE map types.\n\n\tChange on 2016/05/31 by kstanger <kstanger@google.com>\n\n-------------\nCreated by MOE: https://github.com/google/moe\nMOE_MIGRATED_REVID=123645390\n', 'author_name': 'Keith Stanger', 'lang': 'h'}