• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===--- HeaderIncludes.cpp - Generate Header Includes --------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "clang/Frontend/DependencyOutputOptions.h"
11 #include "clang/Frontend/Utils.h"
12 #include "clang/Basic/SourceManager.h"
13 #include "clang/Frontend/FrontendDiagnostic.h"
14 #include "clang/Lex/Preprocessor.h"
15 #include "llvm/ADT/SmallString.h"
16 #include "llvm/Support/raw_ostream.h"
17 using namespace clang;
18 
19 namespace {
20 class 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 
31 public:
HeaderIncludesCallback(const Preprocessor * PP,bool ShowAllHeaders_,raw_ostream * OutputFile_,const DependencyOutputOptions & DepOpts,bool OwnsOutputFile_,bool ShowDepth_,bool MSStyle_)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 
~HeaderIncludesCallback()41   ~HeaderIncludesCallback() override {
42     if (OwnsOutputFile)
43       delete OutputFile;
44   }
45 
46   void FileChanged(SourceLocation Loc, FileChangeReason Reason,
47                    SrcMgr::CharacteristicKind FileType,
48                    FileID PrevFID) override;
49 };
50 }
51 
PrintHeaderInfo(raw_ostream * OutputFile,StringRef Filename,bool ShowDepth,unsigned CurrentIncludeDepth,bool MSStyle)52 static void PrintHeaderInfo(raw_ostream *OutputFile, StringRef Filename,
53                             bool ShowDepth, unsigned CurrentIncludeDepth,
54                             bool MSStyle) {
55   // Write to a temporary string to avoid unnecessary flushing on errs().
56   SmallString<512> Pathname(Filename);
57   if (!MSStyle)
58     Lexer::Stringify(Pathname);
59 
60   SmallString<256> Msg;
61   if (MSStyle)
62     Msg += "Note: including file:";
63 
64   if (ShowDepth) {
65     // The main source file is at depth 1, so skip one dot.
66     for (unsigned i = 1; i != CurrentIncludeDepth; ++i)
67       Msg += MSStyle ? ' ' : '.';
68 
69     if (!MSStyle)
70       Msg += ' ';
71   }
72   Msg += Pathname;
73   Msg += '\n';
74 
75   *OutputFile << Msg;
76   OutputFile->flush();
77 }
78 
AttachHeaderIncludeGen(Preprocessor & PP,const DependencyOutputOptions & DepOpts,bool ShowAllHeaders,StringRef OutputPath,bool ShowDepth,bool MSStyle)79 void clang::AttachHeaderIncludeGen(Preprocessor &PP,
80                                    const DependencyOutputOptions &DepOpts,
81                                    bool ShowAllHeaders, StringRef OutputPath,
82                                    bool ShowDepth, bool MSStyle) {
83   raw_ostream *OutputFile = MSStyle ? &llvm::outs() : &llvm::errs();
84   bool OwnsOutputFile = false;
85 
86   // Open the output file, if used.
87   if (!OutputPath.empty()) {
88     std::error_code EC;
89     llvm::raw_fd_ostream *OS = new llvm::raw_fd_ostream(
90         OutputPath.str(), EC, llvm::sys::fs::F_Append | llvm::sys::fs::F_Text);
91     if (EC) {
92       PP.getDiagnostics().Report(clang::diag::warn_fe_cc_print_header_failure)
93           << EC.message();
94       delete OS;
95     } else {
96       OS->SetUnbuffered();
97       OutputFile = OS;
98       OwnsOutputFile = true;
99     }
100   }
101 
102   // Print header info for extra headers, pretending they were discovered by
103   // the regular preprocessor. The primary use case is to support proper
104   // generation of Make / Ninja file dependencies for implicit includes, such
105   // as sanitizer blacklists. It's only important for cl.exe compatibility,
106   // the GNU way to generate rules is -M / -MM / -MD / -MMD.
107   for (const auto &Header : DepOpts.ExtraDeps)
108     PrintHeaderInfo(OutputFile, Header, ShowDepth, 2, MSStyle);
109   PP.addPPCallbacks(llvm::make_unique<HeaderIncludesCallback>(
110       &PP, ShowAllHeaders, OutputFile, DepOpts, OwnsOutputFile, ShowDepth,
111       MSStyle));
112 }
113 
FileChanged(SourceLocation Loc,FileChangeReason Reason,SrcMgr::CharacteristicKind NewFileType,FileID PrevFID)114 void HeaderIncludesCallback::FileChanged(SourceLocation Loc,
115                                          FileChangeReason Reason,
116                                        SrcMgr::CharacteristicKind NewFileType,
117                                        FileID PrevFID) {
118   // Unless we are exiting a #include, make sure to skip ahead to the line the
119   // #include directive was at.
120   PresumedLoc UserLoc = SM.getPresumedLoc(Loc);
121   if (UserLoc.isInvalid())
122     return;
123 
124   // Adjust the current include depth.
125   if (Reason == PPCallbacks::EnterFile) {
126     ++CurrentIncludeDepth;
127   } else if (Reason == PPCallbacks::ExitFile) {
128     if (CurrentIncludeDepth)
129       --CurrentIncludeDepth;
130 
131     // We track when we are done with the predefines by watching for the first
132     // place where we drop back to a nesting depth of 1.
133     if (CurrentIncludeDepth == 1 && !HasProcessedPredefines) {
134       if (!DepOpts.ShowIncludesPretendHeader.empty()) {
135         PrintHeaderInfo(OutputFile, DepOpts.ShowIncludesPretendHeader,
136                         ShowDepth, 2, MSStyle);
137       }
138       HasProcessedPredefines = true;
139     }
140 
141     return;
142   } else
143     return;
144 
145   // Show the header if we are (a) past the predefines, or (b) showing all
146   // headers and in the predefines at a depth past the initial file and command
147   // line buffers.
148   bool ShowHeader = (HasProcessedPredefines ||
149                      (ShowAllHeaders && CurrentIncludeDepth > 2));
150   unsigned IncludeDepth = CurrentIncludeDepth;
151   if (!HasProcessedPredefines)
152     --IncludeDepth; // Ignore indent from <built-in>.
153   else if (!DepOpts.ShowIncludesPretendHeader.empty())
154     ++IncludeDepth; // Pretend inclusion by ShowIncludesPretendHeader.
155 
156   // Dump the header include information we are past the predefines buffer or
157   // are showing all headers and this isn't the magic implicit <command line>
158   // header.
159   // FIXME: Identify headers in a more robust way than comparing their name to
160   // "<command line>" and "<built-in>" in a bunch of places.
161   if (ShowHeader && Reason == PPCallbacks::EnterFile &&
162       UserLoc.getFilename() != StringRef("<command line>")) {
163     PrintHeaderInfo(OutputFile, UserLoc.getFilename(), ShowDepth, IncludeDepth,
164                     MSStyle);
165   }
166 }
167