diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Frontend/HeaderIncludeGen.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Frontend/HeaderIncludeGen.cpp | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/contrib/llvm-project/clang/lib/Frontend/HeaderIncludeGen.cpp b/contrib/llvm-project/clang/lib/Frontend/HeaderIncludeGen.cpp new file mode 100644 index 000000000000..5f91157816b0 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Frontend/HeaderIncludeGen.cpp @@ -0,0 +1,180 @@ +//===-- HeaderIncludeGen.cpp - Generate Header Includes -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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::OF_Append | llvm::sys::fs::OF_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(std::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); + } +} |