diff options
author | 2020-08-03 14:31:31 +0000 | |
---|---|---|
committer | 2020-08-03 14:31:31 +0000 | |
commit | e5dd70708596ae51455a0ffa086a00c5b29f8583 (patch) | |
tree | 5d676f27b570bacf71e786c3b5cff3e6f6679b59 /gnu/llvm/clang/unittests/Tooling/ExecutionTest.cpp | |
parent | Import LLVM 10.0.0 release including clang, lld and lldb. (diff) | |
download | wireguard-openbsd-e5dd70708596ae51455a0ffa086a00c5b29f8583.tar.xz wireguard-openbsd-e5dd70708596ae51455a0ffa086a00c5b29f8583.zip |
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom
tested by plenty
Diffstat (limited to 'gnu/llvm/clang/unittests/Tooling/ExecutionTest.cpp')
-rw-r--r-- | gnu/llvm/clang/unittests/Tooling/ExecutionTest.cpp | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/gnu/llvm/clang/unittests/Tooling/ExecutionTest.cpp b/gnu/llvm/clang/unittests/Tooling/ExecutionTest.cpp new file mode 100644 index 00000000000..16455fb2fd7 --- /dev/null +++ b/gnu/llvm/clang/unittests/Tooling/ExecutionTest.cpp @@ -0,0 +1,297 @@ +//===- unittest/Tooling/ExecutionTest.cpp - Tool execution tests. --------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Execution.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Tooling/AllTUsExecution.h" +#include "clang/Tooling/CompilationDatabase.h" +#include "clang/Tooling/StandaloneExecution.h" +#include "clang/Tooling/ToolExecutorPluginRegistry.h" +#include "clang/Tooling/Tooling.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include <algorithm> +#include <string> + +namespace clang { +namespace tooling { + +namespace { + +// This traverses the AST and outputs function name as key and "1" as value for +// each function declaration. +class ASTConsumerWithResult + : public ASTConsumer, + public RecursiveASTVisitor<ASTConsumerWithResult> { +public: + using ASTVisitor = RecursiveASTVisitor<ASTConsumerWithResult>; + + explicit ASTConsumerWithResult(ExecutionContext *Context) : Context(Context) { + assert(Context != nullptr); + } + + void HandleTranslationUnit(clang::ASTContext &Context) override { + TraverseDecl(Context.getTranslationUnitDecl()); + } + + bool TraverseFunctionDecl(clang::FunctionDecl *Decl) { + Context->reportResult(Decl->getNameAsString(), + Context->getRevision() + ":" + Context->getCorpus() + + ":" + Context->getCurrentCompilationUnit() + + "/1"); + return ASTVisitor::TraverseFunctionDecl(Decl); + } + +private: + ExecutionContext *const Context; +}; + +class ReportResultAction : public ASTFrontendAction { +public: + explicit ReportResultAction(ExecutionContext *Context) : Context(Context) { + assert(Context != nullptr); + } + +protected: + std::unique_ptr<clang::ASTConsumer> + CreateASTConsumer(clang::CompilerInstance &compiler, + StringRef /* dummy */) override { + std::unique_ptr<clang::ASTConsumer> ast_consumer{ + new ASTConsumerWithResult(Context)}; + return ast_consumer; + } + +private: + ExecutionContext *const Context; +}; + +class ReportResultActionFactory : public FrontendActionFactory { +public: + ReportResultActionFactory(ExecutionContext *Context) : Context(Context) {} + std::unique_ptr<FrontendAction> create() override { + return std::make_unique<ReportResultAction>(Context); + } + +private: + ExecutionContext *const Context; +}; + +} // namespace + +class TestToolExecutor : public ToolExecutor { +public: + static const char *ExecutorName; + + TestToolExecutor(CommonOptionsParser Options) + : OptionsParser(std::move(Options)) {} + + StringRef getExecutorName() const override { return ExecutorName; } + + llvm::Error + execute(llvm::ArrayRef<std::pair<std::unique_ptr<FrontendActionFactory>, + ArgumentsAdjuster>>) override { + return llvm::Error::success(); + } + + ExecutionContext *getExecutionContext() override { return nullptr; }; + + ToolResults *getToolResults() override { return nullptr; } + + llvm::ArrayRef<std::string> getSourcePaths() const { + return OptionsParser.getSourcePathList(); + } + + void mapVirtualFile(StringRef FilePath, StringRef Content) override { + VFS[FilePath] = Content; + } + +private: + CommonOptionsParser OptionsParser; + std::string SourcePaths; + std::map<std::string, std::string> VFS; +}; + +const char *TestToolExecutor::ExecutorName = "test-executor"; + +class TestToolExecutorPlugin : public ToolExecutorPlugin { +public: + llvm::Expected<std::unique_ptr<ToolExecutor>> + create(CommonOptionsParser &OptionsParser) override { + return std::make_unique<TestToolExecutor>(std::move(OptionsParser)); + } +}; + +static ToolExecutorPluginRegistry::Add<TestToolExecutorPlugin> + X("test-executor", "Plugin for TestToolExecutor."); + +llvm::cl::OptionCategory TestCategory("execution-test options"); + +TEST(CreateToolExecutorTest, FailedCreateExecutorUndefinedFlag) { + std::vector<const char *> argv = {"prog", "--fake_flag_no_no_no", "f"}; + int argc = argv.size(); + auto Executor = internal::createExecutorFromCommandLineArgsImpl( + argc, &argv[0], TestCategory); + ASSERT_FALSE((bool)Executor); + llvm::consumeError(Executor.takeError()); +} + +TEST(CreateToolExecutorTest, RegisterFlagsBeforeReset) { + llvm::cl::opt<std::string> BeforeReset( + "before_reset", llvm::cl::desc("Defined before reset."), + llvm::cl::init("")); + + llvm::cl::ResetAllOptionOccurrences(); + + std::vector<const char *> argv = {"prog", "--before_reset=set", "f"}; + int argc = argv.size(); + auto Executor = internal::createExecutorFromCommandLineArgsImpl( + argc, &argv[0], TestCategory); + ASSERT_TRUE((bool)Executor); + EXPECT_EQ(BeforeReset, "set"); + BeforeReset.removeArgument(); +} + +TEST(CreateToolExecutorTest, CreateStandaloneToolExecutor) { + std::vector<const char *> argv = {"prog", "standalone.cpp"}; + int argc = argv.size(); + auto Executor = internal::createExecutorFromCommandLineArgsImpl( + argc, &argv[0], TestCategory); + ASSERT_TRUE((bool)Executor); + EXPECT_EQ(Executor->get()->getExecutorName(), + StandaloneToolExecutor::ExecutorName); +} + +TEST(CreateToolExecutorTest, CreateTestToolExecutor) { + std::vector<const char *> argv = {"prog", "test.cpp", + "--executor=test-executor"}; + int argc = argv.size(); + auto Executor = internal::createExecutorFromCommandLineArgsImpl( + argc, &argv[0], TestCategory); + ASSERT_TRUE((bool)Executor); + EXPECT_EQ(Executor->get()->getExecutorName(), TestToolExecutor::ExecutorName); +} + +TEST(StandaloneToolTest, SynctaxOnlyActionOnSimpleCode) { + FixedCompilationDatabase Compilations(".", std::vector<std::string>()); + StandaloneToolExecutor Executor(Compilations, + std::vector<std::string>(1, "a.cc")); + Executor.mapVirtualFile("a.cc", "int x = 0;"); + + auto Err = Executor.execute(newFrontendActionFactory<SyntaxOnlyAction>(), + getClangSyntaxOnlyAdjuster()); + ASSERT_TRUE(!Err); +} + +TEST(StandaloneToolTest, SimpleAction) { + FixedCompilationDatabase Compilations(".", std::vector<std::string>()); + StandaloneToolExecutor Executor(Compilations, + std::vector<std::string>(1, "a.cc")); + Executor.mapVirtualFile("a.cc", "int x = 0;"); + + auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>( + new ReportResultActionFactory(Executor.getExecutionContext()))); + ASSERT_TRUE(!Err); + auto KVs = Executor.getToolResults()->AllKVResults(); + ASSERT_EQ(KVs.size(), 0u); +} + +TEST(StandaloneToolTest, SimpleActionWithResult) { + FixedCompilationDatabase Compilations(".", std::vector<std::string>()); + StandaloneToolExecutor Executor(Compilations, + std::vector<std::string>(1, "a.cc")); + Executor.mapVirtualFile("a.cc", "int x = 0; void f() {}"); + + auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>( + new ReportResultActionFactory(Executor.getExecutionContext()))); + ASSERT_TRUE(!Err); + auto KVs = Executor.getToolResults()->AllKVResults(); + ASSERT_EQ(KVs.size(), 1u); + EXPECT_EQ("f", KVs[0].first); + // Currently the standlone executor returns empty corpus, revision, and + // compilation unit. + EXPECT_EQ("::/1", KVs[0].second); + + Executor.getToolResults()->forEachResult( + [](StringRef, StringRef Value) { EXPECT_EQ("::/1", Value); }); +} + +class FixedCompilationDatabaseWithFiles : public CompilationDatabase { +public: + FixedCompilationDatabaseWithFiles(Twine Directory, + ArrayRef<std::string> Files, + ArrayRef<std::string> CommandLine) + : FixedCompilations(Directory, CommandLine), Files(Files) {} + + std::vector<CompileCommand> + getCompileCommands(StringRef FilePath) const override { + return FixedCompilations.getCompileCommands(FilePath); + } + + std::vector<std::string> getAllFiles() const override { return Files; } + +private: + FixedCompilationDatabase FixedCompilations; + std::vector<std::string> Files; +}; + +MATCHER_P(Named, Name, "") { return arg.first == Name; } + +TEST(AllTUsToolTest, AFewFiles) { + FixedCompilationDatabaseWithFiles Compilations( + ".", {"a.cc", "b.cc", "c.cc", "ignore.cc"}, std::vector<std::string>()); + AllTUsToolExecutor Executor(Compilations, /*ThreadCount=*/0); + Filter.setValue("[a-c].cc"); + Executor.mapVirtualFile("a.cc", "void x() {}"); + Executor.mapVirtualFile("b.cc", "void y() {}"); + Executor.mapVirtualFile("c.cc", "void z() {}"); + Executor.mapVirtualFile("ignore.cc", "void d() {}"); + + auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>( + new ReportResultActionFactory(Executor.getExecutionContext()))); + ASSERT_TRUE(!Err); + EXPECT_THAT( + Executor.getToolResults()->AllKVResults(), + ::testing::UnorderedElementsAre(Named("x"), Named("y"), Named("z"))); + Filter.setValue(".*"); // reset to default value. +} + +TEST(AllTUsToolTest, ManyFiles) { + unsigned NumFiles = 100; + std::vector<std::string> Files; + std::map<std::string, std::string> FileToContent; + std::vector<std::string> ExpectedSymbols; + for (unsigned i = 1; i <= NumFiles; ++i) { + std::string File = "f" + std::to_string(i) + ".cc"; + std::string Symbol = "looong_function_name_" + std::to_string(i); + Files.push_back(File); + FileToContent[File] = "void " + Symbol + "() {}"; + ExpectedSymbols.push_back(Symbol); + } + FixedCompilationDatabaseWithFiles Compilations(".", Files, + std::vector<std::string>()); + AllTUsToolExecutor Executor(Compilations, /*ThreadCount=*/0); + for (const auto &FileAndContent : FileToContent) { + Executor.mapVirtualFile(FileAndContent.first, FileAndContent.second); + } + + auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>( + new ReportResultActionFactory(Executor.getExecutionContext()))); + ASSERT_TRUE(!Err); + std::vector<std::string> Results; + Executor.getToolResults()->forEachResult( + [&](StringRef Name, StringRef) { Results.push_back(Name); }); + EXPECT_THAT(ExpectedSymbols, ::testing::UnorderedElementsAreArray(Results)); +} + +} // end namespace tooling +} // end namespace clang |