/// \code
/// namespace a { namespace b { class X; } }
/// \endcode
-AST_MATCHER_P(NamedDecl, hasName, std::string, Name) {
- assert(!Name.empty());
- const std::string FullNameString = "::" + Node.getQualifiedNameAsString();
- const StringRef FullName = FullNameString;
- const StringRef Pattern = Name;
- if (Pattern.startswith("::")) {
- return FullName == Pattern;
- } else {
- return FullName.endswith(("::" + Pattern).str());
- }
+inline internal::Matcher<NamedDecl> hasName(StringRef Name) {
+ return internal::Matcher<NamedDecl>(new internal::HasNameMatcher(Name));
}
/// \brief Matches NamedDecl nodes whose fully qualified names contain
std::string Name;
};
+/// \brief Matches named declarations with a specific name.
+///
+/// See \c hasName() in ASTMatchers.h for details.
+class HasNameMatcher : public SingleNodeMatcherInterface<NamedDecl> {
+ public:
+ explicit HasNameMatcher(StringRef Name);
+
+ bool matchesNode(const NamedDecl &Node) const override;
+
+ private:
+ /// \brief Unqualified match routine.
+ ///
+ /// It is much faster than the full match, but it only works for unqualified
+ /// matches.
+ bool matchesNodeUnqualified(const NamedDecl &Node) const;
+
+ /// \brief Full match routine
+ ///
+ /// It generates the fully qualified name of the declaration (which is
+ /// expensive) before trying to match.
+ /// It is slower but simple and works on all cases.
+ bool matchesNodeFull(const NamedDecl &Node) const;
+
+ const bool UseUnqualifiedMatch;
+ const std::string Name;
+};
+
/// \brief Matches declarations for QualType and CallExpr.
///
/// Type argument DeclMatcherT is required by PolymorphicMatcherWithParam1 but
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchersInternal.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ManagedStatic.h"
namespace clang {
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