<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  <NAME> <<EMAIL>>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "cling/Interpreter/Transaction.h"

#include "cling/Utils/AST.h"
#include "IncrementalExecutor.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Sema.h"

#include "llvm/IR/Module.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang;

namespace cling {

  Transaction::Transaction(Sema& S) : m_Sema(S) {
    Initialize(S);
  }

  Transaction::Transaction(const CompilationOptions& Opts, Sema& S)
    : m_Sema(S) {
    Initialize(S);
    m_Opts = Opts; // intentional copy.
  }

  void Transaction::Initialize(Sema& S) {
    m_NestedTransactions.reset(0);
    m_Parent = 0;
    m_State = kCollecting;
    m_IssuedDiags = kNone;
    m_Opts = CompilationOptions();
    m_Module = 0;
    m_ExeUnload = {(void*)(size_t)-1};
    m_WrapperFD = 0;
    m_Next = 0;
    //m_Sema = S;
    m_BufferFID = FileID(); // sets it to invalid.
    m_Exe = 0;
  }

  Transaction::~Transaction() {
    if (hasNestedTransactions())
      for (size_t i = 0; i < m_NestedTransactions->size(); ++i) {
        assert(((*m_NestedTransactions)[i]->getState() == kCommitted
                || (*m_NestedTransactions)[i]->getState() == kRolledBack)
               && "All nested transactions must be committed!");
        delete (*m_NestedTransactions)[i];
      }
    if (getExecutor())
      getExecutor()->unloadFromJIT(m_Module.get(), getExeUnloadHandle());
  }

  NamedDecl* Transaction::containsNamedDecl(llvm::StringRef name) const {
    for (auto I = decls_begin(), E = decls_end(); I < E; ++I)
      for (auto DI : I->m_DGR) {
        if (NamedDecl* ND = dyn_cast<NamedDecl>(DI))
          if (name.equals(ND->getNameAsString()))
            return ND;
      }
    return 0;
  }

  void Transaction::addNestedTransaction(Transaction* nested) {
    // Create lazily the list
    if (!m_NestedTransactions)
      m_NestedTransactions.reset(new NestedTransactions());

    nested->setParent(this);
    // Leave a marker in the parent transaction, where the nested transaction
    // started.
    DelayCallInfo marker(clang::DeclGroupRef(), Transaction::kCCINone);
    m_DeclQueue.push_back(marker);
    m_NestedTransactions->push_back(nested);
  }

  void Transaction::removeNestedTransaction(Transaction* nested) {
    assert(hasNestedTransactions() && "Does not contain nested transactions");
    int nestedPos = -1;
    for (size_t i = 0; i < m_NestedTransactions->size(); ++i)
      if ((*m_NestedTransactions)[i] == nested) {
        nestedPos = i;
        break;
      }
    assert(nestedPos > -1 && "Not found!?");
    m_NestedTransactions->erase(m_NestedTransactions->begin() + nestedPos);
    // We need to remove the marker too.
    int markerPos = -1;
    for (iterator I = decls_begin(), E = decls_end(); I != E; ++I) {
      if (I->m_DGR.isNull() && I->m_Call == kCCINone) {
        ++markerPos;
        if (nestedPos == markerPos) {
          erase(I); // Safe because of the break stmt.
          break;
        }
      }
    }
    if (!m_NestedTransactions->size())
      m_NestedTransactions.reset(0);
  }

  void Transaction::append(DelayCallInfo DCI) {
    assert(!DCI.m_DGR.isNull() && "Appending null DGR?!");
    assert(getState() == kCollecting
           && "Cannot append declarations in current state.");
    forceAppend(DCI);
  }

