brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.3 KiB · c810493 Raw
295 lines · cpp
1//===- unittest/Tooling/ExecutionTest.cpp - Tool execution tests. --------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/Tooling/Execution.h"10#include "clang/AST/ASTConsumer.h"11#include "clang/AST/DeclCXX.h"12#include "clang/AST/DynamicRecursiveASTVisitor.h"13#include "clang/Frontend/ASTUnit.h"14#include "clang/Frontend/FrontendAction.h"15#include "clang/Frontend/FrontendActions.h"16#include "clang/Tooling/AllTUsExecution.h"17#include "clang/Tooling/CompilationDatabase.h"18#include "clang/Tooling/StandaloneExecution.h"19#include "clang/Tooling/ToolExecutorPluginRegistry.h"20#include "clang/Tooling/Tooling.h"21#include "gmock/gmock.h"22#include "gtest/gtest.h"23#include <algorithm>24#include <string>25 26namespace clang {27namespace tooling {28 29namespace {30 31// This traverses the AST and outputs function name as key and "1" as value for32// each function declaration.33class ASTConsumerWithResult : public ASTConsumer,34                              public DynamicRecursiveASTVisitor {35public:36  explicit ASTConsumerWithResult(ExecutionContext *Context) : Context(Context) {37    assert(Context != nullptr);38  }39 40  void HandleTranslationUnit(clang::ASTContext &Context) override {41    TraverseDecl(Context.getTranslationUnitDecl());42  }43 44  bool TraverseFunctionDecl(clang::FunctionDecl *Decl) override {45    Context->reportResult(Decl->getNameAsString(),46                          Context->getRevision() + ":" + Context->getCorpus() +47                              ":" + Context->getCurrentCompilationUnit() +48                              "/1");49    return DynamicRecursiveASTVisitor::TraverseFunctionDecl(Decl);50  }51 52private:53  ExecutionContext *const Context;54};55 56class ReportResultAction : public ASTFrontendAction {57public:58  explicit ReportResultAction(ExecutionContext *Context) : Context(Context) {59    assert(Context != nullptr);60  }61 62protected:63  std::unique_ptr<clang::ASTConsumer>64  CreateASTConsumer(clang::CompilerInstance &compiler,65                    StringRef /* dummy */) override {66    std::unique_ptr<clang::ASTConsumer> ast_consumer{67        new ASTConsumerWithResult(Context)};68    return ast_consumer;69  }70 71private:72  ExecutionContext *const Context;73};74 75class ReportResultActionFactory : public FrontendActionFactory {76public:77  ReportResultActionFactory(ExecutionContext *Context) : Context(Context) {}78  std::unique_ptr<FrontendAction> create() override {79    return std::make_unique<ReportResultAction>(Context);80  }81 82private:83  ExecutionContext *const Context;84};85 86} // namespace87 88class TestToolExecutor : public ToolExecutor {89public:90  static const char *ExecutorName;91 92  TestToolExecutor(CommonOptionsParser Options)93      : OptionsParser(std::move(Options)) {}94 95  StringRef getExecutorName() const override { return ExecutorName; }96 97  llvm::Error98  execute(llvm::ArrayRef<std::pair<std::unique_ptr<FrontendActionFactory>,99                                   ArgumentsAdjuster>>) override {100    return llvm::Error::success();101  }102 103  ExecutionContext *getExecutionContext() override { return nullptr; };104 105  ToolResults *getToolResults() override { return nullptr; }106 107  llvm::ArrayRef<std::string> getSourcePaths() const {108    return OptionsParser.getSourcePathList();109  }110 111  void mapVirtualFile(StringRef FilePath, StringRef Content) override {112    VFS[std::string(FilePath)] = std::string(Content);113  }114 115private:116  CommonOptionsParser OptionsParser;117  std::string SourcePaths;118  std::map<std::string, std::string> VFS;119};120 121const char *TestToolExecutor::ExecutorName = "test-executor";122 123class TestToolExecutorPlugin : public ToolExecutorPlugin {124public:125  llvm::Expected<std::unique_ptr<ToolExecutor>>126  create(CommonOptionsParser &OptionsParser) override {127    return std::make_unique<TestToolExecutor>(std::move(OptionsParser));128  }129};130 131static ToolExecutorPluginRegistry::Add<TestToolExecutorPlugin>132    X("test-executor", "Plugin for TestToolExecutor.");133 134llvm::cl::OptionCategory TestCategory("execution-test options");135 136TEST(CreateToolExecutorTest, FailedCreateExecutorUndefinedFlag) {137  std::vector<const char *> argv = {"prog", "--fake_flag_no_no_no", "f"};138  int argc = argv.size();139  auto Executor = internal::createExecutorFromCommandLineArgsImpl(140      argc, &argv[0], TestCategory);141  ASSERT_FALSE((bool)Executor);142  llvm::consumeError(Executor.takeError());143}144 145TEST(CreateToolExecutorTest, RegisterFlagsBeforeReset) {146  llvm::cl::opt<std::string> BeforeReset(147      "before_reset", llvm::cl::desc("Defined before reset."),148      llvm::cl::init(""));149 150  llvm::cl::ResetAllOptionOccurrences();151 152  std::vector<const char *> argv = {"prog", "--before_reset=set", "f"};153  int argc = argv.size();154  auto Executor = internal::createExecutorFromCommandLineArgsImpl(155      argc, &argv[0], TestCategory);156  ASSERT_TRUE((bool)Executor);157  EXPECT_EQ(BeforeReset, "set");158  BeforeReset.removeArgument();159}160 161TEST(CreateToolExecutorTest, CreateStandaloneToolExecutor) {162  std::vector<const char *> argv = {"prog", "standalone.cpp"};163  int argc = argv.size();164  auto Executor = internal::createExecutorFromCommandLineArgsImpl(165      argc, &argv[0], TestCategory);166  ASSERT_TRUE((bool)Executor);167  EXPECT_EQ(Executor->get()->getExecutorName(),168            StandaloneToolExecutor::ExecutorName);169}170 171TEST(CreateToolExecutorTest, CreateTestToolExecutor) {172  std::vector<const char *> argv = {"prog", "test.cpp",173                                    "--executor=test-executor"};174  int argc = argv.size();175  auto Executor = internal::createExecutorFromCommandLineArgsImpl(176      argc, &argv[0], TestCategory);177  ASSERT_TRUE((bool)Executor);178  EXPECT_EQ(Executor->get()->getExecutorName(), TestToolExecutor::ExecutorName);179}180 181TEST(StandaloneToolTest, SynctaxOnlyActionOnSimpleCode) {182  FixedCompilationDatabase Compilations(".", std::vector<std::string>());183  StandaloneToolExecutor Executor(Compilations,184                                  std::vector<std::string>(1, "a.cc"));185  Executor.mapVirtualFile("a.cc", "int x = 0;");186 187  auto Err = Executor.execute(newFrontendActionFactory<SyntaxOnlyAction>(),188                              getClangSyntaxOnlyAdjuster());189  ASSERT_TRUE(!Err);190}191 192TEST(StandaloneToolTest, SimpleAction) {193  FixedCompilationDatabase Compilations(".", std::vector<std::string>());194  StandaloneToolExecutor Executor(Compilations,195                                  std::vector<std::string>(1, "a.cc"));196  Executor.mapVirtualFile("a.cc", "int x = 0;");197 198  auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>(199      new ReportResultActionFactory(Executor.getExecutionContext())));200  ASSERT_TRUE(!Err);201  auto KVs = Executor.getToolResults()->AllKVResults();202  ASSERT_EQ(KVs.size(), 0u);203}204 205TEST(StandaloneToolTest, SimpleActionWithResult) {206  FixedCompilationDatabase Compilations(".", std::vector<std::string>());207  StandaloneToolExecutor Executor(Compilations,208                                  std::vector<std::string>(1, "a.cc"));209  Executor.mapVirtualFile("a.cc", "int x = 0; void f() {}");210 211  auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>(212      new ReportResultActionFactory(Executor.getExecutionContext())));213  ASSERT_TRUE(!Err);214  auto KVs = Executor.getToolResults()->AllKVResults();215  ASSERT_EQ(KVs.size(), 1u);216  EXPECT_EQ("f", KVs[0].first);217  // Currently the standalone executor returns empty corpus, revision, and218  // compilation unit.219  EXPECT_EQ("::/1", KVs[0].second);220 221  Executor.getToolResults()->forEachResult(222      [](StringRef, StringRef Value) { EXPECT_EQ("::/1", Value); });223}224 225class FixedCompilationDatabaseWithFiles : public CompilationDatabase {226public:227  FixedCompilationDatabaseWithFiles(Twine Directory,228                                    ArrayRef<std::string> Files,229                                    ArrayRef<std::string> CommandLine)230      : FixedCompilations(Directory, CommandLine), Files(Files) {}231 232  std::vector<CompileCommand>233  getCompileCommands(StringRef FilePath) const override {234    return FixedCompilations.getCompileCommands(FilePath);235  }236 237  std::vector<std::string> getAllFiles() const override { return Files; }238 239private:240  FixedCompilationDatabase FixedCompilations;241  std::vector<std::string> Files;242};243 244MATCHER_P(Named, Name, "") { return arg.first == Name; }245 246TEST(AllTUsToolTest, AFewFiles) {247  FixedCompilationDatabaseWithFiles Compilations(248      ".", {"a.cc", "b.cc", "c.cc", "ignore.cc"}, std::vector<std::string>());249  AllTUsToolExecutor Executor(Compilations, /*ThreadCount=*/0);250  Filter.setValue("[a-c].cc");251  Executor.mapVirtualFile("a.cc", "void x() {}");252  Executor.mapVirtualFile("b.cc", "void y() {}");253  Executor.mapVirtualFile("c.cc", "void z() {}");254  Executor.mapVirtualFile("ignore.cc", "void d() {}");255 256  auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>(257      new ReportResultActionFactory(Executor.getExecutionContext())));258  ASSERT_TRUE(!Err);259  EXPECT_THAT(260      Executor.getToolResults()->AllKVResults(),261      ::testing::UnorderedElementsAre(Named("x"), Named("y"), Named("z")));262  Filter.setValue(".*"); // reset to default value.263}264 265TEST(AllTUsToolTest, ManyFiles) {266  unsigned NumFiles = 100;267  std::vector<std::string> Files;268  std::map<std::string, std::string> FileToContent;269  std::vector<std::string> ExpectedSymbols;270  for (unsigned i = 1; i <= NumFiles; ++i) {271    std::string File = "f" + std::to_string(i) + ".cc";272    std::string Symbol = "looong_function_name_" + std::to_string(i);273    Files.push_back(File);274    FileToContent[File] = "void " + Symbol + "() {}";275    ExpectedSymbols.push_back(Symbol);276  }277  FixedCompilationDatabaseWithFiles Compilations(".", Files,278                                                 std::vector<std::string>());279  AllTUsToolExecutor Executor(Compilations, /*ThreadCount=*/0);280  for (const auto &FileAndContent : FileToContent) {281    Executor.mapVirtualFile(FileAndContent.first, FileAndContent.second);282  }283 284  auto Err = Executor.execute(std::unique_ptr<FrontendActionFactory>(285      new ReportResultActionFactory(Executor.getExecutionContext())));286  ASSERT_TRUE(!Err);287  std::vector<std::string> Results;288  Executor.getToolResults()->forEachResult(289      [&](StringRef Name, StringRef) { Results.push_back(std::string(Name)); });290  EXPECT_THAT(ExpectedSymbols, ::testing::UnorderedElementsAreArray(Results));291}292 293} // end namespace tooling294} // end namespace clang295