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());
63 StringRef FileName,
bool IsAngled,
65 StringRef SearchPath, StringRef RelativePath,
75 void EndOfMainFile()
override {
85 bool IsSystem)
override {
86 StringRef Filename = Entry.
getName();
97 bool needsInputFileVisitation()
override {
return true; }
98 bool needsSystemInputFileVisitation()
override {
101 void visitModuleFile(StringRef Filename,
107 bool visitInputFile(StringRef Filename,
bool IsSystem,
108 bool IsOverridden,
bool IsExplicitModule)
override {
109 if (IsOverridden || IsExplicitModule)
120 bool IsSystem,
bool IsModuleFile,
122 if (Seen.insert(Filename).second &&
123 sawDependency(Filename, FromModule, IsSystem, IsModuleFile, IsMissing))
124 Dependencies.push_back(Filename);
128 return llvm::StringSwitch<bool>(
Filename)
129 .Case(
"<built-in>",
true)
130 .Case(
"<stdin>",
true)
135 bool IsSystem,
bool IsModuleFile,
138 (needSystemDependencies() || !IsSystem);
146 llvm::make_unique<DepCollectorMMCallbacks>(*
this));
149 R.
addListener(llvm::make_unique<DepCollectorASTListener>(*
this));
155 std::vector<std::string> Files;
156 llvm::StringSet<> FilesSet;
158 std::string OutputFile;
159 std::vector<std::string> Targets;
160 bool IncludeSystemHeaders;
162 bool AddMissingHeaderDeps;
163 bool SeenMissingHeader;
164 bool IncludeModuleFiles;
166 unsigned InputFileIndex;
169 bool FileMatchesDepCriteria(
const char *Filename,
171 void OutputDependencyFile();
179 SeenMissingHeader(
false),
183 for (
const auto &ExtraDep : Opts.
ExtraDeps) {
184 if (AddFilename(ExtraDep))
193 void FileSkipped(
const FileEntry &SkippedFile,
const Token &FilenameTok,
197 StringRef FileName,
bool IsAngled,
199 StringRef SearchPath, StringRef RelativePath,
203 void EndOfMainFile()
override {
204 OutputDependencyFile();
207 bool AddFilename(StringRef Filename);
208 bool includeSystemHeaders()
const {
return IncludeSystemHeaders; }
209 bool includeModuleFiles()
const {
return IncludeModuleFiles; }
215 DFGMMCallback(DFGImpl &Parent) :
Parent(Parent) {}
217 bool IsSystem)
override {
218 if (!IsSystem || Parent.includeSystemHeaders())
219 Parent.AddFilename(Entry.
getName());
226 DFGASTReaderListener(DFGImpl &Parent)
228 bool needsInputFileVisitation()
override {
return true; }
229 bool needsSystemInputFileVisitation()
override {
230 return Parent.includeSystemHeaders();
232 void visitModuleFile(StringRef Filename,
234 bool visitInputFile(StringRef Filename,
bool isSystem,
235 bool isOverridden,
bool isExplicitModule)
override;
239 DependencyFileGenerator::DependencyFileGenerator(
void *Impl)
254 DFGImpl *Callback =
new DFGImpl(&PP, Opts);
257 llvm::make_unique<DFGMMCallback>(*Callback));
262 DFGImpl *I =
reinterpret_cast<DFGImpl *
>(Impl);
263 assert(I &&
"missing implementation");
264 R.
addListener(llvm::make_unique<DFGASTReaderListener>(*I));
269 bool DFGImpl::FileMatchesDepCriteria(
const char *Filename,
274 if (IncludeSystemHeaders)
281 FileChangeReason Reason,
296 StringRef Filename = FE->
getName();
297 if (!FileMatchesDepCriteria(Filename.data(), FileType))
300 AddFilename(llvm::sys::path::remove_leading_dotslash(Filename));
303 void DFGImpl::FileSkipped(
const FileEntry &SkippedFile,
304 const Token &FilenameTok,
306 StringRef Filename = SkippedFile.
getName();
307 if (!FileMatchesDepCriteria(Filename.data(), FileType))
310 AddFilename(llvm::sys::path::remove_leading_dotslash(Filename));
314 const Token &IncludeTok,
319 StringRef SearchPath,
320 StringRef RelativePath,
324 if (AddMissingHeaderDeps)
325 AddFilename(FileName);
327 SeenMissingHeader =
true;
331 bool DFGImpl::AddFilename(StringRef Filename) {
332 if (FilesSet.insert(Filename).second) {
333 Files.push_back(Filename);
393 if (Filename.find_first_of(
" #${}^!") != StringRef::npos)
394 OS <<
'\"' << Filename <<
'\"';
400 for (
unsigned i = 0, e = Filename.size(); i != e; ++i) {
401 if (Filename[i] ==
'#')
403 else if (Filename[i] ==
' ') {
406 while (j > 0 && Filename[--j] ==
'\\')
408 }
else if (Filename[i] ==
'$')
414 void DFGImpl::OutputDependencyFile() {
415 if (SeenMissingHeader) {
416 llvm::sys::fs::remove(OutputFile);
421 llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text);
423 PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile
432 const unsigned MaxColumns = 75;
433 unsigned Columns = 0;
435 for (StringRef
Target : Targets) {
436 unsigned N =
Target.size();
439 }
else if (Columns + N + 2 > MaxColumns) {
455 for (StringRef File : Files) {
459 unsigned N = File.size();
460 if (Columns + (N + 1) + 2 > MaxColumns) {
471 if (PhonyTarget && !Files.empty()) {
473 for (
auto I = Files.begin(), E = Files.end(); I != E; ++I) {
474 if (Index++ == InputFileIndex)
483 bool DFGASTReaderListener::visitInputFile(llvm::StringRef Filename,
484 bool IsSystem,
bool IsOverridden,
485 bool IsExplicitModule) {
486 assert(!IsSystem || needsSystemInputFileVisitation());
487 if (IsOverridden || IsExplicitModule)
490 Parent.AddFilename(Filename);
494 void DFGASTReaderListener::visitModuleFile(llvm::StringRef Filename,
496 if (
Parent.includeModuleFiles())
497 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.