I updated it accordingly to the comments (thanks!).
One of the changes is the replacement of an initializer list through an
explicit call to the default-constructor of std::vector<std::pair<std::string,
std::string>>, to initialize the new introduced VirtualMappedFiles-parameter of
the functions runToolOnCodeWithArgs and matchesConditionally. Due to the
repeated usage of the type-declaration, it would be nice to declare a typedef
for std::vector<std::pair<std::string, std::string>>, that could also be used
for the RemappedFiles-instance-variable of the class PreprocessorOptions.
If it is appropriate to add the typedef, where should I add it and how should I
name it?
http://reviews.llvm.org/D4283
Files:
include/clang/ASTMatchers/ASTMatchers.h
include/clang/Tooling/Tooling.h
lib/ASTMatchers/Dynamic/Registry.cpp
lib/Tooling/Tooling.cpp
unittests/ASTMatchers/ASTMatchersTest.cpp
unittests/ASTMatchers/ASTMatchersTest.h
Index: include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -47,6 +47,7 @@
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchersInternal.h"
#include "clang/ASTMatchers/ASTMatchersMacros.h"
#include "llvm/ADT/Twine.h"
@@ -142,6 +143,95 @@
/// Usable as: Any Matcher
inline internal::TrueMatcher anything() { return internal::TrueMatcher(); }
+/// \brief Matches typedef declarations.
+///
+/// Given
+/// \code
+/// typedef int X;
+/// \endcode
+/// typedefDecl()
+/// matches "typedef int X"
+const internal::VariadicDynCastAllOfMatcher<Decl, TypedefDecl> typedefDecl;
+
+/// \brief Matches AST nodes that were expanded within the main-file
+///
+/// Example matches X but not Y (matcher = recordDecl(isInMainFile())
+/// \code
+/// #include <Y.h>
+/// class X {};
+/// \endcode
+/// Y.h:
+/// \code
+/// class Y {};
+/// \endcode
+///
+/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
+AST_POLYMORPHIC_MATCHER(isInMainFile,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_3(Decl, Stmt,
+ TypeLoc)) {
+ auto &SourceManager = Finder->getASTContext().getSourceManager();
+ return SourceManager.isInMainFile(
+ SourceManager.getExpansionLoc(Node.getLocStart()));
+}
+
+/// \brief Matches AST nodes that were expanded within system-header-files
+///
+/// Example matches Y but not X (matcher = recordDecl(isInSytemHeader())
+/// \code
+/// #include <SystemHeader.h>
+/// class X {};
+/// \endcode
+/// SystemHeader.h:
+/// \code
+/// class Y {};
+/// \endcode
+///
+/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
+AST_POLYMORPHIC_MATCHER(isInSystemHeader,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_3(Decl, Stmt,
+ TypeLoc)) {
+ auto &SourceManager = Finder->getASTContext().getSourceManager();
+ auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart());
+ if (ExpansionLoc.isInvalid()) {
+ return false;
+ }
+ return SourceManager.isInSystemHeader(ExpansionLoc);
+}
+
+/// \brief Matches AST nodes that were expanded within files whose name is
+/// partially matching a given regex
+///
+/// Example matches Y but not X (matcher = recordDecl(isInFileMatchingName("AST.*"))
+/// \code
+/// #include "ASTMatcher.h"
+/// class X {};
+/// \endcode
+/// ASTMatcher.h:
+/// \code
+/// class Y {};
+/// \endcode
+///
+/// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc>
+AST_POLYMORPHIC_MATCHER_P(isInFileMatchingName,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_3(Decl, Stmt,
+ TypeLoc),
+ std::string, RegExp) {
+ auto &SourceManager = Finder->getASTContext().getSourceManager();
+ auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart());
+ if (ExpansionLoc.isInvalid()) {
+ return false;
+ }
+ auto FileEntry =
+ SourceManager.getFileEntryForID(SourceManager.getFileID(ExpansionLoc));
+ if (!FileEntry) {
+ return false;
+ }
+
+ auto Filename = FileEntry->getName();
+ llvm::Regex RE(RegExp);
+ return RE.match(Filename);
+}
+
/// \brief Matches declarations.
///
/// Examples matches \c X, \c C, and the friend declaration inside \c C;
Index: include/clang/Tooling/Tooling.h
===================================================================
--- include/clang/Tooling/Tooling.h
+++ include/clang/Tooling/Tooling.h
@@ -152,9 +152,11 @@
/// \param FileName The file name which 'Code' will be mapped as.
///
/// \return - True if 'ToolAction' was successfully executed.
-bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code,
- const std::vector<std::string> &Args,
- const Twine &FileName = "input.cc");
+bool runToolOnCodeWithArgs(
+ clang::FrontendAction *ToolAction, const Twine &Code,
+ const std::vector<std::string> &Args, const Twine &FileName = "input.cc",
+ const std::vector<std::pair<std::string, std::string>> &VirtualMappedFiles =
+ std::vector<std::pair<std::string, std::string>>());
/// \brief Builds an AST for 'Code'.
///
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===================================================================
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -242,7 +242,10 @@
REGISTER_MATCHER(isExpr);
REGISTER_MATCHER(isExternC);
REGISTER_MATCHER(isImplicit);
+ REGISTER_MATCHER(isInFileMatchingName);
+ REGISTER_MATCHER(isInMainFile);
REGISTER_MATCHER(isInstantiated);
+ REGISTER_MATCHER(isInSystemHeader);
REGISTER_MATCHER(isInteger);
REGISTER_MATCHER(isIntegral);
REGISTER_MATCHER(isInTemplateInstantiation);
@@ -314,6 +317,7 @@
REGISTER_MATCHER(to);
REGISTER_MATCHER(tryStmt);
REGISTER_MATCHER(type);
+ REGISTER_MATCHER(typedefDecl);
REGISTER_MATCHER(typedefType);
REGISTER_MATCHER(typeLoc);
REGISTER_MATCHER(unaryExprOrTypeTraitExpr);
Index: lib/Tooling/Tooling.cpp
===================================================================
--- lib/Tooling/Tooling.cpp
+++ lib/Tooling/Tooling.cpp
@@ -121,19 +121,29 @@
return Args;
}
-bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code,
- const std::vector<std::string> &Args,
- const Twine &FileName) {
+bool
+runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code,
+ const std::vector<std::string> &Args,
+ const Twine &FileName,
+ const std::vector<std::pair<std::string, std::string>> &
+ VirtualMappedFiles) {
+
SmallString<16> FileNameStorage;
StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
llvm::IntrusiveRefCntPtr<FileManager> Files(
new FileManager(FileSystemOptions()));
- ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef), ToolAction,
- Files.get());
+ ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef),
+ ToolAction, Files.get());
SmallString<1024> CodeStorage;
Invocation.mapVirtualFile(FileNameRef,
Code.toNullTerminatedStringRef(CodeStorage));
+
+ for (auto &FilenameWithContent : VirtualMappedFiles) {
+ Invocation.mapVirtualFile(FilenameWithContent.first,
+ FilenameWithContent.second);
+ }
+
return Invocation.run();
}
Index: unittests/ASTMatchers/ASTMatchersTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -4597,5 +4597,45 @@
.bind("data")));
}
+TEST(TypeDefDeclMatcher, Match) {
+ EXPECT_TRUE(matches("typedef int typedefDeclTest;",
+ typedefDecl(hasName("typedefDeclTest"))));
+}
+
+TEST(Matcher, IsInMainFileMatcher) {
+ EXPECT_TRUE(matches(
+ "class X {};", recordDecl(hasName("X"), isInMainFile())));
+ EXPECT_TRUE(notMatches("", recordDecl(isInMainFile())));
+ EXPECT_TRUE(matchesConditionally("#include <other>\n",
+ recordDecl(isInMainFile()), false,
+ "-isystem/", {{"/other", "class X {};"}}));
+}
+
+TEST(Matcher, IsInSystemHeaderMatcher) {
+ EXPECT_TRUE(matchesConditionally("#include \"other\"\n",
+ recordDecl(isInSystemHeader()), true,
+ "-isystem/", {{"/other", "class X {};"}}));
+ EXPECT_TRUE(matchesConditionally("#include \"other\"\n",
+ recordDecl(isInSystemHeader()), false, "-I/",
+ {{"/other", "class X {};"}}));
+ EXPECT_TRUE(notMatches("class X {};", recordDecl(isInSystemHeader())));
+ EXPECT_TRUE(notMatches("", recordDecl(isInSystemHeader())));
+}
+
+TEST(Matcher, IsInFileMatchingName) {
+ EXPECT_TRUE(matchesConditionally(
+ "#include <foo>\n"
+ "#include <bar>\n"
+ "class X {};",
+ recordDecl(isInFileMatchingName("b.*"), hasName("B")), true, "-isystem/",
+ {{"/foo", "class A {};"}, {"/bar", "class B {};"}}));
+ EXPECT_TRUE(matchesConditionally(
+ "#include <foo>\n"
+ "#include <bar>\n"
+ "class X {};",
+ recordDecl(isInFileMatchingName("f.*"), hasName("X")), false, "-isystem/",
+ {{"/foo", "class A {};"}, {"/bar", "class B {};"}}));
+}
+
} // end namespace ast_matchers
} // end namespace clang
Index: unittests/ASTMatchers/ASTMatchersTest.h
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.h
+++ unittests/ASTMatchers/ASTMatchersTest.h
@@ -58,10 +58,11 @@
};
template <typename T>
-testing::AssertionResult matchesConditionally(const std::string &Code,
- const T &AMatcher,
- bool ExpectMatch,
- llvm::StringRef CompileArg) {
+testing::AssertionResult matchesConditionally(
+ const std::string &Code, const T &AMatcher, bool ExpectMatch,
+ llvm::StringRef CompileArg,
+ const std::vector<std::pair<std::string, std::string>> &VirtualMappedFiles =
+ std::vector<std::pair<std::string, std::string>>()) {
bool Found = false, DynamicFound = false;
MatchFinder Finder;
VerifyMatch VerifyFound(nullptr, &Found);
@@ -73,7 +74,8 @@
newFrontendActionFactory(&Finder));
// Some tests use typeof, which is a gnu extension.
std::vector<std::string> Args(1, CompileArg);
- if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) {
+ if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, "input.cc",
+ VirtualMappedFiles)) {
return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
}
if (Found != DynamicFound) {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits