Initial implementation of member name lookup

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62247 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaInherit.cpp b/lib/Sema/SemaInherit.cpp
index a02dd1e..0791ac2 100644
--- a/lib/Sema/SemaInherit.cpp
+++ b/lib/Sema/SemaInherit.cpp
@@ -20,6 +20,7 @@
 #include "clang/AST/Type.h"
 #include "clang/AST/TypeOrdering.h"
 #include "clang/Basic/Diagnostic.h"
+#include <algorithm>
 #include <memory>
 #include <set>
 #include <string>
@@ -45,6 +46,17 @@
   DetectedVirtual = 0;
 }
 
+/// @brief Swaps the contents of this BasePaths structure with the
+/// contents of Other.
+void BasePaths::swap(BasePaths &Other) {
+  Paths.swap(Other.Paths);
+  ClassSubobjects.swap(Other.ClassSubobjects);
+  std::swap(FindAmbiguities, Other.FindAmbiguities);
+  std::swap(RecordPaths, Other.RecordPaths);
+  std::swap(DetectVirtual, Other.DetectVirtual);
+  std::swap(DetectedVirtual, Other.DetectedVirtual);
+}
+
 /// IsDerivedFrom - Determine whether the type Derived is derived from
 /// the type Base, ignoring qualifiers on Base and Derived. This
 /// routine does not assess whether an actual conversion from a
