From 24db0f0afd425fdb0854d3d6a6e04f87c76dd27f Mon Sep 17 00:00:00 2001 From: Manuel Klimek Date: Tue, 14 May 2013 09:13:00 +0000 Subject: First revision of the dynamic ASTMatcher library. This library supports all the features of the compile-time based ASTMatcher library, but allows the user to specify and construct the matchers at runtime. It contains the following modules: - A variant type, to be used by the matcher factory. - A registry, where the matchers are indexed by name and have a factory method with a generic signature. - A simple matcher expression parser, that can be used to convert a matcher expression string into actual matchers that can be used with the AST at runtime. Many features where omitted from this first revision to simplify this code review. The main ideas are still represented in this change and it already has support working use cases. Things that are missing: - Support for polymorphic matchers. These requires supporting code in the registry, the marshallers and the variant type. - Support for numbers, char and bool arguments to the matchers. This requires supporting code in the parser and the variant type. - A command line program putting everything together and providing an already functional tool. Patch by Samuel Benzaquen. llvm-svn: 181768 --- .../unittests/ASTMatchers/Dynamic/RegistryTest.cpp | 112 +++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp (limited to 'clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp') diff --git a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp new file mode 100644 index 00000000000..64af120193b --- /dev/null +++ b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp @@ -0,0 +1,112 @@ +//===- unittest/ASTMatchers/Dynamic/RegistryTest.cpp - Registry unit tests -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===-----------------------------------------------------------------------===// + +#include + +#include "../ASTMatchersTest.h" +#include "clang/ASTMatchers/Dynamic/Registry.h" +#include "gtest/gtest.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { +namespace { + +using ast_matchers::internal::Matcher; + +DynTypedMatcher *constructMatcher(StringRef MatcherName, Diagnostics *Error) { + const std::vector Args; + return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error); +} + +DynTypedMatcher *constructMatcher(StringRef MatcherName, + const VariantValue &Arg1, + Diagnostics *Error) { + std::vector Args(1); + Args[0].Value = Arg1; + return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error); +} + +DynTypedMatcher *constructMatcher(StringRef MatcherName, + const VariantValue &Arg1, + const VariantValue &Arg2, + Diagnostics *Error) { + std::vector Args(2); + Args[0].Value = Arg1; + Args[1].Value = Arg2; + return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error); +} + +TEST(RegistryTest, CanConstructNoArgs) { + OwningPtr IsArrowValue(constructMatcher("isArrow", NULL)); + OwningPtr BoolValue(constructMatcher("boolLiteral", NULL)); + + const std::string ClassSnippet = "struct Foo { int x; };\n" + "Foo *foo = new Foo;\n" + "int i = foo->x;\n"; + const std::string BoolSnippet = "bool Foo = true;\n"; + + EXPECT_TRUE(matchesDynamic(ClassSnippet, *IsArrowValue)); + EXPECT_TRUE(matchesDynamic(BoolSnippet, *BoolValue)); + EXPECT_FALSE(matchesDynamic(ClassSnippet, *BoolValue)); + EXPECT_FALSE(matchesDynamic(BoolSnippet, *IsArrowValue)); +} + +TEST(RegistryTest, ConstructWithSimpleArgs) { + OwningPtr Value( + constructMatcher("hasName", std::string("X"), NULL)); + EXPECT_TRUE(matchesDynamic("class X {};", *Value)); + EXPECT_FALSE(matchesDynamic("int x;", *Value)); +} + +TEST(RegistryTest, ConstructWithMatcherArgs) { + OwningPtr HasInitializerSimple( + constructMatcher("hasInitializer", stmt(), NULL)); + OwningPtr HasInitializerComplex( + constructMatcher("hasInitializer", callExpr(), NULL)); + + std::string code = "int i;"; + EXPECT_FALSE(matchesDynamic(code, *HasInitializerSimple)); + EXPECT_FALSE(matchesDynamic(code, *HasInitializerComplex)); + + code = "int i = 1;"; + EXPECT_TRUE(matchesDynamic(code, *HasInitializerSimple)); + EXPECT_FALSE(matchesDynamic(code, *HasInitializerComplex)); + + code = "int y(); int i = y();"; + EXPECT_TRUE(matchesDynamic(code, *HasInitializerSimple)); + EXPECT_TRUE(matchesDynamic(code, *HasInitializerComplex)); +} + +TEST(RegistryTest, Errors) { + // Incorrect argument count. + OwningPtr Error(new Diagnostics()); + EXPECT_TRUE(NULL == constructMatcher("hasInitializer", Error.get())); + EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)", + Error->ToString()); + Error.reset(new Diagnostics()); + EXPECT_TRUE(NULL == constructMatcher("isArrow", std::string(), Error.get())); + EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)", + Error->ToString()); + + // Bad argument type + Error.reset(new Diagnostics()); + EXPECT_TRUE(NULL == constructMatcher("ofClass", std::string(), Error.get())); + EXPECT_EQ("Incorrect type on function ofClass for arg 1.", Error->ToString()); + Error.reset(new Diagnostics()); + EXPECT_TRUE(NULL == constructMatcher("recordDecl", recordDecl(), + ::std::string(), Error.get())); + EXPECT_EQ("Incorrect type on function recordDecl for arg 2.", + Error->ToString()); +} + +} // end anonymous namespace +} // end namespace dynamic +} // end namespace ast_matchers +} // end namespace clang -- cgit v1.2.3