<commit_before>//===-- PrologEpilogInserter.cpp - Insert Prolog/Epilog code in function --===//
//
// This pass is responsible for finalizing the functions frame layout, saving
// callee saved registers, and for emitting prolog & epilog code for the
// function.
//
// This pass must be run after register allocation.  After this pass is
// executed, it is illegal to construct MO_FrameIndex operands.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/MRegisterInfo.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetInstrInfo.h"

namespace {
  struct PEI : public MachineFunctionPass {
    const char *getPassName() const {
      return "Prolog/Epilog Insertion & Frame Finalization";
    }

    /// runOnMachineFunction - Insert prolog/epilog code and replace abstract
    /// frame indexes with appropriate references.
    ///
    bool runOnMachineFunction(MachineFunction &Fn) {
      // Scan the function for modified caller saved registers and insert spill
      // code for any caller saved registers that are modified.  Also calculate
      // the MaxCallFrameSize and HasCalls variables for the function's frame
      // information and eliminates call frame pseudo instructions.
      saveCallerSavedRegisters(Fn);

      // Allow the target machine to make final modifications to the function
      // before the frame layout is finalized.
      Fn.getTarget().getRegisterInfo()->processFunctionBeforeFrameFinalized(Fn);

      // Calculate actual frame offsets for all of the abstract stack objects...
      calculateFrameObjectOffsets(Fn);

      // Add prolog and epilog code to the function.
      insertPrologEpilogCode(Fn);

      // Replace all MO_FrameIndex operands with physical register references
      // and actual offsets.
      //
      replaceFrameIndices(Fn);
      return true;
    }

  private:
    void saveCallerSavedRegisters(MachineFunction &Fn);
    void calculateFrameObjectOffsets(MachineFunction &Fn);
    void replaceFrameIndices(MachineFunction &Fn);
    void insertPrologEpilogCode(MachineFunction &Fn);
  };
}

/// createPrologEpilogCodeInserter - This function returns a pass that inserts
/// prolog and epilog code, and eliminates abstract frame references.
///
Pass *createPrologEpilogCodeInserter() { return new PEI(); }

/// saveCallerSavedRegisters - Scan the function for modified caller saved
/// registers and insert spill code for any caller saved registers that are
/// modified.  Also calculate the MaxCallFrameSize and HasCalls variables for
/// the function's frame information and eliminates call frame pseudo
/// instructions.
///
void PEI::saveCallerSavedRegisters(MachineFunction &Fn) {
  const MRegisterInfo *RegInfo = Fn.getTarget().getRegisterInfo();
  const TargetFrameInfo &FrameInfo = Fn.getTarget().getFrameInfo();

  // Get the callee saved register list...
  const unsigned *CSRegs = RegInfo->getCalleeSaveRegs();

  // Get the function call frame set-up and tear-down instruction opcode
  int FrameSetupOpcode   = RegInfo->getCallFrameSetupOpcode();
  int FrameDestroyOpcode = RegInfo->getCallFrameDestroyOpcode();

  // Early exit for targets which have no callee saved registers and no call
  // frame setup/destroy pseudo instructions.
  if ((CSRegs == 0 || CSRegs[0] == 0) &&
      FrameSetupOpcode == -1 && FrameDestroyOpcode == -1)
    return;

  // This bitset contains an entry for each physical register for the target...
  std::vector<bool> ModifiedRegs(MRegisterInfo::FirstVirtualRegister);
  unsigned MaxCallFrameSize = 0;
  bool HasCalls = false;

  for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB)
    for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); )
      if ((*I)->getOpcode() == FrameSetupOpcode ||
	  (*I)->getOpcode() == FrameDestroyOpcode) {
	assert((*I)->getNumOperands() == 1 && "Call Frame Setup/Destroy Pseudo"
	       " instructions should have a single immediate argument!");
	unsigned Size = (*I)->getOperand(0).getImmedValue();
	if (Size > MaxCallFrameSize) MaxCallFrameSize = Size;
	HasCalls = true;
	RegInfo->eliminateCallFramePseudoInstr(Fn, *BB, I);
      } else {
	for (unsigned i = 0, e = (*I)->getNumOperands(); i != e; ++i) {
	  MachineOperand &MO = (*I)->getOperand(i);
	  assert(!MO.isVirtualRegister() &&
		 "Register allocation must be performed!");
	  if (MO.isPhysicalRegister() && MO.opIsDef())
	    ModifiedRegs[MO.getReg()] = true;         // Register is modified
	}
	++I;
      }

  MachineFrameInfo *FFI = Fn.getFrameInfo();
  FFI->setHasCalls(HasCalls);
  FFI->setMaxCallFrameSize(MaxCallFrameSize);

  // Now figure out which *callee saved* registers are modified by the current
  // function, thus needing to be saved and restored in the prolog/epilog.
  //
  std::vector<unsigned> RegsToSave;
  for (unsigned i = 0; CSRegs[i]; ++i) {
    unsigned Reg = CSRegs[i];
    if (ModifiedRegs[Reg]) {
      RegsToSave.push_back(Reg);  // If modified register...
    } else if (const unsigned *AliasSet = RegInfo->getAliasSet(Reg))
      for (unsigned j = 0; AliasSet[j]; ++j)     // Check alias registers too...
	if (ModifiedRegs[AliasSet[j]]) {
	  RegsToSave.push_back(Reg);
	  break;
	}
  }

  if (RegsToSave.empty())
    return;   // Early exit if no caller saved registers are modified!

  // Now that we know which registers need to be saved and restored, allocate
  // stack slots for them.
  std::vector<int> StackSlots;
  for (unsigned i = 0, e = RegsToSave.size(); i != e; ++i) {
    int FrameIdx = FFI->CreateStackObject(RegInfo->getRegClass(RegsToSave[i]));
    StackSlots.push_back(FrameIdx);
  }

  // Now that we have a stack slot for each register to be saved, insert spill
  // code into the entry block...
  MachineBasicBlock *MBB = Fn.begin();
  MachineBasicBlock::iterator I = MBB->begin();
  for (unsigned i = 0, e = RegsToSave.size(); i != e; ++i) {
    const TargetRegisterClass *RC = RegInfo->getRegClass(RegsToSave[i]);

    // Insert the spill to the stack frame...
    RegInfo->storeRegToStackSlot(*MBB, I, RegsToSave[i], StackSlots[i], RC);
  }

  // Add code to restore the callee-save registers in each exiting block.
  const TargetInstrInfo &TII = Fn.getTarget().getInstrInfo();
  for (MachineFunction::iterator FI = Fn.begin(), E = Fn.end(); FI != E; ++FI) {
    // If last instruction is a return instruction, add an epilogue
    if (TII.isReturn(FI->back()->getOpcode())) {
      MBB = FI; I = MBB->end()-1;

      for (unsigned i = 0, e = RegsToSave.size(); i != e; ++i) {
	const TargetRegisterClass *RC = RegInfo->getRegClass(RegsToSave[i]);
	RegInfo->loadRegFromStackSlot(*MBB, I, RegsToSave[i],StackSlots[i], RC);
	--I;  // Insert in reverse order
      }
    }
  }
}

/// calculateFrameObjectOffsets - Calculate actual frame offsets for all of the
/// abstract stack objects...
///
void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) {
  const TargetFrameInfo &TFI = Fn.getTarget().getFrameInfo();

  bool StackGrowsDown =
    TFI.getStackGrowthDirection() == TargetFrameInfo::StackGrowsDown;
  assert(StackGrowsDown && "Only tested on stack down growing targets!");

  // Loop over all of the stack objects, assigning sequential addresses...
  MachineFrameInfo *FFI = Fn.getFrameInfo();

  unsigned StackAlignment = TFI.getStackAlignment();

  // Start at the beginning of the local area...
  int Offset = TFI.getOffsetOfLocalArea();
  for (unsigned i = 0, e = FFI->getObjectIndexEnd(); i != e; ++i) {
    Offset += FFI->getObjectSize(i);         // Allocate Size bytes...

    unsigned Align = FFI->getObjectAlignment(i);
    assert(Align <= StackAlignment && "Cannot align stack object to higher "
           "alignment boundary than the stack itself!");
    Offset = (Offset+Align-1)/Align*Align;   // Adjust to Alignment boundary...

    FFI->setObjectOffset(i, -Offset);        // Set the computed offset
  }

  // Align the final stack pointer offset...
  Offset = (Offset+StackAlignment-1)/StackAlignment*StackAlignment;

  // Set the final value of the stack pointer...
  FFI->setStackSize(Offset-TFI.getOffsetOfLocalArea());
}

/// insertPrologEpilogCode - Scan the function for modified caller saved
/// registers, insert spill code for these caller saved registers, then add
/// prolog and epilog code to the function.
///
void PEI::insertPrologEpilogCode(MachineFunction &Fn) {
  // Add prologue to the function...
  Fn.getTarget().getRegisterInfo()->emitPrologue(Fn);

  // Add epilogue to restore the callee-save registers in each exiting block
  const TargetInstrInfo &TII = Fn.getTarget().getInstrInfo();
  for (MachineFunction::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I) {
    // If last instruction is a return instruction, add an epilogue
    if (!I->empty() && TII.isReturn(I->back()->getOpcode()))
      Fn.getTarget().getRegisterInfo()->emitEpilogue(Fn, *I);
  }
}

/// replaceFrameIndices - Replace all MO_FrameIndex operands with physical
/// register references and actual offsets.
///
void PEI::replaceFrameIndices(MachineFunction &Fn) {
  if (!Fn.getFrameInfo()->hasStackObjects()) return; // Nothing to do?

  const TargetMachine &TM = Fn.getTarget();
  assert(TM.getRegisterInfo() && "TM::getRegisterInfo() must be implemented!");
  const MRegisterInfo &MRI = *TM.getRegisterInfo();

  for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB)
    for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ++I)
      for (unsigned i = 0, e = (*I)->getNumOperands(); i != e; ++i)
	if ((*I)->getOperand(i).isFrameIndex()) {
	  // If this instruction has a FrameIndex operand, we need to use that
	  // target machine register info object to eliminate it.
	  MRI.eliminateFrameIndex(Fn, I);
	  break;
	}
}
<commit_msg>Fix a bug which occurred with empty basic blocks<commit_after>//===-- PrologEpilogInserter.cpp - Insert Prolog/Epilog code in function --===//
//
// This pass is responsible for finalizing the functions frame layout, saving
// callee saved registers, and for emitting prolog & epilog code for the
// function.
//
// This pass must be run after register allocation.  After this pass is
// executed, it is illegal to construct MO_FrameIndex operands.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/MRegisterInfo.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetInstrInfo.h"

namespace {
  struct PEI : public MachineFunctionPass {
    const char *getPassName() const {
      return "Prolog/Epilog Insertion & Frame Finalization";
    }

