Coverage Report

Created: 2020-02-15 09:57

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Tooling/AllTUsExecution.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- lib/Tooling/AllTUsExecution.cpp - Execute actions on all TUs. ------===//
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-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "clang/Tooling/AllTUsExecution.h"
10
#include "clang/Tooling/ToolExecutorPluginRegistry.h"
11
#include "llvm/Support/Threading.h"
12
#include "llvm/Support/ThreadPool.h"
13
#include "llvm/Support/VirtualFileSystem.h"
14
15
namespace clang {
16
namespace tooling {
17
18
const char *AllTUsToolExecutor::ExecutorName = "AllTUsToolExecutor";
19
20
namespace {
21
0
llvm::Error make_string_error(const llvm::Twine &Message) {
22
0
  return llvm::make_error<llvm::StringError>(Message,
23
0
                                             llvm::inconvertibleErrorCode());
24
0
}
25
26
103
ArgumentsAdjuster getDefaultArgumentsAdjusters() {
27
103
  return combineAdjusters(
28
103
      getClangStripOutputAdjuster(),
29
103
      combineAdjusters(getClangSyntaxOnlyAdjuster(),
30
103
                       getClangStripDependencyFileAdjuster()));
31
103
}
32
33
class ThreadSafeToolResults : public ToolResults {
34
public:
35
99
  void addResult(StringRef Key, StringRef Value) override {
36
99
    std::unique_lock<std::mutex> LockGuard(Mutex);
37
99
    Results.addResult(Key, Value);
38
99
  }
39
40
  std::vector<std::pair<llvm::StringRef, llvm::StringRef>>
41
1
  AllKVResults() override {
42
1
    return Results.AllKVResults();
43
1
  }
44
45
  void forEachResult(llvm::function_ref<void(StringRef Key, StringRef Value)>
46
1
                         Callback) override {
47
1
    Results.forEachResult(Callback);
48
1
  }
49
50
private:
51
  InMemoryToolResults Results;
52
  std::mutex Mutex;
53
};
54
55
} // namespace
56
57
llvm::cl::opt<std::string>
58
    Filter("filter",
59
           llvm::cl::desc("Only process files that match this filter. "
60
                          "This flag only applies to all-TUs."),
61
           llvm::cl::init(".*"));
62
63
AllTUsToolExecutor::AllTUsToolExecutor(
64
    const CompilationDatabase &Compilations, unsigned ThreadCount,
65
    std::shared_ptr<PCHContainerOperations> PCHContainerOps)
66
    : Compilations(Compilations), Results(new ThreadSafeToolResults),
67
2
      Context(Results.get()), ThreadCount(ThreadCount) {}
68
69
AllTUsToolExecutor::AllTUsToolExecutor(
70
    CommonOptionsParser Options, unsigned ThreadCount,
71
    std::shared_ptr<PCHContainerOperations> PCHContainerOps)
72
    : OptionsParser(std::move(Options)),
73
      Compilations(OptionsParser->getCompilations()),
74
      Results(new ThreadSafeToolResults), Context(Results.get()),
75
0
      ThreadCount(ThreadCount) {}
76
77
llvm::Error AllTUsToolExecutor::execute(
78
    llvm::ArrayRef<
79
        std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>>
80
2
        Actions) {
81
2
  if (Actions.empty())
82
0
    return make_string_error("No action to execute.");
83
2
84
2
  if (Actions.size() != 1)
85
0
    return make_string_error(
86
0
        "Only support executing exactly 1 action at this point.");
87
2
88
2
  std::string ErrorMsg;
89
2
  std::mutex TUMutex;
90
2
  auto AppendError = [&](llvm::Twine Err) {
91
0
    std::unique_lock<std::mutex> LockGuard(TUMutex);
92
0
    ErrorMsg += Err.str();
93
0
  };
94
2
95
102
  auto Log = [&](llvm::Twine Msg) {
96
102
    std::unique_lock<std::mutex> LockGuard(TUMutex);
97
102
    llvm::errs() << Msg.str() << "\n";
98
102
  };
99
2
100
2
  std::vector<std::string> Files;
101
2
  llvm::Regex RegexFilter(Filter);
102
104
  for (const auto& File : Compilations.getAllFiles()) {
103
104
    if (RegexFilter.match(File))
104
103
      Files.push_back(File);
105
104
  }
106
2
  // Add a counter to track the progress.
107
2
  const std::string TotalNumStr = std::to_string(Files.size());
108
2
  unsigned Counter = 0;
109
103
  auto Count = [&]() {
110
103
    std::unique_lock<std::mutex> LockGuard(TUMutex);
111
103
    return ++Counter;
112
103
  };
113
2
114
2
  auto &Action = Actions.front();
115
2
116
2
  {
117
2
    llvm::ThreadPool Pool(llvm::hardware_concurrency(ThreadCount));
118
103
    for (std::string File : Files) {
119
103
      Pool.async(
120
103
          [&](std::string Path) {
121
103
            Log("[" + std::to_string(Count()) + "/" + TotalNumStr +
122
103
                "] Processing file " + Path);
123
103
            // Each thread gets an indepent copy of a VFS to allow different
124
103
            // concurrent working directories.
125
103
            IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
126
103
                llvm::vfs::createPhysicalFileSystem().release();
127
103
            ClangTool Tool(Compilations, {Path},
128
103
                           std::make_shared<PCHContainerOperations>(), FS);
129
103
            Tool.appendArgumentsAdjuster(Action.second);
130
103
            Tool.appendArgumentsAdjuster(getDefaultArgumentsAdjusters());
131
103
            for (const auto &FileAndContent : OverlayFiles)
132
9.83k
              Tool.mapVirtualFile(FileAndContent.first(),
133
9.83k
                                  FileAndContent.second);
134
103
            if (Tool.run(Action.first.get()))
135
0
              AppendError(llvm::Twine("Failed to run action on ") + Path +
136
0
                          "\n");
137
103
          },
138
103
          File);
139
103
    }
140
2
    // Make sure all tasks have finished before resetting the working directory.
141
2
    Pool.wait();
142
2
  }
143
2
144
2
  if (!ErrorMsg.empty())
145
0
    return make_string_error(ErrorMsg);
146
2
147
2
  return llvm::Error::success();
148
2
}
149
150
llvm::cl::opt<unsigned> ExecutorConcurrency(
151
    "execute-concurrency",
152
    llvm::cl::desc("The number of threads used to process all files in "
153
                   "parallel. Set to 0 for hardware concurrency. "
154
                   "This flag only applies to all-TUs."),
155
    llvm::cl::init(0));
156
157
class AllTUsToolExecutorPlugin : public ToolExecutorPlugin {
158
public:
159
  llvm::Expected<std::unique_ptr<ToolExecutor>>
160
0
  create(CommonOptionsParser &OptionsParser) override {
161
0
    if (OptionsParser.getSourcePathList().empty())
162
0
      return make_string_error(
163
0
          "[AllTUsToolExecutorPlugin] Please provide a directory/file path in "
164
0
          "the compilation database.");
165
0
    return std::make_unique<AllTUsToolExecutor>(std::move(OptionsParser),
166
0
                                                 ExecutorConcurrency);
167
0
  }
168
};
169
170
static ToolExecutorPluginRegistry::Add<AllTUsToolExecutorPlugin>
171
    X("all-TUs", "Runs FrontendActions on all TUs in the compilation database. "
172
                 "Tool results are stored in memory.");
173
174
// This anchor is used to force the linker to link in the generated object file
175
// and thus register the plugin.
176
volatile int AllTUsToolExecutorAnchorSource = 0;
177
178
} // end namespace tooling
179
} // end namespace clang