diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp')
| -rw-r--r-- | contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp | 180 | 
1 files changed, 180 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp b/contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp new file mode 100644 index 000000000000..9dc107c9d546 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp @@ -0,0 +1,180 @@ +//===--- HeaderIncludes.cpp - Generate Header Includes --------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/DependencyOutputOptions.h" +#include "clang/Frontend/Utils.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +namespace { +class HeaderIncludesCallback : public PPCallbacks { +  SourceManager &SM; +  raw_ostream *OutputFile; +  const DependencyOutputOptions &DepOpts; +  unsigned CurrentIncludeDepth; +  bool HasProcessedPredefines; +  bool OwnsOutputFile; +  bool ShowAllHeaders; +  bool ShowDepth; +  bool MSStyle; + +public: +  HeaderIncludesCallback(const Preprocessor *PP, bool ShowAllHeaders_, +                         raw_ostream *OutputFile_, +                         const DependencyOutputOptions &DepOpts, +                         bool OwnsOutputFile_, bool ShowDepth_, bool MSStyle_) +      : SM(PP->getSourceManager()), OutputFile(OutputFile_), DepOpts(DepOpts), +        CurrentIncludeDepth(0), HasProcessedPredefines(false), +        OwnsOutputFile(OwnsOutputFile_), ShowAllHeaders(ShowAllHeaders_), +        ShowDepth(ShowDepth_), MSStyle(MSStyle_) {} + +  ~HeaderIncludesCallback() override { +    if (OwnsOutputFile) +      delete OutputFile; +  } + +  void FileChanged(SourceLocation Loc, FileChangeReason Reason, +                   SrcMgr::CharacteristicKind FileType, +                   FileID PrevFID) override; +}; +} + +static void PrintHeaderInfo(raw_ostream *OutputFile, StringRef Filename, +                            bool ShowDepth, unsigned CurrentIncludeDepth, +                            bool MSStyle) { +  // Write to a temporary string to avoid unnecessary flushing on errs(). +  SmallString<512> Pathname(Filename); +  if (!MSStyle) +    Lexer::Stringify(Pathname); + +  SmallString<256> Msg; +  if (MSStyle) +    Msg += "Note: including file:"; + +  if (ShowDepth) { +    // The main source file is at depth 1, so skip one dot. +    for (unsigned i = 1; i != CurrentIncludeDepth; ++i) +      Msg += MSStyle ? ' ' : '.'; + +    if (!MSStyle) +      Msg += ' '; +  } +  Msg += Pathname; +  Msg += '\n'; + +  *OutputFile << Msg; +  OutputFile->flush(); +} + +void clang::AttachHeaderIncludeGen(Preprocessor &PP, +                                   const DependencyOutputOptions &DepOpts, +                                   bool ShowAllHeaders, StringRef OutputPath, +                                   bool ShowDepth, bool MSStyle) { +  raw_ostream *OutputFile = &llvm::errs(); +  bool OwnsOutputFile = false; + +  // Choose output stream, when printing in cl.exe /showIncludes style. +  if (MSStyle) { +    switch (DepOpts.ShowIncludesDest) { +    default: +      llvm_unreachable("Invalid destination for /showIncludes output!"); +    case ShowIncludesDestination::Stderr: +      OutputFile = &llvm::errs(); +      break; +    case ShowIncludesDestination::Stdout: +      OutputFile = &llvm::outs(); +      break; +    } +  } + +  // Open the output file, if used. +  if (!OutputPath.empty()) { +    std::error_code EC; +    llvm::raw_fd_ostream *OS = new llvm::raw_fd_ostream( +        OutputPath.str(), EC, llvm::sys::fs::F_Append | llvm::sys::fs::F_Text); +    if (EC) { +      PP.getDiagnostics().Report(clang::diag::warn_fe_cc_print_header_failure) +          << EC.message(); +      delete OS; +    } else { +      OS->SetUnbuffered(); +      OutputFile = OS; +      OwnsOutputFile = true; +    } +  } + +  // Print header info for extra headers, pretending they were discovered by +  // the regular preprocessor. The primary use case is to support proper +  // generation of Make / Ninja file dependencies for implicit includes, such +  // as sanitizer blacklists. It's only important for cl.exe compatibility, +  // the GNU way to generate rules is -M / -MM / -MD / -MMD. +  for (const auto &Header : DepOpts.ExtraDeps) +    PrintHeaderInfo(OutputFile, Header, ShowDepth, 2, MSStyle); +  PP.addPPCallbacks(llvm::make_unique<HeaderIncludesCallback>( +      &PP, ShowAllHeaders, OutputFile, DepOpts, OwnsOutputFile, ShowDepth, +      MSStyle)); +} + +void HeaderIncludesCallback::FileChanged(SourceLocation Loc, +                                         FileChangeReason Reason, +                                       SrcMgr::CharacteristicKind NewFileType, +                                       FileID PrevFID) { +  // Unless we are exiting a #include, make sure to skip ahead to the line the +  // #include directive was at. +  PresumedLoc UserLoc = SM.getPresumedLoc(Loc); +  if (UserLoc.isInvalid()) +    return; + +  // Adjust the current include depth. +  if (Reason == PPCallbacks::EnterFile) { +    ++CurrentIncludeDepth; +  } else if (Reason == PPCallbacks::ExitFile) { +    if (CurrentIncludeDepth) +      --CurrentIncludeDepth; + +    // We track when we are done with the predefines by watching for the first +    // place where we drop back to a nesting depth of 1. +    if (CurrentIncludeDepth == 1 && !HasProcessedPredefines) { +      if (!DepOpts.ShowIncludesPretendHeader.empty()) { +        PrintHeaderInfo(OutputFile, DepOpts.ShowIncludesPretendHeader, +                        ShowDepth, 2, MSStyle); +      } +      HasProcessedPredefines = true; +    } + +    return; +  } else +    return; + +  // Show the header if we are (a) past the predefines, or (b) showing all +  // headers and in the predefines at a depth past the initial file and command +  // line buffers. +  bool ShowHeader = (HasProcessedPredefines || +                     (ShowAllHeaders && CurrentIncludeDepth > 2)); +  unsigned IncludeDepth = CurrentIncludeDepth; +  if (!HasProcessedPredefines) +    --IncludeDepth; // Ignore indent from <built-in>. +  else if (!DepOpts.ShowIncludesPretendHeader.empty()) +    ++IncludeDepth; // Pretend inclusion by ShowIncludesPretendHeader. + +  // Dump the header include information we are past the predefines buffer or +  // are showing all headers and this isn't the magic implicit <command line> +  // header. +  // FIXME: Identify headers in a more robust way than comparing their name to +  // "<command line>" and "<built-in>" in a bunch of places. +  if (ShowHeader && Reason == PPCallbacks::EnterFile && +      UserLoc.getFilename() != StringRef("<command line>")) { +    PrintHeaderInfo(OutputFile, UserLoc.getFilename(), ShowDepth, IncludeDepth, +                    MSStyle); +  } +}  | 