    /// runOnMachineFunction - Insert prolog/epilog code and replace abstract
    /// frame indexes with appropriate references.
    ///
    bool runOnMachineFunction(MachineFunction &Fn) {
      // Scan the function for modified caller saved registers and insert spill
      // code for any caller saved registers that are modified.  Also calculate
      // the MaxCallFrameSize and HasCalls variables for the function's frame
      // information and eliminates call frame pseudo instructions.
      saveCallerSavedRegisters(Fn);

      // Allow the target machine to make final modifications to the function
      // before the frame layout is finalized.
      Fn.getTarget().getRegisterInfo()->processFunctionBeforeFrameFinalized(Fn);

      // Calculate actual frame offsets for all of the abstract stack objects...
      calculateFrameObjectOffsets(Fn);

      // Add prolog and epilog code to the function.
      insertPrologEpilogCode(Fn);

      // Replace all MO_FrameIndex operands with physical register references
      // and actual offsets.
      //
      replaceFrameIndices(Fn);
      return true;
    }

  private:
    void saveCallerSavedRegisters(MachineFunction &Fn);
    void calculateFrameObjectOffsets(MachineFunction &Fn);
    void replaceFrameIndices(MachineFunction &Fn);
    void insertPrologEpilogCode(MachineFunction &Fn);
  };
}

/// createPrologEpilogCodeInserter - This function returns a pass that inserts
/// prolog and epilog code, and eliminates abstract frame references.
///
Pass *createPrologEpilogCodeInserter() { return new PEI(); }

/// saveCallerSavedRegisters - Scan the function for modified caller saved
/// registers and insert spill code for any caller saved registers that are
/// modified.  Also calculate the MaxCallFrameSize and HasCalls variables for
/// the function's frame information and eliminates call frame pseudo
/// instructions.
///
void PEI::saveCallerSavedRegisters(MachineFunction &Fn) {
  const MRegisterInfo *RegInfo = Fn.getTarget().getRegisterInfo();
  const TargetFrameInfo &FrameInfo = Fn.getTarget().getFrameInfo();

  // Get the callee saved register list...
  const unsigned *CSRegs = RegInfo->getCalleeSaveRegs();

  // Get the function call frame set-up and tear-down instruction opcode
  int FrameSetupOpcode   = RegInfo->getCallFrameSetupOpcode();
  int FrameDestroyOpcode = RegInfo->getCallFrameDestroyOpcode();

  // Early exit for targets which have no callee saved registers and no call
  // frame setup/destroy pseudo instructions.
  if ((CSRegs == 0 || CSRegs[0] == 0) &&
      FrameSetupOpcode == -1 && FrameDestroyOpcode == -1)
    return;

  // This bitset contains an entry for each physical register for the target...
  std::vector<bool> ModifiedRegs(MRegisterInfo::FirstVirtualRegister);
  unsigned MaxCallFrameSize = 0;
  bool HasCalls = false;

  for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB)
    for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); )
      if ((*I)->getOpcode() == FrameSetupOpcode ||
	  (*I)->getOpcode() == FrameDestroyOpcode) {
	assert((*I)->getNumOperands() == 1 && "Call Frame Setup/Destroy Pseudo"
	       " instructions should have a single immediate argument!");
	unsigned Size = (*I)->getOperand(0).getImmedValue();
	if (Size > MaxCallFrameSize) MaxCallFrameSize = Size;
	HasCalls = true;
	RegInfo->eliminateCallFramePseudoInstr(Fn, *BB, I);
      } else {
	for (unsigned i = 0, e = (*I)->getNumOperands(); i != e; ++i) {
	  MachineOperand &MO = (*I)->getOperand(i);
	  assert(!MO.isVirtualRegister() &&
		 "Register allocation must be performed!");
	  if (MO.isPhysicalRegister() && MO.opIsDef())
	    ModifiedRegs[MO.getReg()] = true;         // Register is modified
	}
	++I;
      }

  MachineFrameInfo *FFI = Fn.getFrameInfo();
  FFI->setHasCalls(HasCalls);
  FFI->setMaxCallFrameSize(MaxCallFrameSize);

  // Now figure out which *callee saved* registers are modified by the current
  // function, thus needing to be saved and restored in the prolog/epilog.
  //
  std::vector<unsigned> RegsToSave;
  for (unsigned i = 0; CSRegs[i]; ++i) {
    unsigned Reg = CSRegs[i];
    if (ModifiedRegs[Reg]) {
      RegsToSave.push_back(Reg);  // If modified register...
    } else if (const unsigned *AliasSet = RegInfo->getAliasSet(Reg))
      for (unsigned j = 0; AliasSet[j]; ++j)     // Check alias registers too...
	if (ModifiedRegs[AliasSet[j]]) {
	  RegsToSave.push_back(Reg);
	  break;
	}
  }

  if (RegsToSave.empty())
    return;   // Early exit if no caller saved registers are modified!

  // Now that we know which registers need to be saved and restored, allocate
  // stack slots for them.
  std::vector<int> StackSlots;
  for (unsigned i = 0, e = RegsToSave.size(); i != e; ++i) {
    int FrameIdx = FFI->CreateStackObject(RegInfo->getRegClass(RegsToSave[i]));
    StackSlots.push_back(FrameIdx);
  }

  // Now that we have a stack slot for each register to be saved, insert spill
  // code into the entry block...
  MachineBasicBlock *MBB = Fn.begin();
  MachineBasicBlock::iterator I = MBB->begin();
  for (unsigned i = 0, e = RegsToSave.size(); i != e; ++i) {
    const TargetRegisterClass *RC = RegInfo->getRegClass(RegsToSave[i]);

    // Insert the spill to the stack frame...
    RegInfo->storeRegToStackSlot(*MBB, I, RegsToSave[i], StackSlots[i], RC);
  }

  // Add code to restore the callee-save registers in each exiting block.
  const TargetInstrInfo &TII = Fn.getTarget().getInstrInfo();
  for (MachineFunction::iterator FI = Fn.begin(), E = Fn.end(); FI != E; ++FI) {
    // If last instruction is a return instruction, add an epilogue
    if (!FI->empty() && TII.isReturn(FI->back()->getOpcode())) {
      MBB = FI; I = MBB->end()-1;

      for (unsigned i = 0, e = RegsToSave.size(); i != e; ++i) {
	const TargetRegisterClass *RC = RegInfo->getRegClass(RegsToSave[i]);
	RegInfo->loadRegFromStackSlot(*MBB, I, RegsToSave[i],StackSlots[i], RC);
	--I;  // Insert in reverse order
      }
    }
  }
}

/// calculateFrameObjectOffsets - Calculate actual frame offsets for all of the
/// abstract stack objects...
///
void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) {
  const TargetFrameInfo &TFI = Fn.getTarget().getFrameInfo();

  bool StackGrowsDown =
    TFI.getStackGrowthDirection() == TargetFrameInfo::StackGrowsDown;
  assert(StackGrowsDown && "Only tested on stack down growing targets!");

  // Loop over all of the stack objects, assigning sequential addresses...
  MachineFrameInfo *FFI = Fn.getFrameInfo();

  unsigned StackAlignment = TFI.getStackAlignment();

  // Start at the beginning of the local area...
  int Offset = TFI.getOffsetOfLocalArea();
  for (unsigned i = 0, e = FFI->getObjectIndexEnd(); i != e; ++i) {
    Offset += FFI->getObjectSize(i);         // Allocate Size bytes...

    unsigned Align = FFI->getObjectAlignment(i);
    assert(Align <= StackAlignment && "Cannot align stack object to higher "
           "alignment boundary than the stack itself!");
    Offset = (Offset+Align-1)/Align*Align;   // Adjust to Alignment boundary...

    FFI->setObjectOffset(i, -Offset);        // Set the computed offset
  }

  // Align the final stack pointer offset...
  Offset = (Offset+StackAlignment-1)/StackAlignment*StackAlignment;

  // Set the final value of the stack pointer...
  FFI->setStackSize(Offset-TFI.getOffsetOfLocalArea());
}

/// insertPrologEpilogCode - Scan the function for modified caller saved
/// registers, insert spill code for these caller saved registers, then add
/// prolog and epilog code to the function.
///
void PEI::insertPrologEpilogCode(MachineFunction &Fn) {
  // Add prologue to the function...
  Fn.getTarget().getRegisterInfo()->emitPrologue(Fn);

  // Add epilogue to restore the callee-save registers in each exiting block
  const TargetInstrInfo &TII = Fn.getTarget().getInstrInfo();
  for (MachineFunction::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I) {
    // If last instruction is a return instruction, add an epilogue
    if (!I->empty() && TII.isReturn(I->back()->getOpcode()))
      Fn.getTarget().getRegisterInfo()->emitEpilogue(Fn, *I);
  }
}

/// replaceFrameIndices - Replace all MO_FrameIndex operands with physical
/// register references and actual offsets.
///
void PEI::replaceFrameIndices(MachineFunction &Fn) {
  if (!Fn.getFrameInfo()->hasStackObjects()) return; // Nothing to do?

  const TargetMachine &TM = Fn.getTarget();
  assert(TM.getRegisterInfo() && "TM::getRegisterInfo() must be implemented!");
  const MRegisterInfo &MRI = *TM.getRegisterInfo();

  for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB)
    for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ++I)
      for (unsigned i = 0, e = (*I)->getNumOperands(); i != e; ++i)
	if ((*I)->getOperand(i).isFrameIndex()) {
	  // If this instruction has a FrameIndex operand, we need to use that
	  // target machine register info object to eliminate it.
	  MRI.eliminateFrameIndex(Fn, I);
	  break;
	}
}
<|endoftext|>


<commit_before>#pragma once

#include <eosio/chain/authority.hpp>
#include <eosio/chain/chain_config.hpp>
#include <eosio/chain/config.hpp>
#include <eosio/chain/types.hpp>

#include <boost/multiprecision/cpp_int.hpp>

namespace eosio { namespace chain { namespace contracts {

using namespace boost::multiprecision;

template<size_t Size>
using uint_t = number<cpp_int_backend<Size, Size, unsigned_magnitude, unchecked, void> >;

using uint8     = uint_t<8>;
using uint16    = uint_t<16>;
using uint32    = uint_t<32>;
using uint64    = uint_t<64>;

using fixed_string32 = fc::fixed_string<fc::array<uint64,4>>;
using fixed_string16 = fc::fixed_string<>;
using type_name      = string;
using field_name     = string;
using table_name     = name;
using action_name    = eosio::chain::action_name;

struct type_def {
   type_def() = default;
   type_def(const type_name& new_type_name, const type_name& type)
   :new_type_name(new_type_name), type(type)
   {}

   type_name   new_type_name;
   type_name   type;
};

struct field_def {
   field_def() = default;
   field_def(const field_name& name, const type_name& type)
   :name(name), type(type)
   {}

   field_name name;
   type_name  type;

   bool operator==(const field_def& other) const {
      return std::tie(name, type) == std::tie(other.name, other.type);
   }
};

struct struct_def {
   struct_def() = default;
   struct_def(const type_name& name, const type_name& base, const vector<field_def>& fields)
   :name(name), base(base), fields(fields)
   {}

   type_name            name;
   type_name            base;
   vector<field_def>    fields;

