]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / Frontend / HeaderIncludeGen.cpp
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:
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   void FileChanged(SourceLocation Loc, FileChangeReason Reason,
47                    SrcMgr::CharacteristicKind FileType,
48                    FileID PrevFID) override;
49 };
50 }
51
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
79 void clang::AttachHeaderIncludeGen(Preprocessor &PP,
80                                    const DependencyOutputOptions &DepOpts,
81                                    bool ShowAllHeaders, StringRef OutputPath,
82                                    bool ShowDepth, bool MSStyle) {
83   raw_ostream *OutputFile = &llvm::errs();
84   bool OwnsOutputFile = false;
85
86   // Choose output stream, when printing in cl.exe /showIncludes style.
87   if (MSStyle) {
88     switch (DepOpts.ShowIncludesDest) {
89     default:
90       llvm_unreachable("Invalid destination for /showIncludes output!");
91     case ShowIncludesDestination::Stderr:
92       OutputFile = &llvm::errs();
93       break;
94     case ShowIncludesDestination::Stdout:
95       OutputFile = &llvm::outs();
96       break;
97     }
98   }
99
100   // Open the output file, if used.
101   if (!OutputPath.empty()) {
102     std::error_code EC;
103     llvm::raw_fd_ostream *OS = new llvm::raw_fd_ostream(
104         OutputPath.str(), EC, llvm::sys::fs::F_Append | llvm::sys::fs::F_Text);
105     if (EC) {
106       PP.getDiagnostics().Report(clang::diag::warn_fe_cc_print_header_failure)
107           << EC.message();
108       delete OS;
109     } else {
110       OS->SetUnbuffered();
111       OutputFile = OS;
112       OwnsOutputFile = true;
113     }
114   }
115
116   // Print header info for extra headers, pretending they were discovered by
117   // the regular preprocessor. The primary use case is to support proper
118   // generation of Make / Ninja file dependencies for implicit includes, such
119   // as sanitizer blacklists. It's only important for cl.exe compatibility,
120   // the GNU way to generate rules is -M / -MM / -MD / -MMD.
121   for (const auto &Header : DepOpts.ExtraDeps)
122     PrintHeaderInfo(OutputFile, Header, ShowDepth, 2, MSStyle);
123   PP.addPPCallbacks(llvm::make_unique<HeaderIncludesCallback>(
124       &PP, ShowAllHeaders, OutputFile, DepOpts, OwnsOutputFile, ShowDepth,
125       MSStyle));
126 }
127
128 void HeaderIncludesCallback::FileChanged(SourceLocation Loc,
129                                          FileChangeReason Reason,
130                                        SrcMgr::CharacteristicKind NewFileType,
131                                        FileID PrevFID) {
132   // Unless we are exiting a #include, make sure to skip ahead to the line the
133   // #include directive was at.
134   PresumedLoc UserLoc = SM.getPresumedLoc(Loc);
135   if (UserLoc.isInvalid())
136     return;
137
138   // Adjust the current include depth.
139   if (Reason == PPCallbacks::EnterFile) {
140     ++CurrentIncludeDepth;
141   } else if (Reason == PPCallbacks::ExitFile) {
142     if (CurrentIncludeDepth)
143       --CurrentIncludeDepth;
144
145     // We track when we are done with the predefines by watching for the first
146     // place where we drop back to a nesting depth of 1.
147     if (CurrentIncludeDepth == 1 && !HasProcessedPredefines) {
148       if (!DepOpts.ShowIncludesPretendHeader.empty()) {
149         PrintHeaderInfo(OutputFile, DepOpts.ShowIncludesPretendHeader,
150                         ShowDepth, 2, MSStyle);
151       }
152       HasProcessedPredefines = true;
153     }
154
155     return;
156   } else
157     return;
158
159   // Show the header if we are (a) past the predefines, or (b) showing all
160   // headers and in the predefines at a depth past the initial file and command
161   // line buffers.
162   bool ShowHeader = (HasProcessedPredefines ||
163                      (ShowAllHeaders && CurrentIncludeDepth > 2));
164   unsigned IncludeDepth = CurrentIncludeDepth;
165   if (!HasProcessedPredefines)
166     --IncludeDepth; // Ignore indent from <built-in>.
167   else if (!DepOpts.ShowIncludesPretendHeader.empty())
168     ++IncludeDepth; // Pretend inclusion by ShowIncludesPretendHeader.
169
170   // Dump the header include information we are past the predefines buffer or
171   // are showing all headers and this isn't the magic implicit <command line>
172   // header.
173   // FIXME: Identify headers in a more robust way than comparing their name to
174   // "<command line>" and "<built-in>" in a bunch of places.
175   if (ShowHeader && Reason == PPCallbacks::EnterFile &&
176       UserLoc.getFilename() != StringRef("<command line>")) {
177     PrintHeaderInfo(OutputFile, UserLoc.getFilename(), ShowDepth, IncludeDepth,
178                     MSStyle);
179   }
180 }