[cfe-commits] r163794 - in /cfe/trunk: include/clang/ASTMatchers/ASTMatchFinder.h include/clang/ASTMatchers/ASTMatchers.h include/clang/ASTMatchers/ASTMatchersInternal.h include/clang/ASTMatchers/ASTMatchersMacros.h include/clang/ASTMatchers/ASTTypeTraits.h lib/ASTMatchers/ASTMatchFinder.cpp unittests/ASTMatchers/ASTMatchersTest.cpp

Daniel Jasper djasper at google.com
Thu Sep 13 06:11:25 PDT 2012


Author: djasper
Date: Thu Sep 13 08:11:25 2012
New Revision: 163794

URL: http://llvm.org/viewvc/llvm-project?rev=163794&view=rev
Log:
Create initial support for matching and binding NestedNameSpecifier(Loc)s.

Review: http://llvm-reviews.chandlerc.com/D39

Modified:
    cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h
    cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
    cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
    cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h
    cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h
    cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp
    cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp

Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h?rev=163794&r1=163793&r2=163794&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h Thu Sep 13 08:11:25 2012
@@ -112,6 +112,10 @@
                   MatchCallback *Action);
   void addMatcher(const StatementMatcher &NodeMatch,
                   MatchCallback *Action);
+  void addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
+                  MatchCallback *Action);
+  void addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
+                  MatchCallback *Action);
   /// @}
 
   /// \brief Creates a clang ASTConsumer that finds all matches.

Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=163794&r1=163793&r2=163794&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Thu Sep 13 08:11:25 2012
@@ -110,6 +110,8 @@
 typedef internal::Matcher<Decl> DeclarationMatcher;
 typedef internal::Matcher<QualType> TypeMatcher;
 typedef internal::Matcher<Stmt> StatementMatcher;
+typedef internal::Matcher<NestedNameSpecifier> NestedNameSpecifierMatcher;
+typedef internal::Matcher<NestedNameSpecifierLoc> NestedNameSpecifierLocMatcher;
 /// @}
 
 /// \brief Matches any node.
@@ -2288,6 +2290,83 @@
     internal::IsExplicitTemplateSpecializationMatcher>();
 }
 
+/// \brief Matches nested name specifiers.
+///
+/// Given
+/// \code
+///   namespace ns {
+///     struct A { static void f(); };
+///     void A::f() {}
+///     void g() { A::f(); }
+///   }
+///   ns::A a;
+/// \endcode
+/// nestedNameSpecifier()
+///   matches "ns::" and both "A::"
+const internal::VariadicAllOfMatcher<NestedNameSpecifier> nestedNameSpecifier;
+
+/// \brief Same as \c nestedNameSpecifier but matches \c NestedNameSpecifierLoc.
+const internal::VariadicAllOfMatcher<
+  NestedNameSpecifierLoc> nestedNameSpecifierLoc;
+
+/// \brief Matches \c NestedNameSpecifierLocs for which the given inner
+/// NestedNameSpecifier-matcher matches.
+inline internal::BindableMatcher<NestedNameSpecifierLoc> loc(
+    const internal::Matcher<NestedNameSpecifier> &InnerMatcher) {
+  return internal::BindableMatcher<NestedNameSpecifierLoc>(
+      new internal::LocMatcher<NestedNameSpecifierLoc, NestedNameSpecifier>(
+          InnerMatcher));
+}
+
+/// \brief Matches nested name specifiers that specify a type matching the
+/// given \c QualType matcher without qualifiers.
+/// FIXME: This is a temporary solution. Switch to using Type-matchers as soon
+/// as we have those.
+///
+/// Given
+/// \code
+///   struct A { struct B { struct C {}; }; };
+///   A::B::C c;
+/// \endcode
+/// nestedNameSpecifier(specifiesType(hasDeclaration(recordDecl(hasName("A")))))
+///   matches "A::"
+AST_MATCHER_P(NestedNameSpecifier, specifiesType,
+              internal::Matcher<QualType>, InnerMatcher) {
+  if (Node.getAsType() == NULL)
+    return false;
+  return InnerMatcher.matches(QualType(Node.getAsType(), 0), Finder, Builder);
+}
+
+/// \brief Matches on the prefix of a \c NestedNameSpecifier or
+/// \c NestedNameSpecifierLoc.
+///
+/// Given
+/// \code
+///   struct A { struct B { struct C {}; }; };
+///   A::B::C c;
+/// \endcode
+/// nestedNameSpecifier(hasPrefix(specifiesType(asString("struct A")))) and
+/// nestedNameSpecifierLoc(hasPrefix(loc(specifiesType(asString("struct A")))))
+///   both match "A::"
+LOC_TRAVERSE_MATCHER(hasPrefix, NestedNameSpecifier, getPrefix)
+
+/// \brief Matches nested name specifiers that specify a namespace matching the
+/// given namespace matcher.
+///
+/// Given
+/// \code
+///   namespace ns { struct A {}; }
+///   ns::A a;
+/// \endcode
+/// nestedNameSpecifier(specifiesNamespace(hasName("ns")))
+///   matches "ns::"
+AST_MATCHER_P(NestedNameSpecifier, specifiesNamespace,
+              internal::Matcher<NamespaceDecl>, InnerMatcher) {
+  if (Node.getAsNamespace() == NULL)
+    return false;
+  return InnerMatcher.matches(*Node.getAsNamespace(), Finder, Builder);
+}
+
 } // end namespace ast_matchers
 } // end namespace clang
 

Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=163794&r1=163793&r2=163794&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h Thu Sep 13 08:11:25 2012
@@ -380,6 +380,8 @@
       (llvm::is_same<T, Decl>::value ||
        llvm::is_same<T, Stmt>::value ||
        llvm::is_same<T, QualType>::value ||
+       llvm::is_same<T, NestedNameSpecifier>::value ||
+       llvm::is_same<T, NestedNameSpecifierLoc>::value ||
        llvm::is_same<T, CXXCtorInitializer>::value);
 };
 template <typename T>