   bool operator==(const struct_def& other) const {
      return std::tie(name, base, fields) == std::tie(other.name, other.base, other.fields);
   }
};

struct action_def {
   action_def() = default;
   action_def(const action_name& name, const type_name& type)
   :name(name), type(type)
   {}

   action_name name;
   type_name type;
};

struct table_def {
   table_def() = default;
   table_def(const table_name& name, const type_name& index_type, const vector<field_name>& key_names, const vector<type_name>& key_types, const type_name& type)
   :name(name), index_type(index_type), key_names(key_names), key_types(key_types), type(type)
   {}

   table_name         name;        // the name of the table
   type_name          index_type;  // the kind of index, i64, i128i128, etc
   vector<field_name> key_names;   // names for the keys defined by key_types
   vector<type_name>  key_types;   // the type of key parameters
   type_name          type;        // type of binary data stored in this table
};

struct abi_def {
   abi_def() = default;
   abi_def(const vector<type_def>& types, const vector<struct_def>& structs, const vector<action_def>& actions, const vector<table_def>& tables)
   :types(types), structs(structs), actions(actions), tables(tables)
   {}

   vector<type_def>     types;
   vector<struct_def>   structs;
   vector<action_def>   actions;
   vector<table_def>    tables;
};

struct newaccount {
   account_name                     creator;
   account_name                     name;
   authority                        owner;
   authority                        active;
   authority                        recovery;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(newaccount);
   }
};

struct setcode {
   account_name                     account;
   uint8                            vmtype;
   uint8                            vmversion;
   bytes                            code;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(setcode);
   }
};

struct setabi {
   account_name                     account;
   abi_def                          abi;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(setabi);
   }
};

struct updateauth {
   account_name                      account;
   permission_name                   permission;
   permission_name                   parent;
   authority                         data;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(updateauth);
   }
};

struct deleteauth {
   deleteauth() = default;
   deleteauth(const account_name& account, const permission_name& permission)
   :account(account), permission(permission)
   {}

   account_name                      account;
   permission_name                   permission;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(deleteauth);
   }
};

struct linkauth {
   linkauth() = default;
   linkauth(const account_name& account, const account_name& code, const action_name& type, const permission_name& requirement)
   :account(account), code(code), type(type), requirement(requirement)
   {}

   account_name                      account;
   account_name                      code;
   action_name                       type;
   permission_name                   requirement;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(linkauth);
   }
};

struct unlinkauth {
   unlinkauth() = default;
   unlinkauth(const account_name& account, const account_name& code, const action_name& type)
   :account(account), code(code), type(type)
   {}

   account_name                      account;
   account_name                      code;
   action_name                       type;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(unlinkauth);
   }
};

struct onerror : bytes {
   using bytes::bytes;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(onerror);
   }
};

struct postrecovery {
   account_name       account;
   authority          data;
   string             memo;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(postrecovery);
   }
};

struct passrecovery {
   account_name   account;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(passrecovery);
   }
};

struct vetorecovery {
   account_name   account;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(vetorecovery);
   }
};

} } } /// namespace eosio::chain::contracts

FC_REFLECT( eosio::chain::contracts::type_def                         , (new_type_name)(type) )
FC_REFLECT( eosio::chain::contracts::field_def                        , (name)(type) )
FC_REFLECT( eosio::chain::contracts::struct_def                       , (name)(base)(fields) )
FC_REFLECT( eosio::chain::contracts::action_def                       , (name)(type) )
FC_REFLECT( eosio::chain::contracts::table_def                        , (name)(index_type)(key_names)(key_types)(type) )
FC_REFLECT( eosio::chain::contracts::abi_def                          , (types)(structs)(actions)(tables) )

FC_REFLECT( eosio::chain::contracts::newaccount                       , (creator)(name)(owner)(active)(recovery) )
FC_REFLECT( eosio::chain::contracts::setcode                          , (account)(vmtype)(vmversion)(code) ) //abi
FC_REFLECT( eosio::chain::contracts::setabi                           , (account)(abi) )
FC_REFLECT( eosio::chain::contracts::updateauth                       , (account)(permission)(parent)(data) )
FC_REFLECT( eosio::chain::contracts::deleteauth                       , (account)(permission) )
FC_REFLECT( eosio::chain::contracts::linkauth                         , (account)(code)(type)(requirement) )
FC_REFLECT( eosio::chain::contracts::unlinkauth                       , (account)(code)(type) )
FC_REFLECT( eosio::chain::contracts::postrecovery                     , (account)(data)(memo) )
FC_REFLECT( eosio::chain::contracts::passrecovery                     , (account) )
FC_REFLECT( eosio::chain::contracts::vetorecovery                     , (account) )
<commit_msg>remove extra space<commit_after>#pragma once

#include <eosio/chain/authority.hpp>
#include <eosio/chain/chain_config.hpp>
#include <eosio/chain/config.hpp>
#include <eosio/chain/types.hpp>

#include <boost/multiprecision/cpp_int.hpp>

namespace eosio { namespace chain { namespace contracts {

using namespace boost::multiprecision;

template<size_t Size>
using uint_t = number<cpp_int_backend<Size, Size, unsigned_magnitude, unchecked, void> >;

using uint8     = uint_t<8>;
using uint16    = uint_t<16>;
using uint32    = uint_t<32>;
using uint64    = uint_t<64>;

using fixed_string32 = fc::fixed_string<fc::array<uint64,4>>;
using fixed_string16 = fc::fixed_string<>;
using type_name      = string;
using field_name     = string;
using table_name     = name;
using action_name    = eosio::chain::action_name;

struct type_def {
   type_def() = default;
   type_def(const type_name& new_type_name, const type_name& type)
   :new_type_name(new_type_name), type(type)
   {}

   type_name   new_type_name;
   type_name   type;
};

struct field_def {
   field_def() = default;
   field_def(const field_name& name, const type_name& type)
   :name(name), type(type)
   {}

   field_name name;
   type_name  type;

   bool operator==(const field_def& other) const {
      return std::tie(name, type) == std::tie(other.name, other.type);
   }
};

struct struct_def {
   struct_def() = default;
   struct_def(const type_name& name, const type_name& base, const vector<field_def>& fields)
   :name(name), base(base), fields(fields)
   {}

   type_name            name;
   type_name            base;
   vector<field_def>    fields;

   bool operator==(const struct_def& other) const {
      return std::tie(name, base, fields) == std::tie(other.name, other.base, other.fields);
   }
};

struct action_def {
   action_def() = default;
   action_def(const action_name& name, const type_name& type)
   :name(name), type(type)
   {}

   action_name name;
   type_name type;
};

struct table_def {
   table_def() = default;
   table_def(const table_name& name, const type_name& index_type, const vector<field_name>& key_names, const vector<type_name>& key_types, const type_name& type)
   :name(name), index_type(index_type), key_names(key_names), key_types(key_types), type(type)
   {}

   table_name         name;        // the name of the table
   type_name          index_type;  // the kind of index, i64, i128i128, etc
   vector<field_name> key_names;   // names for the keys defined by key_types
   vector<type_name>  key_types;   // the type of key parameters
   type_name          type;        // type of binary data stored in this table
};

struct abi_def {
   abi_def() = default;
   abi_def(const vector<type_def>& types, const vector<struct_def>& structs, const vector<action_def>& actions, const vector<table_def>& tables)
   :types(types), structs(structs), actions(actions), tables(tables)
   {}

   vector<type_def>     types;
   vector<struct_def>   structs;
   vector<action_def>   actions;
   vector<table_def>    tables;
};

struct newaccount {
   account_name                     creator;
   account_name                     name;
   authority                        owner;
   authority                        active;
   authority                        recovery;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(newaccount);
   }
};

struct setcode {
   account_name                     account;
   uint8                            vmtype;
   uint8                            vmversion;
   bytes                            code;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(setcode);
   }
};

struct setabi {
   account_name                     account;
   abi_def                          abi;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(setabi);
   }
};

struct updateauth {
   account_name                      account;
   permission_name                   permission;
   permission_name                   parent;
   authority                         data;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(updateauth);
   }
};

struct deleteauth {
   deleteauth() = default;
   deleteauth(const account_name& account, const permission_name& permission)
   :account(account), permission(permission)
   {}

   account_name                      account;
   permission_name                   permission;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(deleteauth);
   }
};

struct linkauth {
   linkauth() = default;
   linkauth(const account_name& account, const account_name& code, const action_name& type, const permission_name& requirement)
   :account(account), code(code), type(type), requirement(requirement)
   {}

   account_name                      account;
   account_name                      code;
   action_name                       type;
   permission_name                   requirement;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(linkauth);
   }
};

struct unlinkauth {
   unlinkauth() = default;
   unlinkauth(const account_name& account, const account_name& code, const action_name& type)
   :account(account), code(code), type(type)
   {}

   account_name                      account;
   account_name                      code;
   action_name                       type;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(unlinkauth);
   }
};

struct onerror : bytes {
   using bytes::bytes;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(onerror);
   }
};

struct postrecovery {
   account_name       account;
   authority          data;
   string             memo;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(postrecovery);
   }
};

struct passrecovery {
   account_name   account;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(passrecovery);
   }
};

struct vetorecovery {
   account_name   account;

   static account_name get_account() {
      return config::system_account_name;
   }

   static action_name get_name() {
      return N(vetorecovery);
   }
};

} } } /// namespace eosio::chain::contracts

FC_REFLECT( eosio::chain::contracts::type_def                         , (new_type_name)(type) )
FC_REFLECT( eosio::chain::contracts::field_def                        , (name)(type) )
FC_REFLECT( eosio::chain::contracts::struct_def                       , (name)(base)(fields) )
FC_REFLECT( eosio::chain::contracts::action_def                       , (name)(type) )
FC_REFLECT( eosio::chain::contracts::table_def                        , (name)(index_type)(key_names)(key_types)(type) )
FC_REFLECT( eosio::chain::contracts::abi_def                          , (types)(structs)(actions)(tables) )

FC_REFLECT( eosio::chain::contracts::newaccount                       , (creator)(name)(owner)(active)(recovery) )
FC_REFLECT( eosio::chain::contracts::setcode                          , (account)(vmtype)(vmversion)(code) ) //abi
FC_REFLECT( eosio::chain::contracts::setabi                           , (account)(abi) )
FC_REFLECT( eosio::chain::contracts::updateauth                       , (account)(permission)(parent)(data) )
FC_REFLECT( eosio::chain::contracts::deleteauth                       , (account)(permission) )
FC_REFLECT( eosio::chain::contracts::linkauth                         , (account)(code)(type)(requirement) )
FC_REFLECT( eosio::chain::contracts::unlinkauth                       , (account)(code)(type) )
FC_REFLECT( eosio::chain::contracts::postrecovery                     , (account)(data)(memo) )
FC_REFLECT( eosio::chain::contracts::passrecovery                     , (account) )
FC_REFLECT( eosio::chain::contracts::vetorecovery                     , (account) )
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Manasij Mukherjee  <manasij7479@gmail.com>
// author:  Vassil Vassilev <vvasilev@cern.ch>
//
// 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 "llvm/ADT/SmallVector.h"
#include "llvm/Support/Path.h"
#include "clang/Sema/Sema.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTContext.h" // for operator new[](unsigned long, ASTCtx..)
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Frontend/CompilerInstance.h"

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/AutoloadCallback.h"
#include "cling/Interpreter/Transaction.h"

