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 
00028 public:
00029   HeaderIncludesCallback(const Preprocessor *PP, bool ShowAllHeaders_,
00030                          raw_ostream *OutputFile_, bool OwnsOutputFile_,
00031                          bool ShowDepth_)
00032     : SM(PP->getSourceManager()), OutputFile(OutputFile_),
00033       CurrentIncludeDepth(0), HasProcessedPredefines(false),
00034       OwnsOutputFile(OwnsOutputFile_), ShowAllHeaders(ShowAllHeaders_),
00035       ShowDepth(ShowDepth_) {}
00036 
00037   ~HeaderIncludesCallback() {
00038     if (OwnsOutputFile)
00039       delete OutputFile;
00040   }
00041 
00042   virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
00043                            SrcMgr::CharacteristicKind FileType,
00044                            FileID PrevFID);
00045 };
00046 }
00047 
00048 void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders,
00049                                    StringRef OutputPath, bool ShowDepth) {
00050   raw_ostream *OutputFile = &llvm::errs();
00051   bool OwnsOutputFile = false;
00052 
00053   // Open the output file, if used.
00054   if (!OutputPath.empty()) {
00055     std::string Error;
00056     llvm::raw_fd_ostream *OS = new llvm::raw_fd_ostream(
00057       OutputPath.str().c_str(), Error, llvm::raw_fd_ostream::F_Append);
00058     if (!Error.empty()) {
00059       PP.getDiagnostics().Report(
00060         clang::diag::warn_fe_cc_print_header_failure) << Error;
00061       delete OS;
00062     } else {
00063       OS->SetUnbuffered();
00064       OS->SetUseAtomicWrites(true);
00065       OutputFile = OS;
00066       OwnsOutputFile = true;
00067     }
00068   }
00069 
00070   PP.addPPCallbacks(new HeaderIncludesCallback(&PP, ShowAllHeaders,
00071                                                OutputFile, OwnsOutputFile,
00072                                                ShowDepth));
00073 }
00074 
00075 void HeaderIncludesCallback::FileChanged(SourceLocation Loc,
00076                                          FileChangeReason Reason,
00077                                        SrcMgr::CharacteristicKind NewFileType,
00078                                        FileID PrevFID) {
00079   // Unless we are exiting a #include, make sure to skip ahead to the line the
00080   // #include directive was at.
00081   PresumedLoc UserLoc = SM.getPresumedLoc(Loc);
00082   if (UserLoc.isInvalid())
00083     return;
00084 
00085   // Adjust the current include depth.
00086   if (Reason == PPCallbacks::EnterFile) {
00087     ++CurrentIncludeDepth;
00088   } else if (Reason == PPCallbacks::ExitFile) {
00089     if (CurrentIncludeDepth)
00090       --CurrentIncludeDepth;
00091 
00092     // We track when we are done with the predefines by watching for the first
00093     // place where we drop back to a nesting depth of 1.
00094     if (CurrentIncludeDepth == 1 && !HasProcessedPredefines)
00095       HasProcessedPredefines = true;
00096 
00097     return;
00098   } else
00099     return;
00100 
00101   // Show the header if we are (a) past the predefines, or (b) showing all
00102   // headers and in the predefines at a depth past the initial file and command
00103   // line buffers.
00104   bool ShowHeader = (HasProcessedPredefines ||
00105                      (ShowAllHeaders && CurrentIncludeDepth > 2));
00106 
00107   // Dump the header include information we are past the predefines buffer or
00108   // are showing all headers.
00109   if (ShowHeader && Reason == PPCallbacks::EnterFile) {
00110     // Write to a temporary string to avoid unnecessary flushing on errs().
00111     SmallString<512> Filename(UserLoc.getFilename());
00112     Lexer::Stringify(Filename);
00113 
00114     SmallString<256> Msg;
00115     if (ShowDepth) {
00116       // The main source file is at depth 1, so skip one dot.
00117       for (unsigned i = 1; i != CurrentIncludeDepth; ++i)
00118         Msg += '.';
00119       Msg += ' ';
00120     }
00121     Msg += Filename;
00122     Msg += '\n';
00123 
00124     OutputFile->write(Msg.data(), Msg.size());
00125   }
00126 }