annotate clang-tools-extra/modularize/CoverageChecker.cpp @ 171:66f3bfe93da9

git version 2c4ca6832fa6b306ee6a7010bfb80a3f2596f824
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 11:07:02 +0900
parents 1d019706d866
children 0572611fdcc8
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===--- extra/module-map-checker/CoverageChecker.cpp -------------------===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8 //
anatofuz
parents:
diff changeset
9 // This file implements a class that validates a module map by checking that
anatofuz
parents:
diff changeset
10 // all headers in the corresponding directories are accounted for.
anatofuz
parents:
diff changeset
11 //
anatofuz
parents:
diff changeset
12 // This class uses a previously loaded module map object.
anatofuz
parents:
diff changeset
13 // Starting at the module map file directory, or just the include
anatofuz
parents:
diff changeset
14 // paths, if specified, it will collect the names of all the files it
anatofuz
parents:
diff changeset
15 // considers headers (no extension, .h, or .inc--if you need more, modify the
anatofuz
parents:
diff changeset
16 // ModularizeUtilities::isHeader function).
anatofuz
parents:
diff changeset
17 // It then compares the headers against those referenced
anatofuz
parents:
diff changeset
18 // in the module map, either explicitly named, or implicitly named via an
anatofuz
parents:
diff changeset
19 // umbrella directory or umbrella file, as parsed by the ModuleMap object.
anatofuz
parents:
diff changeset
20 // If headers are found which are not referenced or covered by an umbrella
anatofuz
parents:
diff changeset
21 // directory or file, warning messages will be produced, and the doChecks
anatofuz
parents:
diff changeset
22 // function will return an error code of 1. Other errors result in an error
anatofuz
parents:
diff changeset
23 // code of 2. If no problems are found, an error code of 0 is returned.
anatofuz
parents:
diff changeset
24 //
anatofuz
parents:
diff changeset
25 // Note that in the case of umbrella headers, this tool invokes the compiler
anatofuz
parents:
diff changeset
26 // to preprocess the file, and uses a callback to collect the header files
anatofuz
parents:
diff changeset
27 // included by the umbrella header or any of its nested includes. If any
anatofuz
parents:
diff changeset
28 // front end options are needed for these compiler invocations, these are
anatofuz
parents:
diff changeset
29 // to be passed in via the CommandLine parameter.
anatofuz
parents:
diff changeset
30 //
anatofuz
parents:
diff changeset
31 // Warning message have the form:
anatofuz
parents:
diff changeset
32 //
anatofuz
parents:
diff changeset
33 // warning: module.modulemap does not account for file: Level3A.h
anatofuz
parents:
diff changeset
34 //
anatofuz
parents:
diff changeset
35 // Note that for the case of the module map referencing a file that does
anatofuz
parents:
diff changeset
36 // not exist, the module map parser in Clang will (at the time of this
anatofuz
parents:
diff changeset
37 // writing) display an error message.
anatofuz
parents:
diff changeset
38 //
anatofuz
parents:
diff changeset
39 // Potential problems with this program:
anatofuz
parents:
diff changeset
40 //
anatofuz
parents:
diff changeset
41 // 1. Might need a better header matching mechanism, or extensions to the
anatofuz
parents:
diff changeset
42 // canonical file format used.
anatofuz
parents:
diff changeset
43 //
anatofuz
parents:
diff changeset
44 // 2. It might need to support additional header file extensions.
anatofuz
parents:
diff changeset
45 //
anatofuz
parents:
diff changeset
46 // Future directions:
anatofuz
parents:
diff changeset
47 //
anatofuz
parents:
diff changeset
48 // 1. Add an option to fix the problems found, writing a new module map.
anatofuz
parents:
diff changeset
49 // Include an extra option to add unaccounted-for headers as excluded.
anatofuz
parents:
diff changeset
50 //
anatofuz
parents:
diff changeset
51 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
52
anatofuz
parents:
diff changeset
53 #include "ModularizeUtilities.h"
anatofuz
parents:
diff changeset
54 #include "clang/AST/ASTConsumer.h"
anatofuz
parents:
diff changeset
55 #include "CoverageChecker.h"
anatofuz
parents:
diff changeset
56 #include "clang/AST/ASTContext.h"
anatofuz
parents:
diff changeset
57 #include "clang/AST/RecursiveASTVisitor.h"
anatofuz
parents:
diff changeset
58 #include "clang/Basic/SourceManager.h"
anatofuz
parents:
diff changeset
59 #include "clang/Driver/Options.h"
anatofuz
parents:
diff changeset
60 #include "clang/Frontend/CompilerInstance.h"
anatofuz
parents:
diff changeset
61 #include "clang/Frontend/FrontendAction.h"
anatofuz
parents:
diff changeset
62 #include "clang/Frontend/FrontendActions.h"
anatofuz
parents:
diff changeset
63 #include "clang/Lex/PPCallbacks.h"
anatofuz
parents:
diff changeset
64 #include "clang/Lex/Preprocessor.h"
anatofuz
parents:
diff changeset
65 #include "clang/Tooling/CompilationDatabase.h"
anatofuz
parents:
diff changeset
66 #include "clang/Tooling/Tooling.h"
anatofuz
parents:
diff changeset
67 #include "llvm/Option/Option.h"
anatofuz
parents:
diff changeset
68 #include "llvm/Support/CommandLine.h"
anatofuz
parents:
diff changeset
69 #include "llvm/Support/FileSystem.h"
anatofuz
parents:
diff changeset
70 #include "llvm/Support/Path.h"
anatofuz
parents:
diff changeset
71 #include "llvm/Support/raw_ostream.h"
anatofuz
parents:
diff changeset
72
anatofuz
parents:
diff changeset
73 using namespace Modularize;
anatofuz
parents:
diff changeset
74 using namespace clang;
anatofuz
parents:
diff changeset
75 using namespace clang::driver;
anatofuz
parents:
diff changeset
76 using namespace clang::driver::options;
anatofuz
parents:
diff changeset
77 using namespace clang::tooling;
anatofuz
parents:
diff changeset
78 namespace cl = llvm::cl;
anatofuz
parents:
diff changeset
79 namespace sys = llvm::sys;
anatofuz
parents:
diff changeset
80
anatofuz
parents:
diff changeset
81 // Preprocessor callbacks.
anatofuz
parents:
diff changeset
82 // We basically just collect include files.
anatofuz
parents:
diff changeset
83 class CoverageCheckerCallbacks : public PPCallbacks {
anatofuz
parents:
diff changeset
84 public:
anatofuz
parents:
diff changeset
85 CoverageCheckerCallbacks(CoverageChecker &Checker) : Checker(Checker) {}
anatofuz
parents:
diff changeset
86 ~CoverageCheckerCallbacks() override {}
anatofuz
parents:
diff changeset
87
anatofuz
parents:
diff changeset
88 // Include directive callback.
anatofuz
parents:
diff changeset
89 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
anatofuz
parents:
diff changeset
90 StringRef FileName, bool IsAngled,
anatofuz
parents:
diff changeset
91 CharSourceRange FilenameRange, const FileEntry *File,
anatofuz
parents:
diff changeset
92 StringRef SearchPath, StringRef RelativePath,
anatofuz
parents:
diff changeset
93 const Module *Imported,
anatofuz
parents:
diff changeset
94 SrcMgr::CharacteristicKind FileType) override {
anatofuz
parents:
diff changeset
95 Checker.collectUmbrellaHeaderHeader(File->getName());
anatofuz
parents:
diff changeset
96 }
anatofuz
parents:
diff changeset
97
anatofuz
parents:
diff changeset
98 private:
anatofuz
parents:
diff changeset
99 CoverageChecker &Checker;
anatofuz
parents:
diff changeset
100 };
anatofuz
parents:
diff changeset
101
anatofuz
parents:
diff changeset
102 // Frontend action stuff:
anatofuz
parents:
diff changeset
103
anatofuz
parents:
diff changeset
104 // Consumer is responsible for setting up the callbacks.
anatofuz
parents:
diff changeset
105 class CoverageCheckerConsumer : public ASTConsumer {
anatofuz
parents:
diff changeset
106 public:
anatofuz
parents:
diff changeset
107 CoverageCheckerConsumer(CoverageChecker &Checker, Preprocessor &PP) {
anatofuz
parents:
diff changeset
108 // PP takes ownership.
anatofuz
parents:
diff changeset
109 PP.addPPCallbacks(std::make_unique<CoverageCheckerCallbacks>(Checker));
anatofuz
parents:
diff changeset
110 }
anatofuz
parents:
diff changeset
111 };
anatofuz
parents:
diff changeset
112
anatofuz
parents:
diff changeset
113 class CoverageCheckerAction : public SyntaxOnlyAction {
anatofuz
parents:
diff changeset
114 public:
anatofuz
parents:
diff changeset
115 CoverageCheckerAction(CoverageChecker &Checker) : Checker(Checker) {}
anatofuz
parents:
diff changeset
116
anatofuz
parents:
diff changeset
117 protected:
anatofuz
parents:
diff changeset
118 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
anatofuz
parents:
diff changeset
119 StringRef InFile) override {
anatofuz
parents:
diff changeset
120 return std::make_unique<CoverageCheckerConsumer>(Checker,
anatofuz
parents:
diff changeset
121 CI.getPreprocessor());
anatofuz
parents:
diff changeset
122 }
anatofuz
parents:
diff changeset
123
anatofuz
parents:
diff changeset
124 private:
anatofuz
parents:
diff changeset
125 CoverageChecker &Checker;
anatofuz
parents:
diff changeset
126 };
anatofuz
parents:
diff changeset
127
anatofuz
parents:
diff changeset
128 class CoverageCheckerFrontendActionFactory : public FrontendActionFactory {
anatofuz
parents:
diff changeset
129 public:
anatofuz
parents:
diff changeset
130 CoverageCheckerFrontendActionFactory(CoverageChecker &Checker)
anatofuz
parents:
diff changeset
131 : Checker(Checker) {}
anatofuz
parents:
diff changeset
132
anatofuz
parents:
diff changeset
133 std::unique_ptr<FrontendAction> create() override {
anatofuz
parents:
diff changeset
134 return std::make_unique<CoverageCheckerAction>(Checker);
anatofuz
parents:
diff changeset
135 }
anatofuz
parents:
diff changeset
136
anatofuz
parents:
diff changeset
137 private:
anatofuz
parents:
diff changeset
138 CoverageChecker &Checker;
anatofuz
parents:
diff changeset
139 };
anatofuz
parents:
diff changeset
140
anatofuz
parents:
diff changeset
141 // CoverageChecker class implementation.
anatofuz
parents:
diff changeset
142
anatofuz
parents:
diff changeset
143 // Constructor.
anatofuz
parents:
diff changeset
144 CoverageChecker::CoverageChecker(StringRef ModuleMapPath,
anatofuz
parents:
diff changeset
145 std::vector<std::string> &IncludePaths,
anatofuz
parents:
diff changeset
146 ArrayRef<std::string> CommandLine,
anatofuz
parents:
diff changeset
147 clang::ModuleMap *ModuleMap)
anatofuz
parents:
diff changeset
148 : ModuleMapPath(ModuleMapPath), IncludePaths(IncludePaths),
anatofuz
parents:
diff changeset
149 CommandLine(CommandLine),
anatofuz
parents:
diff changeset
150 ModMap(ModuleMap) {}
anatofuz
parents:
diff changeset
151
anatofuz
parents:
diff changeset
152 // Create instance of CoverageChecker, to simplify setting up
anatofuz
parents:
diff changeset
153 // subordinate objects.
anatofuz
parents:
diff changeset
154 std::unique_ptr<CoverageChecker> CoverageChecker::createCoverageChecker(
anatofuz
parents:
diff changeset
155 StringRef ModuleMapPath, std::vector<std::string> &IncludePaths,
anatofuz
parents:
diff changeset
156 ArrayRef<std::string> CommandLine, clang::ModuleMap *ModuleMap) {
anatofuz
parents:
diff changeset
157
anatofuz
parents:
diff changeset
158 return std::make_unique<CoverageChecker>(ModuleMapPath, IncludePaths,
anatofuz
parents:
diff changeset
159 CommandLine, ModuleMap);
anatofuz
parents:
diff changeset
160 }
anatofuz
parents:
diff changeset
161
anatofuz
parents:
diff changeset
162 // Do checks.
anatofuz
parents:
diff changeset
163 // Starting from the directory of the module.modulemap file,
anatofuz
parents:
diff changeset
164 // Find all header files, optionally looking only at files
anatofuz
parents:
diff changeset
165 // covered by the include path options, and compare against
anatofuz
parents:
diff changeset
166 // the headers referenced by the module.modulemap file.
anatofuz
parents:
diff changeset
167 // Display warnings for unaccounted-for header files.
anatofuz
parents:
diff changeset
168 // Returns error_code of 0 if there were no errors or warnings, 1 if there
anatofuz
parents:
diff changeset
169 // were warnings, 2 if any other problem, such as if a bad
anatofuz
parents:
diff changeset
170 // module map path argument was specified.
anatofuz
parents:
diff changeset
171 std::error_code CoverageChecker::doChecks() {
anatofuz
parents:
diff changeset
172 std::error_code returnValue;
anatofuz
parents:
diff changeset
173
anatofuz
parents:
diff changeset
174 // Collect the headers referenced in the modules.
anatofuz
parents:
diff changeset
175 collectModuleHeaders();
anatofuz
parents:
diff changeset
176
anatofuz
parents:
diff changeset
177 // Collect the file system headers.
anatofuz
parents:
diff changeset
178 if (!collectFileSystemHeaders())
anatofuz
parents:
diff changeset
179 return std::error_code(2, std::generic_category());
anatofuz
parents:
diff changeset
180
anatofuz
parents:
diff changeset
181 // Do the checks. These save the problematic file names.
anatofuz
parents:
diff changeset
182 findUnaccountedForHeaders();
anatofuz
parents:
diff changeset
183
anatofuz
parents:
diff changeset
184 // Check for warnings.
anatofuz
parents:
diff changeset
185 if (!UnaccountedForHeaders.empty())
anatofuz
parents:
diff changeset
186 returnValue = std::error_code(1, std::generic_category());
anatofuz
parents:
diff changeset
187
anatofuz
parents:
diff changeset
188 return returnValue;
anatofuz
parents:
diff changeset
189 }
anatofuz
parents:
diff changeset
190
anatofuz
parents:
diff changeset
191 // The following functions are called by doChecks.
anatofuz
parents:
diff changeset
192
anatofuz
parents:
diff changeset
193 // Collect module headers.
anatofuz
parents:
diff changeset
194 // Walks the modules and collects referenced headers into
anatofuz
parents:
diff changeset
195 // ModuleMapHeadersSet.
anatofuz
parents:
diff changeset
196 void CoverageChecker::collectModuleHeaders() {
anatofuz
parents:
diff changeset
197 for (ModuleMap::module_iterator I = ModMap->module_begin(),
anatofuz
parents:
diff changeset
198 E = ModMap->module_end();
anatofuz
parents:
diff changeset
199 I != E; ++I) {
anatofuz
parents:
diff changeset
200 collectModuleHeaders(*I->second);
anatofuz
parents:
diff changeset
201 }
anatofuz
parents:
diff changeset
202 }
anatofuz
parents:
diff changeset
203
anatofuz
parents:
diff changeset
204 // Collect referenced headers from one module.
anatofuz
parents:
diff changeset
205 // Collects the headers referenced in the given module into
anatofuz
parents:
diff changeset
206 // ModuleMapHeadersSet.
anatofuz
parents:
diff changeset
207 // FIXME: Doesn't collect files from umbrella header.
anatofuz
parents:
diff changeset
208 bool CoverageChecker::collectModuleHeaders(const Module &Mod) {
anatofuz
parents:
diff changeset
209
anatofuz
parents:
diff changeset
210 if (const FileEntry *UmbrellaHeader = Mod.getUmbrellaHeader().Entry) {
anatofuz
parents:
diff changeset
211 // Collect umbrella header.
anatofuz
parents:
diff changeset
212 ModuleMapHeadersSet.insert(ModularizeUtilities::getCanonicalPath(
anatofuz
parents:
diff changeset
213 UmbrellaHeader->getName()));
anatofuz
parents:
diff changeset
214 // Preprocess umbrella header and collect the headers it references.
anatofuz
parents:
diff changeset
215 if (!collectUmbrellaHeaderHeaders(UmbrellaHeader->getName()))
anatofuz
parents:
diff changeset
216 return false;
anatofuz
parents:
diff changeset
217 }
anatofuz
parents:
diff changeset
218 else if (const DirectoryEntry *UmbrellaDir = Mod.getUmbrellaDir().Entry) {
anatofuz
parents:
diff changeset
219 // Collect headers in umbrella directory.
anatofuz
parents:
diff changeset
220 if (!collectUmbrellaHeaders(UmbrellaDir->getName()))
anatofuz
parents:
diff changeset
221 return false;
anatofuz
parents:
diff changeset
222 }
anatofuz
parents:
diff changeset
223
anatofuz
parents:
diff changeset
224 for (auto &HeaderKind : Mod.Headers)
anatofuz
parents:
diff changeset
225 for (auto &Header : HeaderKind)
anatofuz
parents:
diff changeset
226 ModuleMapHeadersSet.insert(ModularizeUtilities::getCanonicalPath(
anatofuz
parents:
diff changeset
227 Header.Entry->getName()));
anatofuz
parents:
diff changeset
228
anatofuz
parents:
diff changeset
229 for (auto MI = Mod.submodule_begin(), MIEnd = Mod.submodule_end();
anatofuz
parents:
diff changeset
230 MI != MIEnd; ++MI)
anatofuz
parents:
diff changeset
231 collectModuleHeaders(**MI);
anatofuz
parents:
diff changeset
232
anatofuz
parents:
diff changeset
233 return true;
anatofuz
parents:
diff changeset
234 }
anatofuz
parents:
diff changeset
235
anatofuz
parents:
diff changeset
236 // Collect headers from an umbrella directory.
anatofuz
parents:
diff changeset
237 bool CoverageChecker::collectUmbrellaHeaders(StringRef UmbrellaDirName) {
anatofuz
parents:
diff changeset
238 // Initialize directory name.
anatofuz
parents:
diff changeset
239 SmallString<256> Directory(ModuleMapDirectory);
anatofuz
parents:
diff changeset
240 if (UmbrellaDirName.size())
anatofuz
parents:
diff changeset
241 sys::path::append(Directory, UmbrellaDirName);
anatofuz
parents:
diff changeset
242 if (Directory.size() == 0)
anatofuz
parents:
diff changeset
243 Directory = ".";
anatofuz
parents:
diff changeset
244 // Walk the directory.
anatofuz
parents:
diff changeset
245 std::error_code EC;
anatofuz
parents:
diff changeset
246 for (sys::fs::directory_iterator I(Directory.str(), EC), E; I != E;
anatofuz
parents:
diff changeset
247 I.increment(EC)) {
anatofuz
parents:
diff changeset
248 if (EC)
anatofuz
parents:
diff changeset
249 return false;
anatofuz
parents:
diff changeset
250 std::string File(I->path());
anatofuz
parents:
diff changeset
251 llvm::ErrorOr<sys::fs::basic_file_status> Status = I->status();
anatofuz
parents:
diff changeset
252 if (!Status)
anatofuz
parents:
diff changeset
253 return false;
anatofuz
parents:
diff changeset
254 sys::fs::file_type Type = Status->type();
anatofuz
parents:
diff changeset
255 // If the file is a directory, ignore the name and recurse.
anatofuz
parents:
diff changeset
256 if (Type == sys::fs::file_type::directory_file) {
anatofuz
parents:
diff changeset
257 if (!collectUmbrellaHeaders(File))
anatofuz
parents:
diff changeset
258 return false;
anatofuz
parents:
diff changeset
259 continue;
anatofuz
parents:
diff changeset
260 }
anatofuz
parents:
diff changeset
261 // If the file does not have a common header extension, ignore it.
anatofuz
parents:
diff changeset
262 if (!ModularizeUtilities::isHeader(File))
anatofuz
parents:
diff changeset
263 continue;
anatofuz
parents:
diff changeset
264 // Save header name.
anatofuz
parents:
diff changeset
265 ModuleMapHeadersSet.insert(ModularizeUtilities::getCanonicalPath(File));
anatofuz
parents:
diff changeset
266 }
anatofuz
parents:
diff changeset
267 return true;
anatofuz
parents:
diff changeset
268 }
anatofuz
parents:
diff changeset
269
anatofuz
parents:
diff changeset
270 // Collect headers rferenced from an umbrella file.
anatofuz
parents:
diff changeset
271 bool
anatofuz
parents:
diff changeset
272 CoverageChecker::collectUmbrellaHeaderHeaders(StringRef UmbrellaHeaderName) {
anatofuz
parents:
diff changeset
273
anatofuz
parents:
diff changeset
274 SmallString<256> PathBuf(ModuleMapDirectory);
anatofuz
parents:
diff changeset
275
anatofuz
parents:
diff changeset
276 // If directory is empty, it's the current directory.
anatofuz
parents:
diff changeset
277 if (ModuleMapDirectory.length() == 0)
anatofuz
parents:
diff changeset
278 sys::fs::current_path(PathBuf);
anatofuz
parents:
diff changeset
279
anatofuz
parents:
diff changeset
280 // Create the compilation database.
anatofuz
parents:
diff changeset
281 std::unique_ptr<CompilationDatabase> Compilations;
anatofuz
parents:
diff changeset
282 Compilations.reset(new FixedCompilationDatabase(Twine(PathBuf), CommandLine));
anatofuz
parents:
diff changeset
283
anatofuz
parents:
diff changeset
284 std::vector<std::string> HeaderPath;
anatofuz
parents:
diff changeset
285 HeaderPath.push_back(std::string(UmbrellaHeaderName));
anatofuz
parents:
diff changeset
286
anatofuz
parents:
diff changeset
287 // Create the tool and run the compilation.
anatofuz
parents:
diff changeset
288 ClangTool Tool(*Compilations, HeaderPath);
anatofuz
parents:
diff changeset
289 int HadErrors = Tool.run(new CoverageCheckerFrontendActionFactory(*this));
anatofuz
parents:
diff changeset
290
anatofuz
parents:
diff changeset
291 // If we had errors, exit early.
anatofuz
parents:
diff changeset
292 return !HadErrors;
anatofuz
parents:
diff changeset
293 }
anatofuz
parents:
diff changeset
294
anatofuz
parents:
diff changeset
295 // Called from CoverageCheckerCallbacks to track a header included
anatofuz
parents:
diff changeset
296 // from an umbrella header.
anatofuz
parents:
diff changeset
297 void CoverageChecker::collectUmbrellaHeaderHeader(StringRef HeaderName) {
anatofuz
parents:
diff changeset
298
anatofuz
parents:
diff changeset
299 SmallString<256> PathBuf(ModuleMapDirectory);
anatofuz
parents:
diff changeset
300 // If directory is empty, it's the current directory.
anatofuz
parents:
diff changeset
301 if (ModuleMapDirectory.length() == 0)
anatofuz
parents:
diff changeset
302 sys::fs::current_path(PathBuf);
anatofuz
parents:
diff changeset
303 // HeaderName will have an absolute path, so if it's the module map
anatofuz
parents:
diff changeset
304 // directory, we remove it, also skipping trailing separator.
anatofuz
parents:
diff changeset
305 if (HeaderName.startswith(PathBuf))
anatofuz
parents:
diff changeset
306 HeaderName = HeaderName.substr(PathBuf.size() + 1);
anatofuz
parents:
diff changeset
307 // Save header name.
anatofuz
parents:
diff changeset
308 ModuleMapHeadersSet.insert(ModularizeUtilities::getCanonicalPath(HeaderName));
anatofuz
parents:
diff changeset
309 }
anatofuz
parents:
diff changeset
310
anatofuz
parents:
diff changeset
311 // Collect file system header files.
anatofuz
parents:
diff changeset
312 // This function scans the file system for header files,
anatofuz
parents:
diff changeset
313 // starting at the directory of the module.modulemap file,
anatofuz
parents:
diff changeset
314 // optionally filtering out all but the files covered by
anatofuz
parents:
diff changeset
315 // the include path options.
anatofuz
parents:
diff changeset
316 // Returns true if no errors.
anatofuz
parents:
diff changeset
317 bool CoverageChecker::collectFileSystemHeaders() {
anatofuz
parents:
diff changeset
318
anatofuz
parents:
diff changeset
319 // Get directory containing the module.modulemap file.
anatofuz
parents:
diff changeset
320 // Might be relative to current directory, absolute, or empty.
anatofuz
parents:
diff changeset
321 ModuleMapDirectory = ModularizeUtilities::getDirectoryFromPath(ModuleMapPath);
anatofuz
parents:
diff changeset
322
anatofuz
parents:
diff changeset
323 // If no include paths specified, we do the whole tree starting
anatofuz
parents:
diff changeset
324 // at the module.modulemap directory.
anatofuz
parents:
diff changeset
325 if (IncludePaths.size() == 0) {
anatofuz
parents:
diff changeset
326 if (!collectFileSystemHeaders(StringRef("")))
anatofuz
parents:
diff changeset
327 return false;
anatofuz
parents:
diff changeset
328 }
anatofuz
parents:
diff changeset
329 else {
anatofuz
parents:
diff changeset
330 // Otherwise we only look at the sub-trees specified by the
anatofuz
parents:
diff changeset
331 // include paths.
anatofuz
parents:
diff changeset
332 for (std::vector<std::string>::const_iterator I = IncludePaths.begin(),
anatofuz
parents:
diff changeset
333 E = IncludePaths.end();
anatofuz
parents:
diff changeset
334 I != E; ++I) {
anatofuz
parents:
diff changeset
335 if (!collectFileSystemHeaders(*I))
anatofuz
parents:
diff changeset
336 return false;
anatofuz
parents:
diff changeset
337 }
anatofuz
parents:
diff changeset
338 }
anatofuz
parents:
diff changeset
339
anatofuz
parents:
diff changeset
340 // Sort it, because different file systems might order the file differently.
anatofuz
parents:
diff changeset
341 std::sort(FileSystemHeaders.begin(), FileSystemHeaders.end());
anatofuz
parents:
diff changeset
342
anatofuz
parents:
diff changeset
343 return true;
anatofuz
parents:
diff changeset
344 }
anatofuz
parents:
diff changeset
345
anatofuz
parents:
diff changeset
346 // Collect file system header files from the given path.
anatofuz
parents:
diff changeset
347 // This function scans the file system for header files,
anatofuz
parents:
diff changeset
348 // starting at the given directory, which is assumed to be
anatofuz
parents:
diff changeset
349 // relative to the directory of the module.modulemap file.
anatofuz
parents:
diff changeset
350 // \returns True if no errors.
anatofuz
parents:
diff changeset
351 bool CoverageChecker::collectFileSystemHeaders(StringRef IncludePath) {
anatofuz
parents:
diff changeset
352
anatofuz
parents:
diff changeset
353 // Initialize directory name.
anatofuz
parents:
diff changeset
354 SmallString<256> Directory(ModuleMapDirectory);
anatofuz
parents:
diff changeset
355 if (IncludePath.size())
anatofuz
parents:
diff changeset
356 sys::path::append(Directory, IncludePath);
anatofuz
parents:
diff changeset
357 if (Directory.size() == 0)
anatofuz
parents:
diff changeset
358 Directory = ".";
anatofuz
parents:
diff changeset
359 if (IncludePath.startswith("/") || IncludePath.startswith("\\") ||
anatofuz
parents:
diff changeset
360 ((IncludePath.size() >= 2) && (IncludePath[1] == ':'))) {
anatofuz
parents:
diff changeset
361 llvm::errs() << "error: Include path \"" << IncludePath
anatofuz
parents:
diff changeset
362 << "\" is not relative to the module map file.\n";
anatofuz
parents:
diff changeset
363 return false;
anatofuz
parents:
diff changeset
364 }
anatofuz
parents:
diff changeset
365
anatofuz
parents:
diff changeset
366 // Recursively walk the directory tree.
anatofuz
parents:
diff changeset
367 std::error_code EC;
anatofuz
parents:
diff changeset
368 int Count = 0;
anatofuz
parents:
diff changeset
369 for (sys::fs::recursive_directory_iterator I(Directory.str(), EC), E; I != E;
anatofuz
parents:
diff changeset
370 I.increment(EC)) {
anatofuz
parents:
diff changeset
371 if (EC)
anatofuz
parents:
diff changeset
372 return false;
anatofuz
parents:
diff changeset
373 //std::string file(I->path());
anatofuz
parents:
diff changeset
374 StringRef file(I->path());
anatofuz
parents:
diff changeset
375 llvm::ErrorOr<sys::fs::basic_file_status> Status = I->status();
anatofuz
parents:
diff changeset
376 if (!Status)
anatofuz
parents:
diff changeset
377 return false;
anatofuz
parents:
diff changeset
378 sys::fs::file_type type = Status->type();
anatofuz
parents:
diff changeset
379 // If the file is a directory, ignore the name (but still recurses).
anatofuz
parents:
diff changeset
380 if (type == sys::fs::file_type::directory_file)
anatofuz
parents:
diff changeset
381 continue;
anatofuz
parents:
diff changeset
382 // Assume directories or files starting with '.' are private and not to
anatofuz
parents:
diff changeset
383 // be considered.
anatofuz
parents:
diff changeset
384 if ((file.find("\\.") != StringRef::npos) ||
anatofuz
parents:
diff changeset
385 (file.find("/.") != StringRef::npos))
anatofuz
parents:
diff changeset
386 continue;
anatofuz
parents:
diff changeset
387 // If the file does not have a common header extension, ignore it.
anatofuz
parents:
diff changeset
388 if (!ModularizeUtilities::isHeader(file))
anatofuz
parents:
diff changeset
389 continue;
anatofuz
parents:
diff changeset
390 // Save header name.
anatofuz
parents:
diff changeset
391 FileSystemHeaders.push_back(ModularizeUtilities::getCanonicalPath(file));
anatofuz
parents:
diff changeset
392 Count++;
anatofuz
parents:
diff changeset
393 }
anatofuz
parents:
diff changeset
394 if (Count == 0) {
anatofuz
parents:
diff changeset
395 llvm::errs() << "warning: No headers found in include path: \""
anatofuz
parents:
diff changeset
396 << IncludePath << "\"\n";
anatofuz
parents:
diff changeset
397 }
anatofuz
parents:
diff changeset
398 return true;
anatofuz
parents:
diff changeset
399 }
anatofuz
parents:
diff changeset
400
anatofuz
parents:
diff changeset
401 // Find headers unaccounted-for in module map.
anatofuz
parents:
diff changeset
402 // This function compares the list of collected header files
anatofuz
parents:
diff changeset
403 // against those referenced in the module map. Display
anatofuz
parents:
diff changeset
404 // warnings for unaccounted-for header files.
anatofuz
parents:
diff changeset
405 // Save unaccounted-for file list for possible.
anatofuz
parents:
diff changeset
406 // fixing action.
anatofuz
parents:
diff changeset
407 // FIXME: There probably needs to be some canonalization
anatofuz
parents:
diff changeset
408 // of file names so that header path can be correctly
anatofuz
parents:
diff changeset
409 // matched. Also, a map could be used for the headers
anatofuz
parents:
diff changeset
410 // referenced in the module, but
anatofuz
parents:
diff changeset
411 void CoverageChecker::findUnaccountedForHeaders() {
anatofuz
parents:
diff changeset
412 // Walk over file system headers.
anatofuz
parents:
diff changeset
413 for (std::vector<std::string>::const_iterator I = FileSystemHeaders.begin(),
anatofuz
parents:
diff changeset
414 E = FileSystemHeaders.end();
anatofuz
parents:
diff changeset
415 I != E; ++I) {
anatofuz
parents:
diff changeset
416 // Look for header in module map.
anatofuz
parents:
diff changeset
417 if (ModuleMapHeadersSet.insert(*I).second) {
anatofuz
parents:
diff changeset
418 UnaccountedForHeaders.push_back(*I);
anatofuz
parents:
diff changeset
419 llvm::errs() << "warning: " << ModuleMapPath
anatofuz
parents:
diff changeset
420 << " does not account for file: " << *I << "\n";
anatofuz
parents:
diff changeset
421 }
anatofuz
parents:
diff changeset
422 }
anatofuz
parents:
diff changeset
423 }