123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- //===- 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
|