@@ -652,9 +654,6 @@
   /// The returned matcher is equivalent to this matcher, but will
   /// bind the matched node on a match.
   Matcher<T> bind(StringRef ID) const {
-    TOOLING_COMPILE_ASSERT((llvm::is_base_of<Stmt, T>::value ||
-                            llvm::is_base_of<Decl, T>::value),
-      trying_to_bind_unsupported_node_type__only_decl_and_stmt_supported);
     return Matcher<T>(new IdMatcher<T>(ID, *this));
   }
 };
@@ -779,6 +778,20 @@
   const Matcher<T> InnertMatcher2;
 };
 
+/// \brief Creates a Matcher<T> that matches if all inner matchers match.
+template<typename T>
+BindableMatcher<T> makeAllOfComposite(
+    ArrayRef<const Matcher<T> *> InnerMatchers) {
+  if (InnerMatchers.empty())
+    return BindableMatcher<T>(new TrueMatcher<T>);
+  MatcherInterface<T> *InnerMatcher = new TrueMatcher<T>;
+  for (int i = InnerMatchers.size() - 1; i >= 0; --i) {
+    InnerMatcher = new AllOfMatcher<T, Matcher<T>, Matcher<T> >(
+      *InnerMatchers[i], makeMatcher(InnerMatcher));
+  }
+  return BindableMatcher<T>(InnerMatcher);
+}
+
 /// \brief Creates a Matcher<T> that matches if
 /// T is dyn_cast'able into InnerT and all inner matchers match.
 ///
@@ -788,17 +801,8 @@
 template<typename T, typename InnerT>
 BindableMatcher<T> makeDynCastAllOfComposite(
     ArrayRef<const Matcher<InnerT> *> InnerMatchers) {
-  if (InnerMatchers.empty()) {
-    Matcher<InnerT> InnerMatcher = makeMatcher(new TrueMatcher<InnerT>);
-    return BindableMatcher<T>(new DynCastMatcher<T, InnerT>(InnerMatcher));
-  }
-  Matcher<InnerT> InnerMatcher = *InnerMatchers.back();
-  for (int i = InnerMatchers.size() - 2; i >= 0; --i) {
-    InnerMatcher = makeMatcher(
-        new AllOfMatcher<InnerT, Matcher<InnerT>, Matcher<InnerT> >(
-            *InnerMatchers[i], InnerMatcher));
-  }
-  return BindableMatcher<T>(new DynCastMatcher<T, InnerT>(InnerMatcher));
+  return BindableMatcher<T>(new DynCastMatcher<T, InnerT>(
+    makeAllOfComposite(InnerMatchers)));
 }
 
 /// \brief Matches nodes of type T that have at least one descendant node of
