25 #include "llvm/ADT/StringSet.h"
26 #include "llvm/ADT/StringSwitch.h"
27 #include "llvm/Support/FileSystem.h"
28 #include "llvm/Support/Path.h"
29 #include "llvm/Support/raw_ostream.h"
31 using namespace clang;
34 struct DepCollectorPPCallbacks :
public PPCallbacks {
38 : DepCollector(L), SM(SM) { }
55 llvm::sys::path::remove_leading_dotslash(FE->
getName());
57 DepCollector.maybeAddDependency(Filename,
false,
65 StringRef SearchPath, StringRef RelativePath,
66 const Module *Imported)
override {
68 DepCollector.maybeAddDependency(FileName,
false,
74 void EndOfMainFile()
override {
75 DepCollector.finishedMainFile();
84 bool IsSystem)
override {
85 StringRef Filename = Entry.
getName();
86 DepCollector.maybeAddDependency(Filename,
false,
96 bool needsInputFileVisitation()
override {
return true; }
97 bool needsSystemInputFileVisitation()
override {
98 return DepCollector.needSystemDependencies();
100 void visitModuleFile(StringRef Filename,
102 DepCollector.maybeAddDependency(Filename,
true,
106 bool visitInputFile(StringRef Filename,
bool IsSystem,
107 bool IsOverridden,
bool IsExplicitModule)
override {
108 if (IsOverridden || IsExplicitModule)
111 DepCollector.maybeAddDependency(Filename,
true, IsSystem,
119 bool IsSystem,
bool IsModuleFile,
121 if (Seen.insert(Filename).second &&
122 sawDependency(Filename, FromModule, IsSystem, IsModuleFile, IsMissing))
123 Dependencies.push_back(Filename);
127 return llvm::StringSwitch<bool>(
Filename)
128 .Case(
"<built-in>",
true)
129 .Case(
"<stdin>",
true)
134 bool IsSystem,
bool IsModuleFile,
145 llvm::make_unique<DepCollectorMMCallbacks>(*
this));
148 R.
addListener(llvm::make_unique<DepCollectorASTListener>(*
this));
154 std::vector<std::string> Files;
155 llvm::StringSet<> FilesSet;
157 std::string OutputFile;
158 std::vector<std::string> Targets;
159 bool IncludeSystemHeaders;
161 bool AddMissingHeaderDeps;
162 bool SeenMissingHeader;
163 bool IncludeModuleFiles;
167 bool FileMatchesDepCriteria(
const char *Filename,
169 void OutputDependencyFile();
173 : PP(_PP), OutputFile(Opts.OutputFile), Targets(Opts.Targets),
174 IncludeSystemHeaders(Opts.IncludeSystemHeaders),
175 PhonyTarget(Opts.UsePhonyTargets),
176 AddMissingHeaderDeps(Opts.AddMissingHeaderDeps),
177 SeenMissingHeader(
false),
178 IncludeModuleFiles(Opts.IncludeModuleFiles),
179 OutputFormat(Opts.OutputFormat) {
180 for (
const auto &ExtraDep : Opts.
ExtraDeps) {
181 AddFilename(ExtraDep);
189 StringRef FileName,
bool IsAngled,
191 StringRef SearchPath, StringRef RelativePath,
192 const Module *Imported)
override;
194 void EndOfMainFile()
override {
195 OutputDependencyFile();
198 void AddFilename(StringRef Filename);
199 bool includeSystemHeaders()
const {
return IncludeSystemHeaders; }
200 bool includeModuleFiles()
const {
return IncludeModuleFiles; }
206 DFGMMCallback(DFGImpl &Parent) : Parent(Parent) {}
208 bool IsSystem)
override {
209 if (!IsSystem || Parent.includeSystemHeaders())
210 Parent.AddFilename(Entry.
getName());
217 DFGASTReaderListener(DFGImpl &Parent)
219 bool needsInputFileVisitation()
override {
return true; }
220 bool needsSystemInputFileVisitation()
override {
221 return Parent.includeSystemHeaders();
223 void visitModuleFile(StringRef Filename,
225 bool visitInputFile(StringRef Filename,
bool isSystem,
226 bool isOverridden,
bool isExplicitModule)
override;
230 DependencyFileGenerator::DependencyFileGenerator(
void *Impl)
245 DFGImpl *
Callback =
new DFGImpl(&PP, Opts);
248 llvm::make_unique<DFGMMCallback>(*Callback));
253 DFGImpl *
I =
reinterpret_cast<DFGImpl *
>(Impl);
254 assert(I &&
"missing implementation");
255 R.
addListener(llvm::make_unique<DFGASTReaderListener>(*I));
260 bool DFGImpl::FileMatchesDepCriteria(
const char *Filename,
265 if (IncludeSystemHeaders)
272 FileChangeReason Reason,
287 StringRef Filename = FE->
getName();
288 if (!FileMatchesDepCriteria(Filename.data(), FileType))
291 AddFilename(llvm::sys::path::remove_leading_dotslash(Filename));
295 const Token &IncludeTok,
300 StringRef SearchPath,
301 StringRef RelativePath,
304 if (AddMissingHeaderDeps)
305 AddFilename(FileName);
307 SeenMissingHeader =
true;
311 void DFGImpl::AddFilename(StringRef Filename) {
312 if (FilesSet.insert(Filename).second)
313 Files.push_back(Filename);
370 if (Filename.find_first_of(
" #${}^!") != StringRef::npos)
371 OS <<
'\"' << Filename <<
'\"';
377 for (
unsigned i = 0, e = Filename.size(); i != e; ++i) {
378 if (Filename[i] ==
'#')
380 else if (Filename[i] ==
' ') {
383 while (j > 0 && Filename[--j] ==
'\\')
385 }
else if (Filename[i] ==
'$')
391 void DFGImpl::OutputDependencyFile() {
392 if (SeenMissingHeader) {
393 llvm::sys::fs::remove(OutputFile);
398 llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text);
400 PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile
409 const unsigned MaxColumns = 75;
410 unsigned Columns = 0;
413 I = Targets.begin(),
E = Targets.end();
I !=
E; ++
I) {
414 unsigned N =
I->length();
417 }
else if (Columns + N + 2 > MaxColumns) {
434 E = Files.end();
I !=
E; ++
I) {
438 unsigned N =
I->length();
439 if (Columns + (N + 1) + 2 > MaxColumns) {
450 if (PhonyTarget && !Files.empty()) {
453 E = Files.end();
I !=
E; ++
I) {
461 bool DFGASTReaderListener::visitInputFile(llvm::StringRef Filename,
462 bool IsSystem,
bool IsOverridden,
463 bool IsExplicitModule) {
464 assert(!IsSystem || needsSystemInputFileVisitation());
465 if (IsOverridden || IsExplicitModule)
468 Parent.AddFilename(Filename);
472 void DFGASTReaderListener::visitModuleFile(llvm::StringRef Filename,
474 if (Parent.includeModuleFiles())
475 Parent.AddFilename(Filename);
SourceManager & getSourceManager() const
Defines the clang::FileManager interface and associated types.
An interface for collecting the dependencies of a compilation.
Defines the SourceManager interface.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
This interface provides a way to observe the actions of the preprocessor as it does its thing...
virtual bool needSystemDependencies()
Return true if system files should be passed to sawDependency().
Token - This structure provides full information about a lexed token.
Describes a module or submodule.
void SetSuppressIncludeNotFoundError(bool Suppress)
virtual void attachToASTReader(ASTReader &R)
HeaderSearch & getHeaderSearchInfo() const
void addModuleMapCallbacks(std::unique_ptr< ModuleMapCallbacks > Callback)
Add a module map callback.
detail::InMemoryDirectory::const_iterator I
Builds a depdenency file when attached to a Preprocessor (for includes) and ASTReader (for module imp...
static DependencyFileGenerator * CreateAndAttachToPreprocessor(Preprocessor &PP, const DependencyOutputOptions &Opts)
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
ModuleKind
Specifies the kind of module that has been loaded.
void maybeAddDependency(StringRef Filename, bool FromModule, bool IsSystem, bool IsModuleFile, bool IsMissing)
Add a dependency Filename if it has not been seen before and sawDependency() returns true...
static bool isSpecialFilename(StringRef Filename)
Represents a character-granular source range.
MatchFinder::MatchCallback * Callback
Defines the clang::Preprocessor interface.
A mechanism to observe the actions of the module map parser as it reads module map files...
Record the location of an inclusion directive, such as an #include or #import statement.
void addListener(std::unique_ptr< ASTReaderListener > L)
Add an AST callback listener.
void AttachToASTReader(ASTReader &R)
const char * getName() const
Encodes a location in the source.
const TemplateArgument * iterator
Cached information about one file (either on disk or in the virtual file system). ...
DependencyOutputOptions - Options for controlling the compiler dependency file generation.
std::vector< std::string > ExtraDeps
A list of filenames to be used as extra dependencies for every target.
DiagnosticsEngine & getDiagnostics() const
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Reads an AST files chain containing the contents of a translation unit.
detail::InMemoryDirectory::const_iterator E
virtual ~DependencyCollector()
Abstract interface for callback invocations by the ASTReader.
virtual void attachToPreprocessor(Preprocessor &PP)
Defines the PPCallbacks interface.
std::vector< std::string > Targets
A list of names to use as the targets in the dependency file; this list must contain at least one ent...
unsigned AddMissingHeaderDeps
Add missing headers to dependency list.
virtual bool sawDependency(StringRef Filename, bool FromModule, bool IsSystem, bool IsModuleFile, bool IsMissing)
Called when a new file is seen.
static void PrintFilename(raw_ostream &OS, StringRef Filename, DependencyOutputFormat OutputFormat)
Print the filename, with escaping or quoting that accommodates the three most likely tools that use d...
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
DependencyOutputFormat
DependencyOutputFormat - Format for the compiler dependency file.
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
This class handles loading and caching of source files into memory.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.