clang: lib/Frontend/HeaderIncludeGen.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

14#include "llvm/ADT/SmallString.h"

15#include "llvm/Support/JSON.h"

16#include "llvm/Support/raw_ostream.h"

17using namespace clang;

18

19namespace {

20class HeaderIncludesCallback : public PPCallbacks {

21 SourceManager &SM;

22 raw_ostream *OutputFile;

23 const DependencyOutputOptions &DepOpts;

24 unsigned CurrentIncludeDepth;

25 bool HasProcessedPredefines;

26 bool OwnsOutputFile;

27 bool ShowAllHeaders;

28 bool ShowDepth;

29 bool MSStyle;

30

31public:

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_) {}

40

41 ~HeaderIncludesCallback() override {

42 if (OwnsOutputFile)

43 delete OutputFile;

44 }

45

46 HeaderIncludesCallback(const HeaderIncludesCallback &) = delete;

47 HeaderIncludesCallback &operator=(const HeaderIncludesCallback &) = delete;

48

49 void FileChanged(SourceLocation Loc, FileChangeReason Reason,

51 FileID PrevFID) override;

52

53 void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok,

55

56private:

58 if (!DepOpts.IncludeSystemHeaders && isSystem(HeaderType))

59 return false;

60

61

62

63

64 return (HasProcessedPredefines ||

65 (ShowAllHeaders && CurrentIncludeDepth > 2));

66 }

67};

68

69

70

71

72

73

74

75

76

77

78

79class HeaderIncludesJSONCallback : public PPCallbacks {

80 SourceManager &SM;

81 raw_ostream *OutputFile;

82 bool OwnsOutputFile;

83 SmallVector<std::string, 16> IncludedHeaders;

84

85public:

86 HeaderIncludesJSONCallback(const Preprocessor *PP, raw_ostream *OutputFile_,

87 bool OwnsOutputFile_)

88 : SM(PP->getSourceManager()), OutputFile(OutputFile_),

89 OwnsOutputFile(OwnsOutputFile_) {}

90

91 ~HeaderIncludesJSONCallback() override {

92 if (OwnsOutputFile)

93 delete OutputFile;

94 }

95

96 HeaderIncludesJSONCallback(const HeaderIncludesJSONCallback &) = delete;

97 HeaderIncludesJSONCallback &

98 operator=(const HeaderIncludesJSONCallback &) = delete;

99

100 void EndOfMainFile() override;

101

102 void FileChanged(SourceLocation Loc, FileChangeReason Reason,

104 FileID PrevFID) override;

105

106 void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok,

108};

109

110

111

112

113

114class HeaderIncludesDirectPerFileCallback : public PPCallbacks {

115 struct HeaderIncludeInfo {

116 SourceLocation Location;

117 FileEntryRef File;

118 const Module *ImportedModule;

119

120 HeaderIncludeInfo(SourceLocation Location, FileEntryRef File,

121 const Module *ImportedModule)

122 : Location(Location), File(File), ImportedModule(ImportedModule) {}

123 };

124

125 SourceManager &SM;

127 raw_ostream *OutputFile;

128 bool OwnsOutputFile;

129 using DependencyMap =

130 llvm::DenseMap<FileEntryRef, SmallVector>;

131 DependencyMap Dependencies;

132

133public:

134 HeaderIncludesDirectPerFileCallback(const Preprocessor *PP,

135 raw_ostream *OutputFile_,

136 bool OwnsOutputFile_)

137 : SM(PP->getSourceManager()), HSI(PP->getHeaderSearchInfo()),

138 OutputFile(OutputFile_), OwnsOutputFile(OwnsOutputFile_) {}

139

140 ~HeaderIncludesDirectPerFileCallback() override {

141 if (OwnsOutputFile)

142 delete OutputFile;

143 }

144

145 HeaderIncludesDirectPerFileCallback(

146 const HeaderIncludesDirectPerFileCallback &) = delete;

147 HeaderIncludesDirectPerFileCallback &

148 operator=(const HeaderIncludesDirectPerFileCallback &) = delete;

149

150 void EndOfMainFile() override;

151

152 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,

153 StringRef FileName, bool IsAngled,

154 CharSourceRange FilenameRange,

156 StringRef RelativePath, const Module *SuggestedModule,

157 bool ModuleImported,

159

160 void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path,

161 const Module *Imported) override;

