Fix unowned/retain ptr conversion and assignment.

Define all the possible ctor/assignment possibilities rather than
letting the compiler deduce anything.

-- Make tests consistent with each other.

Change-Id: I7ed7f747d283b3d3e1394c84921d38867e76c13b
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/98455
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fxcrt/retain_ptr.h b/core/fxcrt/retain_ptr.h
index eda9517..ccf3615 100644
--- a/core/fxcrt/retain_ptr.h
+++ b/core/fxcrt/retain_ptr.h
@@ -60,7 +60,20 @@
     Unleak(that.Leak());
   }
 
+  // Assign a RetainPtr from nullptr;
+  RetainPtr& operator=(std::nullptr_t) noexcept {
+    Reset();
+    return *this;
+  }
+
+  // Assign a RetainPtr from a raw ptr.
+  RetainPtr& operator=(T* that) noexcept {
+    Reset(that);
+    return *this;
+  }
+
   // Copy-assign a RetainPtr.
+  // Required in addition to copy conversion assignment below.
   RetainPtr& operator=(const RetainPtr& that) {
     if (*this != that)
       Reset(that.Get());
@@ -68,11 +81,31 @@
   }
 
   // Move-assign a RetainPtr. After assignment, |that| will be NULL.
+  // Required in addition to move conversion assignment below.
   RetainPtr& operator=(RetainPtr&& that) noexcept {
     Unleak(that.Leak());
     return *this;
   }
 
+  // Copy-convert assign a RetainPtr.
+  template <class U,
+            typename = typename std::enable_if<
+                std::is_convertible<U*, T*>::value>::type>
+  RetainPtr& operator=(const RetainPtr<U>& that) {
+    if (*this != that)
+      Reset(that.Get());
+    return *this;
+  }
+
+  // Move-convert assign a RetainPtr. After assignment, |that| will be NULL.
+  template <class U,
+            typename = typename std::enable_if<
+                std::is_convertible<U*, T*>::value>::type>
+  RetainPtr& operator=(RetainPtr<U>&& that) noexcept {
+    Unleak(that.Leak());
+    return *this;
+  }
+
   ~RetainPtr() = default;
 
   template <class U>
diff --git a/core/fxcrt/retain_ptr_unittest.cpp b/core/fxcrt/retain_ptr_unittest.cpp
index 2fdd993..2312e3f 100644
--- a/core/fxcrt/retain_ptr_unittest.cpp
+++ b/core/fxcrt/retain_ptr_unittest.cpp
@@ -36,12 +36,17 @@
 
 }  // namespace
 