using namespace clang;

namespace cling {

  void AutoloadCallback::report(clang::SourceLocation l, llvm::StringRef name,
                                llvm::StringRef header) {
    Sema& sema= m_Interpreter->getSema();

    unsigned id
      = sema.getDiagnostics().getCustomDiagID (DiagnosticsEngine::Level::Warning,
                                                 "Note: '%0' can be found in %1");
/*    unsigned idn //TODO: To be enabled after we have a way to get the full path
      = sema.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Level::Note,
                                                "Type : %0 , Full Path: %1")*/;

    if (header.startswith(llvm::StringRef("$clingAutoload$", 15)))
      sema.Diags.Report(l, id) << name << header.drop_front(15);

  }

  bool AutoloadCallback::LookupObject (TagDecl *t) {
    if (m_ShowSuggestions && t->hasAttr<AnnotateAttr>())
      report(t->getLocation(),t->getNameAsString(),t->getAttr<AnnotateAttr>()->getAnnotation());
    return false;
  }

  class AutoloadingVisitor: public RecursiveASTVisitor<AutoloadingVisitor> {
  private:
    bool m_IsStoringState;
    AutoloadCallback::FwdDeclsMap* m_Map;
    clang::Preprocessor* m_PP;
  private:
    void InsertIntoAutoloadingState (Decl* decl, llvm::StringRef annotation) {

      assert(!annotation.empty() && "Empty annotation!");
      if (!annotation.startswith(llvm::StringRef("$clingAutoload$", 15))) {
        // not an autoload annotation.
        return;
      }

      assert(m_PP);

      const FileEntry* FE = 0;
      SourceLocation fileNameLoc;
      bool isAngled = false;
      const DirectoryLookup* LookupFrom = 0;
      const DirectoryLookup* CurDir = 0;

      FE = m_PP->LookupFile(fileNameLoc, annotation.data() + 15, isAngled,
                            LookupFrom, CurDir, /*SearchPath*/0,
                            /*RelativePath*/ 0, /*suggestedModule*/0,
                            /*SkipCache*/false, /*OpenFile*/ false,
                            /*CacheFail*/ false);

      assert(FE && "Must have a valid FileEntry");

      if (m_Map->find(FE) == m_Map->end())
        (*m_Map)[FE] = std::vector<Decl*>();

      (*m_Map)[FE].push_back(decl);
    }

  public:
    AutoloadingVisitor() : m_IsStoringState(false), m_Map(0) {}
    void RemoveDefaultArgsOf(Decl* D) {
      //D = D->getMostRecentDecl();
      TraverseDecl(D);
      //while ((D = D->getPreviousDecl()))
      //  TraverseDecl(D);
    }

    void TrackDefaultArgStateOf(Decl* D, AutoloadCallback::FwdDeclsMap& map,
                                Preprocessor& PP) {
      m_IsStoringState = true;
      m_Map = ↦
      m_PP = &PP;
      TraverseDecl(D);
      m_PP = 0;
      m_Map = 0;
      m_IsStoringState = false;
    }

    bool shouldVisitTemplateInstantiations() { return true; }

    bool VisitDecl(Decl* D) {
      if (!m_IsStoringState)
        return true;

      if (!D->hasAttr<AnnotateAttr>())
        return true;

      AnnotateAttr* attr = D->getAttr<AnnotateAttr>();
      if (!attr)
        return true;

      switch (D->getKind()) {
      default:
        InsertIntoAutoloadingState(D, attr->getAnnotation());
        break;
      case Decl::Enum:
        // EnumDecls have extra information 2 chars after the filename used
        // for extra fixups.
          EnumDecl* ED = cast<EnumDecl>(D);
          if (ED->isFixed()) {
            StringRef str = ED->getAttr<AnnotateAttr>()->getAnnotation();
            char ch = str.back();
//            str.drop_back(2);
            ED->getAttr<AnnotateAttr>()->setAnnotation(ED->getASTContext(), str);
            struct EnumDeclDerived: public EnumDecl {
              static void setFixed(EnumDecl* ED, bool value = true) {
                ((EnumDeclDerived*)ED)->IsFixed = value;
              }
            };

            if (ch != '1')
              EnumDeclDerived::setFixed(ED, false);
          }
        InsertIntoAutoloadingState(D, attr->getAnnotation().drop_back(2));
        break;
      }

      return true;
    }

    bool VisitCXXRecordDecl(CXXRecordDecl* D) {
      if (!D->hasAttr<AnnotateAttr>())
        return true;

      VisitDecl(D);

      if (ClassTemplateDecl* TmplD = D->getDescribedClassTemplate())
        return VisitTemplateDecl(TmplD);
      return true;
    }

    bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitTemplateDecl(TemplateDecl* D) {
      if (D->getTemplatedDecl() &&
          !D->getTemplatedDecl()->hasAttr<AnnotateAttr>())
        return true;

      VisitDecl(D);

      for(auto P: D->getTemplateParameters()->asArray())
        TraverseDecl(P);
      return true;
    }

    bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitParmVarDecl(ParmVarDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArg())
        D->setDefaultArg(nullptr);
      return true;
    }
  };

  void AutoloadCallback::InclusionDirective(clang::SourceLocation HashLoc,
                          const clang::Token &IncludeTok,
                          llvm::StringRef FileName,
                          bool IsAngled,
                          clang::CharSourceRange FilenameRange,
                          const clang::FileEntry *File,
                          llvm::StringRef SearchPath,
                          llvm::StringRef RelativePath,
                          const clang::Module *Imported) {
    // If File is 0 this means that the #included file doesn't exist.
    if (!File)
      return;

    auto found = m_Map.find(File);
    if (found == m_Map.end())
     return; // nothing to do, file not referred in any annotation

    AutoloadingVisitor defaultArgsCleaner;
    for (auto D : found->second) {
      defaultArgsCleaner.RemoveDefaultArgsOf(D);
    }
    // Don't need to keep track of cleaned up decls from file.
    m_Map.erase(found);
  }

  AutoloadCallback::~AutoloadCallback() {
  }

  void AutoloadCallback::TransactionCommitted(const Transaction &T) {
    if (T.decls_begin() == T.decls_end())
      return;
    if (T.decls_begin()->m_DGR.isNull())
      return;

    if (const NamedDecl* ND = dyn_cast<NamedDecl>(*T.decls_begin()->m_DGR.begin()))
      if (ND->getIdentifier() && ND->getName().equals("__Cling_Autoloading_Map")) {
        AutoloadingVisitor defaultArgsStateCollector;
        Preprocessor& PP = m_Interpreter->getCI()->getPreprocessor();
        for (Transaction::const_iterator I = T.decls_begin(), E = T.decls_end();
             I != E; ++I) {
          Transaction::DelayCallInfo DCI = *I;

          // if (DCI.m_Call != Transaction::kCCIHandleTopLevelDecl)
          //   continue;
          if (DCI.m_DGR.isNull())
            continue;

          if (const NamedDecl* ND = dyn_cast<NamedDecl>(*T.decls_begin()->m_DGR.begin()))
            if (ND->getIdentifier()
                && ND->getName().equals("__Cling_Autoloading_Map")) {

              for (Transaction::const_iterator I = T.decls_begin(),
                     E = T.decls_end(); I != E; ++I) {
                Transaction::DelayCallInfo DCI = *I;
                for (DeclGroupRef::iterator J = DCI.m_DGR.begin(),
                       JE = DCI.m_DGR.end(); J != JE; ++J) {
                    defaultArgsStateCollector.TrackDefaultArgStateOf(*J, m_Map, PP);
                }
              }
            }

        }
      }
  }

} //end namespace cling
<commit_msg>Do not use (non-0-term) data(); factor out the tag.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Manasij Mukherjee  <manasij7479@gmail.com>
// author:  Vassil Vassilev <vvasilev@cern.ch>
//
// 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 "llvm/ADT/SmallVector.h"
#include "llvm/Support/Path.h"
#include "clang/Sema/Sema.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTContext.h" // for operator new[](unsigned long, ASTCtx..)
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Frontend/CompilerInstance.h"

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/AutoloadCallback.h"
#include "cling/Interpreter/Transaction.h"

namespace {
  constexpr const char annoTag[] = "$clingAutoload$";
  constexpr const size_t lenAnnoTag = sizeof(annoTag) - 1;
}

using namespace clang;

namespace cling {

  void AutoloadCallback::report(clang::SourceLocation l, llvm::StringRef name,
                                llvm::StringRef header) {
    Sema& sema= m_Interpreter->getSema();

    unsigned id
      = sema.getDiagnostics().getCustomDiagID (DiagnosticsEngine::Level::Warning,
                                                 "Note: '%0' can be found in %1");
/*    unsigned idn //TODO: To be enabled after we have a way to get the full path
      = sema.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Level::Note,
                                                "Type : %0 , Full Path: %1")*/;

    if (header.startswith(llvm::StringRef(annoTag, lenAnnoTag)))
      sema.Diags.Report(l, id) << name << header.drop_front(lenAnnoTag);

  }

  bool AutoloadCallback::LookupObject (TagDecl *t) {
    if (m_ShowSuggestions && t->hasAttr<AnnotateAttr>())
      report(t->getLocation(),t->getNameAsString(),t->getAttr<AnnotateAttr>()->getAnnotation());
    return false;
  }

  class AutoloadingVisitor: public RecursiveASTVisitor<AutoloadingVisitor> {
  private:
    bool m_IsStoringState;
    AutoloadCallback::FwdDeclsMap* m_Map;
    clang::Preprocessor* m_PP;
  private:
    void InsertIntoAutoloadingState (Decl* decl, llvm::StringRef annotation) {

      assert(!annotation.empty() && "Empty annotation!");
      if (!annotation.startswith(llvm::StringRef(annoTag, lenAnnoTag))) {
        // not an autoload annotation.
        return;
      }

      assert(m_PP);

      const FileEntry* FE = 0;
      SourceLocation fileNameLoc;
      bool isAngled = false;
      const DirectoryLookup* LookupFrom = 0;
      const DirectoryLookup* CurDir = 0;

      FE = m_PP->LookupFile(fileNameLoc,
                            annotation.drop_front(lenAnnoTag), isAngled,
                            LookupFrom, CurDir, /*SearchPath*/0,
                            /*RelativePath*/ 0, /*suggestedModule*/0,
                            /*SkipCache*/false, /*OpenFile*/ false,
                            /*CacheFail*/ false);

      assert(FE && "Must have a valid FileEntry");

      if (m_Map->find(FE) == m_Map->end())
        (*m_Map)[FE] = std::vector<Decl*>();

      (*m_Map)[FE].push_back(decl);
    }