@@ -980,6 +984,99 @@
   VariadicDynCastAllOfMatcher() {}
 };
 
+/// \brief A \c VariadicAllOfMatcher<T> object is a variadic functor that takes
+/// a number of \c Matcher<T> and returns a \c Matcher<T> that matches \c T
+/// nodes that are matched by all of the given matchers.
+///
+/// For example:
+///   const VariadicAllOfMatcher<NestedNameSpecifier> nestedNameSpecifier;
+/// Creates a functor nestedNameSpecifier(...) that creates a
+/// \c Matcher<NestedNameSpecifier> given a variable number of arguments of type
+/// \c Matcher<NestedNameSpecifier>.
+/// The returned matcher matches if all given matchers match.
+template <typename T>
+class VariadicAllOfMatcher : public llvm::VariadicFunction<
+                               BindableMatcher<T>, Matcher<T>,
+                               makeAllOfComposite<T> > {
+public:
+  VariadicAllOfMatcher() {}
+};
+
+/// \brief Matches nodes of type \c TLoc for which the inner
+/// \c Matcher<T> matches.
+template <typename TLoc, typename T>
+class LocMatcher : public MatcherInterface<TLoc> {
+public:
+  explicit LocMatcher(const Matcher<T> &InnerMatcher)
+      : InnerMatcher(InnerMatcher) {}
+
+  virtual bool matches(const TLoc &Node,
+                       ASTMatchFinder *Finder,
+                       BoundNodesTreeBuilder *Builder) const {
+    if (!Node)
+      return false;
+    return InnerMatcher.matches(*extract(Node), Finder, Builder);
+  }
+
+private:
+  const NestedNameSpecifier *extract(const NestedNameSpecifierLoc &Loc) const {
+    return Loc.getNestedNameSpecifier();
+  }
+  // FIXME: Add overload for TypeLoc when implementing TypeLoc-matchers.
+
+  const Matcher<T> InnerMatcher;
+};
+
+/// \brief Matches nodes of type \c T for which the inner matcher matches on a
+/// another node of type \c T that can be reached using a given traverse
+/// function.
+template <typename T>
+class TraverseMatcher : public MatcherInterface<T> {
+public:
+  explicit TraverseMatcher(const Matcher<T> &InnerMatcher,
+                           T *(T::*TraverseFunction)() const)
+      : InnerMatcher(InnerMatcher), TraverseFunction(TraverseFunction) {}
+
+  virtual bool matches(const T &Node,
+                       ASTMatchFinder *Finder,
+                       BoundNodesTreeBuilder *Builder) const {
+    T* NextNode = (Node.*TraverseFunction)();
+    if (NextNode == NULL)
+      return false;
+    return InnerMatcher.matches(*NextNode, Finder, Builder);
+  }
+
+private:
+  const Matcher<T> InnerMatcher;
+  T *(T::*TraverseFunction)() const;
+};
+
+/// \brief Matches nodes of type \c T in a ..Loc hierarchy, for which the inner
+/// matcher matches on a another node of type \c T that can be reached using a
+/// given traverse function.
+template <typename T>
+class LocTraverseMatcher : public MatcherInterface<T> {
+public:
+  explicit LocTraverseMatcher(const Matcher<T> &InnerMatcher,
+                              T (T::*TraverseFunction)() const)
+      : InnerMatcher(InnerMatcher), TraverseFunction(TraverseFunction) {}
+
+  virtual bool matches(const T &Node,
+                       ASTMatchFinder *Finder,
+                       BoundNodesTreeBuilder *Builder) const {
+    if (!Node)
+      return false;
+    T NextNode = (Node.*TraverseFunction)();
+    if (!NextNode)
+      return false;
+    return InnerMatcher.matches(NextNode, Finder, Builder);
+  }
+
+private:
+  const Matcher<T> InnerMatcher;
+  T (T::*TraverseFunction)() const;
+};
+
 } // end namespace internal
 } // end namespace ast_matchers
 } // end namespace clang

Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h?rev=163794&r1=163793&r2=163794&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h Thu Sep 13 08:11:25 2012
@@ -221,4 +221,22 @@
       const NodeType &Node, ASTMatchFinder *Finder,                            \
       BoundNodesTreeBuilder *Builder) const
 
