//===- DeclContextInternals.h - DeclContext Representation ------*- 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 data structures used in the implementation
 
//  of DeclContext.
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H
 
#define LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H
 
 
 
#include "clang/AST/ASTContext.h"
 
#include "clang/AST/Decl.h"
 
#include "clang/AST/DeclBase.h"
 
#include "clang/AST/DeclCXX.h"
 
#include "clang/AST/DeclarationName.h"
 
#include "llvm/ADT/DenseMap.h"
 
#include "llvm/ADT/PointerIntPair.h"
 
#include "llvm/ADT/PointerUnion.h"
 
#include <cassert>
 
 
 
namespace clang {
 
 
 
class DependentDiagnostic;
 
 
 
/// An array of decls optimized for the common case of only containing
 
/// one entry.
 
class StoredDeclsList {
 
  using Decls = DeclListNode::Decls;
 
 
 
  /// A collection of declarations, with a flag to indicate if we have
 
  /// further external declarations.
 
  using DeclsAndHasExternalTy = llvm::PointerIntPair<Decls, 1, bool>;
 
 
 
  /// The stored data, which will be either a pointer to a NamedDecl,
 
  /// or a pointer to a list with a flag to indicate if there are further
 
  /// external declarations.
 
  DeclsAndHasExternalTy Data;
 
 
 
  template<typename Fn>
 
  void erase_if(Fn ShouldErase) {
 
    Decls List = Data.getPointer();
 
    if (!List)
 
      return;
 
    ASTContext &C = getASTContext();
 
    DeclListNode::Decls NewHead = nullptr;
 
    DeclListNode::Decls *NewLast = nullptr;
 
    DeclListNode::Decls *NewTail = &NewHead;
 
    while (true) {
 
      if (!ShouldErase(*DeclListNode::iterator(List))) {
 
        NewLast = NewTail;
 
        *NewTail = List;
 
        if (auto *Node = List.dyn_cast<DeclListNode*>()) {
 
          NewTail = &Node->Rest;
 
          List = Node->Rest;
 
        } else {
 
          break;
 
        }
 
      } else if (DeclListNode *N = List.dyn_cast<DeclListNode*>()) {
 
        List = N->Rest;
 
        C.DeallocateDeclListNode(N);
 
      } else {
 
        // We're discarding the last declaration in the list. The last node we
 
        // want to keep (if any) will be of the form DeclListNode(D, <rest>);
 
        // replace it with just D.
 
        if (NewLast) {
 
          DeclListNode *Node = NewLast->get<DeclListNode*>();
 
          *NewLast = Node->D;
 
          C.DeallocateDeclListNode(Node);
 
        }
 
        break;
 
      }
 
    }
 
    Data.setPointer(NewHead);
 
 
 
    assert(llvm::none_of(getLookupResult(), ShouldErase) && "Still exists!");
 
  }
 
 
 
  void erase(NamedDecl *ND) {
 
    erase_if([ND](NamedDecl *D) { return D == ND; });
 
  }
 
 
 
public:
 
  StoredDeclsList() = default;
 
 
 
  StoredDeclsList(StoredDeclsList &&RHS) : Data(RHS.Data) {
 
    RHS.Data.setPointer(nullptr);
 
    RHS.Data.setInt(false);
 
  }
 
 
 
  void MaybeDeallocList() {
 
    if (isNull())
 
      return;
 
    // If this is a list-form, free the list.
 
    ASTContext &C = getASTContext();
 
    Decls List = Data.getPointer();
 
    while (DeclListNode *ToDealloc = List.dyn_cast<DeclListNode *>()) {
 
      List = ToDealloc->Rest;
 
      C.DeallocateDeclListNode(ToDealloc);
 
    }
 
  }
 
 
 
  ~StoredDeclsList() {
 
    MaybeDeallocList();
 
  }
 
 
 
  StoredDeclsList &operator=(StoredDeclsList &&RHS) {
 
    MaybeDeallocList();
 
 
 
    Data = RHS.Data;
 
    RHS.Data.setPointer(nullptr);
 
    RHS.Data.setInt(false);
 
    return *this;
 
  }
 
 
 
  bool isNull() const { return Data.getPointer().isNull(); }
 
 
 
  ASTContext &getASTContext() {
 
    assert(!isNull() && "No ASTContext.");
 
    if (NamedDecl *ND = getAsDecl())
 
      return ND->getASTContext();
 
    return getAsList()->D->getASTContext();
 
  }
 
 
 
  DeclsAndHasExternalTy getAsListAndHasExternal() const { return Data; }
 
 
 
  NamedDecl *getAsDecl() const {
 
    return getAsListAndHasExternal().getPointer().dyn_cast<NamedDecl *>();
 
  }
 
 
 
  DeclListNode *getAsList() const {
 
    return getAsListAndHasExternal().getPointer().dyn_cast<DeclListNode*>();
 
  }
 
 
 
  bool hasExternalDecls() const {
 
    return getAsListAndHasExternal().getInt();
 
  }
 
 
 
  void setHasExternalDecls() {
 
    Data.setInt(true);
 
  }
 
 
 
  void remove(NamedDecl *D) {
 
    assert(!isNull() && "removing from empty list");
 
    erase(D);
 
  }
 
 
 
  /// Remove any declarations which were imported from an external AST source.
 
  void removeExternalDecls() {
 
    erase_if([](NamedDecl *ND) { return ND->isFromASTFile(); });
 
 
 
    // Don't have any pending external decls any more.
 
    Data.setInt(false);
 
  }
 
 
 