  public:
    AutoloadingVisitor() : m_IsStoringState(false), m_Map(0) {}
    void RemoveDefaultArgsOf(Decl* D) {
      //D = D->getMostRecentDecl();
      TraverseDecl(D);
      //while ((D = D->getPreviousDecl()))
      //  TraverseDecl(D);
    }

    void TrackDefaultArgStateOf(Decl* D, AutoloadCallback::FwdDeclsMap& map,
                                Preprocessor& PP) {
      m_IsStoringState = true;
      m_Map = ↦
      m_PP = &PP;
      TraverseDecl(D);
      m_PP = 0;
      m_Map = 0;
      m_IsStoringState = false;
    }

    bool shouldVisitTemplateInstantiations() { return true; }

    bool VisitDecl(Decl* D) {
      if (!m_IsStoringState)
        return true;

      if (!D->hasAttr<AnnotateAttr>())
        return true;

      AnnotateAttr* attr = D->getAttr<AnnotateAttr>();
      if (!attr)
        return true;

      switch (D->getKind()) {
      default:
        InsertIntoAutoloadingState(D, attr->getAnnotation());
        break;
      case Decl::Enum:
        // EnumDecls have extra information 2 chars after the filename used
        // for extra fixups.
          EnumDecl* ED = cast<EnumDecl>(D);
          if (ED->isFixed()) {
            StringRef str = ED->getAttr<AnnotateAttr>()->getAnnotation();
            char ch = str.back();
//            str.drop_back(2);
            ED->getAttr<AnnotateAttr>()->setAnnotation(ED->getASTContext(), str);
            struct EnumDeclDerived: public EnumDecl {
              static void setFixed(EnumDecl* ED, bool value = true) {
                ((EnumDeclDerived*)ED)->IsFixed = value;
              }
            };

            if (ch != '1')
              EnumDeclDerived::setFixed(ED, false);
          }
        InsertIntoAutoloadingState(D, attr->getAnnotation().drop_back(2));
        break;
      }

      return true;
    }

    bool VisitCXXRecordDecl(CXXRecordDecl* D) {
      if (!D->hasAttr<AnnotateAttr>())
        return true;

      VisitDecl(D);

      if (ClassTemplateDecl* TmplD = D->getDescribedClassTemplate())
        return VisitTemplateDecl(TmplD);
      return true;
    }

    bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitTemplateDecl(TemplateDecl* D) {
      if (D->getTemplatedDecl() &&
          !D->getTemplatedDecl()->hasAttr<AnnotateAttr>())
        return true;

      VisitDecl(D);

      for(auto P: D->getTemplateParameters()->asArray())
        TraverseDecl(P);
      return true;
    }

    bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitParmVarDecl(ParmVarDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArg())
        D->setDefaultArg(nullptr);
      return true;
    }
  };

  void AutoloadCallback::InclusionDirective(clang::SourceLocation HashLoc,
                          const clang::Token &IncludeTok,
                          llvm::StringRef FileName,
                          bool IsAngled,
                          clang::CharSourceRange FilenameRange,
                          const clang::FileEntry *File,
                          llvm::StringRef SearchPath,
                          llvm::StringRef RelativePath,
                          const clang::Module *Imported) {
    // If File is 0 this means that the #included file doesn't exist.
    if (!File)
      return;

    auto found = m_Map.find(File);
    if (found == m_Map.end())
     return; // nothing to do, file not referred in any annotation

    AutoloadingVisitor defaultArgsCleaner;
    for (auto D : found->second) {
      defaultArgsCleaner.RemoveDefaultArgsOf(D);
    }
    // Don't need to keep track of cleaned up decls from file.
    m_Map.erase(found);
  }

  AutoloadCallback::~AutoloadCallback() {
  }

  void AutoloadCallback::TransactionCommitted(const Transaction &T) {
    if (T.decls_begin() == T.decls_end())
      return;
    if (T.decls_begin()->m_DGR.isNull())
      return;

    if (const NamedDecl* ND = dyn_cast<NamedDecl>(*T.decls_begin()->m_DGR.begin()))
      if (ND->getIdentifier() && ND->getName().equals("__Cling_Autoloading_Map")) {
        AutoloadingVisitor defaultArgsStateCollector;
        Preprocessor& PP = m_Interpreter->getCI()->getPreprocessor();
        for (Transaction::const_iterator I = T.decls_begin(), E = T.decls_end();
             I != E; ++I) {
          Transaction::DelayCallInfo DCI = *I;

          // if (DCI.m_Call != Transaction::kCCIHandleTopLevelDecl)
          //   continue;
          if (DCI.m_DGR.isNull())
            continue;

          if (const NamedDecl* ND = dyn_cast<NamedDecl>(*T.decls_begin()->m_DGR.begin()))
            if (ND->getIdentifier()
                && ND->getName().equals("__Cling_Autoloading_Map")) {

              for (Transaction::const_iterator I = T.decls_begin(),
                     E = T.decls_end(); I != E; ++I) {
                Transaction::DelayCallInfo DCI = *I;
                for (DeclGroupRef::iterator J = DCI.m_DGR.begin(),
                       JE = DCI.m_DGR.end(); J != JE; ++J) {
                    defaultArgsStateCollector.TrackDefaultArgStateOf(*J, m_Map, PP);
                }
              }
            }

        }
      }
  }

} //end namespace cling
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Manasij Mukherjee  <manasij7479@gmail.com>
// author:  Vassil Vassilev <vvasilev@cern.ch>
//
// 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 "llvm/ADT/SmallVector.h"
#include "llvm/Support/Path.h"
#include "clang/Sema/Sema.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTContext.h" // for operator new[](unsigned long, ASTCtx..)
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Frontend/CompilerInstance.h"

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/AutoloadCallback.h"
#include "cling/Interpreter/Transaction.h"

namespace {
  constexpr const char annoTag[] = "$clingAutoload$";
  constexpr const size_t lenAnnoTag = sizeof(annoTag) - 1;
}

using namespace clang;

namespace cling {

  void AutoloadCallback::report(clang::SourceLocation l, llvm::StringRef name,
                                llvm::StringRef header) {
    Sema& sema= m_Interpreter->getSema();

    unsigned id
      = sema.getDiagnostics().getCustomDiagID (DiagnosticsEngine::Level::Warning,
                                                 "Note: '%0' can be found in %1");
/*    unsigned idn //TODO: To be enabled after we have a way to get the full path
      = sema.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Level::Note,
                                                "Type : %0 , Full Path: %1")*/;

    if (header.startswith(llvm::StringRef(annoTag, lenAnnoTag)))
      sema.Diags.Report(l, id) << name << header.drop_front(lenAnnoTag);

  }

  bool AutoloadCallback::LookupObject (TagDecl *t) {
    if (m_ShowSuggestions && t->hasAttr<AnnotateAttr>())
      report(t->getLocation(),t->getNameAsString(),t->getAttr<AnnotateAttr>()->getAnnotation());
    return false;
  }

  class AutoloadingVisitor: public RecursiveASTVisitor<AutoloadingVisitor> {
  private:
    bool m_IsStoringState;
    AutoloadCallback::FwdDeclsMap* m_Map;
    clang::Preprocessor* m_PP;
    clang::FileEntry* m_PrevFE;
    std::string m_PrevFileName;
  private:
    void InsertIntoAutoloadingState (Decl* decl, llvm::StringRef annotation) {

      assert(!annotation.empty() && "Empty annotation!");
      if (!annotation.startswith(llvm::StringRef(annoTag, lenAnnoTag))) {
        // not an autoload annotation.
        return;
      }

      assert(m_PP);

      const FileEntry* FE = 0;
      SourceLocation fileNameLoc;
      bool isAngled = false;
      const DirectoryLookup* LookupFrom = 0;
      const DirectoryLookup* CurDir = 0;
      if (m_PrevFE && m_PrevFileName == annotation.drop_front(lenAnnoTag))
        FE = m_PrevFE;
      else
        FE = m_PP->LookupFile(fileNameLoc,
                              annotation.drop_front(lenAnnoTag), isAngled,
                              LookupFrom, CurDir, /*SearchPath*/0,
                              /*RelativePath*/ 0, /*suggestedModule*/0,
                              /*SkipCache*/false, /*OpenFile*/ false,
                              /*CacheFail*/ false);

      assert(FE && "Must have a valid FileEntry");

      auto& Vec = (*m_Map)[FE];
      Vec.push_back(decl);
    }

  public:
    AutoloadingVisitor():
      m_IsStoringState(false), m_Map(0), m_PP(0), m_PrevFE(0) {}
    void RemoveDefaultArgsOf(Decl* D) {
      //D = D->getMostRecentDecl();
      TraverseDecl(D);
      //while ((D = D->getPreviousDecl()))
      //  TraverseDecl(D);
    }

    void TrackDefaultArgStateOf(Decl* D, AutoloadCallback::FwdDeclsMap& map,
                                Preprocessor& PP) {
      m_IsStoringState = true;
      m_Map = ↦
      m_PP = &PP;
      TraverseDecl(D);
      m_PP = 0;
      m_Map = 0;
      m_IsStoringState = false;
    }

    bool shouldVisitTemplateInstantiations() { return true; }

    bool VisitDecl(Decl* D) {
      if (!m_IsStoringState)
        return true;

      if (!D->hasAttr<AnnotateAttr>())
        return true;

      AnnotateAttr* attr = D->getAttr<AnnotateAttr>();
      if (!attr)
        return true;

      switch (D->getKind()) {
      default:
        InsertIntoAutoloadingState(D, attr->getAnnotation());
        break;
      case Decl::Enum:
        // EnumDecls have extra information 2 chars after the filename used
        // for extra fixups.
          EnumDecl* ED = cast<EnumDecl>(D);
          if (ED->isFixed()) {
            StringRef str = ED->getAttr<AnnotateAttr>()->getAnnotation();
            char ch = str.back();
//            str.drop_back(2);
            ED->getAttr<AnnotateAttr>()->setAnnotation(ED->getASTContext(), str);
            struct EnumDeclDerived: public EnumDecl {
              static void setFixed(EnumDecl* ED, bool value = true) {
                ((EnumDeclDerived*)ED)->IsFixed = value;
              }
            };

            if (ch != '1')
              EnumDeclDerived::setFixed(ED, false);
          }
        InsertIntoAutoloadingState(D, attr->getAnnotation().drop_back(2));
        break;
      }

      return true;
    }

    bool VisitCXXRecordDecl(CXXRecordDecl* D) {
      if (!D->hasAttr<AnnotateAttr>())
        return true;

      VisitDecl(D);

      if (ClassTemplateDecl* TmplD = D->getDescribedClassTemplate())
        return VisitTemplateDecl(TmplD);
      return true;
    }

    bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitTemplateDecl(TemplateDecl* D) {
      if (D->getTemplatedDecl() &&
          !D->getTemplatedDecl()->hasAttr<AnnotateAttr>())
        return true;

      VisitDecl(D);

      for(auto P: D->getTemplateParameters()->asArray())
        TraverseDecl(P);
      return true;
    }

    bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitParmVarDecl(ParmVarDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArg())
        D->setDefaultArg(nullptr);
      return true;
    }
  };

  void AutoloadCallback::InclusionDirective(clang::SourceLocation HashLoc,
                          const clang::Token &IncludeTok,
                          llvm::StringRef FileName,
                          bool IsAngled,
                          clang::CharSourceRange FilenameRange,
                          const clang::FileEntry *File,
                          llvm::StringRef SearchPath,
                          llvm::StringRef RelativePath,
                          const clang::Module *Imported) {
    // If File is 0 this means that the #included file doesn't exist.
    if (!File)
      return;

    auto found = m_Map.find(File);
    if (found == m_Map.end())
     return; // nothing to do, file not referred in any annotation

    AutoloadingVisitor defaultArgsCleaner;
    for (auto D : found->second) {
      defaultArgsCleaner.RemoveDefaultArgsOf(D);
    }
    // Don't need to keep track of cleaned up decls from file.
    m_Map.erase(found);
  }

  AutoloadCallback::~AutoloadCallback() {
  }

  void AutoloadCallback::TransactionCommitted(const Transaction &T) {
    if (T.decls_begin() == T.decls_end())
      return;
    if (T.decls_begin()->m_DGR.isNull())
      return;

    if (const NamedDecl* ND = dyn_cast<NamedDecl>(*T.decls_begin()->m_DGR.begin()))
      if (ND->getIdentifier() && ND->getName().equals("__Cling_Autoloading_Map")) {
        AutoloadingVisitor defaultArgsStateCollector;
        Preprocessor& PP = m_Interpreter->getCI()->getPreprocessor();
        for (Transaction::const_iterator I = T.decls_begin(), E = T.decls_end();
             I != E; ++I) {
          Transaction::DelayCallInfo DCI = *I;

          // if (DCI.m_Call != Transaction::kCCIHandleTopLevelDecl)
          //   continue;
          if (DCI.m_DGR.isNull())
            continue;

          if (const NamedDecl* ND = dyn_cast<NamedDecl>(*T.decls_begin()->m_DGR.begin()))
            if (ND->getIdentifier()
                && ND->getName().equals("__Cling_Autoloading_Map")) {

              for (Transaction::const_iterator I = T.decls_begin(),
                     E = T.decls_end(); I != E; ++I) {
                Transaction::DelayCallInfo DCI = *I;
                for (DeclGroupRef::iterator J = DCI.m_DGR.begin(),
                       JE = DCI.m_DGR.end(); J != JE; ++J) {
                    defaultArgsStateCollector.TrackDefaultArgStateOf(*J, m_Map, PP);
                }
              }
            }

        }
      }
  }

} //end namespace cling
<commit_msg>Fix compilation errors on Windows (constexpr is not known by standard MSVC compiler)<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Manasij Mukherjee  <manasij7479@gmail.com>
// author:  Vassil Vassilev <vvasilev@cern.ch>
//
// 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 "llvm/ADT/SmallVector.h"
#include "llvm/Support/Path.h"
#include "clang/Sema/Sema.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTContext.h" // for operator new[](unsigned long, ASTCtx..)
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Frontend/CompilerInstance.h"

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/AutoloadCallback.h"
#include "cling/Interpreter/Transaction.h"

namespace {
  static const char annoTag[] = "$clingAutoload$";
  static const size_t lenAnnoTag = sizeof(annoTag) - 1;
}

using namespace clang;

namespace cling {

  void AutoloadCallback::report(clang::SourceLocation l, llvm::StringRef name,
                                llvm::StringRef header) {
    Sema& sema= m_Interpreter->getSema();

    unsigned id
      = sema.getDiagnostics().getCustomDiagID (DiagnosticsEngine::Level::Warning,
                                                 "Note: '%0' can be found in %1");
/*    unsigned idn //TODO: To be enabled after we have a way to get the full path
      = sema.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Level::Note,
                                                "Type : %0 , Full Path: %1")*/;

    if (header.startswith(llvm::StringRef(annoTag, lenAnnoTag)))
      sema.Diags.Report(l, id) << name << header.drop_front(lenAnnoTag);

  }

  bool AutoloadCallback::LookupObject (TagDecl *t) {
    if (m_ShowSuggestions && t->hasAttr<AnnotateAttr>())
      report(t->getLocation(),t->getNameAsString(),t->getAttr<AnnotateAttr>()->getAnnotation());
    return false;
  }

  class AutoloadingVisitor: public RecursiveASTVisitor<AutoloadingVisitor> {
  private:
    bool m_IsStoringState;
    AutoloadCallback::FwdDeclsMap* m_Map;
    clang::Preprocessor* m_PP;
    clang::FileEntry* m_PrevFE;
    std::string m_PrevFileName;
  private:
    void InsertIntoAutoloadingState (Decl* decl, llvm::StringRef annotation) {

      assert(!annotation.empty() && "Empty annotation!");
      if (!annotation.startswith(llvm::StringRef(annoTag, lenAnnoTag))) {
        // not an autoload annotation.
        return;
      }

      assert(m_PP);

      const FileEntry* FE = 0;
      SourceLocation fileNameLoc;
      bool isAngled = false;
      const DirectoryLookup* LookupFrom = 0;
      const DirectoryLookup* CurDir = 0;
      if (m_PrevFE && m_PrevFileName == annotation.drop_front(lenAnnoTag))
        FE = m_PrevFE;
      else
        FE = m_PP->LookupFile(fileNameLoc,
                              annotation.drop_front(lenAnnoTag), isAngled,
                              LookupFrom, CurDir, /*SearchPath*/0,
                              /*RelativePath*/ 0, /*suggestedModule*/0,
                              /*SkipCache*/false, /*OpenFile*/ false,
                              /*CacheFail*/ false);

      assert(FE && "Must have a valid FileEntry");

      auto& Vec = (*m_Map)[FE];
      Vec.push_back(decl);
    }

  public:
    AutoloadingVisitor():
      m_IsStoringState(false), m_Map(0), m_PP(0), m_PrevFE(0) {}
    void RemoveDefaultArgsOf(Decl* D) {
      //D = D->getMostRecentDecl();
      TraverseDecl(D);
      //while ((D = D->getPreviousDecl()))
      //  TraverseDecl(D);
    }

    void TrackDefaultArgStateOf(Decl* D, AutoloadCallback::FwdDeclsMap& map,
                                Preprocessor& PP) {
      m_IsStoringState = true;
      m_Map = ↦
      m_PP = &PP;
      TraverseDecl(D);
      m_PP = 0;
      m_Map = 0;
      m_IsStoringState = false;
    }

    bool shouldVisitTemplateInstantiations() { return true; }

    bool VisitDecl(Decl* D) {
      if (!m_IsStoringState)
        return true;

      if (!D->hasAttr<AnnotateAttr>())
        return true;

      AnnotateAttr* attr = D->getAttr<AnnotateAttr>();
      if (!attr)
        return true;

      switch (D->getKind()) {
      default:
        InsertIntoAutoloadingState(D, attr->getAnnotation());
        break;
      case Decl::Enum:
        // EnumDecls have extra information 2 chars after the filename used
        // for extra fixups.
          EnumDecl* ED = cast<EnumDecl>(D);
          if (ED->isFixed()) {
            StringRef str = ED->getAttr<AnnotateAttr>()->getAnnotation();
            char ch = str.back();
//            str.drop_back(2);
            ED->getAttr<AnnotateAttr>()->setAnnotation(ED->getASTContext(), str);
            struct EnumDeclDerived: public EnumDecl {
              static void setFixed(EnumDecl* ED, bool value = true) {
                ((EnumDeclDerived*)ED)->IsFixed = value;
              }
            };

            if (ch != '1')
              EnumDeclDerived::setFixed(ED, false);
          }
        InsertIntoAutoloadingState(D, attr->getAnnotation().drop_back(2));
        break;
      }

      return true;
    }

    bool VisitCXXRecordDecl(CXXRecordDecl* D) {
      if (!D->hasAttr<AnnotateAttr>())
        return true;

      VisitDecl(D);

      if (ClassTemplateDecl* TmplD = D->getDescribedClassTemplate())
        return VisitTemplateDecl(TmplD);
      return true;
    }

    bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitTemplateDecl(TemplateDecl* D) {
      if (D->getTemplatedDecl() &&
          !D->getTemplatedDecl()->hasAttr<AnnotateAttr>())
        return true;

      VisitDecl(D);

      for(auto P: D->getTemplateParameters()->asArray())
        TraverseDecl(P);
      return true;
    }

    bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitParmVarDecl(ParmVarDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArg())
        D->setDefaultArg(nullptr);
      return true;
    }
  };

  void AutoloadCallback::InclusionDirective(clang::SourceLocation HashLoc,
                          const clang::Token &IncludeTok,
                          llvm::StringRef FileName,
                          bool IsAngled,
                          clang::CharSourceRange FilenameRange,
                          const clang::FileEntry *File,
                          llvm::StringRef SearchPath,
                          llvm::StringRef RelativePath,
                          const clang::Module *Imported) {
    // If File is 0 this means that the #included file doesn't exist.
    if (!File)
      return;

    auto found = m_Map.find(File);
    if (found == m_Map.end())
     return; // nothing to do, file not referred in any annotation

    AutoloadingVisitor defaultArgsCleaner;
    for (auto D : found->second) {
      defaultArgsCleaner.RemoveDefaultArgsOf(D);
    }
    // Don't need to keep track of cleaned up decls from file.
    m_Map.erase(found);
  }

  AutoloadCallback::~AutoloadCallback() {
  }

  void AutoloadCallback::TransactionCommitted(const Transaction &T) {
    if (T.decls_begin() == T.decls_end())
      return;
    if (T.decls_begin()->m_DGR.isNull())
      return;

    if (const NamedDecl* ND = dyn_cast<NamedDecl>(*T.decls_begin()->m_DGR.begin()))
      if (ND->getIdentifier() && ND->getName().equals("__Cling_Autoloading_Map")) {
        AutoloadingVisitor defaultArgsStateCollector;
        Preprocessor& PP = m_Interpreter->getCI()->getPreprocessor();
        for (Transaction::const_iterator I = T.decls_begin(), E = T.decls_end();
             I != E; ++I) {
          Transaction::DelayCallInfo DCI = *I;

          // if (DCI.m_Call != Transaction::kCCIHandleTopLevelDecl)
          //   continue;
          if (DCI.m_DGR.isNull())
            continue;

          if (const NamedDecl* ND = dyn_cast<NamedDecl>(*T.decls_begin()->m_DGR.begin()))
            if (ND->getIdentifier()
                && ND->getName().equals("__Cling_Autoloading_Map")) {

              for (Transaction::const_iterator I = T.decls_begin(),
                     E = T.decls_end(); I != E; ++I) {
                Transaction::DelayCallInfo DCI = *I;
                for (DeclGroupRef::iterator J = DCI.m_DGR.begin(),
                       JE = DCI.m_DGR.end(); J != JE; ++J) {
                    defaultArgsStateCollector.TrackDefaultArgStateOf(*J, m_Map, PP);
                }
              }
            }

        }
      }
  }

} //end namespace cling
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
 */