+/// \brief LOC_TRAVERSE_MATCHER(MatcherName, NodeType, FunctionName)
+/// defines the matcher \c MatcherName that can be used to traverse
+/// a Type or NestedNameSpecifier as well as the corresponding ..Loc.
+///
+/// The traversal is done using the given \c FunctionName.
+#define LOC_TRAVERSE_MATCHER(                                                  \
+      MatcherName, NodeType, FunctionName)                                     \
+  inline internal::Matcher<NodeType> hasPrefix(                                \
+      const internal::Matcher<NodeType> &InnerMatcher) {                       \
+    return makeMatcher(new internal::TraverseMatcher<NodeType>(                \
+      InnerMatcher, &NodeType::getPrefix));                                    \
+  }                                                                            \
+  inline internal::Matcher<NodeType##Loc> hasPrefix(                           \
+      const internal::Matcher<NodeType##Loc> &InnerMatcher) {                  \
+    return makeMatcher(new internal::LocTraverseMatcher<NodeType##Loc>(        \
+      InnerMatcher, &NodeType##Loc::getPrefix));                               \
+  }
+
 #endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H

Modified: cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h?rev=163794&r1=163793&r2=163794&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h Thu Sep 13 08:11:25 2012
@@ -74,6 +74,8 @@
   enum NodeTypeTag {
     NT_Decl,
     NT_Stmt,
+    NT_NestedNameSpecifier,
+    NT_NestedNameSpecifierLoc,
     NT_QualType
   } Tag;
 
@@ -83,7 +85,7 @@
   /// guaranteed to be unique pointers pointing to dedicated storage in the
   /// AST. \c QualTypes on the other hand do not have storage or unique
   /// pointers and thus need to be stored by value.
-  llvm::AlignedCharArrayUnion<Decl*, Stmt*, QualType> Storage;
+  llvm::AlignedCharArrayUnion<Decl*, Stmt*, NestedNameSpecifierLoc, QualType> Storage;
 };
 template<typename T> struct DynTypedNode::BaseConverter<T,
     typename llvm::enable_if<llvm::is_base_of<Decl, T> >::type> {
@@ -113,6 +115,33 @@
     return Result;
   }
 };
+template<> struct DynTypedNode::BaseConverter<NestedNameSpecifier, void> {
+  static const NestedNameSpecifier *get(NodeTypeTag Tag, const char Storage[]) {
+    if (Tag == NT_NestedNameSpecifier)
+      return *reinterpret_cast<NestedNameSpecifier*const*>(Storage);
+    return NULL;
+  }
+  static DynTypedNode create(const NestedNameSpecifier &Node) {
+    DynTypedNode Result;
+    Result.Tag = NT_NestedNameSpecifier;
+    new (Result.Storage.buffer) const NestedNameSpecifier*(&Node);
+    return Result;
+  }
+};
+template<> struct DynTypedNode::BaseConverter<NestedNameSpecifierLoc, void> {
+  static const NestedNameSpecifierLoc *get(NodeTypeTag Tag,
+                                           const char Storage[]) {
+    if (Tag == NT_NestedNameSpecifierLoc)
+      return reinterpret_cast<const NestedNameSpecifierLoc*>(Storage);
+    return NULL;
+  }
+  static DynTypedNode create(const NestedNameSpecifierLoc &Node) {
+    DynTypedNode Result;
+    Result.Tag = NT_NestedNameSpecifierLoc;
+    new (Result.Storage.buffer) NestedNameSpecifierLoc(Node);
+    return Result;
+  }
+};
 template<> struct DynTypedNode::BaseConverter<QualType, void> {
   static const QualType *get(NodeTypeTag Tag, const char Storage[]) {
     if (Tag == NT_QualType)
@@ -146,4 +175,3 @@
 } // end namespace clang
 
 #endif // LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H
-

Modified: cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp?rev=163794&r1=163793&r2=163794&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp Thu Sep 13 08:11:25 2012
@@ -313,6 +313,8 @@
   bool TraverseStmt(Stmt *StmtNode);
   bool TraverseType(QualType TypeNode);
   bool TraverseTypeLoc(TypeLoc TypeNode);
+  bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
+  bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
 
   // Matches children or descendants of 'Node' with 'BaseMatcher'.
   bool memoizedMatchesRecursively(const ast_type_traits::DynTypedNode &Node,
@@ -556,6 +558,21 @@
       TraverseTypeLoc(TypeLoc);
 }
 
+bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
+  match(*NNS);
+  return RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifier(NNS);
+}
+
+bool MatchASTVisitor::TraverseNestedNameSpecifierLoc(
+    NestedNameSpecifierLoc NNS) {
+  match(NNS);
+  // We only match the nested name specifier here (as opposed to traversing it)
+  // because the traversal is already done in the parallel "Loc"-hierarchy.
+  match(*NNS.getNestedNameSpecifier());
+  return
+      RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifierLoc(NNS);
+}
+
 class MatchASTConsumer : public ASTConsumer {
 public:
   MatchASTConsumer(
@@ -619,6 +636,18 @@
     new internal::Matcher<Stmt>(NodeMatch), Action));
 }
 
