#ifndef LLVM_ANALYSIS_FUNCTIONCALLSINFOANALYSIS_H
#define LLVM_ANALYSIS_FUNCTIONCALLSINFOANALYSIS_H

#include "llvm/Analysis/CallSiteAnalysis.h"
#include "llvm/Analysis/TBAATypeReconstruction.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Pass.h"
#include <map>
#include <set>

namespace llvm {

std::optional<std::set<Function *>>
getCalledFunctions(CallBase *Call, aocc::CSFunctionProperty &CS);

class FunctionCallsInfo {
public:
  FunctionCallsInfo(TBAATypeReconstruction &TypeRecon,
                    aocc::CSFunctionProperty &CS)
      : TypeRecon(TypeRecon), CS(CS) {}
  std::map<CallBase *, std::vector<TBAATypeReconstruction::TypeInfo *>> MCT;
  std::map<Function *, std::set<CallBase *>> MFC;
  std::map<CallBase *, std::set<Function *>> MCF;
  std::set<CallBase *> unresolved;
  std::optional<std::set<Function *>> getFunctions(CallBase *Call);
  std::optional<std::set<CallBase *>> getCalls(Function *F);
  void analyze(Module &M, ModuleAnalysisManager &AM);
  bool invalidate(Module &M, const PreservedAnalyses &PA,
                  ModuleAnalysisManager::Invalidator &Inv);

private:
  TBAATypeReconstruction &TypeRecon;
  aocc::CSFunctionProperty &CS;
  std::map<Function *, bool> FB;
};

class FunctionCallsInfoAnalysis
    : public AnalysisInfoMixin<FunctionCallsInfoAnalysis> {
  friend AnalysisInfoMixin<FunctionCallsInfoAnalysis>;
  static AnalysisKey Key;

public:
  typedef FunctionCallsInfo Result;
  Result run(Module &, ModuleAnalysisManager &AM);
};
} // namespace llvm

#endif