clang API Documentation

HeaderIncludeGen.cpp
Go to the documentation of this file.
00001 //===--- HeaderIncludes.cpp - Generate Header Includes --------------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 
00010 #include "clang/Frontend/Utils.h"
00011 #include "clang/Basic/SourceManager.h"
00012 #include "clang/Frontend/FrontendDiagnostic.h"
00013 #include "clang/Lex/Preprocessor.h"
00014 #include "llvm/ADT/SmallString.h"
00015 #include "llvm/Support/raw_ostream.h"
00016 using namespace clang;
00017 
00018 namespace {
00019 class HeaderIncludesCallback : public PPCallbacks {
00020   SourceManager &SM;
00021   raw_ostream *OutputFile;
00022   unsigned CurrentIncludeDepth;
00023   bool HasProcessedPredefines;
00024   bool OwnsOutputFile;
00025   bool ShowAllHeaders;
00026   bool ShowDepth;
00027   bool MSStyle;
00028 
00029 public:
00030   HeaderIncludesCallback(const Preprocessor *PP, bool ShowAllHeaders_,
00031                          raw_ostream *OutputFile_, bool OwnsOutputFile_,
00032                          bool ShowDepth_, bool MSStyle_)
00033     : SM(PP->getSourceManager()), OutputFile(OutputFile_),
00034       CurrentIncludeDepth(0), HasProcessedPredefines(false),
00035       OwnsOutputFile(OwnsOutputFile_), ShowAllHeaders(ShowAllHeaders_),
00036       ShowDepth(ShowDepth_), MSStyle(MSStyle_) {}
00037 
00038   ~HeaderIncludesCallback() {
00039     if (OwnsOutputFile)
00040       delete OutputFile;
00041   }
00042 
00043   void FileChanged(SourceLocation Loc, FileChangeReason Reason,
00044                    SrcMgr::CharacteristicKind FileType,
00045                    FileID PrevFID) override;
00046 };
00047 }
00048 
00049 void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders,
00050                                    StringRef OutputPath, bool ShowDepth,
00051                                    bool MSStyle) {
00052   raw_ostream *OutputFile = MSStyle ? &llvm::outs() : &llvm::errs();
00053   bool OwnsOutputFile = false;
00054 
00055   // Open the output file, if used.
00056   if (!OutputPath.empty()) {
00057     std::error_code EC;
00058     llvm::raw_fd_ostream *OS = new llvm::raw_fd_ostream(
00059         OutputPath.str(), EC, llvm::sys::fs::F_Append | llvm::sys::fs::F_Text);
00060     if (EC) {
00061       PP.getDiagnostics().Report(clang::diag::warn_fe_cc_print_header_failure)
00062           << EC.message();
00063       delete OS;
00064     } else {
00065       OS->SetUnbuffered();
00066       OS->SetUseAtomicWrites(true);
00067       OutputFile = OS;
00068       OwnsOutputFile = true;
00069     }
00070   }
00071 
00072   PP.addPPCallbacks(llvm::make_unique<HeaderIncludesCallback>(&PP,
00073                                                               ShowAllHeaders,
00074                                                               OutputFile,
00075                                                               OwnsOutputFile,
00076                                                               ShowDepth,
00077                                                               MSStyle));
00078 }
00079 
00080 void HeaderIncludesCallback::FileChanged(SourceLocation Loc,
00081                                          FileChangeReason Reason,
00082                                        SrcMgr::CharacteristicKind NewFileType,
00083                                        FileID PrevFID) {
00084   // Unless we are exiting a #include, make sure to skip ahead to the line the
00085   // #include directive was at.
00086   PresumedLoc UserLoc = SM.getPresumedLoc(Loc);
00087   if (UserLoc.isInvalid())
00088     return;
00089 
00090   // Adjust the current include depth.
00091   if (Reason == PPCallbacks::EnterFile) {
00092     ++CurrentIncludeDepth;
00093   } else if (Reason == PPCallbacks::ExitFile) {
00094     if (CurrentIncludeDepth)
00095       --CurrentIncludeDepth;
00096 
00097     // We track when we are done with the predefines by watching for the first
00098     // place where we drop back to a nesting depth of 1.
00099     if (CurrentIncludeDepth == 1 && !HasProcessedPredefines)
00100       HasProcessedPredefines = true;
00101 
00102     return;
00103   } else
00104     return;
00105 
00106   // Show the header if we are (a) past the predefines, or (b) showing all
00107   // headers and in the predefines at a depth past the initial file and command
00108   // line buffers.
00109   bool ShowHeader = (HasProcessedPredefines ||
00110                      (ShowAllHeaders && CurrentIncludeDepth > 2));
00111 
00112   // Dump the header include information we are past the predefines buffer or
00113   // are showing all headers.
00114   if (ShowHeader && Reason == PPCallbacks::EnterFile) {
00115     // Write to a temporary string to avoid unnecessary flushing on errs().
00116     SmallString<512> Filename(UserLoc.getFilename());
00117     if (!MSStyle)
00118       Lexer::Stringify(Filename);
00119 
00120     SmallString<256> Msg;
00121     if (MSStyle)
00122       Msg += "Note: including file:";
00123 
00124     if (ShowDepth) {
00125       // The main source file is at depth 1, so skip one dot.
00126       for (unsigned i = 1; i != CurrentIncludeDepth; ++i)
00127         Msg += MSStyle ? ' ' : '.';
00128 
00129       if (!MSStyle)
00130         Msg += ' ';
00131     }
00132     Msg += Filename;
00133     Msg += '\n';
00134 
00135     OutputFile->write(Msg.data(), Msg.size());
00136     OutputFile->flush();
00137   }
00138 }