+void MatchFinder::addMatcher(const NestedNameSpecifierMatcher &NodeMatch,
+                             MatchCallback *Action) {
+  MatcherCallbackPairs.push_back(std::make_pair(
+    new NestedNameSpecifierMatcher(NodeMatch), Action));
+}
+
+void MatchFinder::addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch,
+                             MatchCallback *Action) {
+  MatcherCallbackPairs.push_back(std::make_pair(
+    new NestedNameSpecifierLocMatcher(NodeMatch), Action));
+}
+
 ASTConsumer *MatchFinder::newASTConsumer() {
   return new internal::MatchASTConsumer(&MatcherCallbackPairs, ParsingDone);
 }

Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp?rev=163794&r1=163793&r2=163794&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp Thu Sep 13 08:11:25 2012
@@ -607,36 +607,40 @@
 // Decl bound to Id that can be dynamically cast to T.
 // Optionally checks that the check succeeded a specific number of times.
 template <typename T>
-class VerifyIdIsBoundToDecl : public BoundNodesCallback {
+class VerifyIdIsBoundTo : public BoundNodesCallback {
 public:
   // Create an object that checks that a node of type \c T was bound to \c Id.
   // Does not check for a certain number of matches.
-  explicit VerifyIdIsBoundToDecl(llvm::StringRef Id)
+  explicit VerifyIdIsBoundTo(llvm::StringRef Id)
     : Id(Id), ExpectedCount(-1), Count(0) {}
 
   // Create an object that checks that a node of type \c T was bound to \c Id.
   // Checks that there were exactly \c ExpectedCount matches.
-  VerifyIdIsBoundToDecl(llvm::StringRef Id, int ExpectedCount)
+  VerifyIdIsBoundTo(llvm::StringRef Id, int ExpectedCount)
     : Id(Id), ExpectedCount(ExpectedCount), Count(0) {}
 
   // Create an object that checks that a node of type \c T was bound to \c Id.
-  // Checks that there was exactly one match with the name \c ExpectedDeclName.
+  // Checks that there was exactly one match with the name \c ExpectedName.
   // Note that \c T must be a NamedDecl for this to work.
-  VerifyIdIsBoundToDecl(llvm::StringRef Id, llvm::StringRef ExpectedDeclName)
-    : Id(Id), ExpectedCount(1), Count(0), ExpectedDeclName(ExpectedDeclName) {}
+  VerifyIdIsBoundTo(llvm::StringRef Id, llvm::StringRef ExpectedName)
+    : Id(Id), ExpectedCount(1), Count(0), ExpectedName(ExpectedName) {}
 
-  ~VerifyIdIsBoundToDecl() {
+  ~VerifyIdIsBoundTo() {
     if (ExpectedCount != -1)
       EXPECT_EQ(ExpectedCount, Count);
-    if (!ExpectedDeclName.empty())
-      EXPECT_EQ(ExpectedDeclName, DeclName);
+    if (!ExpectedName.empty())
+      EXPECT_EQ(ExpectedName, Name);
   }
 
   virtual bool run(const BoundNodes *Nodes) {
-    if (const Decl *Node = Nodes->getDeclAs<T>(Id)) {
+    if (Nodes->getNodeAs<T>(Id)) {
       ++Count;
-      if (const NamedDecl *Named = llvm::dyn_cast<NamedDecl>(Node)) {
-        DeclName = Named->getNameAsString();
+      if (const NamedDecl *Named = Nodes->getNodeAs<NamedDecl>(Id)) {
+        Name = Named->getNameAsString();
+      } else if (const NestedNameSpecifier *NNS =
+                 Nodes->getNodeAs<NestedNameSpecifier>(Id)) {
+        llvm::raw_string_ostream OS(Name);
+        NNS->print(OS, PrintingPolicy(LangOptions()));
       }
       return true;
     }
@@ -647,43 +651,32 @@
   const std::string Id;
   const int ExpectedCount;
   int Count;
-  const std::string ExpectedDeclName;
-  std::string DeclName;
-};
-template <typename T>
-class VerifyIdIsBoundToStmt : public BoundNodesCallback {
-public:
-  explicit VerifyIdIsBoundToStmt(const std::string &Id) : Id(Id) {}
-  virtual bool run(const BoundNodes *Nodes) {
-    const T *Node = Nodes->getStmtAs<T>(Id);
-    return Node != NULL;
-  }
-private:
-  const std::string Id;
+  const std::string ExpectedName;
+  std::string Name;
 };
 
 TEST(Matcher, BindMatchedNodes) {
   DeclarationMatcher ClassX = has(recordDecl(hasName("::X")).bind("x"));
 
   EXPECT_TRUE(matchAndVerifyResultTrue("class X {};",
-      ClassX, new VerifyIdIsBoundToDecl<CXXRecordDecl>("x")));
+      ClassX, new VerifyIdIsBoundTo<CXXRecordDecl>("x")));
 
   EXPECT_TRUE(matchAndVerifyResultFalse("class X {};",
-      ClassX, new VerifyIdIsBoundToDecl<CXXRecordDecl>("other-id")));
+      ClassX, new VerifyIdIsBoundTo<CXXRecordDecl>("other-id")));
 
   TypeMatcher TypeAHasClassB = hasDeclaration(
       recordDecl(hasName("A"), has(recordDecl(hasName("B")).bind("b"))));
 
   EXPECT_TRUE(matchAndVerifyResultTrue("class A { public: A *a; class B {}; };",
       TypeAHasClassB,
-      new VerifyIdIsBoundToDecl<Decl>("b")));
+      new VerifyIdIsBoundTo<Decl>("b")));
 
   StatementMatcher MethodX =
       callExpr(callee(methodDecl(hasName("x")))).bind("x");
 
   EXPECT_TRUE(matchAndVerifyResultTrue("class A { void x() { x(); } };",
       MethodX,
-      new VerifyIdIsBoundToStmt<CXXMemberCallExpr>("x")));
+      new VerifyIdIsBoundTo<CXXMemberCallExpr>("x")));
 }
 
 TEST(Matcher, BindTheSameNameInAlternatives) {
@@ -700,7 +693,7 @@
       // The second branch binds x to f() and succeeds.
       "int f() { return 0 + f(); }",
       matcher,
-      new VerifyIdIsBoundToStmt<CallExpr>("x")));
+      new VerifyIdIsBoundTo<CallExpr>("x")));
 }
 
 TEST(Matcher, BindsIDForMemoizedResults) {
@@ -712,7 +705,7 @@
       DeclarationMatcher(anyOf(
           recordDecl(hasName("A"), hasDescendant(ClassX)),
           recordDecl(hasName("B"), hasDescendant(ClassX)))),
-      new VerifyIdIsBoundToDecl<Decl>("x", 2)));
+      new VerifyIdIsBoundTo<Decl>("x", 2)));
 }
 
 TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) {
@@ -1918,13 +1911,13 @@
   DeclarationMatcher HasClassB = just(has(recordDecl(hasName("B")).bind("b")));
 
   EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };",