162};

163}

164

165static void PrintHeaderInfo(raw_ostream *OutputFile, StringRef Filename,

166 bool ShowDepth, unsigned CurrentIncludeDepth,

167 bool MSStyle) {

168

170 if (!MSStyle)

172

174 if (MSStyle)

175 Msg += "Note: including file:";

176

177 if (ShowDepth) {

178

179 for (unsigned i = 1; i != CurrentIncludeDepth; ++i)

180 Msg += MSStyle ? ' ' : '.';

181

182 if (!MSStyle)

183 Msg += ' ';

184 }

185 Msg += Pathname;

186 Msg += '\n';

187

188 *OutputFile << Msg;

189 OutputFile->flush();

190}

191

194 bool ShowAllHeaders, StringRef OutputPath,

195 bool ShowDepth, bool MSStyle) {

196 raw_ostream *OutputFile = &llvm::errs();

197 bool OwnsOutputFile = false;

198

199

200 if (MSStyle) {

202 default:

203 llvm_unreachable("Invalid destination for /showIncludes output!");

205 OutputFile = &llvm::errs();

206 break;

208 OutputFile = &llvm::outs();

209 break;

210 }

211 }

212

213

214 if (!OutputPath.empty()) {

215 std::error_code EC;

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);

219 if (EC) {

221 << EC.message();

222 delete OS;

223 } else {

224 OS->SetUnbuffered();

225 OutputFile = OS;

226 OwnsOutputFile = true;

227 }

228 }

229

232 llvm_unreachable("unexpected header format kind");

235 "header filtering is currently always disabled when output format is"

236 "textual");

237

238

239

240

241

242 for (const auto &Header : DepOpts.ExtraDeps)

243 PrintHeaderInfo(OutputFile, Header.first, ShowDepth, 2, MSStyle);

244 PP.addPPCallbacks(std::make_unique(

245 &PP, ShowAllHeaders, OutputFile, DepOpts, OwnsOutputFile, ShowDepth,

246 MSStyle));

247 break;

248 }

251 default:

252 llvm_unreachable("Unknown HeaderIncludeFilteringKind enum");

254 PP.addPPCallbacks(std::make_unique(

255 &PP, OutputFile, OwnsOutputFile));

256 break;

258 PP.addPPCallbacks(std::make_unique(

259 &PP, OutputFile, OwnsOutputFile));

260 break;

261 }

262 break;

263 }

264}

265

266void HeaderIncludesCallback::FileChanged(SourceLocation Loc,

267 FileChangeReason Reason,

270

271

274 return;

275

276

278 ++CurrentIncludeDepth;

280 if (CurrentIncludeDepth)

281 --CurrentIncludeDepth;

282

283

284

285 if (CurrentIncludeDepth == 1 && !HasProcessedPredefines)

286 HasProcessedPredefines = true;

287

288 return;

289 } else {

290 return;

291 }

292

293 if (!ShouldShowHeader(NewFileType))

294 return;

295

296 unsigned IncludeDepth = CurrentIncludeDepth;

297 if (!HasProcessedPredefines)

298 --IncludeDepth;

299

300

301

303 UserLoc.getFilename() != StringRef("")) {

305 MSStyle);

306 }

307}

308

309void HeaderIncludesCallback::FileSkipped(const FileEntryRef &SkippedFile,

310 const Token &FilenameTok,

313 return;

314

315 if (!ShouldShowHeader(FileType))

316 return;

317

319 CurrentIncludeDepth + 1, MSStyle);

320}

321

322void HeaderIncludesJSONCallback::EndOfMainFile() {

324 SmallString<256> MainFile;

325 if (FE) {

326 MainFile += FE->getName();

327 SM.getFileManager().makeAbsolutePath(MainFile);

328 }

329

330 std::string Str;

331 llvm::raw_string_ostream OS(Str);

332 llvm::json::OStream JOS(OS);

333 JOS.object([&] {

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)

339 JOS.value(H);

340 });