@@ -65,8 +77,6 @@
 /// ambiguous paths (if @c Paths.isFindingAmbiguities()) and record
 /// information about all of the paths (if @c Paths.isRecordingPaths()).
 bool Sema::IsDerivedFrom(QualType Derived, QualType Base, BasePaths &Paths) {
-  bool FoundPath = false;
-
   Derived = Context.getCanonicalType(Derived).getUnqualifiedType();
   Base = Context.getCanonicalType(Base).getUnqualifiedType();
 
@@ -76,71 +86,112 @@
   if (Derived == Base)
     return false;
 
-  if (const RecordType *DerivedType = Derived->getAsRecordType()) {
-    const CXXRecordDecl *Decl 
-      = static_cast<const CXXRecordDecl *>(DerivedType->getDecl());
-    for (CXXRecordDecl::base_class_const_iterator BaseSpec = Decl->bases_begin();
-         BaseSpec != Decl->bases_end(); ++BaseSpec) {
-      // Find the record of the base class subobjects for this type.
-      QualType BaseType = Context.getCanonicalType(BaseSpec->getType());
-      BaseType = BaseType.getUnqualifiedType();
-      
-      // Determine whether we need to visit this base class at all,
-      // updating the count of subobjects appropriately.
-      std::pair<bool, unsigned>& Subobjects = Paths.ClassSubobjects[BaseType];
-      bool VisitBase = true;
-      bool SetVirtual = false;
-      if (BaseSpec->isVirtual()) {
-        VisitBase = !Subobjects.first;
-        Subobjects.first = true;
-        if (Paths.isDetectingVirtual() && Paths.DetectedVirtual == 0) {
-          // If this is the first virtual we find, remember it. If it turns out
-          // there is no base path here, we'll reset it later.
-          Paths.DetectedVirtual = static_cast<const CXXRecordType*>(
-            BaseType->getAsRecordType());
-          SetVirtual = true;
-        }
-      } else
-        ++Subobjects.second;
+  return LookupInBases(cast<CXXRecordType>(Derived->getAsRecordType())->getDecl(),
+                       MemberLookupCriteria(Base), Paths);
+}
 
+/// LookupInBases - Look for something that meets the specified
+/// Criteria within the base classes of Class (or any of its base
+/// classes, transitively). This routine populates BasePaths with the
+/// list of paths that one can take to find the entity that meets the
+/// search criteria, and returns true if any such entity is found. The
+/// various options passed to the BasePath constructor will affect the
+/// behavior of this lookup, e.g., whether it finds ambiguities,
+/// records paths, or attempts to detect the use of virtual base
+/// classes.
+bool Sema::LookupInBases(CXXRecordDecl *Class, 
+                         const MemberLookupCriteria& Criteria,
+                         BasePaths &Paths) {
+  bool FoundPath = false;
+
+  for (CXXRecordDecl::base_class_const_iterator BaseSpec = Class->bases_begin(),
+                                             BaseSpecEnd = Class->bases_end(); 
+       BaseSpec != BaseSpecEnd; ++BaseSpec) {
+    // Find the record of the base class subobjects for this type.
+    QualType BaseType = Context.getCanonicalType(BaseSpec->getType());
+    BaseType = BaseType.getUnqualifiedType();
+    
+    // Determine whether we need to visit this base class at all,
+    // updating the count of subobjects appropriately.
+    std::pair<bool, unsigned>& Subobjects = Paths.ClassSubobjects[BaseType];
+    bool VisitBase = true;
+    bool SetVirtual = false;
+    if (BaseSpec->isVirtual()) {
+      VisitBase = !Subobjects.first;
+      Subobjects.first = true;
+      if (Paths.isDetectingVirtual() && Paths.DetectedVirtual == 0) {
+        // If this is the first virtual we find, remember it. If it turns out
+        // there is no base path here, we'll reset it later.
+        Paths.DetectedVirtual = cast<CXXRecordType>(BaseType->getAsRecordType());
+        SetVirtual = true;
+      }
+    } else
+      ++Subobjects.second;
+
+    if (Paths.isRecordingPaths()) {
+      // Add this base specifier to the current path.
+      BasePathElement Element;
+      Element.Base = &*BaseSpec;
+      if (BaseSpec->isVirtual())
+        Element.SubobjectNumber = 0;
+      else
+        Element.SubobjectNumber = Subobjects.second;
+      Paths.ScratchPath.push_back(Element);
+    }
+
+    CXXRecordDecl *BaseRecord 
+      = cast<CXXRecordDecl>(BaseSpec->getType()->getAsRecordType()->getDecl());
+
+    // Either look at the base class type or look into the base class
+    // type to see if we've found a member that meets the search
+    // criteria.
+    bool FoundPathToThisBase = false;
+    if (Criteria.LookupBase) {
+      FoundPathToThisBase 
+        = (Context.getCanonicalType(BaseSpec->getType()) == Criteria.Base);
+    } else {
+      Paths.ScratchPath.Decls = BaseRecord->lookup(Criteria.Name);
+      while (Paths.ScratchPath.Decls.first != Paths.ScratchPath.Decls.second) {
+        if (Criteria.Criteria.isLookupResult(*Paths.ScratchPath.Decls.first)) {
+          FoundPathToThisBase = true;
+          break;
+        }
+        ++Paths.ScratchPath.Decls.first;
+      }
+    }
+
+    if (FoundPathToThisBase) {
+      // We've found a path that terminates that this base.
+      FoundPath = true;
       if (Paths.isRecordingPaths()) {
-        // Add this base specifier to the current path.
-        BasePathElement Element;
-        Element.Base = &*BaseSpec;
-        if (BaseSpec->isVirtual())
-          Element.SubobjectNumber = 0;
-        else
-          Element.SubobjectNumber = Subobjects.second;
-        Paths.ScratchPath.push_back(Element);
+        // We have a path. Make a copy of it before moving on.
+        Paths.Paths.push_back(Paths.ScratchPath);
+      } else if (!Paths.isFindingAmbiguities()) {
+        // We found a path and we don't care about ambiguities;
+        // return immediately.
+        return FoundPath;
       }
+    } 
+    // C++ [class.member.lookup]p2:
+    //   A member name f in one sub-object B hides a member name f in
+    //   a sub-object A if A is a base class sub-object of B. Any
+    //   declarations that are so hidden are eliminated from
+    //   consideration.
+    else if (VisitBase && LookupInBases(BaseRecord, Criteria, Paths)) {
+      // There is a path to a base class that meets the criteria. If we're not
+      // collecting paths or finding ambiguities, we're done.
+      FoundPath = true;
+      if (!Paths.isFindingAmbiguities())
+        return FoundPath;
+    }
 
-      if (Context.getCanonicalType(BaseSpec->getType()) == Base) {
-        // We've found the base we're looking for.
-        FoundPath = true;
-        if (Paths.isRecordingPaths()) {
-          // We have a path. Make a copy of it before moving on.
-          Paths.Paths.push_back(Paths.ScratchPath);
-        } else if (!Paths.isFindingAmbiguities()) {
-          // We found a path and we don't care about ambiguities;
-          // return immediately.
-          return FoundPath;
-        }
-      } else if (VisitBase && IsDerivedFrom(BaseSpec->getType(), Base, Paths)) {
-        // There is a path to the base we want. If we're not
-        // collecting paths or finding ambiguities, we're done.
-        FoundPath = true;
-        if (!Paths.isFindingAmbiguities())
-          return FoundPath;
-      }
-
-      // Pop this base specifier off the current path (if we're
-      // collecting paths).
-      if (Paths.isRecordingPaths())
-        Paths.ScratchPath.pop_back();
-      // If we set a virtual earlier, and this isn't a path, forget it again.
-      if (SetVirtual && !FoundPath) {
-        Paths.DetectedVirtual = 0;
-      }
+    // Pop this base specifier off the current path (if we're
+    // collecting paths).
+    if (Paths.isRecordingPaths())
+      Paths.ScratchPath.pop_back();
+    // If we set a virtual earlier, and this isn't a path, forget it again.
+    if (SetVirtual && !FoundPath) {
+      Paths.DetectedVirtual = 0;
     }
   }
 
@@ -208,4 +259,3 @@
     << Derived << Base << PathDisplayStr << Range;
   return true;
 }
-