-      HasClassB, new VerifyIdIsBoundToDecl<Decl>("b")));
+      HasClassB, new VerifyIdIsBoundTo<Decl>("b")));
 
   EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };",
-      HasClassB, new VerifyIdIsBoundToDecl<Decl>("a")));
+      HasClassB, new VerifyIdIsBoundTo<Decl>("a")));
 
   EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };",
-      HasClassB, new VerifyIdIsBoundToDecl<Decl>("b")));
+      HasClassB, new VerifyIdIsBoundTo<Decl>("b")));
 }
 
 AST_POLYMORPHIC_MATCHER_P(
@@ -1943,13 +1936,13 @@
       polymorphicHas(recordDecl(hasName("B")).bind("b"));
 
   EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };",
-      HasClassB, new VerifyIdIsBoundToDecl<Decl>("b")));
+      HasClassB, new VerifyIdIsBoundTo<Decl>("b")));
 
   EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };",
-      HasClassB, new VerifyIdIsBoundToDecl<Decl>("a")));
+      HasClassB, new VerifyIdIsBoundTo<Decl>("a")));
 
   EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };",
-      HasClassB, new VerifyIdIsBoundToDecl<Decl>("b")));
+      HasClassB, new VerifyIdIsBoundTo<Decl>("b")));
 
   StatementMatcher StatementHasClassB =
       polymorphicHas(recordDecl(hasName("B")));