341 });

342 OS << "\n";

343

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())

347 *OutputFile << Str;

348 } else

349 *OutputFile << Str;

350}

351

352

353

354

359

360void HeaderIncludesJSONCallback::FileChanged(

361 SourceLocation Loc, FileChangeReason Reason,

365 return;

366

367

368

369 PresumedLoc UserLoc = SM.getPresumedLoc(Loc);

371 return;

372

374 UserLoc.getFilename() != StringRef(""))

375 IncludedHeaders.push_back(UserLoc.getFilename());

376}

377

378void HeaderIncludesJSONCallback::FileSkipped(

379 const FileEntryRef &SkippedFile, const Token &FilenameTok,

382 return;

383

384 IncludedHeaders.push_back(SkippedFile.getName().str());

385}

386

387void HeaderIncludesDirectPerFileCallback::EndOfMainFile() {

388 if (Dependencies.empty())

389 return;

390

391

392 SmallVector SourceFiles;

393 for (auto F = Dependencies.begin(), FEnd = Dependencies.end(); F != FEnd;

394 ++F) {

395 SourceFiles.push_back(F->first);

396 }

397 llvm::sort(SourceFiles, [](const FileEntryRef &LHS, const FileEntryRef &RHS) {

399 });

400

401 std::string Str;

402 llvm::raw_string_ostream OS(Str);

403 llvm::json::OStream JOS(OS);

404 JOS.object([&] {

405 JOS.attribute("version", "2.0.0");

406 JOS.attributeArray("dependencies", [&] {

407 for (const auto &S : SourceFiles) {

408 JOS.object([&] {

409 SmallVector &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) {

414 JOS.object([&] {

415 JOS.attribute("location", Deps[I].Location.printToString(SM));

416 JOS.attribute("file", Deps[I].File.getName());

417 });

418 }

419 }

420 });

421 JOS.attributeArray("imports", [&] {

422 for (unsigned I = 0, N = Deps.size(); I != N; ++I) {

423 if (Deps[I].ImportedModule) {

424 JOS.object([&] {

425 JOS.attribute("location", Deps[I].Location.printToString(SM));

426 JOS.attribute(

427 "module",

428 Deps[I].ImportedModule->getTopLevelModuleName());

429 JOS.attribute("file", Deps[I].File.getName());

430 });

431 }

432 }

433 });

434 });

435 }

436 });

437 });

438

439 OS << "\n";

440

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())

444 *OutputFile << Str;

445 } else

446 *OutputFile << Str;

447}

448

449void HeaderIncludesDirectPerFileCallback::InclusionDirective(

450 SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,

452 StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,

455 return;

456

457 SourceLocation Loc = SM.getExpansionLoc(HashLoc);

458 if (SM.isInSystemHeader(Loc))

459 return;

461 if (!FromFile)

462 return;

463

464 FileEntryRef HeaderOrModuleMapFile = *File;

465 if (ModuleImported && SuggestedModule) {

468 if (ModuleMapFile) {

469 HeaderOrModuleMapFile = *ModuleMapFile;

470 }

471 }

472

473 HeaderIncludeInfo DependenciesEntry(

474 Loc, HeaderOrModuleMapFile, (ModuleImported ? SuggestedModule : nullptr));

475 Dependencies[*FromFile].push_back(DependenciesEntry);

476}

477

478void HeaderIncludesDirectPerFileCallback::moduleImport(SourceLocation ImportLoc,

480 const Module *Imported) {

481 if (!Imported)

482 return;

483

484 SourceLocation Loc = SM.getExpansionLoc(ImportLoc);

485 if (SM.isInSystemHeader(Loc))

486 return;

488 if (!FromFile)

489 return;

490

493 if (!ModuleMapFile)

494 return;

495

496 HeaderIncludeInfo DependenciesEntry(Loc, *ModuleMapFile, Imported);

497 Dependencies[*FromFile].push_back(DependenciesEntry);

498}

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.

@ HeaderSearch

Remove unused header search paths including header maps.

@ 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...

Definition HeaderIncludeGen.cpp:192