#pragma once

#include <bitset>
#include <algorithm>
#include <stdexcept>
#include <uavcan/internal/impl_constants.hpp>
#include <uavcan/internal/util.hpp>
#include <uavcan/internal/marshalling/type_util.hpp>

namespace uavcan
{

enum ArrayMode { ArrayModeStatic, ArrayModeDynamic };

template <unsigned int Size>
class StaticArrayBase
{
public:
    enum { SizeBitLen = 0 };
    typedef unsigned int SizeType;
    SizeType size()     const { return Size; }
    SizeType capacity() const { return Size; }

protected:
    StaticArrayBase() { }
    ~StaticArrayBase() { }

    SizeType validateRange(SizeType pos) const
    {
        if (pos < Size)
            return pos;
#if UAVCAN_EXCEPTIONS
        throw std::out_of_range(typeid(*this).name());
#else
        assert(0);
        return Size - 1;  // Ha ha
#endif
    }
};

template <unsigned int MaxSize>
class DynamicArrayBase
{
protected:
    typedef IntegerSpec<IntegerBitLen<MaxSize>::Result, SignednessUnsigned, CastModeSaturate> RawSizeType;
public:
    typedef typename StorageType<RawSizeType>::Type SizeType;

private:
    SizeType size_;

protected:
    DynamicArrayBase() : size_(0) { }
    ~DynamicArrayBase() { }

    SizeType validateRange(SizeType pos) const
    {
        if (pos < size_)
            return pos;
#if UAVCAN_EXCEPTIONS
        throw std::out_of_range(typeid(*this).name());
#else
        assert(0);
        return (size_ == 0) ? 0 : (size_ - 1);
#endif
    }

    void grow()
    {
        if (size_ >= MaxSize)
            validateRange(MaxSize);  // Will throw, assert() or do nothing
        else
            size_++;
    }

    void shrink()
    {
        if (size_ > 0)
            size_--;
    }

public:
    enum { SizeBitLen = RawSizeType::BitLen };

    SizeType size() const
    {
        assert(size_ ? ((size_ - 1u) <= (MaxSize - 1u)) : 1); // -Werror=type-limits
        return size_;
    }

    SizeType capacity() const { return MaxSize; }
};

/**
 * Statically allocated array with optional dynamic-like behavior
 */
template <typename T, ArrayMode ArrayMode, unsigned int MaxSize>
class ArrayImpl : public StaticIf<ArrayMode == ArrayModeDynamic,
                                  DynamicArrayBase<MaxSize>,
                                  StaticArrayBase<MaxSize> >::Result
{
    typedef ArrayImpl<T, ArrayMode, MaxSize> SelfType;
    typedef typename StaticIf<ArrayMode == ArrayModeDynamic,
                              DynamicArrayBase<MaxSize>,
                              StaticArrayBase<MaxSize> >::Result Base;

    typename StorageType<T>::Type data_[MaxSize];

    template <typename U>
    typename EnableIf<sizeof(U(0) == U())>::Type initialize(int) { std::fill(data_, data_ + MaxSize, U()); }
    template <typename> void initialize(...) { }

public:
    typedef typename StorageType<T>::Type ValueType;
    typedef typename Base::SizeType SizeType;

    using Base::size;
    using Base::capacity;

    ArrayImpl() { initialize<ValueType>(0); }

    ValueType& at(SizeType pos)             { return data_[validateRange(pos)]; }
    const ValueType& at(SizeType pos) const { return data_[Base::validateRange(pos)]; }

    ValueType& operator[](SizeType pos)             { return at(pos); }
    const ValueType& operator[](SizeType pos) const { return at(pos); }

    ValueType* begin()             { return data_; }
    const ValueType* begin() const { return data_; }
    ValueType* end()               { return data_ + Base::size(); }
    const ValueType* end()   const { return data_ + Base::size(); }

    ValueType& front()             { return at(0); }
    const ValueType& front() const { return at(0); }
    ValueType& back()              { return at(Base::size() - 1); }
    const ValueType& back()  const { return at(Base::size() - 1); }

    template <typename R>
    bool operator<(const R& rhs) const
    {
        return std::lexicographical_compare(begin(), end(), rhs.begin(), rhs.end());
    }

    typedef ValueType* iterator;
    typedef const ValueType* const_iterator;
};

/**
 * Bit array specialization
 */
template <unsigned int MaxSize, ArrayMode ArrayMode, CastMode CastMode>
class ArrayImpl<IntegerSpec<1, SignednessUnsigned, CastMode>, ArrayMode, MaxSize>
    : public std::bitset<MaxSize>
    , public StaticIf<ArrayMode == ArrayModeDynamic, DynamicArrayBase<MaxSize>, StaticArrayBase<MaxSize> >::Result
{
    typedef typename StaticIf<ArrayMode == ArrayModeDynamic,
                              DynamicArrayBase<MaxSize>,
                              StaticArrayBase<MaxSize> >::Result ArrayBase;

public:
    typedef typename std::bitset<MaxSize>::reference Reference;
    typedef typename ArrayBase::SizeType SizeType;

    using ArrayBase::size;
    using ArrayBase::capacity;

    Reference at(SizeType pos)  { return std::bitset<MaxSize>::operator[](ArrayBase::validateRange(pos)); }
    bool at(SizeType pos) const { return std::bitset<MaxSize>::operator[](ArrayBase::validateRange(pos)); }

    Reference operator[](SizeType pos)  { return at(pos); }
    bool operator[](SizeType pos) const { return at(pos); }
};

/**
 * Zero length arrays are not allowed
 */
template <typename T, ArrayMode ArrayMode> class ArrayImpl<T, ArrayMode, 0>;

template <typename T, ArrayMode ArrayMode, unsigned int MaxSize_>
class Array : public ArrayImpl<T, ArrayMode, MaxSize_>
{
    typedef ArrayImpl<T, ArrayMode, MaxSize_> Base;
    typedef Array<T, ArrayMode, MaxSize_> SelfType;

    static bool isOptimizedTailArray(TailArrayOptimizationMode tao_mode)
    {
        return (T::MinBitLen >= 8) && (tao_mode == TailArrayOptEnabled);
    }

    int encodeImpl(ScalarCodec& codec, const TailArrayOptimizationMode tao_mode, FalseType) const  /// Static
    {
        assert(size() > 0);
        for (SizeType i = 0; i < size(); i++)
        {
            const bool last_item = i == (size() - 1);
            const int res = RawValueType::encode(Base::at(i), codec, last_item ? tao_mode : TailArrayOptDisabled);
            if (res <= 0)
                return res;
        }
        return 1;
    }

    int encodeImpl(ScalarCodec& codec, const TailArrayOptimizationMode tao_mode, TrueType) const   /// Dynamic
    {
        StaticAssert<IsDynamic>::check();
        const bool self_tao_enabled = isOptimizedTailArray(tao_mode);
        if (!self_tao_enabled)
        {
            const int res_sz = Base::RawSizeType::encode(size(), codec, TailArrayOptDisabled);
            if (res_sz <= 0)
                return res_sz;
        }
        if (size() == 0)
            return 1;
        return encodeImpl(codec, self_tao_enabled ? TailArrayOptDisabled : tao_mode, FalseType());
    }

    int decodeImpl(ScalarCodec& codec, const TailArrayOptimizationMode tao_mode, FalseType)  /// Static
    {
        assert(size() > 0);
        for (SizeType i = 0; i < size(); i++)
        {
            const bool last_item = i == (size() - 1);
            ValueType value;                          // TODO: avoid extra copy
            const int res = RawValueType::decode(value, codec, last_item ? tao_mode : TailArrayOptDisabled);
            if (res <= 0)
                return res;
            Base::at(i) = value;
        }
        return 1;
    }

    int decodeImpl(ScalarCodec& codec, const TailArrayOptimizationMode tao_mode, TrueType)   /// Dynamic
    {
        StaticAssert<IsDynamic>::check();
        clear();
        if (isOptimizedTailArray(tao_mode))
        {
            while (true)
            {
                ValueType value;
                const int res = RawValueType::decode(value, codec, TailArrayOptDisabled);
                if (res < 0)
                    return res;
                if (res == 0)             // Success: End of stream reached (even if zero items were read)
                    return 1;
                if (size() == MaxSize_)   // Error: Max array length reached, but the end of stream is not
                    return -1;
                push_back(value);
            }
        }
        else
        {
            typename StorageType<typename Base::RawSizeType>::Type sz = 0;
            const int res_sz = Base::RawSizeType::decode(sz, codec, TailArrayOptDisabled);
            if (res_sz <= 0)
                return res_sz;
            if ((sz > 0) && ((sz - 1u) > (MaxSize_ - 1u))) // -Werror=type-limits
                return -1;
            resize(sz);
            if (sz == 0)
                return 1;
            return decodeImpl(codec, tao_mode, FalseType());
        }
        assert(0); // Unreachable
        return -1;
    }

public:
    typedef T RawValueType;
    typedef typename StorageType<T>::Type ValueType;
    typedef typename Base::SizeType SizeType;

    using Base::size;

    enum { IsDynamic = ArrayMode == ArrayModeDynamic };
    enum { MaxSize = MaxSize_ };
    enum { MinBitLen = IsDynamic ? 0 : (RawValueType::MinBitLen * MaxSize) };
    enum { MaxBitLen = Base::SizeBitLen + RawValueType::MaxBitLen * MaxSize };

    static int encode(const SelfType& array, ScalarCodec& codec, const TailArrayOptimizationMode tao_mode)
    {
        return array.encodeImpl(codec, tao_mode, BooleanType<IsDynamic>());
    }

    static int decode(SelfType& array, ScalarCodec& codec, const TailArrayOptimizationMode tao_mode)
    {
        return array.decodeImpl(codec, tao_mode, BooleanType<IsDynamic>());
    }

    bool empty() const { return size() == 0; }

    void pop_back() { Base::shrink(); }
    void push_back(const ValueType& value)
    {
        Base::grow();
        Base::at(size() - 1) = value;
    }

    void resize(SizeType new_size, ValueType filler = ValueType())
    {
        if (new_size > size())
        {
            unsigned int cnt = new_size - size();
            while (cnt--)
                push_back(filler);
        }
        else if (new_size < size())
        {
            unsigned int cnt = size() - new_size;
            while (cnt--)
                pop_back();
        }
    }

    void clear() { resize(0); }

    template <typename R>
    bool operator==(const R& rhs) const
    {
        if (size() != rhs.size())
            return false;
        for (SizeType i = 0; i < size(); i++)  // Bitset does not have iterators
            if (!(Base::at(i) == rhs[i]))
                return false;
        return true;
    }
    template <typename R> bool operator!=(const R& rhs) const { return !operator==(rhs); }