@@ -2579,13 +2572,13 @@
 TEST(ForEach, BindsOneNode) {
   EXPECT_TRUE(matchAndVerifyResultTrue("class C { int x; };",
       recordDecl(hasName("C"), forEach(fieldDecl(hasName("x")).bind("x"))),
-      new VerifyIdIsBoundToDecl<FieldDecl>("x", 1)));
+      new VerifyIdIsBoundTo<FieldDecl>("x", 1)));
 }
 
 TEST(ForEach, BindsMultipleNodes) {
   EXPECT_TRUE(matchAndVerifyResultTrue("class C { int x; int y; int z; };",
       recordDecl(hasName("C"), forEach(fieldDecl().bind("f"))),
-      new VerifyIdIsBoundToDecl<FieldDecl>("f", 3)));
+      new VerifyIdIsBoundTo<FieldDecl>("f", 3)));
 }
 
 TEST(ForEach, BindsRecursiveCombinations) {
@@ -2593,14 +2586,14 @@
       "class C { class D { int x; int y; }; class E { int y; int z; }; };",
       recordDecl(hasName("C"),
                  forEach(recordDecl(forEach(fieldDecl().bind("f"))))),
-      new VerifyIdIsBoundToDecl<FieldDecl>("f", 4)));
+      new VerifyIdIsBoundTo<FieldDecl>("f", 4)));
 }
 
 TEST(ForEachDescendant, BindsOneNode) {
   EXPECT_TRUE(matchAndVerifyResultTrue("class C { class D { int x; }; };",
       recordDecl(hasName("C"),
                  forEachDescendant(fieldDecl(hasName("x")).bind("x"))),
-      new VerifyIdIsBoundToDecl<FieldDecl>("x", 1)));
+      new VerifyIdIsBoundTo<FieldDecl>("x", 1)));
 }
 
 TEST(ForEachDescendant, BindsMultipleNodes) {
@@ -2608,7 +2601,7 @@
       "class C { class D { int x; int y; }; "
       "          class E { class F { int y; int z; }; }; };",
       recordDecl(hasName("C"), forEachDescendant(fieldDecl().bind("f"))),
-      new VerifyIdIsBoundToDecl<FieldDecl>("f", 4)));
+      new VerifyIdIsBoundTo<FieldDecl>("f", 4)));
 }
 
 TEST(ForEachDescendant, BindsRecursiveCombinations) {
@@ -2617,7 +2610,7 @@
       "          class E { class F { class G { int y; int z; }; }; }; }; };",
       recordDecl(hasName("C"), forEachDescendant(recordDecl(
           forEachDescendant(fieldDecl().bind("f"))))),
-      new VerifyIdIsBoundToDecl<FieldDecl>("f", 8)));
+      new VerifyIdIsBoundTo<FieldDecl>("f", 8)));
 }
 
 
