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 {
115 struct HeaderIncludeInfo {
116 SourceLocation Location;
118 const Module *ImportedModule;
120 HeaderIncludeInfo(SourceLocation Location, FileEntryRef File,
121 const Module *ImportedModule)
122 : Location(Location), File(File), ImportedModule(ImportedModule) {}
127 raw_ostream *OutputFile;
129 using DependencyMap =
130 llvm::DenseMap<FileEntryRef, SmallVector<HeaderIncludeInfo>>;
131 DependencyMap Dependencies;
134 HeaderIncludesDirectPerFileCallback(
const Preprocessor *PP,
135 raw_ostream *OutputFile_,
136 bool OwnsOutputFile_)
137 : SM(PP->getSourceManager()), HSI(PP->getHeaderSearchInfo()),
138 OutputFile(OutputFile_), OwnsOutputFile(OwnsOutputFile_) {}
140 ~HeaderIncludesDirectPerFileCallback()
override {
145 HeaderIncludesDirectPerFileCallback(
146 const HeaderIncludesDirectPerFileCallback &) =
delete;
147 HeaderIncludesDirectPerFileCallback &
148 operator=(
const HeaderIncludesDirectPerFileCallback &) =
delete;
150 void EndOfMainFile()
override;
152 void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
154 CharSourceRange FilenameRange,
156 StringRef RelativePath,
const Module *SuggestedModule,
160 void moduleImport(SourceLocation ImportLoc,
ModuleIdPath Path,
161 const Module *Imported)
override;
166 bool ShowDepth,
unsigned CurrentIncludeDepth,
175 Msg +=
"Note: including file:";
179 for (
unsigned i = 1; i != CurrentIncludeDepth; ++i)
180 Msg += MSStyle ?
' ' :
'.';
194 bool ShowAllHeaders, StringRef OutputPath,
195 bool ShowDepth,
bool MSStyle) {
196 raw_ostream *OutputFile = &llvm::errs();
197 bool OwnsOutputFile =
false;
203 llvm_unreachable(
"Invalid destination for /showIncludes output!");
205 OutputFile = &llvm::errs();
208 OutputFile = &llvm::outs();
214 if (!OutputPath.empty()) {
216 llvm::raw_fd_ostream *OS =
new llvm::raw_fd_ostream(
217 OutputPath.str(), EC,
218 llvm::sys::fs::OF_Append | llvm::sys::fs::OF_TextWithCRLF);
226 OwnsOutputFile =
true;
232 llvm_unreachable(
"unexpected header format kind");
235 "header filtering is currently always disabled when output format is"
242 for (
const auto &Header : DepOpts.
ExtraDeps)
245 &PP, ShowAllHeaders, OutputFile, DepOpts, OwnsOutputFile, ShowDepth,
252 llvm_unreachable(
"Unknown HeaderIncludeFilteringKind enum");
255 &PP, OutputFile, OwnsOutputFile));
258 PP.
addPPCallbacks(std::make_unique<HeaderIncludesDirectPerFileCallback>(
259 &PP, OutputFile, OwnsOutputFile));
267 FileChangeReason Reason,
278 ++CurrentIncludeDepth;
280 if (CurrentIncludeDepth)
281 --CurrentIncludeDepth;
285 if (CurrentIncludeDepth == 1 && !HasProcessedPredefines)
286 HasProcessedPredefines =
true;
293 if (!ShouldShowHeader(NewFileType))
296 unsigned IncludeDepth = CurrentIncludeDepth;
297 if (!HasProcessedPredefines)
303 UserLoc.
getFilename() != StringRef(
"<command line>")) {
309void HeaderIncludesCallback::FileSkipped(
const FileEntryRef &SkippedFile,
310 const Token &FilenameTok,
319 CurrentIncludeDepth + 1, MSStyle);
322void HeaderIncludesJSONCallback::EndOfMainFile() {
324 SmallString<256> MainFile;
327 SM.getFileManager().makeAbsolutePath(MainFile);
331 llvm::raw_string_ostream
OS(Str);
332 llvm::json::OStream JOS(OS);
334 JOS.attribute(
"source", MainFile.c_str());
335 JOS.attributeArray(
"includes", [&] {
336 llvm::StringSet<> SeenHeaders;
337 for (
const std::string &H : IncludedHeaders)
338 if (SeenHeaders.insert(H).second)
344 if (OutputFile->get_kind() == raw_ostream::OStreamKind::OK_FDStream) {
345 llvm::raw_fd_ostream *FDS =
static_cast<llvm::raw_fd_ostream *
>(OutputFile);
346 if (
auto L = FDS->lock())
360void HeaderIncludesJSONCallback::FileChanged(
361 SourceLocation Loc, FileChangeReason Reason,
369 PresumedLoc UserLoc =
SM.getPresumedLoc(Loc);
374 UserLoc.
getFilename() != StringRef(
"<command line>"))
378void HeaderIncludesJSONCallback::FileSkipped(
379 const FileEntryRef &SkippedFile,
const Token &FilenameTok,
384 IncludedHeaders.push_back(SkippedFile.
getName().str());
387void HeaderIncludesDirectPerFileCallback::EndOfMainFile() {
388 if (Dependencies.empty())
392 SmallVector<FileEntryRef> SourceFiles;
393 for (
auto F = Dependencies.begin(), FEnd = Dependencies.end(); F != FEnd;
395 SourceFiles.push_back(F->first);
397 llvm::sort(SourceFiles, [](
const FileEntryRef &LHS,
const FileEntryRef &RHS) {
402 llvm::raw_string_ostream
OS(Str);
403 llvm::json::OStream JOS(OS);
405 JOS.attribute(
"version",
"2.0.0");
406 JOS.attributeArray(
"dependencies", [&] {
407 for (
const auto &S : SourceFiles) {
409 SmallVector<HeaderIncludeInfo> &Deps = Dependencies[S];
410 JOS.attribute(
"source", S.getName().str());
411 JOS.attributeArray(
"includes", [&] {
412 for (
unsigned I = 0, N = Deps.size(); I != N; ++I) {
413 if (!Deps[I].ImportedModule) {
415 JOS.attribute(
"location", Deps[I].Location.printToString(
SM));
416 JOS.attribute(
"file", Deps[I].
File.getName());
421 JOS.attributeArray(
"imports", [&] {
422 for (
unsigned I = 0, N = Deps.size(); I != N; ++I) {
423 if (Deps[I].ImportedModule) {
425 JOS.attribute(
"location", Deps[I].Location.printToString(
SM));
428 Deps[I].ImportedModule->getTopLevelModuleName());
429 JOS.attribute(
"file", Deps[I].
File.getName());
441 if (OutputFile->get_kind() == raw_ostream::OStreamKind::OK_FDStream) {
442 llvm::raw_fd_ostream *FDS =
static_cast<llvm::raw_fd_ostream *
>(OutputFile);
443 if (
auto L = FDS->lock())
449void HeaderIncludesDirectPerFileCallback::InclusionDirective(
450 SourceLocation HashLoc,
const Token &IncludeTok, StringRef
FileName,
452 StringRef SearchPath, StringRef RelativePath,
const Module *SuggestedModule,
457 SourceLocation Loc =
SM.getExpansionLoc(HashLoc);
458 if (
SM.isInSystemHeader(Loc))
464 FileEntryRef HeaderOrModuleMapFile = *
File;
465 if (ModuleImported && SuggestedModule) {
469 HeaderOrModuleMapFile = *ModuleMapFile;
473 HeaderIncludeInfo DependenciesEntry(
474 Loc, HeaderOrModuleMapFile, (ModuleImported ? SuggestedModule :
nullptr));
475 Dependencies[*FromFile].push_back(DependenciesEntry);
478void HeaderIncludesDirectPerFileCallback::moduleImport(SourceLocation ImportLoc,
484 SourceLocation Loc =
SM.getExpansionLoc(ImportLoc);
485 if (
SM.isInSystemHeader(Loc))
496 HeaderIncludeInfo DependenciesEntry(Loc, *ModuleMapFile, Imported);
497 Dependencies[*FromFile].push_back(DependenciesEntry);
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,...
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...