    typedef ValueType value_type;
    typedef SizeType size_type;
};

}
<commit_msg>Optimized Array<>::clear()<commit_after>/*
 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
 */

#pragma once

#include <bitset>
#include <algorithm>
#include <stdexcept>
#include <uavcan/internal/impl_constants.hpp>
#include <uavcan/internal/util.hpp>
#include <uavcan/internal/marshalling/type_util.hpp>

namespace uavcan
{

enum ArrayMode { ArrayModeStatic, ArrayModeDynamic };

template <unsigned int Size>
class StaticArrayBase
{
public:
    enum { SizeBitLen = 0 };
    typedef unsigned int SizeType;
    SizeType size()     const { return Size; }
    SizeType capacity() const { return Size; }

protected:
    StaticArrayBase() { }
    ~StaticArrayBase() { }

    SizeType validateRange(SizeType pos) const
    {
        if (pos < Size)
            return pos;
#if UAVCAN_EXCEPTIONS
        throw std::out_of_range(typeid(*this).name());
#else
        assert(0);
        return Size - 1;  // Ha ha
#endif
    }
};

template <unsigned int MaxSize>
class DynamicArrayBase
{
protected:
    typedef IntegerSpec<IntegerBitLen<MaxSize>::Result, SignednessUnsigned, CastModeSaturate> RawSizeType;
public:
    typedef typename StorageType<RawSizeType>::Type SizeType;

private:
    SizeType size_;

protected:
    DynamicArrayBase() : size_(0) { }
    ~DynamicArrayBase() { }

    SizeType validateRange(SizeType pos) const
    {
        if (pos < size_)
            return pos;
#if UAVCAN_EXCEPTIONS
        throw std::out_of_range(typeid(*this).name());
#else
        assert(0);
        return (size_ == 0) ? 0 : (size_ - 1);
#endif
    }

    void grow()
    {
        if (size_ >= MaxSize)
            validateRange(MaxSize);  // Will throw, assert() or do nothing
        else
            size_++;
    }

    void shrink()
    {
        if (size_ > 0)
            size_--;
    }

public:
    enum { SizeBitLen = RawSizeType::BitLen };

    SizeType size() const
    {
        assert(size_ ? ((size_ - 1u) <= (MaxSize - 1u)) : 1); // -Werror=type-limits
        return size_;
    }

    SizeType capacity() const { return MaxSize; }

    void clear() { size_ = 0; }
};

/**
 * Statically allocated array with optional dynamic-like behavior
 */
template <typename T, ArrayMode ArrayMode, unsigned int MaxSize>
class ArrayImpl : public StaticIf<ArrayMode == ArrayModeDynamic,
                                  DynamicArrayBase<MaxSize>,
                                  StaticArrayBase<MaxSize> >::Result
{
    typedef ArrayImpl<T, ArrayMode, MaxSize> SelfType;
    typedef typename StaticIf<ArrayMode == ArrayModeDynamic,
                              DynamicArrayBase<MaxSize>,
                              StaticArrayBase<MaxSize> >::Result Base;

    typename StorageType<T>::Type data_[MaxSize];

    template <typename U>
    typename EnableIf<sizeof(U(0) == U())>::Type initialize(int) { std::fill(data_, data_ + MaxSize, U()); }
    template <typename> void initialize(...) { }

public:
    typedef typename StorageType<T>::Type ValueType;
    typedef typename Base::SizeType SizeType;

    using Base::size;
    using Base::capacity;

    ArrayImpl() { initialize<ValueType>(0); }

    ValueType& at(SizeType pos)             { return data_[validateRange(pos)]; }
    const ValueType& at(SizeType pos) const { return data_[Base::validateRange(pos)]; }

    ValueType& operator[](SizeType pos)             { return at(pos); }
    const ValueType& operator[](SizeType pos) const { return at(pos); }

    ValueType* begin()             { return data_; }
    const ValueType* begin() const { return data_; }
    ValueType* end()               { return data_ + Base::size(); }
    const ValueType* end()   const { return data_ + Base::size(); }

    ValueType& front()             { return at(0); }
    const ValueType& front() const { return at(0); }
    ValueType& back()              { return at(Base::size() - 1); }
    const ValueType& back()  const { return at(Base::size() - 1); }

    template <typename R>
    bool operator<(const R& rhs) const
    {
        return std::lexicographical_compare(begin(), end(), rhs.begin(), rhs.end());
    }

    typedef ValueType* iterator;
    typedef const ValueType* const_iterator;
};

/**
 * Bit array specialization
 */
template <unsigned int MaxSize, ArrayMode ArrayMode, CastMode CastMode>
class ArrayImpl<IntegerSpec<1, SignednessUnsigned, CastMode>, ArrayMode, MaxSize>
    : public std::bitset<MaxSize>
    , public StaticIf<ArrayMode == ArrayModeDynamic, DynamicArrayBase<MaxSize>, StaticArrayBase<MaxSize> >::Result
{
    typedef typename StaticIf<ArrayMode == ArrayModeDynamic,
                              DynamicArrayBase<MaxSize>,
                              StaticArrayBase<MaxSize> >::Result ArrayBase;

public:
    typedef typename std::bitset<MaxSize>::reference Reference;
    typedef typename ArrayBase::SizeType SizeType;

    using ArrayBase::size;
    using ArrayBase::capacity;

    Reference at(SizeType pos)  { return std::bitset<MaxSize>::operator[](ArrayBase::validateRange(pos)); }
    bool at(SizeType pos) const { return std::bitset<MaxSize>::operator[](ArrayBase::validateRange(pos)); }

    Reference operator[](SizeType pos)  { return at(pos); }
    bool operator[](SizeType pos) const { return at(pos); }
};

/**
 * Zero length arrays are not allowed
 */
template <typename T, ArrayMode ArrayMode> class ArrayImpl<T, ArrayMode, 0>;

template <typename T, ArrayMode ArrayMode, unsigned int MaxSize_>
class Array : public ArrayImpl<T, ArrayMode, MaxSize_>
{
    typedef ArrayImpl<T, ArrayMode, MaxSize_> Base;
    typedef Array<T, ArrayMode, MaxSize_> SelfType;

    static bool isOptimizedTailArray(TailArrayOptimizationMode tao_mode)
    {
        return (T::MinBitLen >= 8) && (tao_mode == TailArrayOptEnabled);
    }

    int encodeImpl(ScalarCodec& codec, const TailArrayOptimizationMode tao_mode, FalseType) const  /// Static
    {
        assert(size() > 0);
        for (SizeType i = 0; i < size(); i++)
        {
            const bool last_item = i == (size() - 1);
            const int res = RawValueType::encode(Base::at(i), codec, last_item ? tao_mode : TailArrayOptDisabled);
            if (res <= 0)
                return res;
        }
        return 1;
    }

    int encodeImpl(ScalarCodec& codec, const TailArrayOptimizationMode tao_mode, TrueType) const   /// Dynamic
    {
        StaticAssert<IsDynamic>::check();
        const bool self_tao_enabled = isOptimizedTailArray(tao_mode);
        if (!self_tao_enabled)
        {
            const int res_sz = Base::RawSizeType::encode(size(), codec, TailArrayOptDisabled);
            if (res_sz <= 0)
                return res_sz;
        }
        if (size() == 0)
            return 1;
        return encodeImpl(codec, self_tao_enabled ? TailArrayOptDisabled : tao_mode, FalseType());
    }

    int decodeImpl(ScalarCodec& codec, const TailArrayOptimizationMode tao_mode, FalseType)  /// Static
    {
        assert(size() > 0);
        for (SizeType i = 0; i < size(); i++)
        {
            const bool last_item = i == (size() - 1);
            ValueType value;                          // TODO: avoid extra copy
            const int res = RawValueType::decode(value, codec, last_item ? tao_mode : TailArrayOptDisabled);
            if (res <= 0)
                return res;
            Base::at(i) = value;
        }
        return 1;
    }

    int decodeImpl(ScalarCodec& codec, const TailArrayOptimizationMode tao_mode, TrueType)   /// Dynamic
    {
        StaticAssert<IsDynamic>::check();
        Base::clear();
        if (isOptimizedTailArray(tao_mode))
        {
            while (true)
            {
                ValueType value;
                const int res = RawValueType::decode(value, codec, TailArrayOptDisabled);
                if (res < 0)
                    return res;
                if (res == 0)             // Success: End of stream reached (even if zero items were read)
                    return 1;
                if (size() == MaxSize_)   // Error: Max array length reached, but the end of stream is not
                    return -1;
                push_back(value);
            }
        }
        else
        {
            typename StorageType<typename Base::RawSizeType>::Type sz = 0;
            const int res_sz = Base::RawSizeType::decode(sz, codec, TailArrayOptDisabled);
            if (res_sz <= 0)
                return res_sz;
            if ((sz > 0) && ((sz - 1u) > (MaxSize_ - 1u))) // -Werror=type-limits
                return -1;
            resize(sz);
            if (sz == 0)
                return 1;
            return decodeImpl(codec, tao_mode, FalseType());
        }
        assert(0); // Unreachable
        return -1;
    }

public:
    typedef T RawValueType;
    typedef typename StorageType<T>::Type ValueType;
    typedef typename Base::SizeType SizeType;

    using Base::size;

    enum { IsDynamic = ArrayMode == ArrayModeDynamic };
    enum { MaxSize = MaxSize_ };
    enum { MinBitLen = IsDynamic ? 0 : (RawValueType::MinBitLen * MaxSize) };
    enum { MaxBitLen = Base::SizeBitLen + RawValueType::MaxBitLen * MaxSize };

    static int encode(const SelfType& array, ScalarCodec& codec, const TailArrayOptimizationMode tao_mode)
    {
        return array.encodeImpl(codec, tao_mode, BooleanType<IsDynamic>());
    }

    static int decode(SelfType& array, ScalarCodec& codec, const TailArrayOptimizationMode tao_mode)
    {
        return array.decodeImpl(codec, tao_mode, BooleanType<IsDynamic>());
    }

    bool empty() const { return size() == 0; }

    void pop_back() { Base::shrink(); }
    void push_back(const ValueType& value)
    {
        Base::grow();
        Base::at(size() - 1) = value;
    }

    void resize(SizeType new_size, ValueType filler = ValueType())
    {
        if (new_size > size())
        {
            unsigned int cnt = new_size - size();
            while (cnt--)
                push_back(filler);
        }
        else if (new_size < size())
        {
            unsigned int cnt = size() - new_size;
            while (cnt--)
                pop_back();
        }
    }

    template <typename R>
    bool operator==(const R& rhs) const
    {
        if (size() != rhs.size())
            return false;
        for (SizeType i = 0; i < size(); i++)  // Bitset does not have iterators
            if (!(Base::at(i) == rhs[i]))
                return false;
        return true;
    }
    template <typename R> bool operator!=(const R& rhs) const { return !operator==(rhs); }

    typedef ValueType value_type;
    typedef SizeType size_type;
};

}
<|endoftext|>


<commit_before><commit_msg>Parse several local recipients correctely.<commit_after><|endoftext|>