isExpansionInMainFile and isExpansionInFileMatching - sounds reasonable :)
I'm going with FileContentMappings for now, but feel free to change anytime -
I'm not enthusiastic about names.
I included Tooling.h in PreprocessorOptions.h to have access to the new typedef
FileContentMappings. It feels kinda heavy to add that include for one typedef
only. Furthermore, I'm unsure how to update the description of the
RemappedFiles, as it directly relates to the std::pair that is now no longer
visible in the typename. In my eyes, the usage of std::pair now becomes to an
implementation-detail that should not be exposed in the comment, so i removed
these mentions.
http://reviews.llvm.org/D4283
Files:
include/clang/ASTMatchers/ASTMatchers.h
include/clang/Lex/PreprocessorOptions.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(isExpansionInMainFile,
+ 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(isExpansionInFileMatching,
+ 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/Lex/PreprocessorOptions.h
===================================================================
--- include/clang/Lex/PreprocessorOptions.h
+++ include/clang/Lex/PreprocessorOptions.h
@@ -11,6 +11,7 @@
#define LLVM_CLANG_LEX_PREPROCESSOROPTIONS_H_
#include "clang/Basic/SourceLocation.h"
+#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
@@ -94,10 +95,8 @@
bool RemappedFilesKeepOriginalName;
/// \brief The set of file remappings, which take existing files on
- /// the system (the first part of each pair) and gives them the
- /// contents of other files on the system (the second part of each
- /// pair).
- std::vector<std::pair<std::string, std::string>> RemappedFiles;
+ /// the system and gives them the contents of other files on the system
+ tooling::FileContentMappings RemappedFiles;
/// \brief The set of file-to-buffer remappings, which take existing files
/// on the system (the first part of each pair) and gives them the contents
Index: include/clang/Tooling/Tooling.h
===================================================================
--- include/clang/Tooling/Tooling.h
+++ include/clang/Tooling/Tooling.h
@@ -143,6 +143,10 @@
bool runToolOnCode(clang::FrontendAction *ToolAction, const Twine &Code,
const Twine &FileName = "input.cc");
+/// The first part of the pair is the filename, the second part the
+/// file-content.
+typedef std::vector<std::pair<std::string, std::string>> FileContentMappings;
+
/// \brief Runs (and deletes) the tool on 'Code' with the -fsyntax-only flag and
/// with additional other flags.
///
@@ -152,9 +156,10 @@
/// \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 FileContentMappings &VirtualMappedFiles = FileContentMappings());
/// \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(isExpansionInFileMatching);
+ REGISTER_MATCHER(isExpansionInMainFile);
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
@@ -123,17 +123,25 @@
bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code,
const std::vector<std::string> &Args,
- const Twine &FileName) {
+ const Twine &FileName,
+ const FileContentMappings &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, IsExpansionInMainFileMatcher) {
+ EXPECT_TRUE(matches("class X {};",
+ recordDecl(hasName("X"), isExpansionInMainFile())));
+ EXPECT_TRUE(notMatches("", recordDecl(isExpansionInMainFile())));
+ EXPECT_TRUE(matchesConditionally("#include <other>\n",
+ recordDecl(isExpansionInMainFile()), 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, IsExpansionInFileMatching) {
+ EXPECT_TRUE(matchesConditionally(
+ "#include <foo>\n"
+ "#include <bar>\n"
+ "class X {};",
+ recordDecl(isExpansionInFileMatching("b.*"), hasName("B")), true,
+ "-isystem/", {{"/foo", "class A {};"}, {"/bar", "class B {};"}}));
+ EXPECT_TRUE(matchesConditionally(
+ "#include <foo>\n"
+ "#include <bar>\n"
+ "class X {};",
+ recordDecl(isExpansionInFileMatching("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
@@ -22,6 +22,7 @@
using clang::tooling::newFrontendActionFactory;
using clang::tooling::runToolOnCodeWithArgs;
using clang::tooling::FrontendActionFactory;
+using clang::tooling::FileContentMappings;
class BoundNodesCallback {
public:
@@ -58,10 +59,10 @@
};
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 FileContentMappings &VirtualMappedFiles = FileContentMappings()) {
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