1eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar//===--- HeaderIncludes.cpp - Generate Header Includes --------------------===//
2eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar//
3eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar//                     The LLVM Compiler Infrastructure
4eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar//
5eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar// This file is distributed under the University of Illinois Open Source
6eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar// License. See LICENSE.TXT for details.
7eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar//
8eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar//===----------------------------------------------------------------------===//
9eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar
10eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar#include "clang/Frontend/Utils.h"
11eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar#include "clang/Basic/SourceManager.h"
12f704c61b3c88659a0c9946ea26d1bbff99803792Daniel Dunbar#include "clang/Frontend/FrontendDiagnostic.h"
13eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar#include "clang/Lex/Preprocessor.h"
148fe83e1df954d72c0f4ffc15d20a5222ec151c21Benjamin Kramer#include "llvm/ADT/SmallString.h"
15f704c61b3c88659a0c9946ea26d1bbff99803792Daniel Dunbar#include "llvm/Support/raw_ostream.h"
16eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbarusing namespace clang;
17eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar
18eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbarnamespace {
19eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbarclass HeaderIncludesCallback : public PPCallbacks {
20eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar  SourceManager &SM;
215f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  raw_ostream *OutputFile;
22eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar  unsigned CurrentIncludeDepth;
23eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar  bool HasProcessedPredefines;
24b34d69b9292534c1c574f168f0ac10aea652adcaDaniel Dunbar  bool OwnsOutputFile;
25b34d69b9292534c1c574f168f0ac10aea652adcaDaniel Dunbar  bool ShowAllHeaders;
26da60885cb4ee85d167cf704061f10b758067cf5aDaniel Dunbar  bool ShowDepth;
27708002ede3938256a6223d153a0c040f7a40f5ccHans Wennborg  bool MSStyle;
28eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar
29eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbarpublic:
30b34d69b9292534c1c574f168f0ac10aea652adcaDaniel Dunbar  HeaderIncludesCallback(const Preprocessor *PP, bool ShowAllHeaders_,
315f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner                         raw_ostream *OutputFile_, bool OwnsOutputFile_,
32708002ede3938256a6223d153a0c040f7a40f5ccHans Wennborg                         bool ShowDepth_, bool MSStyle_)
33b34d69b9292534c1c574f168f0ac10aea652adcaDaniel Dunbar    : SM(PP->getSourceManager()), OutputFile(OutputFile_),
34b34d69b9292534c1c574f168f0ac10aea652adcaDaniel Dunbar      CurrentIncludeDepth(0), HasProcessedPredefines(false),
35da60885cb4ee85d167cf704061f10b758067cf5aDaniel Dunbar      OwnsOutputFile(OwnsOutputFile_), ShowAllHeaders(ShowAllHeaders_),
36708002ede3938256a6223d153a0c040f7a40f5ccHans Wennborg      ShowDepth(ShowDepth_), MSStyle(MSStyle_) {}
37b34d69b9292534c1c574f168f0ac10aea652adcaDaniel Dunbar
38b34d69b9292534c1c574f168f0ac10aea652adcaDaniel Dunbar  ~HeaderIncludesCallback() {
39b34d69b9292534c1c574f168f0ac10aea652adcaDaniel Dunbar    if (OwnsOutputFile)
40f704c61b3c88659a0c9946ea26d1bbff99803792Daniel Dunbar      delete OutputFile;
41b34d69b9292534c1c574f168f0ac10aea652adcaDaniel Dunbar  }
42eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar
43651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  void FileChanged(SourceLocation Loc, FileChangeReason Reason,
44651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                   SrcMgr::CharacteristicKind FileType,
45651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                   FileID PrevFID) override;
46eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar};
47eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar}
48eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar
49b376e5e71aa3e608c0481a9a7facb5d8b29d3163Daniel Dunbarvoid clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders,
50708002ede3938256a6223d153a0c040f7a40f5ccHans Wennborg                                   StringRef OutputPath, bool ShowDepth,
51708002ede3938256a6223d153a0c040f7a40f5ccHans Wennborg                                   bool MSStyle) {
52ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  raw_ostream *OutputFile = MSStyle ? &llvm::outs() : &llvm::errs();
53f704c61b3c88659a0c9946ea26d1bbff99803792Daniel Dunbar  bool OwnsOutputFile = false;
54b34d69b9292534c1c574f168f0ac10aea652adcaDaniel Dunbar
55b34d69b9292534c1c574f168f0ac10aea652adcaDaniel Dunbar  // Open the output file, if used.
56f704c61b3c88659a0c9946ea26d1bbff99803792Daniel Dunbar  if (!OutputPath.empty()) {
57f704c61b3c88659a0c9946ea26d1bbff99803792Daniel Dunbar    std::string Error;
58f704c61b3c88659a0c9946ea26d1bbff99803792Daniel Dunbar    llvm::raw_fd_ostream *OS = new llvm::raw_fd_ostream(
59651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        OutputPath.str().c_str(), Error,
60651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        llvm::sys::fs::F_Append | llvm::sys::fs::F_Text);
61f704c61b3c88659a0c9946ea26d1bbff99803792Daniel Dunbar    if (!Error.empty()) {
62f704c61b3c88659a0c9946ea26d1bbff99803792Daniel Dunbar      PP.getDiagnostics().Report(
63f704c61b3c88659a0c9946ea26d1bbff99803792Daniel Dunbar        clang::diag::warn_fe_cc_print_header_failure) << Error;
64f704c61b3c88659a0c9946ea26d1bbff99803792Daniel Dunbar      delete OS;
65f704c61b3c88659a0c9946ea26d1bbff99803792Daniel Dunbar    } else {
66f704c61b3c88659a0c9946ea26d1bbff99803792Daniel Dunbar      OS->SetUnbuffered();
67f704c61b3c88659a0c9946ea26d1bbff99803792Daniel Dunbar      OS->SetUseAtomicWrites(true);
68f704c61b3c88659a0c9946ea26d1bbff99803792Daniel Dunbar      OutputFile = OS;
69f704c61b3c88659a0c9946ea26d1bbff99803792Daniel Dunbar      OwnsOutputFile = true;
70f704c61b3c88659a0c9946ea26d1bbff99803792Daniel Dunbar    }
71b34d69b9292534c1c574f168f0ac10aea652adcaDaniel Dunbar  }
72b34d69b9292534c1c574f168f0ac10aea652adcaDaniel Dunbar
73b34d69b9292534c1c574f168f0ac10aea652adcaDaniel Dunbar  PP.addPPCallbacks(new HeaderIncludesCallback(&PP, ShowAllHeaders,
74da60885cb4ee85d167cf704061f10b758067cf5aDaniel Dunbar                                               OutputFile, OwnsOutputFile,
75708002ede3938256a6223d153a0c040f7a40f5ccHans Wennborg                                               ShowDepth, MSStyle));
76eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar}
77eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar
78eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbarvoid HeaderIncludesCallback::FileChanged(SourceLocation Loc,
79eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar                                         FileChangeReason Reason,
80c892c5fa92db137ff68d95afb13fe969d17f4fb2Argyrios Kyrtzidis                                       SrcMgr::CharacteristicKind NewFileType,
81c892c5fa92db137ff68d95afb13fe969d17f4fb2Argyrios Kyrtzidis                                       FileID PrevFID) {
82eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar  // Unless we are exiting a #include, make sure to skip ahead to the line the
83eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar  // #include directive was at.
84eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar  PresumedLoc UserLoc = SM.getPresumedLoc(Loc);
85eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar  if (UserLoc.isInvalid())
86eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar    return;
87b34d69b9292534c1c574f168f0ac10aea652adcaDaniel Dunbar
88eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar  // Adjust the current include depth.
89eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar  if (Reason == PPCallbacks::EnterFile) {
90eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar    ++CurrentIncludeDepth;
914dddebfef924be24de74b8bdf722a5cff3f3333fSebastian Redl  } else if (Reason == PPCallbacks::ExitFile) {
92eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar    if (CurrentIncludeDepth)
93eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar      --CurrentIncludeDepth;
94eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar
95eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar    // We track when we are done with the predefines by watching for the first
964dddebfef924be24de74b8bdf722a5cff3f3333fSebastian Redl    // place where we drop back to a nesting depth of 1.
974dddebfef924be24de74b8bdf722a5cff3f3333fSebastian Redl    if (CurrentIncludeDepth == 1 && !HasProcessedPredefines)
98eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar      HasProcessedPredefines = true;
994dddebfef924be24de74b8bdf722a5cff3f3333fSebastian Redl
1004dddebfef924be24de74b8bdf722a5cff3f3333fSebastian Redl    return;
1014dddebfef924be24de74b8bdf722a5cff3f3333fSebastian Redl  } else
1024dddebfef924be24de74b8bdf722a5cff3f3333fSebastian Redl    return;
103b376e5e71aa3e608c0481a9a7facb5d8b29d3163Daniel Dunbar
104b376e5e71aa3e608c0481a9a7facb5d8b29d3163Daniel Dunbar  // Show the header if we are (a) past the predefines, or (b) showing all
105b376e5e71aa3e608c0481a9a7facb5d8b29d3163Daniel Dunbar  // headers and in the predefines at a depth past the initial file and command
106b376e5e71aa3e608c0481a9a7facb5d8b29d3163Daniel Dunbar  // line buffers.
107b376e5e71aa3e608c0481a9a7facb5d8b29d3163Daniel Dunbar  bool ShowHeader = (HasProcessedPredefines ||
108b376e5e71aa3e608c0481a9a7facb5d8b29d3163Daniel Dunbar                     (ShowAllHeaders && CurrentIncludeDepth > 2));
109b376e5e71aa3e608c0481a9a7facb5d8b29d3163Daniel Dunbar
110b376e5e71aa3e608c0481a9a7facb5d8b29d3163Daniel Dunbar  // Dump the header include information we are past the predefines buffer or
111b376e5e71aa3e608c0481a9a7facb5d8b29d3163Daniel Dunbar  // are showing all headers.
112b376e5e71aa3e608c0481a9a7facb5d8b29d3163Daniel Dunbar  if (ShowHeader && Reason == PPCallbacks::EnterFile) {
113eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar    // Write to a temporary string to avoid unnecessary flushing on errs().
114f7ccbad5d9949e7ddd1cbef43d482553b811e026Dylan Noblesmith    SmallString<512> Filename(UserLoc.getFilename());
115708002ede3938256a6223d153a0c040f7a40f5ccHans Wennborg    if (!MSStyle)
116708002ede3938256a6223d153a0c040f7a40f5ccHans Wennborg      Lexer::Stringify(Filename);
117eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar
118f7ccbad5d9949e7ddd1cbef43d482553b811e026Dylan Noblesmith    SmallString<256> Msg;
119708002ede3938256a6223d153a0c040f7a40f5ccHans Wennborg    if (MSStyle)
120708002ede3938256a6223d153a0c040f7a40f5ccHans Wennborg      Msg += "Note: including file:";
121708002ede3938256a6223d153a0c040f7a40f5ccHans Wennborg
122da60885cb4ee85d167cf704061f10b758067cf5aDaniel Dunbar    if (ShowDepth) {
1234dddebfef924be24de74b8bdf722a5cff3f3333fSebastian Redl      // The main source file is at depth 1, so skip one dot.
1244dddebfef924be24de74b8bdf722a5cff3f3333fSebastian Redl      for (unsigned i = 1; i != CurrentIncludeDepth; ++i)
125708002ede3938256a6223d153a0c040f7a40f5ccHans Wennborg        Msg += MSStyle ? ' ' : '.';
126708002ede3938256a6223d153a0c040f7a40f5ccHans Wennborg
127708002ede3938256a6223d153a0c040f7a40f5ccHans Wennborg      if (!MSStyle)
128708002ede3938256a6223d153a0c040f7a40f5ccHans Wennborg        Msg += ' ';
129da60885cb4ee85d167cf704061f10b758067cf5aDaniel Dunbar    }
130eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar    Msg += Filename;
131eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar    Msg += '\n';
132eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar
133f704c61b3c88659a0c9946ea26d1bbff99803792Daniel Dunbar    OutputFile->write(Msg.data(), Msg.size());
134eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar  }
135eef63e0997e0f6d6436736ea919b851cfe34955aDaniel Dunbar}
136