  void replaceExternalDecls(ArrayRef<NamedDecl*> Decls) {
 
    // Remove all declarations that are either external or are replaced with
 
    // external declarations.
 
    erase_if([Decls](NamedDecl *ND) {
 
      if (ND->isFromASTFile())
 
        return true;
 
      for (NamedDecl *D : Decls)
 
        if (D->declarationReplaces(ND, /*IsKnownNewer=*/false))
 
          return true;
 
      return false;
 
    });
 
 
 
    // Don't have any pending external decls any more.
 
    Data.setInt(false);
 
 
 
    if (Decls.empty())
 
      return;
 
 
 
    // Convert Decls into a list, in order.
 
    ASTContext &C = Decls.front()->getASTContext();
 
    DeclListNode::Decls DeclsAsList = Decls.back();
 
    for (size_t I = Decls.size() - 1; I != 0; --I) {
 
      DeclListNode *Node = C.AllocateDeclListNode(Decls[I - 1]);
 
      Node->Rest = DeclsAsList;
 
      DeclsAsList = Node;
 
    }
 
 
 
    DeclListNode::Decls Head = Data.getPointer();
 
    if (Head.isNull()) {
 
      Data.setPointer(DeclsAsList);
 
      return;
 
    }
 
 
 
    // Find the end of the existing list.
 
    // FIXME: It would be possible to preserve information from erase_if to
 
    // avoid this rescan looking for the end of the list.
 
    DeclListNode::Decls *Tail = &Head;
 
    while (DeclListNode *Node = Tail->dyn_cast<DeclListNode *>())
 
      Tail = &Node->Rest;
 
 
 
    // Append the Decls.
 
    DeclListNode *Node = C.AllocateDeclListNode(Tail->get<NamedDecl *>());
 
    Node->Rest = DeclsAsList;
 
    *Tail = Node;
 
    Data.setPointer(Head);
 
  }
 
 
 
  /// Return an array of all the decls that this list represents.
 
  DeclContext::lookup_result getLookupResult() const {
 
    return DeclContext::lookup_result(Data.getPointer());
 
  }
 
 
 
  /// If this is a redeclaration of an existing decl, replace the old one with
 
  /// D. Otherwise, append D.
 
  void addOrReplaceDecl(NamedDecl *D) {
 
    const bool IsKnownNewer = true;
 
 
 
    if (isNull()) {
 
      Data.setPointer(D);
 
      return;
 
    }
 
 
 
    // Most decls only have one entry in their list, special case it.
 
    if (NamedDecl *OldD = getAsDecl()) {
 
      if (D->declarationReplaces(OldD, IsKnownNewer)) {
 
        Data.setPointer(D);
 
        return;
 
      }
 
 
 
      // Add D after OldD.
 
      ASTContext &C = D->getASTContext();
 
      DeclListNode *Node = C.AllocateDeclListNode(OldD);
 
      Node->Rest = D;
 
      Data.setPointer(Node);
 
      return;
 
    }
 
 
 
    // FIXME: Move the assert before the single decl case when we fix the
 
    // duplication coming from the ASTReader reading builtin types.
 
    assert(!llvm::is_contained(getLookupResult(), D) && "Already exists!");
 
    // Determine if this declaration is actually a redeclaration.
 
    for (DeclListNode *N = getAsList(); /*return in loop*/;
 
         N = N->Rest.dyn_cast<DeclListNode *>()) {
 
      if (D->declarationReplaces(N->D, IsKnownNewer)) {
 
        N->D = D;
 
        return;
 
      }
 
      if (auto *ND = N->Rest.dyn_cast<NamedDecl *>()) {
 
        if (D->declarationReplaces(ND, IsKnownNewer)) {
 
          N->Rest = D;
 
          return;
 
        }
 
 
 
        // Add D after ND.
 
        ASTContext &C = D->getASTContext();
 
        DeclListNode *Node = C.AllocateDeclListNode(ND);
 
        N->Rest = Node;
 
        Node->Rest = D;
 
        return;
 
      }
 
    }
 
  }
 
 
 
  /// Add a declaration to the list without checking if it replaces anything.
 
  void prependDeclNoReplace(NamedDecl *D) {
 
    if (isNull()) {
 
      Data.setPointer(D);
 
      return;
 
    }
 
 
 
    ASTContext &C = D->getASTContext();
 
    DeclListNode *Node = C.AllocateDeclListNode(D);
 
    Node->Rest = Data.getPointer();
 
    Data.setPointer(Node);
 
  }
 
 
 
  LLVM_DUMP_METHOD void dump() const {
 
    Decls D = Data.getPointer();
 
    if (!D) {
 
      llvm::errs() << "<null>\n";
 
      return;
 
    }
 
 
 
    while (true) {
 
      if (auto *Node = D.dyn_cast<DeclListNode*>()) {
 
        llvm::errs() << '[' << Node->D << "] -> ";
 
        D = Node->Rest;
 
      } else {
 
        llvm::errs() << '[' << D.get<NamedDecl*>() << "]\n";
 
        return;
 
      }
 
    }
 
  }
 
};
 
 
 
class StoredDeclsMap
 
    : public llvm::SmallDenseMap<DeclarationName, StoredDeclsList, 4> {
 
  friend class ASTContext; // walks the chain deleting these
 
  friend class DeclContext;
 
 
 
  llvm::PointerIntPair<StoredDeclsMap*, 1> Previous;
 
public:
 
  static void DestroyAll(StoredDeclsMap *Map, bool Dependent);
 
};
 
 
 
class DependentStoredDeclsMap : public StoredDeclsMap {
 
  friend class DeclContext; // iterates over diagnostics
 
  friend class DependentDiagnostic;
 
 
 
  DependentDiagnostic *FirstDiagnostic = nullptr;
 
public:
 
  DependentStoredDeclsMap() = default;
 
};
 
 
 
} // namespace clang
 
 
 
#endif // LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H