//===- FactsGenerator.h - Lifetime Facts Generation -------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file defines the FactsGenerator, which traverses the AST to generate
// lifetime-relevant facts (such as loan issuance, expiration, origin flow,
// and use) from CFG statements. These facts are used by the dataflow analyses
// to track pointer lifetimes and detect use-after-free errors.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_FACTSGENERATOR_H
#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_FACTSGENERATOR_H

#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/Analyses/LifetimeSafety/Facts.h"
#include "clang/Analysis/Analyses/LifetimeSafety/Origins.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "llvm/ADT/SmallVector.h"

namespace clang::lifetimes::internal {

class FactsGenerator : public ConstStmtVisitor<FactsGenerator> {
  using Base = ConstStmtVisitor<FactsGenerator>;

public:
  FactsGenerator(FactManager &FactMgr, AnalysisDeclContext &AC)
      : FactMgr(FactMgr), AC(AC) {}

  void run();

  void VisitDeclStmt(const DeclStmt *DS);
  void VisitDeclRefExpr(const DeclRefExpr *DRE);
  void VisitCXXConstructExpr(const CXXConstructExpr *CCE);
  void VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE);
  void VisitCallExpr(const CallExpr *CE);
  void VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *N);
  void VisitImplicitCastExpr(const ImplicitCastExpr *ICE);
  void VisitUnaryOperator(const UnaryOperator *UO);
  void VisitReturnStmt(const ReturnStmt *RS);
  void VisitBinaryOperator(const BinaryOperator *BO);
  void VisitConditionalOperator(const ConditionalOperator *CO);
  void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE);
  void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *FCE);
  void VisitInitListExpr(const InitListExpr *ILE);
  void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *MTE);

private:
  OriginList *getOriginsList(const ValueDecl &D);
  OriginList *getOriginsList(const Expr &E);

  void flow(OriginList *Dst, OriginList *Src, bool Kill);

  void handleAssignment(const Expr *LHSExpr, const Expr *RHSExpr);

  void handleLifetimeEnds(const CFGLifetimeEnds &LifetimeEnds);

  void handleGSLPointerConstruction(const CXXConstructExpr *CCE);

  /// Checks if a call-like expression creates a borrow by passing a value to a
  /// reference parameter, creating an IssueFact if it does.
  /// \param IsGslConstruction True if this is a GSL construction where all
  ///   argument origins should flow to the returned origin.
  void handleFunctionCall(const Expr *Call, const FunctionDecl *FD,
                          ArrayRef<const Expr *> Args,
                          bool IsGslConstruction = false);

  template <typename Destination, typename Source>
  void flowOrigin(const Destination &D, const Source &S) {
    flow(getOriginsList(D), getOriginsList(S), /*Kill=*/false);
  }

  template <typename Destination, typename Source>
  void killAndFlowOrigin(const Destination &D, const Source &S) {
    flow(getOriginsList(D), getOriginsList(S), /*Kill=*/true);
  }

  /// Checks if the expression is a `void("__lifetime_test_point_...")` cast.
  /// If so, creates a `TestPointFact` and returns true.
  bool handleTestPoint(const CXXFunctionalCastExpr *FCE);

  // A DeclRefExpr will be treated as a use of the referenced decl. It will be
  // checked for use-after-free unless it is later marked as being written to
  // (e.g. on the left-hand side of an assignment).
  void handleUse(const DeclRefExpr *DRE);

  void markUseAsWrite(const DeclRefExpr *DRE);

  llvm::SmallVector<Fact *> issuePlaceholderLoans();
  FactManager &FactMgr;
  AnalysisDeclContext &AC;
  llvm::SmallVector<Fact *> CurrentBlockFacts;
  // Collect origins that escape the function in this block (OriginEscapesFact),
  // appended at the end of CurrentBlockFacts to ensure they appear after
  // ExpireFact entries.
  llvm::SmallVector<Fact *> EscapesInCurrentBlock;
  // To distinguish between reads and writes for use-after-free checks, this map
  // stores the `UseFact` for each `DeclRefExpr`. We initially identify all
  // `DeclRefExpr`s as "read" uses. When an assignment is processed, the use
  // corresponding to the left-hand side is updated to be a "write", thereby
  // exempting it from the check.
  llvm::DenseMap<const DeclRefExpr *, UseFact *> UseFacts;
};

} // namespace clang::lifetimes::internal

#endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_FACTSGENERATOR_H
