@@ -106,6 +106,49 @@ class HeaderIncludesJSONCallback : public PPCallbacks {
106
106
void FileSkipped (const FileEntryRef &SkippedFile, const Token &FilenameTok,
107
107
SrcMgr::CharacteristicKind FileType) override ;
108
108
};
109
+
110
+ // / A callback for emitting direct header and module usage information to a
111
+ // / file in JSON. The output format is like HeaderIncludesJSONCallback but has
112
+ // / an array of separate entries, one for each non-system source file used in
113
+ // / the compilation showing only the direct includes and imports from that file.
114
+ class HeaderIncludesDirectPerFileCallback : public PPCallbacks {
115
+ SourceManager &SM;
116
+ HeaderSearch &HSI;
117
+ raw_ostream *OutputFile;
118
+ bool OwnsOutputFile;
119
+ using DependencyMap = llvm::DenseMap<FileEntryRef, SmallVector<FileEntryRef>>;
120
+ DependencyMap Dependencies;
121
+
122
+ public:
123
+ HeaderIncludesDirectPerFileCallback (const Preprocessor *PP,
124
+ raw_ostream *OutputFile_,
125
+ bool OwnsOutputFile_)
126
+ : SM(PP->getSourceManager ()), HSI(PP->getHeaderSearchInfo ()),
127
+ OutputFile(OutputFile_), OwnsOutputFile(OwnsOutputFile_) {}
128
+
129
+ ~HeaderIncludesDirectPerFileCallback () override {
130
+ if (OwnsOutputFile)
131
+ delete OutputFile;
132
+ }
133
+
134
+ HeaderIncludesDirectPerFileCallback (
135
+ const HeaderIncludesDirectPerFileCallback &) = delete;
136
+ HeaderIncludesDirectPerFileCallback &
137
+ operator =(const HeaderIncludesDirectPerFileCallback &) = delete;
138
+
139
+ void EndOfMainFile () override ;
140
+
141
+ void InclusionDirective (SourceLocation HashLoc, const Token &IncludeTok,
142
+ StringRef FileName, bool IsAngled,
143
+ CharSourceRange FilenameRange,
144
+ OptionalFileEntryRef File, StringRef SearchPath,
145
+ StringRef RelativePath, const Module *SuggestedModule,
146
+ bool ModuleImported,
147
+ SrcMgr::CharacteristicKind FileType) override ;
148
+
149
+ void moduleImport (SourceLocation ImportLoc, ModuleIdPath Path,
150
+ const Module *Imported) override ;
151
+ };
109
152
}
110
153
111
154
static void PrintHeaderInfo (raw_ostream *OutputFile, StringRef Filename,
@@ -192,14 +235,21 @@ void clang::AttachHeaderIncludeGen(Preprocessor &PP,
192
235
MSStyle));
193
236
break ;
194
237
}
195
- case HIFMT_JSON: {
196
- assert (DepOpts.HeaderIncludeFiltering == HIFIL_Only_Direct_System &&
197
- " only-direct-system is the only option for filtering" );
198
- PP.addPPCallbacks (std::make_unique<HeaderIncludesJSONCallback>(
199
- &PP, OutputFile, OwnsOutputFile));
238
+ case HIFMT_JSON:
239
+ switch (DepOpts.HeaderIncludeFiltering ) {
240
+ default :
241
+ llvm_unreachable (" Unknown HeaderIncludeFilteringKind enum" );
242
+ case HIFIL_Only_Direct_System:
243
+ PP.addPPCallbacks (std::make_unique<HeaderIncludesJSONCallback>(
244
+ &PP, OutputFile, OwnsOutputFile));
245
+ break ;
246
+ case HIFIL_Direct_Per_File:
247
+ PP.addPPCallbacks (std::make_unique<HeaderIncludesDirectPerFileCallback>(
248
+ &PP, OutputFile, OwnsOutputFile));
249
+ break ;
250
+ }
200
251
break ;
201
252
}
202
- }
203
253
}
204
254
205
255
void HeaderIncludesCallback::FileChanged (SourceLocation Loc,
@@ -322,3 +372,81 @@ void HeaderIncludesJSONCallback::FileSkipped(
322
372
323
373
IncludedHeaders.push_back (SkippedFile.getName ().str ());
324
374
}
375
+
376
+ void HeaderIncludesDirectPerFileCallback::EndOfMainFile () {
377
+ if (Dependencies.empty ())
378
+ return ;
379
+
380
+ // Sort the files so that the output does not depend on the DenseMap order.
381
+ SmallVector<FileEntryRef> SourceFiles;
382
+ for (auto F = Dependencies.begin (), FEnd = Dependencies.end (); F != FEnd;
383
+ ++F) {
384
+ SourceFiles.push_back (F->first );
385
+ }
386
+ llvm::sort (SourceFiles, [](const FileEntryRef &LHS, const FileEntryRef &RHS) {
387
+ return LHS.getUID () < RHS.getUID ();
388
+ });
389
+
390
+ std::string Str;
391
+ llvm::raw_string_ostream OS (Str);
392
+ llvm::json::OStream JOS (OS);
393
+ JOS.array ([&] {
394
+ for (auto S = SourceFiles.begin (), SE = SourceFiles.end (); S != SE; ++S) {
395
+ JOS.object ([&] {
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 ());
401
+ });
402
+ });
403
+ }
404
+ });
405
+ OS << " \n " ;
406
+
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 ())
410
+ *OutputFile << Str;
411
+ } else
412
+ *OutputFile << Str;
413
+ }
414
+
415
+ void HeaderIncludesDirectPerFileCallback::InclusionDirective (
416
+ SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
417
+ bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
418
+ StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
419
+ bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
420
+ if (!File)
421
+ return ;
422
+
423
+ SourceLocation Loc = SM.getExpansionLoc (HashLoc);
424
+ if (SM.isInSystemHeader (Loc))
425
+ return ;
426
+ OptionalFileEntryRef FromFile = SM.getFileEntryRefForID (SM.getFileID (Loc));
427
+ if (!FromFile)
428
+ return ;
429
+
430
+ Dependencies[*FromFile].push_back (*File);
431
+ }
432
+
433
+ void HeaderIncludesDirectPerFileCallback::moduleImport (SourceLocation ImportLoc,
434
+ ModuleIdPath Path,
435
+ const Module *Imported) {
436
+ if (!Imported)
437
+ return ;
438
+
439
+ SourceLocation Loc = SM.getExpansionLoc (ImportLoc);
440
+ if (SM.isInSystemHeader (Loc))
441
+ return ;
442
+ OptionalFileEntryRef FromFile = SM.getFileEntryRefForID (SM.getFileID (Loc));
443
+ if (!FromFile)
444
+ return ;
445
+
446
+ OptionalFileEntryRef ModuleMapFile =
447
+ HSI.getModuleMap ().getModuleMapFileForUniquing (Imported);
448
+ if (!ModuleMapFile)
449
+ return ;
450
+
451
+ Dependencies[*FromFile].push_back (*ModuleMapFile);
452
+ }
0 commit comments