//===-- LVSymbol.h ----------------------------------------------*- 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 LVSymbol class, which is used to describe a debug
// information symbol.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSYMBOL_H
#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSYMBOL_H

#include "llvm/DebugInfo/LogicalView/Core/LVElement.h"
#include "llvm/Support/Compiler.h"

namespace llvm {
namespace logicalview {

enum class LVSymbolKind {
  IsCallSiteParameter,
  IsConstant,
  IsInheritance,
  IsMember,
  IsParameter,
  IsUnspecified,
  IsVariable,
  LastEntry
};
using LVSymbolKindSet = std::set<LVSymbolKind>;
using LVSymbolDispatch = std::map<LVSymbolKind, LVSymbolGetFunction>;
using LVSymbolRequest = std::vector<LVSymbolGetFunction>;

class LLVM_ABI LVSymbol final : public LVElement {
  enum class Property { HasLocation, FillGaps, LastEntry };

  // Typed bitvector with kinds and properties for this symbol.
  LVProperties<LVSymbolKind> Kinds;
  LVProperties<Property> Properties;
  static LVSymbolDispatch Dispatch;

  // CodeView symbol Linkage name.
  size_t LinkageNameIndex = 0;

  // Reference to DW_AT_specification, DW_AT_abstract_origin attribute.
  LVSymbol *Reference = nullptr;
  std::unique_ptr<LVLocations> Locations;
  LVLocation *CurrentLocation = nullptr;

  // Bitfields length.
  uint32_t BitSize = 0;

  // Index in the String pool representing any initial value.
  size_t ValueIndex = 0;

  // Coverage factor in units (bytes).
  unsigned CoverageFactor = 0;
  float CoveragePercentage = 0;

  // Add a location gap into the location list.
  LVLocations::iterator addLocationGap(LVLocations::iterator Pos,
                                       LVAddress LowPC, LVAddress HighPC);

  // Find the current symbol in the given 'Targets'.
  LVSymbol *findIn(const LVSymbols *Targets) const;

public:
  LVSymbol() : LVElement(LVSubclassID::LV_SYMBOL) {
    setIsSymbol();
    setIncludeInPrint();
  }
  LVSymbol(const LVSymbol &) = delete;
  LVSymbol &operator=(const LVSymbol &) = delete;
  ~LVSymbol() override = default;

  static bool classof(const LVElement *Element) {
    return Element->getSubclassID() == LVSubclassID::LV_SYMBOL;
  }

  KIND(LVSymbolKind, IsCallSiteParameter);
  KIND(LVSymbolKind, IsConstant);
  KIND(LVSymbolKind, IsInheritance);
  KIND(LVSymbolKind, IsMember);
  KIND(LVSymbolKind, IsParameter);
  KIND(LVSymbolKind, IsUnspecified);
  KIND(LVSymbolKind, IsVariable);

  PROPERTY(Property, HasLocation);
  PROPERTY(Property, FillGaps);

  const char *kind() const override;

  // Access DW_AT_specification, DW_AT_abstract_origin reference.
  LVSymbol *getReference() const { return Reference; }
  void setReference(LVSymbol *Symbol) override {
    Reference = Symbol;
    setHasReference();
  }
  void setReference(LVElement *Element) override {
    assert((!Element || isa<LVSymbol>(Element)) && "Invalid element");
    setReference(static_cast<LVSymbol *>(Element));
  }

  void setLinkageName(StringRef LinkageName) override {
    LinkageNameIndex = getStringPool().getIndex(LinkageName);
  }
  StringRef getLinkageName() const override {
    return getStringPool().getString(LinkageNameIndex);
  }
  size_t getLinkageNameIndex() const override { return LinkageNameIndex; }

  uint32_t getBitSize() const override { return BitSize; }
  void setBitSize(uint32_t Size) override { BitSize = Size; }

  // Process the values for a DW_AT_const_value.
  StringRef getValue() const override {
    return getStringPool().getString(ValueIndex);
  }
  void setValue(StringRef Value) override {
    ValueIndex = getStringPool().getIndex(Value);
  }
  size_t getValueIndex() const override { return ValueIndex; }

  // Add a Location Entry.
  void addLocationConstant(dwarf::Attribute Attr, LVUnsigned Constant,
                           uint64_t LocDescOffset);
  void addLocationOperands(LVSmall Opcode, ArrayRef<uint64_t> Operands);
  void addLocation(dwarf::Attribute Attr, LVAddress LowPC, LVAddress HighPC,
                   LVUnsigned SectionOffset, uint64_t LocDescOffset,
                   bool CallSiteLocation = false);

  // Fill gaps in the location list.
  void fillLocationGaps();

  // Get all the locations associated with symbols.
  void getLocations(LVLocations &LocationList, LVValidLocation ValidLocation,
                    bool RecordInvalid = false);
  void getLocations(LVLocations &LocationList) const;

  // Calculate coverage factor.
  void calculateCoverage();

  unsigned getCoverageFactor() const { return CoverageFactor; }
  void setCoverageFactor(unsigned Value) { CoverageFactor = Value; }
  float getCoveragePercentage() const { return CoveragePercentage; }
  void setCoveragePercentage(float Value) { CoveragePercentage = Value; }

  // Print location in raw format.
  void printLocations(raw_ostream &OS, bool Full = true) const;

  // Follow a chain of references given by DW_AT_abstract_origin and/or
  // DW_AT_specification and update the symbol name.
  StringRef resolveReferencesChain();

  void resolveName() override;
  void resolveReferences() override;

  static LVSymbolDispatch &getDispatch() { return Dispatch; }

  static bool parametersMatch(const LVSymbols *References,
                              const LVSymbols *Targets);

  static void getParameters(const LVSymbols *Symbols, LVSymbols *Parameters);

  // Iterate through the 'References' set and check that all its elements
  // are present in the 'Targets' set. For a missing element, mark its
  // parents as missing.
  static void markMissingParents(const LVSymbols *References,
                                 const LVSymbols *Targets);

  // Returns true if current type is logically equal to the given 'Symbol'.
  bool equals(const LVSymbol *Symbol) const;

  // Returns true if the given 'References' are logically equal to the
  // given 'Targets'.
  static bool equals(const LVSymbols *References, const LVSymbols *Targets);

  // Report the current symbol as missing or added during comparison.
  void report(LVComparePass Pass) override;

  void print(raw_ostream &OS, bool Full = true) const override;
  void printExtra(raw_ostream &OS, bool Full = true) const override;
};

} // end namespace logicalview
} // end namespace llvm

#endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSYMBOL_H