  void Transaction::forceAppend(DelayCallInfo DCI) {
    assert(!DCI.m_DGR.isNull() && "Appending null DGR?!");
    assert((getState() == kCollecting || getState() == kCompleted)
           && "Must not be");

    bool checkForWrapper = !m_WrapperFD;

#ifndef NDEBUG
    // Check for duplicates
    for (size_t i = 0, e = m_DeclQueue.size(); i < e; ++i) {
      DelayCallInfo &oldDCI (m_DeclQueue[i]);
      // FIXME: This is possible bug in clang, which will instantiate one and
      // the same CXXStaticMemberVar several times. This happens when there are
      // two dependent expressions and the first uses another declaration from
      // the redeclaration chain. This will force Sema in to instantiate the
      // definition (usually the most recent decl in the chain) and then the
      // second expression might referece the definition (which was already)
      // instantiated, but Sema seems not to keep track of these kinds of
      // instantiations, even though the points of instantiation are the same!
      //
      // This should be investigated further when we merge with newest clang.
      // This is triggered by running the roottest: ./root/io/newstl
      if (oldDCI.m_Call == kCCIHandleCXXStaticMemberVarInstantiation)
        continue;
      // It is possible to have duplicate calls to HandleVTable with the same
      // declaration, because each time Sema believes a vtable is used it emits
      // that callback.
      // For reference (clang::CodeGen::CodeGenModule::EmitVTable).
      if (oldDCI.m_Call != kCCIHandleVTable)
        assert(oldDCI != DCI && "Duplicates?!");
    }
    // We want to assert there is only one wrapper per transaction.
    checkForWrapper = true;
#endif

    // register the wrapper if any.
    if (checkForWrapper && !DCI.m_DGR.isNull() && DCI.m_DGR.isSingleDecl()) {
      if (FunctionDecl* FD = dyn_cast<FunctionDecl>(DCI.m_DGR.getSingleDecl())){
        if (checkForWrapper && utils::Analyze::IsWrapper(FD)) {
          assert(!m_WrapperFD && "Two wrappers in one transaction?");<commit_msg>Need to also suppress assert for multiple kCCIHandleCXXImplicitFunctionInstantiation.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  <NAME> <<EMAIL>>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "cling/Interpreter/Transaction.h"

#include "cling/Utils/AST.h"
#include "IncrementalExecutor.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Sema.h"

#include "llvm/IR/Module.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang;

namespace cling {

  Transaction::Transaction(Sema& S) : m_Sema(S) {
    Initialize(S);
  }

  Transaction::Transaction(const CompilationOptions& Opts, Sema& S)
    : m_Sema(S) {
    Initialize(S);
    m_Opts = Opts; // intentional copy.
  }

  void Transaction::Initialize(Sema& S) {
    m_NestedTransactions.reset(0);
    m_Parent = 0;
    m_State = kCollecting;
    m_IssuedDiags = kNone;
    m_Opts = CompilationOptions();
    m_Module = 0;
    m_ExeUnload = {(void*)(size_t)-1};
    m_WrapperFD = 0;
    m_Next = 0;
    //m_Sema = S;
    m_BufferFID = FileID(); // sets it to invalid.
    m_Exe = 0;
  }

  Transaction::~Transaction() {
    if (hasNestedTransactions())
      for (size_t i = 0; i < m_NestedTransactions->size(); ++i) {
        assert(((*m_NestedTransactions)[i]->getState() == kCommitted
                || (*m_NestedTransactions)[i]->getState() == kRolledBack)
               && "All nested transactions must be committed!");
        delete (*m_NestedTransactions)[i];
      }
    if (getExecutor())
      getExecutor()->unloadFromJIT(m_Module.get(), getExeUnloadHandle());
  }

  NamedDecl* Transaction::containsNamedDecl(llvm::StringRef name) const {
    for (auto I = decls_begin(), E = decls_end(); I < E; ++I)
      for (auto DI : I->m_DGR) {
        if (NamedDecl* ND = dyn_cast<NamedDecl>(DI))
          if (name.equals(ND->getNameAsString()))
            return ND;
      }
    return 0;
  }

  void Transaction::addNestedTransaction(Transaction* nested) {
    // Create lazily the list
    if (!m_NestedTransactions)
      m_NestedTransactions.reset(new NestedTransactions());

    nested->setParent(this);
    // Leave a marker in the parent transaction, where the nested transaction
    // started.
    DelayCallInfo marker(clang::DeclGroupRef(), Transaction::kCCINone);
    m_DeclQueue.push_back(marker);
    m_NestedTransactions->push_back(nested);
  }

  void Transaction::removeNestedTransaction(Transaction* nested) {
    assert(hasNestedTransactions() && "Does not contain nested transactions");
    int nestedPos = -1;
    for (size_t i = 0; i < m_NestedTransactions->size(); ++i)
      if ((*m_NestedTransactions)[i] == nested) {
        nestedPos = i;
        break;
      }
    assert(nestedPos > -1 && "Not found!?");
    m_NestedTransactions->erase(m_NestedTransactions->begin() + nestedPos);
    // We need to remove the marker too.
    int markerPos = -1;
    for (iterator I = decls_begin(), E = decls_end(); I != E; ++I) {
      if (I->m_DGR.isNull() && I->m_Call == kCCINone) {
        ++markerPos;
        if (nestedPos == markerPos) {
          erase(I); // Safe because of the break stmt.
          break;
        }
      }
    }
    if (!m_NestedTransactions->size())
      m_NestedTransactions.reset(0);
  }

  void Transaction::append(DelayCallInfo DCI) {
    assert(!DCI.m_DGR.isNull() && "Appending null DGR?!");
    assert(getState() == kCollecting
           && "Cannot append declarations in current state.");
    forceAppend(DCI);
  }

  void Transaction::forceAppend(DelayCallInfo DCI) {
    assert(!DCI.m_DGR.isNull() && "Appending null DGR?!");
    assert((getState() == kCollecting || getState() == kCompleted)
           && "Must not be");

    bool checkForWrapper = !m_WrapperFD;

#ifndef NDEBUG
    // Check for duplicates
    for (size_t i = 0, e = m_DeclQueue.size(); i < e; ++i) {
      DelayCallInfo &oldDCI (m_DeclQueue[i]);
      // FIXME: This is possible bug in clang, which will instantiate one and
      // the same CXXStaticMemberVar several times. This happens when there are
      // two dependent expressions and the first uses another declaration from
      // the redeclaration chain. This will force Sema in to instantiate the
      // definition (usually the most recent decl in the chain) and then the
      // second expression might referece the definition (which was already)
      // instantiated, but Sema seems not to keep track of these kinds of
      // instantiations, even though the points of instantiation are the same!
      //
      // This should be investigated further when we merge with newest clang.
      // This is triggered by running the roottest: ./root/io/newstl
      if (oldDCI.m_Call == kCCIHandleCXXStaticMemberVarInstantiation)
        continue;
      // It is possible to have duplicate calls to HandleVTable with the same
      // declaration, because each time Sema believes a vtable is used it emits
      // that callback.
      // For reference (clang::CodeGen::CodeGenModule::EmitVTable).
      if (oldDCI.m_Call != kCCIHandleVTable
          && oldDCI.m_Call != kCCIHandleCXXImplicitFunctionInstantiation)
        assert(oldDCI != DCI && "Duplicates?!");
    }
    // We want to assert there is only one wrapper per transaction.
    checkForWrapper = true;
#endif

    // register the wrapper if any.
    if (checkForWrapper && !DCI.m_DGR.isNull() && DCI.m_DGR.isSingleDecl()) {
      if (FunctionDecl* FD = dyn_cast<FunctionDecl>(DCI.m_DGR.getSingleDecl())){
        if (checkForWrapper && utils::Analyze::IsWrapper(FD)) {
          assert(!m_WrapperFD && "Two wrappers in one transaction?");
{'fraction_non_alphanumeric': 0.149368570711717, 'fraction_numerical': 0.0025089905494689304, 'mean_word_length': 2.7841772151898736, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5824528', 'n_tokens_mistral': 3744, 'n_tokens_neox': 3673, 'n_words': 992}