Refactor VariantMatcher to use an interface underneath.

Summary:
Refactor VariantMatcher to use an interface underneath.
It supports "Single" and "Polymorphic". Will support more in the future.

Reviewers: klimek

CC: cfe-commits, revane

Differential Revision: http://llvm-reviews.chandlerc.com/D1446

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@189032 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/ASTMatchers/Dynamic/VariantValue.cpp b/lib/ASTMatchers/Dynamic/VariantValue.cpp
index a8fd7c6..87aca7d 100644
--- a/lib/ASTMatchers/Dynamic/VariantValue.cpp
+++ b/lib/ASTMatchers/Dynamic/VariantValue.cpp
@@ -21,69 +21,105 @@
 namespace ast_matchers {
 namespace dynamic {
 
-VariantMatcher::VariantMatcher() : List() {}
+VariantMatcher::MatcherOps::~MatcherOps() {}
+VariantMatcher::Payload::~Payload() {}
 
-VariantMatcher::VariantMatcher(const VariantMatcher& Other) {
-  *this = Other;
-}
+class VariantMatcher::SinglePayload : public VariantMatcher::Payload {
+public:
+  SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher.clone()) {}
+
+  virtual bool getSingleMatcher(const DynTypedMatcher *&Out) const {
+    Out = Matcher.get();
+    return true;
+  }
+
+  virtual std::string getTypeAsString() const {
+    return (Twine("Matcher<") + Matcher->getSupportedKind().asStringRef() + ">")
+        .str();
+  }
+
+  virtual bool hasTypedMatcher(const MatcherOps &Ops) const {
+    return Ops.canConstructFrom(*Matcher);
+  }
+
+  virtual const DynTypedMatcher *getTypedMatcher(const MatcherOps &Ops) const {
+    assert(hasTypedMatcher(Ops));
+    return Matcher.get();
+  }
+
+private:
+  OwningPtr<const DynTypedMatcher> Matcher;
+};
+
+class VariantMatcher::PolymorphicPayload : public VariantMatcher::Payload {
+public:
+  PolymorphicPayload(ArrayRef<const DynTypedMatcher *> MatchersIn) {
+    for (size_t i = 0, e = MatchersIn.size(); i != e; ++i) {
+      Matchers.push_back(MatchersIn[i]->clone());
+    }
+  }
+
+  virtual ~PolymorphicPayload() {
+    llvm::DeleteContainerPointers(Matchers);
+  }
+
+  virtual bool getSingleMatcher(const DynTypedMatcher *&Out) const {
+    if (Matchers.size() != 1)
+      return false;
+    Out = Matchers[0];
+    return true;
+  }
+
+  virtual std::string getTypeAsString() const {
+    std::string Inner;
+    for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
+      if (i != 0)
+        Inner += "|";
+      Inner += Matchers[i]->getSupportedKind().asStringRef();
+    }
+    return (Twine("Matcher<") + Inner + ">").str();
+  }
+
+  virtual bool hasTypedMatcher(const MatcherOps &Ops) const {
+    return getTypedMatcher(Ops) != NULL;
+  }
+
+  virtual const DynTypedMatcher *getTypedMatcher(const MatcherOps &Ops) const {
+    const DynTypedMatcher* Found = NULL;
+    for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
+      if (Ops.canConstructFrom(*Matchers[i])) {
+        if (Found) return NULL;
+        Found = Matchers[i];
+      }
+    }
+    return Found;
+  }
+
+private:
+  std::vector<const DynTypedMatcher *> Matchers;
+};
+
+VariantMatcher::VariantMatcher() {}
 
 VariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) {
-  VariantMatcher Out;
-  Out.List.push_back(Matcher.clone());
-  return Out;
+  return VariantMatcher(new SinglePayload(Matcher));
 }
 
 VariantMatcher
 VariantMatcher::PolymorphicMatcher(ArrayRef<const DynTypedMatcher *> Matchers) {
-  VariantMatcher Out;
-  for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
-    Out.List.push_back(Matchers[i]->clone());
-  }
-  return Out;
-}
-
-VariantMatcher::~VariantMatcher() {
-  reset();
-}
-
-VariantMatcher &VariantMatcher::operator=(const VariantMatcher &Other) {
-  if (this == &Other) return *this;
-  reset();
-  for (size_t i = 0, e = Other.List.size(); i != e; ++i) {
-    List.push_back(Other.List[i]->clone());
-  }
-  return *this;
+  return VariantMatcher(new PolymorphicPayload(Matchers));
 }
 
 bool VariantMatcher::getSingleMatcher(const DynTypedMatcher *&Out) const {
-  if (List.size() != 1) return false;
-  Out = List[0];
-  return true;
+  if (Value) return Value->getSingleMatcher(Out);
+  return false;
 }
 
-void VariantMatcher::reset() {
-  llvm::DeleteContainerPointers(List);
-}
+void VariantMatcher::reset() { Value.reset(); }
 
 std::string VariantMatcher::getTypeAsString() const {
-  std::string Inner;
-  for (size_t I = 0, E = List.size(); I != E; ++I) {
-    if (I != 0) Inner += "|";
-    Inner += List[I]->getSupportedKind().asStringRef();
-  }
-  return (Twine("Matcher<") + Inner + ">").str();
-}
-
-const DynTypedMatcher *VariantMatcher::getTypedMatcher(
-    bool (*CanConstructCallback)(const DynTypedMatcher &)) const {
-  const DynTypedMatcher *Out = NULL;
-  for (size_t i = 0, e = List.size(); i != e; ++i) {
-    if (CanConstructCallback(*List[i])) {
-      if (Out) return NULL;
-      Out = List[i];
-    }
-  }
-  return Out;
+  if (Value) return Value->getTypeAsString();
+  return "<Nothing>";
 }
 
 VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) {