@@ -2775,7 +2768,7 @@
   EXPECT_TRUE(matchAndVerifyResultTrue(
       "class C { class D { class E { class F { int y; }; }; }; };",
       fieldDecl(hasAncestor(recordDecl(hasAncestor(recordDecl().bind("r"))))),
-      new VerifyIdIsBoundToDecl<CXXRecordDecl>("r", 1)));
+      new VerifyIdIsBoundTo<CXXRecordDecl>("r", 1)));
 }
 
 TEST(HasAncestor, BindsCombinationsWithHasDescendant) {
@@ -2787,7 +2780,7 @@
                                      hasAncestor(recordDecl())))
           ).bind("d")
       )),
-      new VerifyIdIsBoundToDecl<CXXRecordDecl>("d", "E")));
+      new VerifyIdIsBoundTo<CXXRecordDecl>("d", "E")));
 }
 
 TEST(HasAncestor, MatchesInTemplateInstantiations) {
@@ -2806,5 +2799,62 @@
               hasAncestor(recordDecl(hasName("A")))))))));
 }
 
+TEST(NNS, MatchesNestedNameSpecifiers) {
+  EXPECT_TRUE(matches("namespace ns { struct A {}; } ns::A a;",
+                      nestedNameSpecifier()));
+  EXPECT_TRUE(matches("template <typename T> class A { typename T::B b; };",
+                      nestedNameSpecifier()));
+  EXPECT_TRUE(matches("struct A { void f(); }; void A::f() {}",
+                      nestedNameSpecifier()));
+
+  EXPECT_TRUE(matches(
+    "struct A { static void f() {} }; void g() { A::f(); }",
+    nestedNameSpecifier()));
+  EXPECT_TRUE(notMatches(
+    "struct A { static void f() {} }; void g(A* a) { a->f(); }",
+    nestedNameSpecifier()));
+}
+
+TEST(NNS, MatchesTypes) {
+  NestedNameSpecifierMatcher Matcher = nestedNameSpecifier(
+    specifiesType(hasDeclaration(recordDecl(hasName("A")))));
+  EXPECT_TRUE(matches("struct A { struct B {}; }; A::B b;", Matcher));
+  EXPECT_TRUE(matches("struct A { struct B { struct C {}; }; }; A::B::C c;",
+                      Matcher));
+  EXPECT_TRUE(notMatches("namespace A { struct B {}; } A::B b;", Matcher));
+}
+
+TEST(NNS, MatchesNamespaceDecls) {
+  NestedNameSpecifierMatcher Matcher = nestedNameSpecifier(
+    specifiesNamespace(hasName("ns")));
+  EXPECT_TRUE(matches("namespace ns { struct A {}; } ns::A a;", Matcher));
+  EXPECT_TRUE(notMatches("namespace xx { struct A {}; } xx::A a;", Matcher));
+  EXPECT_TRUE(notMatches("struct ns { struct A {}; }; ns::A a;", Matcher));
+}
+
+TEST(NNS, BindsNestedNameSpecifiers) {
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      "namespace ns { struct E { struct B {}; }; } ns::E::B b;",
+      nestedNameSpecifier(specifiesType(asString("struct ns::E"))).bind("nns"),
+      new VerifyIdIsBoundTo<NestedNameSpecifier>("nns", "ns::struct E::")));
+}
+
+TEST(NNS, BindsNestedNameSpecifierLocs) {
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      "namespace ns { struct B {}; } ns::B b;",
+      loc(nestedNameSpecifier()).bind("loc"),
+      new VerifyIdIsBoundTo<NestedNameSpecifierLoc>("loc", 1)));
+}
+
+TEST(NNS, MatchesNestedNameSpecifierPrefixes) {
+  EXPECT_TRUE(matches(
+      "struct A { struct B { struct C {}; }; }; A::B::C c;",
+      nestedNameSpecifier(hasPrefix(specifiesType(asString("struct A"))))));
+  EXPECT_TRUE(matches(
+      "struct A { struct B { struct C {}; }; }; A::B::C c;",
+      nestedNameSpecifierLoc(hasPrefix(loc(
+          specifiesType(asString("struct A")))))));
+}
+
 } // end namespace ast_matchers
 } // end namespace clang





More information about the cfe-commits mailing list