-TEST(RetainPtr, Null) {
+TEST(RetainPtr, DefaultCtor) {
   RetainPtr<PseudoRetainable> ptr;
   EXPECT_FALSE(ptr.Get());
 }
 
-TEST(RetainPtr, Normal) {
+TEST(RetainPtr, NullptrCtor) {
+  RetainPtr<PseudoRetainable> ptr(nullptr);
+  EXPECT_FALSE(ptr.Get());
+}
+
+TEST(RetainPtr, RawCtor) {
   PseudoRetainable obj;
   {
     RetainPtr<PseudoRetainable> ptr(&obj);
@@ -69,22 +74,6 @@
   EXPECT_EQ(2, obj.release_count());
 }
 
-TEST(RetainPtr, CopyConversionCtor) {
-  PseudoRetainable obj;
-  {
-    RetainPtr<PseudoRetainable> ptr1(&obj);
-    {
-      RetainPtr<const PseudoRetainable> ptr2(ptr1);
-      EXPECT_EQ(2, obj.retain_count());
-      EXPECT_EQ(0, obj.release_count());
-    }
-    EXPECT_EQ(2, obj.retain_count());
-    EXPECT_EQ(1, obj.release_count());
-  }
-  EXPECT_EQ(2, obj.retain_count());
-  EXPECT_EQ(2, obj.release_count());
-}
-
 TEST(RetainPtr, MoveCtor) {
   PseudoRetainable obj;
   {
@@ -103,6 +92,22 @@
   EXPECT_EQ(1, obj.release_count());
 }
 
+TEST(RetainPtr, CopyConversionCtor) {
+  PseudoRetainable obj;
+  {
+    RetainPtr<PseudoRetainable> ptr1(&obj);
+    {
+      RetainPtr<const PseudoRetainable> ptr2(ptr1);
+      EXPECT_EQ(2, obj.retain_count());
+      EXPECT_EQ(0, obj.release_count());
+    }
+    EXPECT_EQ(2, obj.retain_count());
+    EXPECT_EQ(1, obj.release_count());
+  }
+  EXPECT_EQ(2, obj.retain_count());
+  EXPECT_EQ(2, obj.release_count());
+}
+
 TEST(RetainPtr, MoveConversionCtor) {
   PseudoRetainable obj;
   {
@@ -121,6 +126,108 @@
   EXPECT_EQ(1, obj.release_count());
 }
 
+TEST(RetainPtr, NullptrAssign) {
+  PseudoRetainable obj;
+  RetainPtr<PseudoRetainable> ptr(&obj);
+  ptr = nullptr;
+  EXPECT_FALSE(ptr);
+}
+
+TEST(RetainPtr, RawAssign) {
+  PseudoRetainable obj;
+  RetainPtr<PseudoRetainable> ptr;
+  ptr = &obj;
+  EXPECT_EQ(&obj, ptr);
+}
+
+TEST(RetainPtr, CopyAssign) {
+  PseudoRetainable obj;
+  {
+    RetainPtr<PseudoRetainable> ptr(&obj);
+    {
+      RetainPtr<PseudoRetainable> ptr2;
+      ptr2 = ptr;
+      EXPECT_EQ(2, obj.retain_count());
+      EXPECT_EQ(0, obj.release_count());
+    }
+    {
+      // Test assignment from wrapped underlying type.
+      RetainPtr<PseudoRetainable> ptr2;
+      ptr2 = pdfium::WrapRetain(ptr.Get());
+      EXPECT_EQ(3, obj.retain_count());
+      EXPECT_EQ(1, obj.release_count());
+    }
+    EXPECT_EQ(3, obj.retain_count());
+    EXPECT_EQ(2, obj.release_count());
+  }
+  EXPECT_EQ(3, obj.retain_count());
+  EXPECT_EQ(3, obj.release_count());
+}
+
+TEST(RetainPtr, MoveAssign) {
+  PseudoRetainable obj;
+  {
+    RetainPtr<PseudoRetainable> ptr1(&obj);
+    {
+      RetainPtr<PseudoRetainable> ptr2;
+      EXPECT_EQ(&obj, ptr1.Get());
+      EXPECT_FALSE(ptr2.Get());
+      ptr2 = std::move(ptr1);
+      EXPECT_FALSE(ptr1.Get());
+      EXPECT_EQ(&obj, ptr2.Get());
+      EXPECT_EQ(1, obj.retain_count());
+      EXPECT_EQ(0, obj.release_count());
+    }
+    EXPECT_EQ(1, obj.retain_count());
+    EXPECT_EQ(1, obj.release_count());
+  }
+  EXPECT_EQ(1, obj.retain_count());
+  EXPECT_EQ(1, obj.release_count());
+}
+
+TEST(RetainPtr, CopyConvertAssign) {
+  PseudoRetainable obj;
+  {
+    RetainPtr<PseudoRetainable> ptr(&obj);
+    {
+      RetainPtr<const PseudoRetainable> ptr2;
+      ptr2 = ptr;
+      EXPECT_EQ(2, obj.retain_count());
+      EXPECT_EQ(0, obj.release_count());
+    }
+    {
+      // Test assignment from wrapped underlying type.
+      RetainPtr<const PseudoRetainable> ptr2;
+      ptr2 = pdfium::WrapRetain(ptr.Get());
+      EXPECT_EQ(3, obj.retain_count());
+      EXPECT_EQ(1, obj.release_count());
+    }
+    EXPECT_EQ(3, obj.retain_count());
+    EXPECT_EQ(2, obj.release_count());
+  }
+  EXPECT_EQ(3, obj.retain_count());
+  EXPECT_EQ(3, obj.release_count());
+}
+
+TEST(RetainPtr, MoveConvertAssign) {
+  PseudoRetainable obj;
+  {
+    RetainPtr<PseudoRetainable> ptr1(&obj);
+    {
+      RetainPtr<const PseudoRetainable> ptr2;
+      ptr2 = std::move(ptr1);
+      EXPECT_FALSE(ptr1);
+      EXPECT_EQ(&obj, ptr2.Get());
+      EXPECT_EQ(1, obj.retain_count());
+      EXPECT_EQ(0, obj.release_count());
+    }
+    EXPECT_EQ(1, obj.retain_count());
+    EXPECT_EQ(1, obj.release_count());
+  }
+  EXPECT_EQ(1, obj.retain_count());
+  EXPECT_EQ(1, obj.release_count());
+}
+
 TEST(RetainPtr, AmbiguousExpression) {
   class A : public Retainable {};
   class B : public A {};
@@ -223,94 +330,6 @@
   EXPECT_EQ(1, obj1.release_count());
 }
 
-TEST(RetainPtr, Assign) {
-  PseudoRetainable obj;
-  {
-    RetainPtr<PseudoRetainable> ptr(&obj);
-    {
-      RetainPtr<PseudoRetainable> ptr2;
-      ptr2 = ptr;
-      EXPECT_EQ(2, obj.retain_count());
-      EXPECT_EQ(0, obj.release_count());
-    }
-    {
-      // Test assignment from wrapped underlying type.
-      RetainPtr<PseudoRetainable> ptr2;
-      ptr2 = pdfium::WrapRetain(ptr.Get());
-      EXPECT_EQ(3, obj.retain_count());
-      EXPECT_EQ(1, obj.release_count());
-    }
-    EXPECT_EQ(3, obj.retain_count());
-    EXPECT_EQ(2, obj.release_count());
-  }
-  EXPECT_EQ(3, obj.retain_count());
-  EXPECT_EQ(3, obj.release_count());
-}
-
-TEST(RetainPtr, AssignConvert) {
-  PseudoRetainable obj;
-  {
-    RetainPtr<PseudoRetainable> ptr(&obj);
-    {
-      RetainPtr<const PseudoRetainable> ptr2;
-      ptr2 = ptr;
-      EXPECT_EQ(2, obj.retain_count());
-      EXPECT_EQ(0, obj.release_count());
-    }
-    {
-      // Test assignment from wrapped underlying type.
-      RetainPtr<const PseudoRetainable> ptr2;
-      ptr2 = pdfium::WrapRetain(ptr.Get());
-      EXPECT_EQ(3, obj.retain_count());
-      EXPECT_EQ(1, obj.release_count());
-    }
-    EXPECT_EQ(3, obj.retain_count());
-    EXPECT_EQ(2, obj.release_count());
-  }
-  EXPECT_EQ(3, obj.retain_count());
-  EXPECT_EQ(3, obj.release_count());
-}
-
-TEST(RetainPtr, MoveAssign) {
-  PseudoRetainable obj;
-  {
-    RetainPtr<PseudoRetainable> ptr1(&obj);
-    {
-      RetainPtr<PseudoRetainable> ptr2;
-      EXPECT_EQ(&obj, ptr1.Get());
-      EXPECT_FALSE(ptr2.Get());
-      ptr2 = std::move(ptr1);
-      EXPECT_FALSE(ptr1.Get());
-      EXPECT_EQ(&obj, ptr2.Get());
-      EXPECT_EQ(1, obj.retain_count());
-      EXPECT_EQ(0, obj.release_count());
-    }
-    EXPECT_EQ(1, obj.retain_count());
-    EXPECT_EQ(1, obj.release_count());
-  }
-  EXPECT_EQ(1, obj.retain_count());
-  EXPECT_EQ(1, obj.release_count());
-}
-
-TEST(RetainPtr, MoveAssignConvert) {
-  PseudoRetainable obj;
-  {
-    RetainPtr<PseudoRetainable> ptr1(&obj);
-    {
-      RetainPtr<const PseudoRetainable> ptr2;
-      ptr2 = std::move(ptr1);
-      EXPECT_FALSE(ptr1);
-      EXPECT_EQ(&obj, ptr2.Get());
-      EXPECT_EQ(1, obj.retain_count());
-      EXPECT_EQ(0, obj.release_count());
-    }
-    EXPECT_EQ(1, obj.retain_count());
-    EXPECT_EQ(1, obj.release_count());
-  }
-  EXPECT_EQ(1, obj.retain_count());
-  EXPECT_EQ(1, obj.release_count());
-}
-
 TEST(RetainPtr, Equals) {
   PseudoRetainable obj1;
   PseudoRetainable obj2;
diff --git a/core/fxcrt/unowned_ptr.h b/core/fxcrt/unowned_ptr.h
index f9946f0..c506e2d 100644
--- a/core/fxcrt/unowned_ptr.h
+++ b/core/fxcrt/unowned_ptr.h
@@ -63,7 +63,7 @@
   // Required in addition to move conversion constructor below.
   constexpr UnownedPtr(UnownedPtr&& that) noexcept : m_pObj(that.Release()) {}
 
-  // Copy conversion constructor.
+  // Copy-conversion constructor.
   template <class U,
             typename = typename std::enable_if<
                 std::is_convertible<U*, T*>::value>::type>
@@ -77,13 +77,20 @@
     Reset(that.Release());
   }
 
-  // Assing an UnownedPtr from a raw ptr.
+  // Assign an UnownedPtr from nullptr.
+  UnownedPtr& operator=(std::nullptr_t) noexcept {
+    Reset();
+    return *this;
+  }
+
+  // Assign an UnownedPtr from a raw ptr.
   UnownedPtr& operator=(T* that) noexcept {
     Reset(that);
     return *this;
   }
 
   // Copy-assign an UnownedPtr.
+  // Required in addition to copy conversion assignment below.
   UnownedPtr& operator=(const UnownedPtr& that) noexcept {
     if (*this != that)
       Reset(that.Get());
@@ -91,12 +98,33 @@
   }
 
   // Move-assign an UnownedPtr. After assignment, |that| will be NULL.
+  // Required in addition to move conversion assignment below.
   UnownedPtr& operator=(UnownedPtr&& that) noexcept {
     if (*this != that)
       Reset(that.Release());
     return *this;
   }
 
+  // Copy-convert assignment.
+  template <class U,
+            typename = typename std::enable_if<
+                std::is_convertible<U*, T*>::value>::type>
+  UnownedPtr& operator=(const UnownedPtr<U>& that) noexcept {
+    if (*this != that)
+      Reset(that.Get());
+    return *this;
+  }
+
+  // Move-convert assignment. After assignment, |that| will be NULL.
+  template <class U,
+            typename = typename std::enable_if<
+                std::is_convertible<U*, T*>::value>::type>
+  UnownedPtr& operator=(UnownedPtr<U>&& that) noexcept {
+    if (*this != that)
+      Reset(that.Release());
+    return *this;
+  }
+
   ~UnownedPtr() {
     ProbeForLowSeverityLifetimeIssue();
     m_pObj = nullptr;
diff --git a/core/fxcrt/unowned_ptr_unittest.cpp b/core/fxcrt/unowned_ptr_unittest.cpp
index 532d9c4..9807b75 100644
--- a/core/fxcrt/unowned_ptr_unittest.cpp
+++ b/core/fxcrt/unowned_ptr_unittest.cpp
@@ -64,11 +64,104 @@
 
 }  // namespace
 
-TEST(UnownedPtr, Null) {
+TEST(UnownedPtr, DefaultCtor) {
   UnownedPtr<Clink> ptr;
   EXPECT_FALSE(ptr.Get());
 }
 
+TEST(UnownedPtr, NullptrCtor) {
+  UnownedPtr<Clink> ptr(nullptr);
+  EXPECT_FALSE(ptr.Get());
+}
+
+TEST(UnownedPtr, RawCtor) {
+  auto obj = std::make_unique<Clink>();
+  UnownedPtr<Clink> ptr(obj.get());
+  EXPECT_EQ(obj.get(), ptr.Get());
+}
+
+TEST(UnownedPtr, CopyCtor) {
+  std::unique_ptr<Clink> obj = std::make_unique<Clink>();
+  UnownedPtr<Clink> ptr1(obj.get());
+  UnownedPtr<Clink> ptr2(ptr1);
+  EXPECT_EQ(obj.get(), ptr2);
+  EXPECT_EQ(obj.get(), ptr1);
+}
+
+TEST(UnownedPtr, MoveCtor) {
+  std::unique_ptr<Clink> obj = std::make_unique<Clink>();
+  UnownedPtr<Clink> ptr1(obj.get());
+  UnownedPtr<Clink> ptr2(std::move(ptr1));
+  EXPECT_EQ(obj.get(), ptr2);
+  EXPECT_FALSE(ptr1);
+}
+
+TEST(UnownedPtr, CopyConversionCtor) {
+  std::unique_ptr<Clink> obj = std::make_unique<Clink>();
+  UnownedPtr<Clink> ptr1(obj.get());
+  UnownedPtr<const Clink> ptr2(ptr1);
+  EXPECT_EQ(obj.get(), ptr2);
+  EXPECT_EQ(obj.get(), ptr1);
+}
+
+TEST(UnownedPtr, MoveConversionCtor) {
+  std::unique_ptr<Clink> obj = std::make_unique<Clink>();
+  UnownedPtr<Clink> ptr1(obj.get());
+  UnownedPtr<const Clink> ptr2(std::move(ptr1));
+  EXPECT_EQ(obj.get(), ptr2);
+  EXPECT_FALSE(ptr1);
+}
+
+TEST(UnownedPtr, NullptrAssign) {
+  std::unique_ptr<Clink> obj = std::make_unique<Clink>();
+  UnownedPtr<Clink> ptr(obj.get());
+  ptr = nullptr;
+  EXPECT_FALSE(ptr);
+}
+
+TEST(UnownedPtr, RawAssign) {
+  std::unique_ptr<Clink> obj = std::make_unique<Clink>();
+  UnownedPtr<Clink> ptr;
+  ptr = obj.get();
+  EXPECT_EQ(obj.get(), ptr.Get());
+}
+
+TEST(UnownedPtr, CopyAssign) {
+  std::unique_ptr<Clink> obj = std::make_unique<Clink>();
+  UnownedPtr<Clink> ptr1(obj.get());
+  UnownedPtr<Clink> ptr2;
+  ptr2 = ptr1;
+  EXPECT_EQ(obj.get(), ptr1.Get());
+  EXPECT_EQ(obj.get(), ptr2.Get());
+}
+
+TEST(UnownedPtr, MoveAssign) {
+  std::unique_ptr<Clink> obj = std::make_unique<Clink>();
+  UnownedPtr<Clink> ptr1(obj.get());
+  UnownedPtr<Clink> ptr2;
+  ptr2 = std::move(ptr1);
+  EXPECT_FALSE(ptr1);
+  EXPECT_EQ(obj.get(), ptr2.Get());
+}
+
+TEST(UnownedPtr, CopyConversionAssign) {
+  std::unique_ptr<Clink> obj = std::make_unique<Clink>();
+  UnownedPtr<Clink> ptr1(obj.get());
+  UnownedPtr<const Clink> ptr2;
+  ptr2 = ptr1;
+  EXPECT_EQ(obj.get(), ptr1.Get());
+  EXPECT_EQ(obj.get(), ptr2.Get());
+}
+
+TEST(UnownedPtr, MoveConversionAssign) {
+  std::unique_ptr<Clink> obj = std::make_unique<Clink>();
+  UnownedPtr<Clink> ptr1(obj.get());
+  UnownedPtr<const Clink> ptr2;
+  ptr2 = std::move(ptr1);
+  EXPECT_FALSE(ptr1);
+  EXPECT_EQ(obj.get(), ptr2.Get());
+}
+
 TEST(UnownedPtr, PtrOk) {
   auto ptr1 = std::make_unique<Clink>();
   {
@@ -85,22 +178,6 @@
 #endif
 }
 
-TEST(UnownedPtr, CopyCtor) {
-  std::unique_ptr<Clink> obj = std::make_unique<Clink>();
-  UnownedPtr<Clink> ptr1(obj.get());
-  UnownedPtr<Clink> ptr2(ptr1);
-  EXPECT_TRUE(ptr2);
-  EXPECT_TRUE(ptr1);
-}
-
-TEST(UnownedPtr, CopyConversionCtor) {
-  std::unique_ptr<Clink> obj = std::make_unique<Clink>();
-  UnownedPtr<Clink> ptr1(obj.get());
-  UnownedPtr<const Clink> ptr2(ptr1);
-  EXPECT_TRUE(ptr2);
-  EXPECT_TRUE(ptr1);
-}
-
 TEST(UnownedPtr, ResetOk) {
   auto ptr1 = std::make_unique<Clink>();
   {
@@ -144,41 +221,6 @@
   }
 }
 
-TEST(UnownedPtr, MoveCtorOk) {
-  UnownedPtr<Clink> outer;
-  {
-    auto owned = std::make_unique<Clink>();
-    outer = owned.get();
-    UnownedPtr<Clink> inner(std::move(outer));
-    EXPECT_FALSE(outer.Get());
-    EXPECT_EQ(owned.get(), inner.Get());
-  }
-}
-
-TEST(UnownedPtr, MoveConversionCtorOk) {
-  UnownedPtr<Clink> outer;
-  {
-    auto owned = std::make_unique<Clink>();
-    outer = owned.get();
-    UnownedPtr<const Clink> inner(std::move(outer));
-    EXPECT_FALSE(outer.Get());
-  }
-}
-
-TEST(UnownedPtr, MoveConversionAssignOk) {
-  UnownedPtr<Clink> outer;
-  {
-    auto owned = std::make_unique<Clink>();
-    outer = owned.get();
-    // TODO(tsepez): disambiguate ctors and actually const-convert.
-    // UnownedPtr<const Clink> inner;
-    UnownedPtr<Clink> inner;
-    inner = std::move(outer);
-    EXPECT_FALSE(outer);
-    EXPECT_EQ(owned.get(), inner.Get());
-  }
-}
-
 TEST(UnownedPtr, ReleaseNotOk) {
 #if defined(ADDRESS_SANITIZER)
   EXPECT_DEATH(ReleaseDangling(), "");