14#include "llvm/ADT/SmallString.h"
15#include "llvm/Support/JSON.h"
16#include "llvm/Support/raw_ostream.h"
22 raw_ostream *OutputFile;
23 const DependencyOutputOptions &DepOpts;
24 unsigned CurrentIncludeDepth;
25 bool HasProcessedPredefines;
32 HeaderIncludesCallback(
const Preprocessor *PP,
bool ShowAllHeaders_,
33 raw_ostream *OutputFile_,
34 const DependencyOutputOptions &DepOpts,
35 bool OwnsOutputFile_,
bool ShowDepth_,
bool MSStyle_)
36 : SM(PP->getSourceManager()), OutputFile(OutputFile_), DepOpts(DepOpts),
37 CurrentIncludeDepth(0), HasProcessedPredefines(
false),
38 OwnsOutputFile(OwnsOutputFile_), ShowAllHeaders(ShowAllHeaders_),
39 ShowDepth(ShowDepth_), MSStyle(MSStyle_) {}
41 ~HeaderIncludesCallback()
override {
46 HeaderIncludesCallback(
const HeaderIncludesCallback &) =
delete;
47 HeaderIncludesCallback &operator=(
const HeaderIncludesCallback &) =
delete;
49 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
51 FileID PrevFID)
override;
53 void FileSkipped(
const FileEntryRef &SkippedFile,
const Token &FilenameTok,
58 if (!DepOpts.IncludeSystemHeaders &&
isSystem(HeaderType))
64 return (HasProcessedPredefines ||
65 (ShowAllHeaders && CurrentIncludeDepth > 2));
79class HeaderIncludesJSONCallback :
public PPCallbacks {
81 raw_ostream *OutputFile;
83 SmallVector<std::string, 16> IncludedHeaders;
86 HeaderIncludesJSONCallback(
const Preprocessor *PP, raw_ostream *OutputFile_,
88 : SM(PP->getSourceManager()), OutputFile(OutputFile_),
89 OwnsOutputFile(OwnsOutputFile_) {}
91 ~HeaderIncludesJSONCallback()
override {
96 HeaderIncludesJSONCallback(
const HeaderIncludesJSONCallback &) =
delete;
97 HeaderIncludesJSONCallback &
98 operator=(
const HeaderIncludesJSONCallback &) =
delete;
100 void EndOfMainFile()
override;
102 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
104 FileID PrevFID)
override;
106 void FileSkipped(
const FileEntryRef &SkippedFile,
const Token &FilenameTok,
114class HeaderIncludesDirectPerFileCallback :
public PPCallbacks {
117 raw_ostream *OutputFile;
119 using DependencyMap = llvm::DenseMap<FileEntryRef, SmallVector<FileEntryRef>>;
120 DependencyMap Dependencies;
123 HeaderIncludesDirectPerFileCallback(
const Preprocessor *PP,
124 raw_ostream *OutputFile_,
125 bool OwnsOutputFile_)
126 : SM(PP->getSourceManager()), HSI(PP->getHeaderSearchInfo()),
127 OutputFile(OutputFile_), OwnsOutputFile(OwnsOutputFile_) {}
129 ~HeaderIncludesDirectPerFileCallback()
override {
134 HeaderIncludesDirectPerFileCallback(
135 const HeaderIncludesDirectPerFileCallback &) =
delete;
136 HeaderIncludesDirectPerFileCallback &
137 operator=(
const HeaderIncludesDirectPerFileCallback &) =
delete;
139 void EndOfMainFile()
override;
141 void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
143 CharSourceRange FilenameRange,
145 StringRef RelativePath,
const Module *SuggestedModule,
149 void moduleImport(SourceLocation ImportLoc,
ModuleIdPath Path,
150 const Module *Imported)
override;
155 bool ShowDepth,
unsigned CurrentIncludeDepth,
164 Msg +=
"Note: including file:";
168 for (
unsigned i = 1; i != CurrentIncludeDepth; ++i)
169 Msg += MSStyle ?
' ' :
'.';
183 bool ShowAllHeaders, StringRef OutputPath,
184 bool ShowDepth,
bool MSStyle) {
185 raw_ostream *OutputFile = &llvm::errs();
186 bool OwnsOutputFile =
false;
192 llvm_unreachable(
"Invalid destination for /showIncludes output!");
194 OutputFile = &llvm::errs();
197 OutputFile = &llvm::outs();
203 if (!OutputPath.empty()) {
205 llvm::raw_fd_ostream *OS =
new llvm::raw_fd_ostream(
206 OutputPath.str(), EC,
207 llvm::sys::fs::OF_Append | llvm::sys::fs::OF_TextWithCRLF);
215 OwnsOutputFile =
true;
221 llvm_unreachable(
"unexpected header format kind");
224 "header filtering is currently always disabled when output format is"
231 for (
const auto &Header : DepOpts.
ExtraDeps)
234 &PP, ShowAllHeaders, OutputFile, DepOpts, OwnsOutputFile, ShowDepth,
241 llvm_unreachable(
"Unknown HeaderIncludeFilteringKind enum");
244 &PP, OutputFile, OwnsOutputFile));
247 PP.
addPPCallbacks(std::make_unique<HeaderIncludesDirectPerFileCallback>(
248 &PP, OutputFile, OwnsOutputFile));
256 FileChangeReason Reason,
267 ++CurrentIncludeDepth;
269 if (CurrentIncludeDepth)
270 --CurrentIncludeDepth;
274 if (CurrentIncludeDepth == 1 && !HasProcessedPredefines)
275 HasProcessedPredefines =
true;
282 if (!ShouldShowHeader(NewFileType))
285 unsigned IncludeDepth = CurrentIncludeDepth;
286 if (!HasProcessedPredefines)
292 UserLoc.
getFilename() != StringRef(
"<command line>")) {
298void HeaderIncludesCallback::FileSkipped(
const FileEntryRef &SkippedFile,
const
308 CurrentIncludeDepth + 1, MSStyle);
311void HeaderIncludesJSONCallback::EndOfMainFile() {
313 SmallString<256> MainFile;
316 SM.getFileManager().makeAbsolutePath(MainFile);
320 llvm::raw_string_ostream
OS(Str);
321 llvm::json::OStream JOS(OS);
323 JOS.attribute(
"source", MainFile.c_str());
324 JOS.attributeArray(
"includes", [&] {
325 llvm::StringSet<> SeenHeaders;
326 for (
const std::string &H : IncludedHeaders)
327 if (SeenHeaders.insert(H).second)
333 if (OutputFile->get_kind() == raw_ostream::OStreamKind::OK_FDStream) {
334 llvm::raw_fd_ostream *FDS =
static_cast<llvm::raw_fd_ostream *
>(OutputFile);
335 if (
auto L = FDS->lock())
349void HeaderIncludesJSONCallback::FileChanged(
350 SourceLocation Loc, FileChangeReason Reason,
358 PresumedLoc UserLoc =
SM.getPresumedLoc(Loc);
363 UserLoc.
getFilename() != StringRef(
"<command line>"))
367void HeaderIncludesJSONCallback::FileSkipped(
368 const FileEntryRef &SkippedFile,
const Token &FilenameTok,
373 IncludedHeaders.push_back(SkippedFile.
getName().str());
376void HeaderIncludesDirectPerFileCallback::EndOfMainFile() {
377 if (Dependencies.empty())
381 SmallVector<FileEntryRef> SourceFiles;
382 for (
auto F = Dependencies.begin(), FEnd = Dependencies.end(); F != FEnd;
384 SourceFiles.push_back(F->first);
386 llvm::sort(SourceFiles, [](
const FileEntryRef &LHS,
const FileEntryRef &RHS) {
391 llvm::raw_string_ostream
OS(Str);
392 llvm::json::OStream JOS(OS);
394 for (
auto S = SourceFiles.begin(), SE = SourceFiles.end(); S != SE; ++S) {
396 SmallVector<FileEntryRef> &Deps = Dependencies[*S];
397 JOS.attribute(
"source", S->getName().str());
398 JOS.attributeArray(
"includes", [&] {
399 for (
unsigned I = 0, N = Deps.size(); I != N; ++I)
400 JOS.value(Deps[I].
getName().str());
407 if (OutputFile->get_kind() == raw_ostream::OStreamKind::OK_FDStream) {
408 llvm::raw_fd_ostream *FDS =
static_cast<llvm::raw_fd_ostream *
>(OutputFile);
409 if (
auto L = FDS->lock())
415void HeaderIncludesDirectPerFileCallback::InclusionDirective(
416 SourceLocation HashLoc,
const Token &IncludeTok, StringRef
FileName,
418 StringRef SearchPath, StringRef RelativePath,
const Module *SuggestedModule,
423 SourceLocation Loc =
SM.getExpansionLoc(HashLoc);
424 if (
SM.isInSystemHeader(Loc))
430 Dependencies[*FromFile].push_back(*
File);
433void HeaderIncludesDirectPerFileCallback::moduleImport(SourceLocation ImportLoc,
439 SourceLocation Loc =
SM.getExpansionLoc(ImportLoc);
440 if (
SM.isInSystemHeader(Loc))
451 Dependencies[*FromFile].push_back(*ModuleMapFile);
llvm::MachO::FileType FileType
Defines the clang::Preprocessor interface.
Defines the SourceManager interface.
DependencyOutputOptions - Options for controlling the compiler dependency file generation.
ShowIncludesDestination ShowIncludesDest
Destination of cl.exe style /showIncludes info.
HeaderIncludeFormatKind HeaderIncludeFormat
The format of header information.
HeaderIncludeFilteringKind HeaderIncludeFiltering
Determine whether header information should be filtered.
unsigned ShowSkippedHeaderIncludes
With ShowHeaderIncludes, show also includes that were skipped due to the "include guard optimization...
std::vector< std::pair< std::string, ExtraDepKind > > ExtraDeps
A list of extra dependencies (filename and kind) to be used for every target.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
StringRef getName() const
The name of this FileEntry.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
static std::string Stringify(StringRef Str, bool Charify=false)
Stringify - Convert the specified string into a C string by i) escaping '\' and " characters and ii) ...
OptionalFileEntryRef getModuleMapFileForUniquing(const Module *M) const
This interface provides a way to observe the actions of the preprocessor as it does its thing.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
DiagnosticsEngine & getDiagnostics() const
Represents an unpacked "presumed" location which can be presented to the user.
const char * getFilename() const
Return the presumed filename of this location.
bool isInvalid() const
Return true if this object is invalid or uninitialized.
Encodes a location in the source.
This class handles loading and caching of source files into memory.
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
bool isSystem(CharacteristicKind CK)
Determine whether a file / directory characteristic is for system code.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
StringRef getName(const HeaderType T)
The JSON file list parser is used to communicate input to InstallAPI.
CustomizableOptional< FileEntryRef > OptionalFileEntryRef
ArrayRef< IdentifierLoc > ModuleIdPath
A sequence of identifier/location pairs used to describe a particular module or submodule,...
@ HIFIL_Only_Direct_System
@ Module
Module linkage, which indicates that the entity can be referred to from other translation units withi...
void AttachHeaderIncludeGen(Preprocessor &PP, const DependencyOutputOptions &DepOpts, bool ShowAllHeaders=false, StringRef OutputPath={}, bool ShowDepth=true, bool MSStyle=false)
AttachHeaderIncludeGen - Create a header include list generator, and attach it to the given preproces...