24 #include "llvm/ADT/StringSet.h" 25 #include "llvm/ADT/StringSwitch.h" 26 #include "llvm/Support/FileSystem.h" 27 #include "llvm/Support/Path.h" 28 #include "llvm/Support/raw_ostream.h" 30 using namespace clang;
33 struct DepCollectorPPCallbacks :
public PPCallbacks {
37 : DepCollector(L), SM(SM) { }
54 llvm::sys::path::remove_leading_dotslash(FE->
getName());
62 StringRef FileName,
bool IsAngled,
64 StringRef SearchPath, StringRef RelativePath,
74 void EndOfMainFile()
override {
84 bool IsSystem)
override {
85 StringRef Filename = Entry.
getName();
96 bool needsInputFileVisitation()
override {
return true; }
97 bool needsSystemInputFileVisitation()
override {
100 void visitModuleFile(StringRef Filename,
106 bool visitInputFile(StringRef Filename,
bool IsSystem,
107 bool IsOverridden,
bool IsExplicitModule)
override {
108 if (IsOverridden || IsExplicitModule)
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,
137 (needSystemDependencies() || !IsSystem);
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;
165 unsigned InputFileIndex;
168 bool FileMatchesDepCriteria(
const char *Filename,
170 void OutputDependencyFile();
178 SeenMissingHeader(
false),
182 for (
const auto &ExtraDep : Opts.
ExtraDeps) {
183 if (AddFilename(ExtraDep))
192 void FileSkipped(
const FileEntry &SkippedFile,
const Token &FilenameTok,
196 StringRef FileName,
bool IsAngled,
198 StringRef SearchPath, StringRef RelativePath,
202 void HasInclude(
SourceLocation Loc, StringRef SpelledFilename,
bool IsAngled,
206 void EndOfMainFile()
override {
207 OutputDependencyFile();
210 bool AddFilename(StringRef Filename);
211 bool includeSystemHeaders()
const {
return IncludeSystemHeaders; }
212 bool includeModuleFiles()
const {
return IncludeModuleFiles; }
218 DFGMMCallback(DFGImpl &Parent) :
Parent(Parent) {}
220 bool IsSystem)
override {
221 if (!IsSystem || Parent.includeSystemHeaders())
222 Parent.AddFilename(Entry.
getName());
229 DFGASTReaderListener(DFGImpl &Parent)
231 bool needsInputFileVisitation()
override {
return true; }
232 bool needsSystemInputFileVisitation()
override {
233 return Parent.includeSystemHeaders();
235 void visitModuleFile(StringRef Filename,
237 bool visitInputFile(StringRef Filename,
bool isSystem,
238 bool isOverridden,
bool isExplicitModule)
override;
242 DependencyFileGenerator::DependencyFileGenerator(
void *Impl)
257 DFGImpl *Callback =
new DFGImpl(&PP, Opts);
260 llvm::make_unique<DFGMMCallback>(*Callback));
265 DFGImpl *I =
reinterpret_cast<DFGImpl *
>(Impl);
266 assert(I &&
"missing implementation");
267 R.
addListener(llvm::make_unique<DFGASTReaderListener>(*I));
272 bool DFGImpl::FileMatchesDepCriteria(
const char *Filename,
277 if (IncludeSystemHeaders)
284 FileChangeReason Reason,
299 StringRef Filename = FE->
getName();
300 if (!FileMatchesDepCriteria(Filename.data(), FileType))
303 AddFilename(llvm::sys::path::remove_leading_dotslash(Filename));
306 void DFGImpl::FileSkipped(
const FileEntry &SkippedFile,
307 const Token &FilenameTok,
309 StringRef Filename = SkippedFile.
getName();
310 if (!FileMatchesDepCriteria(Filename.data(), FileType))
313 AddFilename(llvm::sys::path::remove_leading_dotslash(Filename));
317 const Token &IncludeTok,
322 StringRef SearchPath,
323 StringRef RelativePath,
327 if (AddMissingHeaderDeps)
328 AddFilename(FileName);
330 SeenMissingHeader =
true;
334 void DFGImpl::HasInclude(
SourceLocation Loc, StringRef SpelledFilename,
339 StringRef Filename = File->
getName();
340 if (!FileMatchesDepCriteria(Filename.data(), FileType))
342 AddFilename(llvm::sys::path::remove_leading_dotslash(Filename));
345 bool DFGImpl::AddFilename(StringRef Filename) {
346 if (FilesSet.insert(Filename).second) {
347 Files.push_back(Filename);
405 llvm::sys::path::native(Filename.str(), NativePath);
411 if (NativePath.find_first_of(
" #${}^!") != StringRef::npos)
412 OS <<
'\"' << NativePath <<
'\"';
418 for (
unsigned i = 0, e = NativePath.size(); i != e; ++i) {
419 if (NativePath[i] ==
'#')
421 else if (NativePath[i] ==
' ') {
424 while (j > 0 && NativePath[--j] ==
'\\')
426 }
else if (NativePath[i] ==
'$')
432 void DFGImpl::OutputDependencyFile() {
433 if (SeenMissingHeader) {
434 llvm::sys::fs::remove(OutputFile);
439 llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text);
441 PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile
450 const unsigned MaxColumns = 75;
451 unsigned Columns = 0;
453 for (StringRef
Target : Targets) {
454 unsigned N =
Target.size();
457 }
else if (Columns + N + 2 > MaxColumns) {
473 for (StringRef File : Files) {
477 unsigned N = File.size();
478 if (Columns + (N + 1) + 2 > MaxColumns) {
489 if (PhonyTarget && !Files.empty()) {
491 for (
auto I = Files.begin(), E = Files.end(); I != E; ++I) {
492 if (Index++ == InputFileIndex)
501 bool DFGASTReaderListener::visitInputFile(llvm::StringRef Filename,
502 bool IsSystem,
bool IsOverridden,
503 bool IsExplicitModule) {
504 assert(!IsSystem || needsSystemInputFileVisitation());
505 if (IsOverridden || IsExplicitModule)
508 Parent.AddFilename(Filename);
512 void DFGASTReaderListener::visitModuleFile(llvm::StringRef Filename,
514 if (
Parent.includeModuleFiles())
515 Parent.AddFilename(Filename);
Defines the clang::FileManager interface and associated types.
An interface for collecting the dependencies of a compilation.
Defines the SourceManager interface.
unsigned IncludeModuleFiles
Include module file dependencies.
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...
unsigned IncludeSystemHeaders
Include system header dependencies.
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
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
void addModuleMapCallbacks(std::unique_ptr< ModuleMapCallbacks > Callback)
Add a module map callback.
Builds a depdenency file when attached to a Preprocessor (for includes) and ASTReader (for module imp...
static DependencyFileGenerator * CreateAndAttachToPreprocessor(Preprocessor &PP, const DependencyOutputOptions &Opts)
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.
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
virtual void finishedMainFile()
Called when the end of the main file is reached.
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.
SourceManager & getSourceManager() const
void addListener(std::unique_ptr< ASTReaderListener > L)
Add an AST callback listener.
void AttachToASTReader(ASTReader &R)
Encodes a location in the source.
StringRef getName() const
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.
std::string OutputFile
The file to write dependency output to.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
DependencyOutputFormat OutputFormat
The format for the dependency file.
Dataflow Directional Tag Classes.
Reads an AST files chain containing the contents of a translation unit.
unsigned UsePhonyTargets
Include phony targets for each dependency, which can avoid some 'make' problems.
virtual ~DependencyCollector()
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
Abstract interface for callback invocations by the ASTReader.
virtual void attachToPreprocessor(Preprocessor &PP)
Defines the PPCallbacks interface.
DiagnosticsEngine & getDiagnostics() const
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...
DependencyOutputFormat
DependencyOutputFormat - Format for the compiler dependency file.
bool isSystem(CharacteristicKind CK)
Determine whether a file / directory characteristic is for system code.
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.