//===--- BackendConsumer.h - LLVM BackendConsumer Header File -------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_LIB_CODEGEN_BACKENDCONSUMER_H
#define LLVM_CLANG_LIB_CODEGEN_BACKENDCONSUMER_H

#include "clang/CodeGen/BackendUtil.h"
#include "clang/CodeGen/CodeGenAction.h"

#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/Support/Timer.h"

namespace llvm {
  class DiagnosticInfoDontCall;
}

namespace clang {
class ASTContext;
class CodeGenAction;
class CoverageSourceInfo;

class BackendConsumer : public ASTConsumer {
  using LinkModule = CodeGenAction::LinkModule;

  virtual void anchor();
  CompilerInstance &CI;
  DiagnosticsEngine &Diags;
  const CodeGenOptions &CodeGenOpts;
  const TargetOptions &TargetOpts;
  const LangOptions &LangOpts;
  std::unique_ptr<raw_pwrite_stream> AsmOutStream;
  ASTContext *Context = nullptr;
  IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;

  llvm::Timer LLVMIRGeneration;
  unsigned LLVMIRGenerationRefCount = 0;

  bool TimerIsEnabled = false;

  BackendAction Action;

  std::unique_ptr<CodeGenerator> Gen;

  SmallVector<LinkModule, 4> LinkModules;

  // A map from mangled names to their function's source location, used for
  // backend diagnostics as the Clang AST may be unavailable. We actually use
  // the mangled name's hash as the key because mangled names can be very
  // long and take up lots of space. Using a hash can cause name collision,
  // but that is rare and the consequences are pointing to a wrong source
  // location which is not severe. This is a vector instead of an actual map
  // because we optimize for time building this map rather than time
  // retrieving an entry, as backend diagnostics are uncommon.
  std::vector<std::pair<llvm::hash_code, FullSourceLoc>>
    ManglingFullSourceLocs;


  // This is here so that the diagnostic printer knows the module a diagnostic
  // refers to.
  llvm::Module *CurLinkModule = nullptr;

public:
  BackendConsumer(CompilerInstance &CI, BackendAction Action,
                  IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
                  llvm::LLVMContext &C, SmallVector<LinkModule, 4> LinkModules,
                  StringRef InFile, std::unique_ptr<raw_pwrite_stream> OS,
                  CoverageSourceInfo *CoverageInfo,
                  llvm::Module *CurLinkModule = nullptr);

  llvm::Module *getModule() const;
  std::unique_ptr<llvm::Module> takeModule();

  CodeGenerator *getCodeGenerator();

  void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override;
  void Initialize(ASTContext &Ctx) override;
  bool HandleTopLevelDecl(DeclGroupRef D) override;
  void HandleInlineFunctionDefinition(FunctionDecl *D) override;
  void HandleInterestingDecl(DeclGroupRef D) override;
  void HandleTranslationUnit(ASTContext &C) override;
  void HandleTagDeclDefinition(TagDecl *D) override;
  void HandleTagDeclRequiredDefinition(const TagDecl *D) override;
  void CompleteTentativeDefinition(VarDecl *D) override;
  void CompleteExternalDeclaration(DeclaratorDecl *D) override;
  void AssignInheritanceModel(CXXRecordDecl *RD) override;
  void HandleVTable(CXXRecordDecl *RD) override;

  // Links each entry in LinkModules into our module.  Returns true on error.
  bool LinkInModules(llvm::Module *M);

  /// Get the best possible source location to represent a diagnostic that
  /// may have associated debug info.
  const FullSourceLoc getBestLocationFromDebugLoc(
    const llvm::DiagnosticInfoWithLocationBase &D,
    bool &BadDebugInfo, StringRef &Filename,
    unsigned &Line, unsigned &Column) const;

  std::optional<FullSourceLoc> getFunctionSourceLocation(
    const llvm::Function &F) const;

  void DiagnosticHandlerImpl(const llvm::DiagnosticInfo &DI);
  /// Specialized handler for InlineAsm diagnostic.
  /// \return True if the diagnostic has been successfully reported, false
  /// otherwise.
  bool InlineAsmDiagHandler(const llvm::DiagnosticInfoInlineAsm &D);
  /// Specialized handler for diagnostics reported using SMDiagnostic.
  void SrcMgrDiagHandler(const llvm::DiagnosticInfoSrcMgr &D);
  /// Specialized handler for StackSize diagnostic.
  /// \return True if the diagnostic has been successfully reported, false
  /// otherwise.
  bool StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D);
  /// Specialized handler for ResourceLimit diagnostic.
  /// \return True if the diagnostic has been successfully reported, false
  /// otherwise.
  bool ResourceLimitDiagHandler(const llvm::DiagnosticInfoResourceLimit &D);

  /// Specialized handler for unsupported backend feature diagnostic.
  void UnsupportedDiagHandler(const llvm::DiagnosticInfoUnsupported &D);
  /// Specialized handlers for optimization remarks.
  /// Note that these handlers only accept remarks and they always handle
  /// them.
  void EmitOptimizationMessage(const llvm::DiagnosticInfoOptimizationBase &D,
                               unsigned DiagID);
  void
    OptimizationRemarkHandler(const llvm::DiagnosticInfoOptimizationBase &D);
  void OptimizationRemarkHandler(
    const llvm::OptimizationRemarkAnalysisFPCommute &D);
  void OptimizationRemarkHandler(
    const llvm::OptimizationRemarkAnalysisAliasing &D);
  void OptimizationFailureHandler(
    const llvm::DiagnosticInfoOptimizationFailure &D);
  void DontCallDiagHandler(const llvm::DiagnosticInfoDontCall &D);
  /// Specialized handler for misexpect warnings.
  /// Note that misexpect remarks are emitted through ORE
  void MisExpectDiagHandler(const llvm::DiagnosticInfoMisExpect &D);
};

} // namespace clang
#endif
