Speed up hasName() matcher.

Summary:
Speed up hasName() matcher by skipping the expensive generation of the
fully qualified name unless we need it.
In the common case of matching an unqualified name, we don't need to
generate the full name. We might not even need to copy any string at
all.
This change speeds up our clang-tidy benchmark by ~10%

Reviewers: klimek

Subscribers: klimek, cfe-commits

Differential Revision: http://reviews.llvm.org/D5776

llvm-svn: 219792
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 9d77cb6..b5d4b52 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -13,6 +13,7 @@
 
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/ASTMatchers/ASTMatchersInternal.h"
+#include "llvm/ADT/SmallString.h"
 #include "llvm/Support/ManagedStatic.h"
 
 namespace clang {
@@ -221,6 +222,51 @@
   return false;
 }
 
+HasNameMatcher::HasNameMatcher(StringRef NameRef)
+    : UseUnqualifiedMatch(NameRef.find("::") == NameRef.npos), Name(NameRef) {
+  assert(!Name.empty());
+}
+
+bool HasNameMatcher::matchesNodeUnqualified(const NamedDecl &Node) const {
+  assert(UseUnqualifiedMatch);
+  if (Node.getIdentifier()) {
+    // Simple name.
+    return Name == Node.getName();
+  } else if (Node.getDeclName()) {
+    // Name needs to be constructed.
+    llvm::SmallString<128> NodeName;
+    llvm::raw_svector_ostream OS(NodeName);
+    Node.printName(OS);
+    return Name == OS.str();
+  } else {
+    return false;
+  }
+}
+
+bool HasNameMatcher::matchesNodeFull(const NamedDecl &Node) const {
+  llvm::SmallString<128> NodeName = StringRef("::");
+  llvm::raw_svector_ostream OS(NodeName);
+  Node.printQualifiedName(OS);
+  const StringRef FullName = OS.str();
+  const StringRef Pattern = Name;
+  if (Pattern.startswith("::")) {
+    return FullName == Pattern;
+  } else {
+    return FullName.endswith(("::" + Pattern).str());
+  }
+}
+
+bool HasNameMatcher::matchesNode(const NamedDecl &Node) const {
+  // FIXME: There is still room for improvement, but it would require copying a
+  // lot of the logic from NamedDecl::printQualifiedName(). The benchmarks do
+  // not show like that extra complexity is needed right now.
+  if (UseUnqualifiedMatch) {
+    assert(matchesNodeUnqualified(Node) == matchesNodeFull(Node));
+    return matchesNodeUnqualified(Node);
+  }
+  return matchesNodeFull(Node);
+}
+
 } // end namespace internal
 } // end namespace ast_matchers
 } // end namespace clang