1 //===--- HeaderIncludes.cpp - Generate Header Includes --------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "clang/Frontend/Utils.h"
11 #include "clang/Basic/SourceManager.h"
12 #include "clang/Frontend/FrontendDiagnostic.h"
13 #include "clang/Lex/Preprocessor.h"
14 #include "llvm/ADT/SmallString.h"
15 #include "llvm/Support/raw_ostream.h"
16 using namespace clang
;
19 class HeaderIncludesCallback
: public PPCallbacks
{
21 raw_ostream
*OutputFile
;
22 unsigned CurrentIncludeDepth
;
23 bool HasProcessedPredefines
;
29 HeaderIncludesCallback(const Preprocessor
*PP
, bool ShowAllHeaders_
,
30 raw_ostream
*OutputFile_
, bool OwnsOutputFile_
,
32 : SM(PP
->getSourceManager()), OutputFile(OutputFile_
),
33 CurrentIncludeDepth(0), HasProcessedPredefines(false),
34 OwnsOutputFile(OwnsOutputFile_
), ShowAllHeaders(ShowAllHeaders_
),
35 ShowDepth(ShowDepth_
) {}
37 ~HeaderIncludesCallback() {
42 virtual void FileChanged(SourceLocation Loc
, FileChangeReason Reason
,
43 SrcMgr::CharacteristicKind FileType
,
48 void clang::AttachHeaderIncludeGen(Preprocessor
&PP
, bool ShowAllHeaders
,
49 StringRef OutputPath
, bool ShowDepth
) {
50 raw_ostream
*OutputFile
= &llvm::errs();
51 bool OwnsOutputFile
= false;
53 // Open the output file, if used.
54 if (!OutputPath
.empty()) {
56 llvm::raw_fd_ostream
*OS
= new llvm::raw_fd_ostream(
57 OutputPath
.str().c_str(), Error
, llvm::raw_fd_ostream::F_Append
);
59 PP
.getDiagnostics().Report(
60 clang::diag::warn_fe_cc_print_header_failure
) << Error
;
64 OS
->SetUseAtomicWrites(true);
66 OwnsOutputFile
= true;
70 PP
.addPPCallbacks(new HeaderIncludesCallback(&PP
, ShowAllHeaders
,
71 OutputFile
, OwnsOutputFile
,
75 void HeaderIncludesCallback::FileChanged(SourceLocation Loc
,
76 FileChangeReason Reason
,
77 SrcMgr::CharacteristicKind NewFileType
,
79 // Unless we are exiting a #include, make sure to skip ahead to the line the
80 // #include directive was at.
81 PresumedLoc UserLoc
= SM
.getPresumedLoc(Loc
);
82 if (UserLoc
.isInvalid())
85 // Adjust the current include depth.
86 if (Reason
== PPCallbacks::EnterFile
) {
87 ++CurrentIncludeDepth
;
88 } else if (Reason
== PPCallbacks::ExitFile
) {
89 if (CurrentIncludeDepth
)
90 --CurrentIncludeDepth
;
92 // We track when we are done with the predefines by watching for the first
93 // place where we drop back to a nesting depth of 1.
94 if (CurrentIncludeDepth
== 1 && !HasProcessedPredefines
)
95 HasProcessedPredefines
= true;
101 // Show the header if we are (a) past the predefines, or (b) showing all
102 // headers and in the predefines at a depth past the initial file and command
104 bool ShowHeader
= (HasProcessedPredefines
||
105 (ShowAllHeaders
&& CurrentIncludeDepth
> 2));
107 // Dump the header include information we are past the predefines buffer or
108 // are showing all headers.
109 if (ShowHeader
&& Reason
== PPCallbacks::EnterFile
) {
110 // Write to a temporary string to avoid unnecessary flushing on errs().
111 SmallString
<512> Filename(UserLoc
.getFilename());
112 Lexer::Stringify(Filename
);
114 SmallString
<256> Msg
;
116 // The main source file is at depth 1, so skip one dot.
117 for (unsigned i
= 1; i
!= CurrentIncludeDepth
; ++i
)
124 OutputFile
->write(Msg
.data(), Msg
.size());