<commit_before>//===- Core/Resolver.cpp - Resolves Atom References -----------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lld/Core/Atom.h"
#include "lld/Core/ArchiveLibraryFile.h"
#include "lld/Core/File.h"
#include "lld/Core/SharedLibraryFile.h"
#include "lld/Core/Instrumentation.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/Resolver.h"
#include "lld/Core/SymbolTable.h"
#include "lld/Core/LinkingContext.h"
#include "lld/Core/UndefinedAtom.h"

#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"

#include <algorithm>
#include <cassert>
#include <vector>

namespace lld {

namespace {

/// This is used as a filter function to std::remove_if to coalesced atoms.
class AtomCoalescedAway {
public:
  explicit AtomCoalescedAway(SymbolTable &sym) : _symbolTable(sym) {}

  bool operator()(const Atom *atom) const {
    const Atom *rep = _symbolTable.replacement(atom);
    return rep != atom;
  }

private:
  SymbolTable &_symbolTable;
};

} // namespace

void Resolver::handleFile(const File &file) {
  bool isEmpty = file.defined().empty() && file.undefined().empty() &&
                 file.sharedLibrary().empty() && file.absolute().empty();
  if (isEmpty)
    return;

  for (const DefinedAtom *atom : file.defined())
    doDefinedAtom(*atom);
  for (const UndefinedAtom *atom : file.undefined())
    doUndefinedAtom(*atom);
  for (const SharedLibraryAtom *atom : file.sharedLibrary())
    doSharedLibraryAtom(*atom);
  for (const AbsoluteAtom *atom : file.absolute())
    doAbsoluteAtom(*atom);

  // Notify the input file manager of the fact that we have made some progress
  // on linking using the current input file. It may want to know the fact for
  // --start-group/--end-group.
  _context.getInputGraph().notifyProgress();
}

void Resolver::forEachUndefines(bool searchForOverrides,
                                UndefCallback callback) {
  // Handle normal archives
  int64_t undefineGenCount = 0;
  do {
    undefineGenCount = _symbolTable.size();
    for (const UndefinedAtom *undefAtom : _symbolTable.undefines()) {
      StringRef undefName = undefAtom->name();
      // load for previous undefine may also have loaded this undefine
      if (!_symbolTable.isDefined(undefName))
        callback(undefName, false);
    }

    // search libraries for overrides of common symbols
    if (searchForOverrides) {
      for (StringRef tentDefName : _symbolTable.tentativeDefinitions()) {
        // Load for previous tentative may also have loaded
        // something that overrode this tentative, so always check.
        const Atom *curAtom = _symbolTable.findByName(tentDefName);
        assert(curAtom != nullptr);
        if (const DefinedAtom *curDefAtom = dyn_cast<DefinedAtom>(curAtom)) {
          if (curDefAtom->merge() == DefinedAtom::mergeAsTentative)
            callback(tentDefName, true);
        }
      }
    }
  } while (undefineGenCount != _symbolTable.size());
}

void Resolver::handleArchiveFile(const File &file) {
  const ArchiveLibraryFile *archiveFile = cast<ArchiveLibraryFile>(&file);
  bool searchForOverrides =
      _context.searchArchivesToOverrideTentativeDefinitions();
  forEachUndefines(searchForOverrides,
                   [&](StringRef undefName, bool dataSymbolOnly) {
    if (const File *member = archiveFile->find(undefName, dataSymbolOnly)) {
      member->setOrdinal(_context.getNextOrdinalAndIncrement());
      handleFile(*member);
    }
  });
}

void Resolver::handleSharedLibrary(const File &file) {
  // Add all the atoms from the shared library
  const SharedLibraryFile *sharedLibrary = cast<SharedLibraryFile>(&file);
  handleFile(*sharedLibrary);
  bool searchForOverrides =
      _context.searchSharedLibrariesToOverrideTentativeDefinitions();
  forEachUndefines(searchForOverrides,
                   [&](StringRef undefName, bool dataSymbolOnly) {
    if (const SharedLibraryAtom *atom =
            sharedLibrary->exports(undefName, dataSymbolOnly))
      doSharedLibraryAtom(*atom);
  });
}

void Resolver::doUndefinedAtom(const UndefinedAtom &atom) {
  DEBUG_WITH_TYPE("resolver", llvm::dbgs()
                    << "       UndefinedAtom: "
                    << llvm::format("0x%09lX", &atom)
                    << ", name=" << atom.name() << "\n");

  // add to list of known atoms
  _atoms.push_back(&atom);

  // tell symbol table
  _symbolTable.add(atom);

  // If the undefined symbol has an alternative name, try to resolve the
  // symbol with the name to give it a second chance. This feature is used
  // for COFF "weak external" symbol.
  if (!_symbolTable.isDefined(atom.name())) {
    if (const UndefinedAtom *fallbackAtom = atom.fallback()) {
      doUndefinedAtom(*fallbackAtom);
      _symbolTable.addReplacement(&atom, fallbackAtom);
    }
  }
}

/// \brief Add the section group and the group-child reference members.
bool Resolver::maybeAddSectionGroupOrGnuLinkOnce(const DefinedAtom &atom) {
  // First time adding a group?
  bool isFirstTime = _symbolTable.addGroup(atom);

  if (!isFirstTime) {
    // If duplicate symbols are allowed, select the first group.
    if (_context.getAllowDuplicates())
      return true;
    const DefinedAtom *prevGroup =
        dyn_cast<DefinedAtom>(_symbolTable.findGroup(atom.name()));
    assert(prevGroup &&
           "Internal Error: The group atom could only be a defined atom");
    // The atoms should be of the same content type, reject invalid group
    // resolution behaviors.
    if (atom.contentType() != prevGroup->contentType())
      return false;
    return true;
  }

  for (const Reference *r : atom) {
    if ((r->kindNamespace() == lld::Reference::KindNamespace::all) &&
        (r->kindValue() == lld::Reference::kindGroupChild)) {
      const DefinedAtom *target = dyn_cast<DefinedAtom>(r->target());
      assert(target && "Internal Error: kindGroupChild references need to "
                       "be associated with Defined Atoms only");
      _atoms.push_back(target);
      _symbolTable.add(*target);
    }
  }
  return true;
}

// called on each atom when a file is added
void Resolver::doDefinedAtom(const DefinedAtom &atom) {
  DEBUG_WITH_TYPE("resolver", llvm::dbgs()
                    << "         DefinedAtom: "
                    << llvm::format("0x%09lX", &atom)
                    << ", file=#"
                    << atom.file().ordinal()
                    << ", atom=#"
                    << atom.ordinal()
                    << ", name="
                    << atom.name()
                    << "\n");

  // Verify on zero-size atoms are pinned to start or end of section.
  if (atom.sectionPosition() == DefinedAtom::sectionPositionStart ||
      atom.sectionPosition() == DefinedAtom::sectionPositionEnd) {
    assert(atom.size() == 0);
  }

  // add to list of known atoms
  _atoms.push_back(&atom);

  if (atom.isGroupParent()) {
    // Raise error if there exists a similar gnu linkonce section.
    if (!maybeAddSectionGroupOrGnuLinkOnce(atom)) {
      llvm::errs() << "SymbolTable: error while merging " << atom.name()
                   << "\n";
      llvm::report_fatal_error("duplicate symbol error");
    }
  } else {
    _symbolTable.add(atom);
  }

  // An atom that should never be dead-stripped is a dead-strip root.
  if (_context.deadStrip() && atom.deadStrip() == DefinedAtom::deadStripNever) {
    _deadStripRoots.insert(&atom);
  }
}

void Resolver::doSharedLibraryAtom(const SharedLibraryAtom &atom) {
  DEBUG_WITH_TYPE("resolver", llvm::dbgs()
                    << "   SharedLibraryAtom: "
                    << llvm::format("0x%09lX", &atom)
                    << ", name="
                    << atom.name()
                    << "\n");

  // add to list of known atoms
  _atoms.push_back(&atom);

  // tell symbol table
  _symbolTable.add(atom);
}

void Resolver::doAbsoluteAtom(const AbsoluteAtom &atom) {
  DEBUG_WITH_TYPE("resolver", llvm::dbgs()
                    << "       AbsoluteAtom: "
                    << llvm::format("0x%09lX", &atom)
                    << ", name="
                    << atom.name()
                    << "\n");

  // add to list of known atoms
  _atoms.push_back(&atom);

  // tell symbol table
  if (atom.scope() != Atom::scopeTranslationUnit)
    _symbolTable.add(atom);
}

// utility to add a vector of atoms
void Resolver::addAtoms(const std::vector<const DefinedAtom *> &newAtoms) {
  for (const DefinedAtom *newAtom : newAtoms)
    doDefinedAtom(*newAtom);
}

// Keep adding atoms until _context.getNextFile() returns an error. This
// function is where undefined atoms are resolved.
bool Resolver::resolveUndefines() {
  ScopedTask task(getDefaultDomain(), "resolveUndefines");

  for (;;) {
    ErrorOr<File &> file = _context.getInputGraph().getNextFile();
    error_code ec = file.getError();
    if (ec == InputGraphError::no_more_files)
      return true;
    if (!file) {
      llvm::errs() << "Error occurred in getNextFile: " << ec.message() << "\n";
      return false;
    }

    switch (file->kind()) {
    case File::kindObject:
      assert(!file->hasOrdinal());
      file->setOrdinal(_context.getNextOrdinalAndIncrement());
      handleFile(*file);
      break;
    case File::kindArchiveLibrary:
      if (!file->hasOrdinal())
        file->setOrdinal(_context.getNextOrdinalAndIncrement());
      handleArchiveFile(*file);
      break;
    case File::kindSharedLibrary:
      if (!file->hasOrdinal())
        file->setOrdinal(_context.getNextOrdinalAndIncrement());
      handleSharedLibrary(*file);
      break;
    }
  }
}

// switch all references to undefined or coalesced away atoms
// to the new defined atom
void Resolver::updateReferences() {
  ScopedTask task(getDefaultDomain(), "updateReferences");
  for (const Atom *atom : _atoms) {
    if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) {
      for (const Reference *ref : *defAtom) {
        const Atom *newTarget = _symbolTable.replacement(ref->target());
        const_cast<Reference *>(ref)->setTarget(newTarget);
      }
    }
  }
}

// For dead code stripping, recursively mark atoms "live"
void Resolver::markLive(const Atom &atom) {
  // Mark the atom is live. If it's already marked live, then stop recursion.
  auto exists = _liveAtoms.insert(&atom);
  if (!exists.second)
    return;

  // Mark all atoms it references as live
  if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&atom))
    for (const Reference *ref : *defAtom)
      if (const Atom *target = ref->target())
        markLive(*target);
}

// remove all atoms not actually used
void Resolver::deadStripOptimize() {
  ScopedTask task(getDefaultDomain(), "deadStripOptimize");
  // only do this optimization with -dead_strip
  if (!_context.deadStrip())
    return;
  assert(_liveAtoms.empty());

  // By default, shared libraries are built with all globals as dead strip roots
  if (_context.globalsAreDeadStripRoots())
    for (const Atom *atom : _atoms)
      if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom))
        if (defAtom->scope() == DefinedAtom::scopeGlobal)
          _deadStripRoots.insert(defAtom);

  // Or, use list of names that are dead strip roots.
  for (const StringRef &name : _context.deadStripRoots()) {
    const Atom *symAtom = _symbolTable.findByName(name);
    assert(symAtom);
    _deadStripRoots.insert(symAtom);
  }

  // mark all roots as live, and recursively all atoms they reference
  for (const Atom *dsrAtom : _deadStripRoots)
    markLive(*dsrAtom);

  // now remove all non-live atoms from _atoms
  _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), [&](const Atom *a) {
                 return _liveAtoms.count(a) == 0;
               }),
               _atoms.end());
}

// error out if some undefines remain
bool Resolver::checkUndefines() {
  // build vector of remaining undefined symbols
  std::vector<const UndefinedAtom *> undefinedAtoms = _symbolTable.undefines();
  if (_context.deadStrip()) {
    // When dead code stripping, we don't care if dead atoms are undefined.
    undefinedAtoms.erase(
        std::remove_if(undefinedAtoms.begin(), undefinedAtoms.end(),
                       [&](const Atom *a) { return _liveAtoms.count(a) == 0; }),
        undefinedAtoms.end());
  }

  // error message about missing symbols
  if (!undefinedAtoms.empty()) {
    // FIXME: need diagnostics interface for writing error messages
    bool foundUndefines = false;
    for (const UndefinedAtom *undefAtom : undefinedAtoms) {
      const File &f = undefAtom->file();

      // Skip over a weak symbol.
      if (undefAtom->canBeNull() != UndefinedAtom::canBeNullNever)
        continue;

      // If this is a library and undefined symbols are allowed on the
      // target platform, skip over it.
      if (isa<SharedLibraryFile>(f) && _context.allowShlibUndefines())
        continue;

      // If the undefine is coalesced away, skip over it.
      if (_symbolTable.replacement(undefAtom) != undefAtom)
        continue;

      // Seems like this symbol is undefined. Warn that.
      foundUndefines = true;
      if (_context.printRemainingUndefines()) {
        llvm::errs() << "Undefined symbol: " << undefAtom->file().path()
                     << ": " << undefAtom->name() << "\n";
      }
    }
    if (foundUndefines) {
      if (_context.printRemainingUndefines())
        llvm::errs() << "symbol(s) not found\n";
      return true;
    }
  }
  return false;
}

// remove from _atoms all coaleseced away atoms
void Resolver::removeCoalescedAwayAtoms() {
  ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms");
  _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(),
                              AtomCoalescedAway(_symbolTable)),
               _atoms.end());
}

bool Resolver::resolve() {
  if (!resolveUndefines())
    return false;
  updateReferences();
  deadStripOptimize();
  if (checkUndefines())
    if (!_context.allowRemainingUndefines())
      return false;
  removeCoalescedAwayAtoms();
  _result->addAtoms(_atoms);
  return true;
}

void Resolver::MergedFile::addAtom(const Atom &atom) {
  if (auto *def = dyn_cast<DefinedAtom>(&atom)) {
    _definedAtoms._atoms.push_back(def);
  } else if (auto *undef = dyn_cast<UndefinedAtom>(&atom)) {
    _undefinedAtoms._atoms.push_back(undef);
  } else if (auto *shared = dyn_cast<SharedLibraryAtom>(&atom)) {
    _sharedLibraryAtoms._atoms.push_back(shared);
  } else if (auto *abs = dyn_cast<AbsoluteAtom>(&atom)) {
    _absoluteAtoms._atoms.push_back(abs);
  } else {
    llvm_unreachable("atom has unknown definition kind");
  }
}

MutableFile::DefinedAtomRange Resolver::MergedFile::definedAtoms() {
  return range<std::vector<const DefinedAtom *>::iterator>(
      _definedAtoms._atoms.begin(), _definedAtoms._atoms.end());
}

void Resolver::MergedFile::addAtoms(std::vector<const Atom *> &all) {
  ScopedTask task(getDefaultDomain(), "addAtoms");
  DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n");
  for (const Atom *atom : all) {
    DEBUG_WITH_TYPE("resolver", llvm::dbgs()
                    << llvm::format("    0x%09lX", atom)
                    << ", name="
                    << atom->name()
                    << "\n");
    addAtom(*atom);
  }
}

} // namespace lld
<commit_msg>SymbolTable::size() returns an unsigned int.<commit_after>//===- Core/Resolver.cpp - Resolves Atom References -----------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lld/Core/Atom.h"
#include "lld/Core/ArchiveLibraryFile.h"
#include "lld/Core/File.h"
#include "lld/Core/SharedLibraryFile.h"
#include "lld/Core/Instrumentation.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/Resolver.h"
#include "lld/Core/SymbolTable.h"
#include "lld/Core/LinkingContext.h"
#include "lld/Core/UndefinedAtom.h"

#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"

#include <algorithm>
#include <cassert>
#include <vector>

namespace lld {

namespace {

/// This is used as a filter function to std::remove_if to coalesced atoms.
class AtomCoalescedAway {
public:
  explicit AtomCoalescedAway(SymbolTable &sym) : _symbolTable(sym) {}

  bool operator()(const Atom *atom) const {
    const Atom *rep = _symbolTable.replacement(atom);
    return rep != atom;
  }

private:
  SymbolTable &_symbolTable;
};

} // namespace

void Resolver::handleFile(const File &file) {
  bool isEmpty = file.defined().empty() && file.undefined().empty() &&
                 file.sharedLibrary().empty() && file.absolute().empty();
  if (isEmpty)
    return;

  for (const DefinedAtom *atom : file.defined())
    doDefinedAtom(*atom);
  for (const UndefinedAtom *atom : file.undefined())
    doUndefinedAtom(*atom);
  for (const SharedLibraryAtom *atom : file.sharedLibrary())
    doSharedLibraryAtom(*atom);
  for (const AbsoluteAtom *atom : file.absolute())
    doAbsoluteAtom(*atom);

  // Notify the input file manager of the fact that we have made some progress
  // on linking using the current input file. It may want to know the fact for
  // --start-group/--end-group.
  _context.getInputGraph().notifyProgress();
}

void Resolver::forEachUndefines(bool searchForOverrides,
                                UndefCallback callback) {
  // Handle normal archives
  unsigned undefineGenCount = 0;
  do {
    undefineGenCount = _symbolTable.size();
    for (const UndefinedAtom *undefAtom : _symbolTable.undefines()) {
      StringRef undefName = undefAtom->name();
      // load for previous undefine may also have loaded this undefine
      if (!_symbolTable.isDefined(undefName))
        callback(undefName, false);
    }

    // search libraries for overrides of common symbols
    if (searchForOverrides) {
      for (StringRef tentDefName : _symbolTable.tentativeDefinitions()) {
        // Load for previous tentative may also have loaded
        // something that overrode this tentative, so always check.
        const Atom *curAtom = _symbolTable.findByName(tentDefName);
        assert(curAtom != nullptr);
        if (const DefinedAtom *curDefAtom = dyn_cast<DefinedAtom>(curAtom)) {
          if (curDefAtom->merge() == DefinedAtom::mergeAsTentative)
            callback(tentDefName, true);
        }
      }
    }
  } while (undefineGenCount != _symbolTable.size());
}

void Resolver::handleArchiveFile(const File &file) {
  const ArchiveLibraryFile *archiveFile = cast<ArchiveLibraryFile>(&file);
  bool searchForOverrides =
      _context.searchArchivesToOverrideTentativeDefinitions();
  forEachUndefines(searchForOverrides,
                   [&](StringRef undefName, bool dataSymbolOnly) {
    if (const File *member = archiveFile->find(undefName, dataSymbolOnly)) {
      member->setOrdinal(_context.getNextOrdinalAndIncrement());
      handleFile(*member);
    }
  });
}

void Resolver::handleSharedLibrary(const File &file) {
  // Add all the atoms from the shared library
  const SharedLibraryFile *sharedLibrary = cast<SharedLibraryFile>(&file);
  handleFile(*sharedLibrary);
  bool searchForOverrides =
      _context.searchSharedLibrariesToOverrideTentativeDefinitions();
  forEachUndefines(searchForOverrides,
                   [&](StringRef undefName, bool dataSymbolOnly) {
    if (const SharedLibraryAtom *atom =
            sharedLibrary->exports(undefName, dataSymbolOnly))
      doSharedLibraryAtom(*atom);
  });
}

void Resolver::doUndefinedAtom(const UndefinedAtom &atom) {
  DEBUG_WITH_TYPE("resolver", llvm::dbgs()
                    << "       UndefinedAtom: "
                    << llvm::format("0x%09lX", &atom)
                    << ", name=" << atom.name() << "\n");

  // add to list of known atoms
  _atoms.push_back(&atom);

  // tell symbol table
  _symbolTable.add(atom);

  // If the undefined symbol has an alternative name, try to resolve the
  // symbol with the name to give it a second chance. This feature is used
  // for COFF "weak external" symbol.
  if (!_symbolTable.isDefined(atom.name())) {
    if (const UndefinedAtom *fallbackAtom = atom.fallback()) {
      doUndefinedAtom(*fallbackAtom);
      _symbolTable.addReplacement(&atom, fallbackAtom);
    }
  }
}

/// \brief Add the section group and the group-child reference members.
bool Resolver::maybeAddSectionGroupOrGnuLinkOnce(const DefinedAtom &atom) {
  // First time adding a group?
  bool isFirstTime = _symbolTable.addGroup(atom);

  if (!isFirstTime) {
    // If duplicate symbols are allowed, select the first group.
    if (_context.getAllowDuplicates())
      return true;
    const DefinedAtom *prevGroup =
        dyn_cast<DefinedAtom>(_symbolTable.findGroup(atom.name()));
    assert(prevGroup &&
           "Internal Error: The group atom could only be a defined atom");
    // The atoms should be of the same content type, reject invalid group
    // resolution behaviors.
    if (atom.contentType() != prevGroup->contentType())
      return false;
    return true;
  }

  for (const Reference *r : atom) {
    if ((r->kindNamespace() == lld::Reference::KindNamespace::all) &&
        (r->kindValue() == lld::Reference::kindGroupChild)) {
      const DefinedAtom *target = dyn_cast<DefinedAtom>(r->target());
      assert(target && "Internal Error: kindGroupChild references need to "
                       "be associated with Defined Atoms only");
      _atoms.push_back(target);
      _symbolTable.add(*target);
    }
  }
  return true;
}

// called on each atom when a file is added
void Resolver::doDefinedAtom(const DefinedAtom &atom) {
  DEBUG_WITH_TYPE("resolver", llvm::dbgs()
                    << "         DefinedAtom: "
                    << llvm::format("0x%09lX", &atom)
                    << ", file=#"
                    << atom.file().ordinal()
                    << ", atom=#"
                    << atom.ordinal()
                    << ", name="
                    << atom.name()
                    << "\n");

  // Verify on zero-size atoms are pinned to start or end of section.
  if (atom.sectionPosition() == DefinedAtom::sectionPositionStart ||
      atom.sectionPosition() == DefinedAtom::sectionPositionEnd) {
    assert(atom.size() == 0);
  }

  // add to list of known atoms
  _atoms.push_back(&atom);

  if (atom.isGroupParent()) {
    // Raise error if there exists a similar gnu linkonce section.
    if (!maybeAddSectionGroupOrGnuLinkOnce(atom)) {
      llvm::errs() << "SymbolTable: error while merging " << atom.name()
                   << "\n";
      llvm::report_fatal_error("duplicate symbol error");
    }
  } else {
    _symbolTable.add(atom);
  }

  // An atom that should never be dead-stripped is a dead-strip root.
  if (_context.deadStrip() && atom.deadStrip() == DefinedAtom::deadStripNever) {
    _deadStripRoots.insert(&atom);
  }
}

void Resolver::doSharedLibraryAtom(const SharedLibraryAtom &atom) {
  DEBUG_WITH_TYPE("resolver", llvm::dbgs()
                    << "   SharedLibraryAtom: "
                    << llvm::format("0x%09lX", &atom)
                    << ", name="
                    << atom.name()
                    << "\n");

  // add to list of known atoms
  _atoms.push_back(&atom);

  // tell symbol table
  _symbolTable.add(atom);
}

void Resolver::doAbsoluteAtom(const AbsoluteAtom &atom) {
  DEBUG_WITH_TYPE("resolver", llvm::dbgs()
                    << "       AbsoluteAtom: "
                    << llvm::format("0x%09lX", &atom)
                    << ", name="
                    << atom.name()
                    << "\n");

  // add to list of known atoms
  _atoms.push_back(&atom);

  // tell symbol table
  if (atom.scope() != Atom::scopeTranslationUnit)
    _symbolTable.add(atom);
}

// utility to add a vector of atoms
void Resolver::addAtoms(const std::vector<const DefinedAtom *> &newAtoms) {
  for (const DefinedAtom *newAtom : newAtoms)
    doDefinedAtom(*newAtom);
}

// Keep adding atoms until _context.getNextFile() returns an error. This
// function is where undefined atoms are resolved.
bool Resolver::resolveUndefines() {
  ScopedTask task(getDefaultDomain(), "resolveUndefines");

  for (;;) {
    ErrorOr<File &> file = _context.getInputGraph().getNextFile();
    error_code ec = file.getError();
    if (ec == InputGraphError::no_more_files)
      return true;
    if (!file) {
      llvm::errs() << "Error occurred in getNextFile: " << ec.message() << "\n";
      return false;
    }

    switch (file->kind()) {
    case File::kindObject:
      assert(!file->hasOrdinal());
      file->setOrdinal(_context.getNextOrdinalAndIncrement());
      handleFile(*file);
      break;
    case File::kindArchiveLibrary:
      if (!file->hasOrdinal())
        file->setOrdinal(_context.getNextOrdinalAndIncrement());
      handleArchiveFile(*file);
      break;
    case File::kindSharedLibrary:
      if (!file->hasOrdinal())
        file->setOrdinal(_context.getNextOrdinalAndIncrement());
      handleSharedLibrary(*file);
      break;
    }
  }
}

// switch all references to undefined or coalesced away atoms
// to the new defined atom
void Resolver::updateReferences() {
  ScopedTask task(getDefaultDomain(), "updateReferences");
  for (const Atom *atom : _atoms) {
    if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom)) {
      for (const Reference *ref : *defAtom) {
        const Atom *newTarget = _symbolTable.replacement(ref->target());
        const_cast<Reference *>(ref)->setTarget(newTarget);
      }
    }
  }
}

// For dead code stripping, recursively mark atoms "live"
void Resolver::markLive(const Atom &atom) {
  // Mark the atom is live. If it's already marked live, then stop recursion.
  auto exists = _liveAtoms.insert(&atom);
  if (!exists.second)
    return;

  // Mark all atoms it references as live
  if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&atom))
    for (const Reference *ref : *defAtom)
      if (const Atom *target = ref->target())
        markLive(*target);
}

// remove all atoms not actually used
void Resolver::deadStripOptimize() {
  ScopedTask task(getDefaultDomain(), "deadStripOptimize");
  // only do this optimization with -dead_strip
  if (!_context.deadStrip())
    return;
  assert(_liveAtoms.empty());

  // By default, shared libraries are built with all globals as dead strip roots
  if (_context.globalsAreDeadStripRoots())
    for (const Atom *atom : _atoms)
      if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom))
        if (defAtom->scope() == DefinedAtom::scopeGlobal)
          _deadStripRoots.insert(defAtom);

  // Or, use list of names that are dead strip roots.
  for (const StringRef &name : _context.deadStripRoots()) {
    const Atom *symAtom = _symbolTable.findByName(name);
    assert(symAtom);
    _deadStripRoots.insert(symAtom);
  }

  // mark all roots as live, and recursively all atoms they reference
  for (const Atom *dsrAtom : _deadStripRoots)
    markLive(*dsrAtom);

  // now remove all non-live atoms from _atoms
  _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), [&](const Atom *a) {
                 return _liveAtoms.count(a) == 0;
               }),
               _atoms.end());
}

// error out if some undefines remain
bool Resolver::checkUndefines() {
  // build vector of remaining undefined symbols
  std::vector<const UndefinedAtom *> undefinedAtoms = _symbolTable.undefines();
  if (_context.deadStrip()) {
    // When dead code stripping, we don't care if dead atoms are undefined.
    undefinedAtoms.erase(
        std::remove_if(undefinedAtoms.begin(), undefinedAtoms.end(),
                       [&](const Atom *a) { return _liveAtoms.count(a) == 0; }),
        undefinedAtoms.end());
  }

  // error message about missing symbols
  if (!undefinedAtoms.empty()) {
    // FIXME: need diagnostics interface for writing error messages
    bool foundUndefines = false;
    for (const UndefinedAtom *undefAtom : undefinedAtoms) {
      const File &f = undefAtom->file();

      // Skip over a weak symbol.
      if (undefAtom->canBeNull() != UndefinedAtom::canBeNullNever)
        continue;

      // If this is a library and undefined symbols are allowed on the
      // target platform, skip over it.
      if (isa<SharedLibraryFile>(f) && _context.allowShlibUndefines())
        continue;

      // If the undefine is coalesced away, skip over it.
      if (_symbolTable.replacement(undefAtom) != undefAtom)
        continue;

      // Seems like this symbol is undefined. Warn that.
      foundUndefines = true;
      if (_context.printRemainingUndefines()) {
        llvm::errs() << "Undefined symbol: " << undefAtom->file().path()
                     << ": " << undefAtom->name() << "\n";
      }
    }
    if (foundUndefines) {
      if (_context.printRemainingUndefines())
        llvm::errs() << "symbol(s) not found\n";
      return true;
    }
  }
  return false;
}

// remove from _atoms all coaleseced away atoms
void Resolver::removeCoalescedAwayAtoms() {
  ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms");
  _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(),
                              AtomCoalescedAway(_symbolTable)),
               _atoms.end());
}

bool Resolver::resolve() {
  if (!resolveUndefines())
    return false;
  updateReferences();
  deadStripOptimize();
  if (checkUndefines())
    if (!_context.allowRemainingUndefines())
      return false;
  removeCoalescedAwayAtoms();
  _result->addAtoms(_atoms);
  return true;
}

void Resolver::MergedFile::addAtom(const Atom &atom) {
  if (auto *def = dyn_cast<DefinedAtom>(&atom)) {
    _definedAtoms._atoms.push_back(def);
  } else if (auto *undef = dyn_cast<UndefinedAtom>(&atom)) {
    _undefinedAtoms._atoms.push_back(undef);
  } else if (auto *shared = dyn_cast<SharedLibraryAtom>(&atom)) {
    _sharedLibraryAtoms._atoms.push_back(shared);
  } else if (auto *abs = dyn_cast<AbsoluteAtom>(&atom)) {
    _absoluteAtoms._atoms.push_back(abs);
  } else {
    llvm_unreachable("atom has unknown definition kind");
  }
}

MutableFile::DefinedAtomRange Resolver::MergedFile::definedAtoms() {
  return range<std::vector<const DefinedAtom *>::iterator>(
      _definedAtoms._atoms.begin(), _definedAtoms._atoms.end());
}

void Resolver::MergedFile::addAtoms(std::vector<const Atom *> &all) {
  ScopedTask task(getDefaultDomain(), "addAtoms");
  DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n");
  for (const Atom *atom : all) {
    DEBUG_WITH_TYPE("resolver", llvm::dbgs()
                    << llvm::format("    0x%09lX", atom)
                    << ", name="
                    << atom->name()
                    << "\n");
    addAtom(*atom);
  }
}

} // namespace lld
<|endoftext|>


<commit_before>#ifndef _NONSTD_TYPE_TRAITS_
#define _NONSTD_TYPE_TRAITS_

#include <type_traits>
#include <cstddef>

namespace nonstd
{

	// incremental id of type
	struct type_info_polymorphic
	{
		using index_t = size_t;

		template<typename Base, typename Derived>
		static index_t id()
		{
			static_assert(std::is_base_of<Base, Derived>::value, "D should be derived from B.");
			static index_t sid = counter<Base>::value++;
			return sid;
		}

	protected:
		template<typename Base>
		struct counter
		{
			static index_t value;
		};
	};

	template<typename B>
	type_info_polymorphic::index_t type_info_polymorphic::counter<B>::value = 0;
}

///////////////////////////////////////////////////////
#define __try_using_rtti__ 1
///////////////////////////////////////////////////////

#ifdef _MSC_VER
#ifndef __cpp_rtti
#define __cpp_rtti _CPPRTTI
#endif // !__cpp_rtti
#endif

#define __cpp_rtti_enabled__ __try_using_rtti__ && __cpp_rtti
#if __cpp_rtti_enabled__
#include <typeindex>
#endif

namespace rtti
{
	class type_index_t;
	namespace detail
	{
		template<typename T>
		const type_index_t& type_id_impl();
	}

	class type_index_t
	{
#if __cpp_rtti_enabled__
		using construct_t = const std::type_info;
#else
		using construct_t = const type_index_t&();
#endif
		construct_t* _info = nullptr;
		type_index_t(construct_t* info) noexcept : _info{ info } {}

		template<typename T>
		friend const type_index_t& detail::type_id_impl();
	public:
		bool operator==(const type_index_t& o) const noexcept
		{
			return hash_code() == o.hash_code();
		}
		bool operator!=(const type_index_t& o) const noexcept
		{
			return hash_code() != o.hash_code();
		}
		bool operator<(const type_index_t& o) const noexcept
		{
			return hash_code() < o.hash_code();
		}
		bool operator>(const type_index_t& o) const noexcept
		{
			return hash_code() > o.hash_code();
		}

		std::size_t hash_code() const noexcept
		{
#if __cpp_rtti_enabled__
			return std::type_index(*_info).hash_code();
#else
			return reinterpret_cast<std::size_t>(_info);
#endif
		}
	};

	namespace detail
	{
		template<typename T>
		const type_index_t& type_id_impl()
		{
#if __cpp_rtti_enabled__
			static type_id_t id(&typeid(T));
#else
			static type_index_t id(&type_id_impl<T>);
#endif
			return id;
		}
	}

	template<typename T>
	const type_index_t& type_id()
	{
		//this is required to copy the behavior of typeid(T)
		return detail::type_id_impl<typename std::remove_cv<T>::type>();
	}

}

#endif<commit_msg>fixed compiler error<commit_after>#ifndef _NONSTD_TYPE_TRAITS_
#define _NONSTD_TYPE_TRAITS_

#include <type_traits>
#include <cstddef>

namespace nonstd
{

	// incremental id of type
	struct type_info_polymorphic
	{
		using index_t = size_t;

		template<typename Base, typename Derived>
		static index_t id()
		{
			static_assert(std::is_base_of<Base, Derived>::value, "D should be derived from B.");
			static index_t sid = counter<Base>::value++;
			return sid;
		}

	protected:
		template<typename Base>
		struct counter
		{
			static index_t value;
		};
	};

	template<typename B>
	type_info_polymorphic::index_t type_info_polymorphic::counter<B>::value = 0;
}

///////////////////////////////////////////////////////
#define __try_using_rtti__ 1
///////////////////////////////////////////////////////

#ifdef _MSC_VER
#ifndef __cpp_rtti
#define __cpp_rtti _CPPRTTI
#endif // !__cpp_rtti
#endif

#define __cpp_rtti_enabled__ __try_using_rtti__ && __cpp_rtti
#if __cpp_rtti_enabled__
#include <typeindex>
#endif

namespace rtti
{
	class type_index_t;
	namespace detail
	{
		template<typename T>
		const type_index_t& type_id_impl();
	}

	class type_index_t
	{
#if __cpp_rtti_enabled__
		using construct_t = const std::type_info;
#else
		using construct_t = const type_index_t&();
#endif
		construct_t* _info = nullptr;
		type_index_t(construct_t* info) noexcept : _info{ info } {}

		template<typename T>
		friend const type_index_t& detail::type_id_impl();
	public:
		bool operator==(const type_index_t& o) const noexcept
		{
			return hash_code() == o.hash_code();
		}
		bool operator!=(const type_index_t& o) const noexcept
		{
			return hash_code() != o.hash_code();
		}
		bool operator<(const type_index_t& o) const noexcept
		{
			return hash_code() < o.hash_code();
		}
		bool operator>(const type_index_t& o) const noexcept
		{
			return hash_code() > o.hash_code();
		}

		std::size_t hash_code() const noexcept
		{
#if __cpp_rtti_enabled__
			return std::type_index(*_info).hash_code();
#else
			return reinterpret_cast<std::size_t>(_info);
#endif
		}
	};

	namespace detail
	{
		template<typename T>
		const type_index_t& type_id_impl()
		{
#if __cpp_rtti_enabled__
			static type_index_t id(&typeid(T));
#else
			static type_index_t id(&type_id_impl<T>);
#endif
			return id;
		}
	}

	template<typename T>
	const type_index_t& type_id()
	{
		//this is required to copy the behavior of typeid(T)
		return detail::type_id_impl<typename std::remove_cv<T>::type>();
	}

}

#endif<|endoftext|>


<commit_before>//===--- Action.cpp - Abstract compilation steps ------------------------*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/Driver/Action.h"

#include <cassert>
using namespace clang::driver;

Action::~Action() {}

const char *Action::getClassName(ActionClass AC) {
  switch (AC) {
  case InputClass: return "input";
  case BindArchClass: return "bind-arch";
  case PreprocessJobClass: return "preprocessor";
  case PrecompileJobClass: return "precompiler";
  case AnalyzeJobClass: return "analyzer";
  case CompileJobClass: return "compiler";
  case AssembleJobClass: return "assembler";
  case LinkJobClass: return "linker";
  case LipoJobClass: return "lipo";
  }

  assert(0 && "invalid class");
  return 0;
}

InputAction::InputAction(const Arg &_Input, types::ID _Type)
  : Action(InputClass, _Type), Input(_Input) {
}

BindArchAction::BindArchAction(Action *Input, const char *_ArchName)
  : Action(BindArchClass, Input, Input->getType()), ArchName(_ArchName) {
}

JobAction::JobAction(ActionClass Kind, Action *Input, types::ID Type)
  : Action(Kind, Input, Type) {
}

JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type)
  : Action(Kind, Inputs, Type) {
}

PreprocessJobAction::PreprocessJobAction(Action *Input, types::ID OutputType)
  : JobAction(PreprocessJobClass, Input, OutputType) {
}

PrecompileJobAction::PrecompileJobAction(Action *Input, types::ID OutputType)
  : JobAction(PrecompileJobClass, Input, OutputType) {
}

AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType)
  : JobAction(AnalyzeJobClass, Input, OutputType) {
}

CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType)
  : JobAction(CompileJobClass, Input, OutputType) {
}

AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType)
  : JobAction(AssembleJobClass, Input, OutputType) {
}

LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type)
  : JobAction(LinkJobClass, Inputs, Type) {
}

LipoJobAction(ActionList &Inputs, types::ID Type)
  : JobAction(LipoJobClass, Inputs, Type) {
}
<commit_msg>Driver: Action vtables were still hungry.<commit_after>//===--- Action.cpp - Abstract compilation steps ------------------------*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/Driver/Action.h"

#include <cassert>
using namespace clang::driver;

Action::~Action() {}

const char *Action::getClassName(ActionClass AC) {
  switch (AC) {
  case InputClass: return "input";
  case BindArchClass: return "bind-arch";
  case PreprocessJobClass: return "preprocessor";
  case PrecompileJobClass: return "precompiler";
  case AnalyzeJobClass: return "analyzer";
  case CompileJobClass: return "compiler";
  case AssembleJobClass: return "assembler";
  case LinkJobClass: return "linker";
  case LipoJobClass: return "lipo";
  }

  assert(0 && "invalid class");
  return 0;
}

InputAction::InputAction(const Arg &_Input, types::ID _Type)
  : Action(InputClass, _Type), Input(_Input) {
}

BindArchAction::BindArchAction(Action *Input, const char *_ArchName)
  : Action(BindArchClass, Input, Input->getType()), ArchName(_ArchName) {
}

JobAction::JobAction(ActionClass Kind, Action *Input, types::ID Type)
  : Action(Kind, Input, Type) {
}

JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type)
  : Action(Kind, Inputs, Type) {
}

PreprocessJobAction::PreprocessJobAction(Action *Input, types::ID OutputType)
  : JobAction(PreprocessJobClass, Input, OutputType) {
}

PrecompileJobAction::PrecompileJobAction(Action *Input, types::ID OutputType)
  : JobAction(PrecompileJobClass, Input, OutputType) {
}

AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType)
  : JobAction(AnalyzeJobClass, Input, OutputType) {
}

CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType)
  : JobAction(CompileJobClass, Input, OutputType) {
}

AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType)
  : JobAction(AssembleJobClass, Input, OutputType) {
}

LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type)
  : JobAction(LinkJobClass, Inputs, Type) {
}

LipoJobAction::LipoJobAction(ActionList &Inputs, types::ID Type)
  : JobAction(LipoJobClass, Inputs, Type) {
}
<|endoftext|>


<commit_before>#include "spec_helper.h"
#include "runtime/alloc.h"
#include "helpers/load_language.h"
#include "helpers/read_test_entries.h"
#include "helpers/spy_input.h"
#include "helpers/stderr_logger.h"
#include "helpers/point_helpers.h"
#include "helpers/encoding_helpers.h"
#include "helpers/record_alloc.h"
#include "helpers/random_helpers.h"
#include "helpers/scope_sequence.h"
#include <set>

static void assert_correct_tree_shape(const TSDocument *document, string tree_string) {
  TSNode root_node = ts_document_root_node(document);
  const char *node_string = ts_node_string(root_node, document);
  string result(node_string);
  ts_free((void *)node_string);
  AssertThat(result, Equals(tree_string));
}

static void assert_consistent_sizes(TSNode node) {
  size_t child_count = ts_node_child_count(node);
  size_t start_byte = ts_node_start_byte(node);
  size_t end_byte = ts_node_end_byte(node);
  TSPoint start_point = ts_node_start_point(node);
  TSPoint end_point = ts_node_end_point(node);
  bool some_child_has_changes = false;

  AssertThat(start_byte, !IsGreaterThan(end_byte));
  AssertThat(start_point, !IsGreaterThan(end_point));

  size_t last_child_end_byte = start_byte;
  TSPoint last_child_end_point = start_point;

  for (size_t i = 0; i < child_count; i++) {
    TSNode child = ts_node_child(node, i);
    size_t child_start_byte = ts_node_start_byte(child);
    TSPoint child_start_point = ts_node_start_point(child);

    AssertThat(child_start_byte, !IsLessThan(last_child_end_byte));
    AssertThat(child_start_point, !IsLessThan(last_child_end_point));
    assert_consistent_sizes(child);
    if (ts_node_has_changes(child))
      some_child_has_changes = true;

    last_child_end_byte = ts_node_end_byte(child);
    last_child_end_point = ts_node_end_point(child);
  }

  if (child_count > 0) {
    AssertThat(end_byte, !IsLessThan(last_child_end_byte));
    AssertThat(end_point, !IsLessThan(last_child_end_point));
  }

  if (some_child_has_changes) {
    AssertThat(ts_node_has_changes(node), IsTrue());
  }
}

static void assert_correct_tree_size(TSDocument *document, string content) {
  TSNode root_node = ts_document_root_node(document);
  size_t expected_size = content.size();

  // In the JSON grammar, the start rule (`_value`) is hidden, so the node
  // returned from `ts_document_root_node` (e.g. an `object` node), does not
  // actually point to the root of the tree. In this weird case, trailing
  // whitespace is not included in the root node's size.
  //
  // TODO: Fix this inconsistency. Maybe disallow the start rule being hidden?
  if (ts_document_language(document) == get_test_language("json") &&
      string(ts_node_type(root_node, document)) != "ERROR")
    expected_size = content.find_last_not_of("\n ") + 1;

  AssertThat(ts_node_end_byte(root_node), Equals(expected_size));
  assert_consistent_sizes(root_node);
}

START_TEST

describe("The Corpus", []() {
  vector<string> test_languages({
    // "javascript",
    "json",
    // "c",
    // "cpp",
  });

  for (auto &language_name : test_languages) {
    describe(("the " + language_name + " language").c_str(), [&]() {
      TSDocument *document;

      before_each([&]() {
        record_alloc::start();
        document = ts_document_new();
        ts_document_set_language(document, get_test_language(language_name));

        // ts_document_set_logger(document, stderr_logger_new(true));
        // ts_document_print_debugging_graphs(document, true);
      });

      after_each([&]() {
        ts_document_free(document);
        AssertThat(record_alloc::outstanding_allocation_indices(), IsEmpty());
      });

      for (auto &entry : read_corpus_entries(language_name)) {
        SpyInput *input;

        auto it_handles_edit_sequence = [&](string name, std::function<void()> edit_sequence){
          it(("parses " + entry.description + ": " + name).c_str(), [&]() {
            input = new SpyInput(entry.input, 3);
            ts_document_set_input(document, input->input());
            edit_sequence();
            assert_correct_tree_shape(document, entry.tree_string);
            assert_correct_tree_size(document, input->content);
            delete input;
          });
        };

        it_handles_edit_sequence("initial parse", [&]() {
          ts_document_parse(document);
        });

        std::set<std::pair<size_t, size_t>> deletions;
        std::set<std::pair<size_t, string>> insertions;

        for (size_t i = 0; i < 60; i++) {
          size_t edit_position = random() % utf8_char_count(entry.input);
          size_t deletion_size = random() % (utf8_char_count(entry.input) - edit_position);
          string inserted_text = random_words(random() % 4 + 1);

          if (insertions.insert({edit_position, inserted_text}).second) {
            string description = "\"" + inserted_text + "\" at " + to_string(edit_position);

            it_handles_edit_sequence("repairing an insertion of " + description, [&]() {
              ts_document_edit(document, input->replace(edit_position, 0, inserted_text));
              ts_document_parse(document);
              assert_correct_tree_size(document, input->content);

              ts_document_edit(document, input->undo());
              assert_correct_tree_size(document, input->content);

              TSRange *ranges;
              uint32_t range_count;
              ScopeSequence old_scope_sequence = build_scope_sequence(document, input->content);
              ts_document_parse_and_get_changed_ranges(document, &ranges, &range_count);

              ScopeSequence new_scope_sequence = build_scope_sequence(document, input->content);
              verify_changed_ranges(old_scope_sequence, new_scope_sequence,
                                    input->content, ranges, range_count);
              ts_free(ranges);
            });
          }

          if (deletions.insert({edit_position, deletion_size}).second) {
            string desription = to_string(edit_position) + "-" + to_string(edit_position + deletion_size);

            it_handles_edit_sequence("repairing a deletion of " + desription, [&]() {
              ts_document_edit(document, input->replace(edit_position, deletion_size, ""));
              ts_document_parse(document);
              assert_correct_tree_size(document, input->content);

              ts_document_edit(document, input->undo());
              assert_correct_tree_size(document, input->content);

              TSRange *ranges;
              uint32_t range_count;
              ScopeSequence old_scope_sequence = build_scope_sequence(document, input->content);
              ts_document_parse_and_get_changed_ranges(document, &ranges, &range_count);

              ScopeSequence new_scope_sequence = build_scope_sequence(document, input->content);
              verify_changed_ranges(old_scope_sequence, new_scope_sequence,
                                    input->content, ranges, range_count);
              ts_free(ranges);
            });
          }
        }
      }
    });
  }
});

END_TEST
<commit_msg>Restore all languages in corpus specs<commit_after>#include "spec_helper.h"
#include "runtime/alloc.h"
#include "helpers/load_language.h"
#include "helpers/read_test_entries.h"
#include "helpers/spy_input.h"
#include "helpers/stderr_logger.h"
#include "helpers/point_helpers.h"
#include "helpers/encoding_helpers.h"
#include "helpers/record_alloc.h"
#include "helpers/random_helpers.h"
#include "helpers/scope_sequence.h"
#include <set>

static void assert_correct_tree_shape(const TSDocument *document, string tree_string) {
  TSNode root_node = ts_document_root_node(document);
  const char *node_string = ts_node_string(root_node, document);
  string result(node_string);
  ts_free((void *)node_string);
  AssertThat(result, Equals(tree_string));
}

static void assert_consistent_sizes(TSNode node) {
  size_t child_count = ts_node_child_count(node);
  size_t start_byte = ts_node_start_byte(node);
  size_t end_byte = ts_node_end_byte(node);
  TSPoint start_point = ts_node_start_point(node);
  TSPoint end_point = ts_node_end_point(node);
  bool some_child_has_changes = false;

  AssertThat(start_byte, !IsGreaterThan(end_byte));
  AssertThat(start_point, !IsGreaterThan(end_point));

  size_t last_child_end_byte = start_byte;
  TSPoint last_child_end_point = start_point;

  for (size_t i = 0; i < child_count; i++) {
    TSNode child = ts_node_child(node, i);
    size_t child_start_byte = ts_node_start_byte(child);
    TSPoint child_start_point = ts_node_start_point(child);

    AssertThat(child_start_byte, !IsLessThan(last_child_end_byte));
    AssertThat(child_start_point, !IsLessThan(last_child_end_point));
    assert_consistent_sizes(child);
    if (ts_node_has_changes(child))
      some_child_has_changes = true;

    last_child_end_byte = ts_node_end_byte(child);
    last_child_end_point = ts_node_end_point(child);
  }

  if (child_count > 0) {
    AssertThat(end_byte, !IsLessThan(last_child_end_byte));
    AssertThat(end_point, !IsLessThan(last_child_end_point));
  }

  if (some_child_has_changes) {
    AssertThat(ts_node_has_changes(node), IsTrue());
  }
}

static void assert_correct_tree_size(TSDocument *document, string content) {
  TSNode root_node = ts_document_root_node(document);
  size_t expected_size = content.size();

  // In the JSON grammar, the start rule (`_value`) is hidden, so the node
  // returned from `ts_document_root_node` (e.g. an `object` node), does not
  // actually point to the root of the tree. In this weird case, trailing
  // whitespace is not included in the root node's size.
  //
  // TODO: Fix this inconsistency. Maybe disallow the start rule being hidden?
  if (ts_document_language(document) == get_test_language("json") &&
      string(ts_node_type(root_node, document)) != "ERROR")
    expected_size = content.find_last_not_of("\n ") + 1;

  AssertThat(ts_node_end_byte(root_node), Equals(expected_size));
  assert_consistent_sizes(root_node);
}

START_TEST

describe("The Corpus", []() {
  vector<string> test_languages({
    "javascript",
    "json",
    "c",
    "cpp",
  });

  for (auto &language_name : test_languages) {
    describe(("the " + language_name + " language").c_str(), [&]() {
      TSDocument *document;

      before_each([&]() {
        record_alloc::start();
        document = ts_document_new();
        ts_document_set_language(document, get_test_language(language_name));

        // ts_document_set_logger(document, stderr_logger_new(true));
        // ts_document_print_debugging_graphs(document, true);
      });

      after_each([&]() {
        ts_document_free(document);
        AssertThat(record_alloc::outstanding_allocation_indices(), IsEmpty());
      });

      for (auto &entry : read_corpus_entries(language_name)) {
        SpyInput *input;

        auto it_handles_edit_sequence = [&](string name, std::function<void()> edit_sequence){
          it(("parses " + entry.description + ": " + name).c_str(), [&]() {
            input = new SpyInput(entry.input, 3);
            ts_document_set_input(document, input->input());
            edit_sequence();
            assert_correct_tree_shape(document, entry.tree_string);
            assert_correct_tree_size(document, input->content);
            delete input;
          });
        };

        it_handles_edit_sequence("initial parse", [&]() {
          ts_document_parse(document);
        });

        std::set<std::pair<size_t, size_t>> deletions;
        std::set<std::pair<size_t, string>> insertions;

        for (size_t i = 0; i < 60; i++) {
          size_t edit_position = random() % utf8_char_count(entry.input);
          size_t deletion_size = random() % (utf8_char_count(entry.input) - edit_position);
          string inserted_text = random_words(random() % 4 + 1);

          if (insertions.insert({edit_position, inserted_text}).second) {
            string description = "\"" + inserted_text + "\" at " + to_string(edit_position);

            it_handles_edit_sequence("repairing an insertion of " + description, [&]() {
              ts_document_edit(document, input->replace(edit_position, 0, inserted_text));
              ts_document_parse(document);
              assert_correct_tree_size(document, input->content);

              ts_document_edit(document, input->undo());
              assert_correct_tree_size(document, input->content);

              TSRange *ranges;
              uint32_t range_count;
              ScopeSequence old_scope_sequence = build_scope_sequence(document, input->content);
              ts_document_parse_and_get_changed_ranges(document, &ranges, &range_count);

              ScopeSequence new_scope_sequence = build_scope_sequence(document, input->content);
              verify_changed_ranges(old_scope_sequence, new_scope_sequence,
                                    input->content, ranges, range_count);
              ts_free(ranges);
            });
          }

          if (deletions.insert({edit_position, deletion_size}).second) {
            string desription = to_string(edit_position) + "-" + to_string(edit_position + deletion_size);

            it_handles_edit_sequence("repairing a deletion of " + desription, [&]() {
              ts_document_edit(document, input->replace(edit_position, deletion_size, ""));
              ts_document_parse(document);
              assert_correct_tree_size(document, input->content);

              ts_document_edit(document, input->undo());
              assert_correct_tree_size(document, input->content);

              TSRange *ranges;
              uint32_t range_count;
              ScopeSequence old_scope_sequence = build_scope_sequence(document, input->content);
              ts_document_parse_and_get_changed_ranges(document, &ranges, &range_count);

              ScopeSequence new_scope_sequence = build_scope_sequence(document, input->content);
              verify_changed_ranges(old_scope_sequence, new_scope_sequence,
                                    input->content, ranges, range_count);
              ts_free(ranges);
            });
          }
        }
      }
    });
  }
});

END_TEST
<|endoftext|>


<commit_before>#include "BaseDeDatos.h"
#include "gtest/gtest.h"
#include <string>
#include <iostream>

using namespace std;

// To use a test fixture, derive a class from testing::Test.
class BaseDeDatosTest : public testing::Test {

 protected:  // You should make the members protected s.t. they can be
             // accessed from sub-classes.

  // virtual void SetUp() will be called before each test is run.  You
  // should define it if you need to initialize the varaibles.
  // Otherwise, this can be skipped.

  virtual void SetUp() {
   	string valor = "valor";
	string valorDiferente = "valorDiferente";
	string clave = "AgregarUnaClaveValorDeUnaClaveExistenteModificaElValorDeLaClave";
	baseDeDatos = new BaseDeDatos("./BaseDeDatosDePrueba");
  }

  // virtual void TearDown() will be called after each test is run.
  // You should define it if there is cleanup work to do.  Otherwise,
  // you don't have to provide it.
  //
  virtual void TearDown() {
	delete baseDeDatos;
  }

	//ACA TAMBIEN PODEMOS DEFINIR FUNCIONES Y UTILIZARLAS PARA HACER
	//EL MISMO TEST CON DIFERENTES DATOS.

  // Declares the variables your tests want to use.
  string clave;
  string valor;
  string valorDiferente;
  BaseDeDatos* baseDeDatos;
};

// El primer parametro es el nombre de la clase en la que describimos
// las variables a utilizar y demas.
//El segundo parametro es el nombre del test.
TEST_F(BaseDeDatosTest, AlHacerDosVecesUnPutConLaMismaClaveElValorAlmacenadoDeberiaSerElUltimoGuardado) {
	//Todas las variables estan definidas en la clase
	baseDeDatos->put(clave,valor);
	baseDeDatos->put(clave,valorDiferente);

	EXPECT_EQ(valorDiferente, baseDeDatos->get(clave));

}
<commit_msg>BUG Fix - No asignaba bien los valores en el SetUp<commit_after>#include "BaseDeDatos.h"
#include "gtest/gtest.h"
#include <string>
#include <iostream>

using namespace std;

// To use a test fixture, derive a class from testing::Test.
class BaseDeDatosTest : public testing::Test {

 protected:  // You should make the members protected s.t. they can be
             // accessed from sub-classes.

  // virtual void SetUp() will be called before each test is run.  You
  // should define it if you need to initialize the varaibles.
  // Otherwise, this can be skipped.

  virtual void SetUp() {
   	valor = "valor";
	valorDiferente = "valorDiferente";
	clave = "AgregarUnaClaveValorDeUnaClaveExistenteModificaElValorDeLaClave";
	baseDeDatos = new BaseDeDatos("./BaseDeDatosDePrueba");
  }

  // virtual void TearDown() will be called after each test is run.
  // You should define it if there is cleanup work to do.  Otherwise,
  // you don't have to provide it.
  //
  virtual void TearDown() {
	delete this->baseDeDatos;
  }

	//ACA TAMBIEN PODEMOS DEFINIR FUNCIONES Y UTILIZARLAS PARA HACER
	//EL MISMO TEST CON DIFERENTES DATOS.

  // Declares the variables your tests want to use.
  string clave;
  string valor;
  string valorDiferente;
  BaseDeDatos* baseDeDatos;
};

TEST_F(BaseDeDatosTest, testAgregarUnaClaveValorNuevaYObtenerla){
	baseDeDatos->put(clave,valor);
	ASSERT_EQ(valor,baseDeDatos->get(clave));
}

// El primer parametro es el nombre de la clase en la que describimos
// las variables a utilizar y demas.
//El segundo parametro es el nombre del test.
TEST_F(BaseDeDatosTest, AlHacerDosVecesUnPutConLaMismaClaveElValorAlmacenadoDeberiaSerElUltimoGuardado) {
	//Todas las variables estan definidas en la clase
	baseDeDatos->put(clave,valor);
	baseDeDatos->put(clave,valorDiferente);

	EXPECT_EQ(valorDiferente, baseDeDatos->get(clave));

}

TEST_F(BaseDeDatosTest, testAlPreguntarPorLaExistenciaDeUnaClaveInexistenteDeberiaDarFalse){
	 string clave = "ExistenciaDeClaveInexistente";
	 EXPECT_EQ(false,baseDeDatos->existe(clave));
}

<|endoftext|>


<commit_before>// -*- coding: us-ascii-unix -*-
// Copyright 2012 Lukas Kemmer
//
// Licensed under the Apache License, Version 2.0 (the "License"); you
// may not use this file except in compliance with the License. You
// may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.

#ifndef FAINT_COLOR_COUNTING_HH
#define FAINT_COLOR_COUNTING_HH
#include <map>
#include <vector>

namespace faint{

class Bitmap;
class Color;
class Mask;

// Maps Colors to a pixel count
using color_counts_t = std::map<Color, int>;

// Adds the colors from the Bitmap to the passed in color_counts_t
void add_color_counts(const Bitmap&, color_counts_t&);

int count_colors(const Bitmap&);

// Returns a vector containing all distinct colors (after stripping
// alpha) in the bitmap sorted by operator<. Masked pixels are
// excluded.
std::vector<ColRGB> unique_colors_rgb(const Bitmap&, const Mask& exclude);

// Returns a copy with all fully transparent color variants
// (i.e. any rgba = {*,*,*,0} removed in favor of a single instance
// of the given preferredRgb with alpha=0, at the end.
//
// If there are no transparent pixels, the resulting vector will be
// identical to the source.
std::vector<Color> merged_fully_transparent(const std::vector<Color>&,
  const ColRGB& preferredRgb);

// Returns the most common color. The color_counts_t must not be empty
Color most_common(const color_counts_t&);

} // namespace

#endif
<commit_msg>Added include.<commit_after>// -*- coding: us-ascii-unix -*-
// Copyright 2012 Lukas Kemmer
//
// Licensed under the Apache License, Version 2.0 (the "License"); you
// may not use this file except in compliance with the License. You
// may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.

#ifndef FAINT_COLOR_COUNTING_HH
#define FAINT_COLOR_COUNTING_HH
#include <map>
#include <vector>

namespace faint{

class Bitmap;
class Color;
class ColRGB;
class Mask;

// Maps Colors to a pixel count
using color_counts_t = std::map<Color, int>;

// Adds the colors from the Bitmap to the passed in color_counts_t
void add_color_counts(const Bitmap&, color_counts_t&);

int count_colors(const Bitmap&);

// Returns a vector containing all distinct colors (after stripping
// alpha) in the bitmap sorted by operator<. Masked pixels are
// excluded.
std::vector<ColRGB> unique_colors_rgb(const Bitmap&, const Mask& exclude);

// Returns a copy with all fully transparent color variants
// (i.e. any rgba = {*,*,*,0} removed in favor of a single instance
// of the given preferredRgb with alpha=0, at the end.
//
// If there are no transparent pixels, the resulting vector will be
// identical to the source.
std::vector<Color> merged_fully_transparent(const std::vector<Color>&,
  const ColRGB& preferredRgb);

// Returns the most common color. The color_counts_t must not be empty
Color most_common(const color_counts_t&);

} // namespace

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/browser/ui/views/menu_bar.h"

#if defined(USE_X11)
#include "gtk/gtk.h"
#endif

#include "atom/browser/ui/views/menu_delegate.h"
#include "atom/browser/ui/views/submenu_button.h"
#include "ui/base/models/menu_model.h"
#include "ui/views/background.h"
#include "ui/views/layout/box_layout.h"

#if defined(OS_WIN)
#include "ui/gfx/color_utils.h"
#elif defined(USE_X11)
#include "chrome/browser/ui/libgtkui/skia_utils_gtk.h"
#endif

namespace atom {

namespace {

const char kViewClassName[] = "ElectronMenuBar";

// Default color of the menu bar.
const SkColor kDefaultColor = SkColorSetARGB(255, 233, 233, 233);

#if defined(USE_X11)
void GetMenuBarColor(SkColor* enabled, SkColor* disabled, SkColor* highlight,
                     SkColor* hover, SkColor* background) {
  GtkWidget* menu_bar = gtk_menu_bar_new();

  GtkStyle* style = gtk_rc_get_style(menu_bar);
  *enabled = libgtkui::GdkColorToSkColor(style->fg[GTK_STATE_NORMAL]);
  *disabled = libgtkui::GdkColorToSkColor(style->fg[GTK_STATE_INSENSITIVE]);
  *highlight = libgtkui::GdkColorToSkColor(style->fg[GTK_STATE_SELECTED]);
  *hover = libgtkui::GdkColorToSkColor(style->fg[GTK_STATE_PRELIGHT]);
  *background = libgtkui::GdkColorToSkColor(style->bg[GTK_STATE_NORMAL]);

  gtk_widget_destroy(menu_bar);
}
#endif

}  // namespace

MenuBar::MenuBar(NativeWindow* window)
    : background_color_(kDefaultColor),
      menu_model_(NULL),
      window_(window) {
  UpdateMenuBarColor();
  SetLayoutManager(new views::BoxLayout(
      views::BoxLayout::kHorizontal, 0, 0, 0));
}

MenuBar::~MenuBar() {
}

void MenuBar::SetMenu(AtomMenuModel* model) {
  menu_model_ = model;
  RemoveAllChildViews(true);

  for (int i = 0; i < model->GetItemCount(); ++i) {
    SubmenuButton* button = new SubmenuButton(model->GetLabelAt(i),
                                              this,
                                              background_color_);
    button->set_tag(i);

#if defined(USE_X11)
    button->SetTextColor(views::Button::STATE_NORMAL, enabled_color_);
    button->SetTextColor(views::Button::STATE_DISABLED, disabled_color_);
    button->SetTextColor(views::Button::STATE_PRESSED, highlight_color_);
    button->SetTextColor(views::Button::STATE_HOVERED, hover_color_);
    button->SetUnderlineColor(enabled_color_);
#elif defined(OS_WIN)
    button->SetUnderlineColor(color_utils::GetSysSkColor(COLOR_GRAYTEXT));
#endif

    AddChildView(button);
  }
}

void MenuBar::SetAcceleratorVisibility(bool visible) {
  for (int i = 0; i < child_count(); ++i)
    static_cast<SubmenuButton*>(child_at(i))->SetAcceleratorVisibility(visible);
}

int MenuBar::GetAcceleratorIndex(base::char16 key) {
  for (int i = 0; i < child_count(); ++i) {
    SubmenuButton* button = static_cast<SubmenuButton*>(child_at(i));
    if (button->accelerator() == key)
      return i;
  }
  return -1;
}

void MenuBar::ActivateAccelerator(base::char16 key) {
  int i = GetAcceleratorIndex(key);
  if (i != -1)
    static_cast<SubmenuButton*>(child_at(i))->Activate(nullptr);
}

int MenuBar::GetItemCount() const {
  return menu_model_->GetItemCount();
}

bool MenuBar::GetMenuButtonFromScreenPoint(const gfx::Point& point,
                                           AtomMenuModel** menu_model,
                                           views::MenuButton** button) {
  gfx::Point location(point);
  views::View::ConvertPointFromScreen(this, &location);

  if (location.x() < 0 || location.x() >= width() || location.y() < 0 ||
      location.y() >= height())
    return false;

  for (int i = 0; i < child_count(); ++i) {
    views::View* view = child_at(i);
    if (view->GetMirroredBounds().Contains(location) &&
        (menu_model_->GetTypeAt(i) == AtomMenuModel::TYPE_SUBMENU)) {
      *menu_model = menu_model_->GetSubmenuModelAt(i);
      *button = static_cast<views::MenuButton*>(view);
      return true;
    }
  }

  return false;
}

const char* MenuBar::GetClassName() const {
  return kViewClassName;
}

void MenuBar::OnMenuButtonClicked(views::MenuButton* source,
                                  const gfx::Point& point,
                                  const ui::Event* event) {
  // Hide the accelerator when a submenu is activated.
  SetAcceleratorVisibility(false);

  if (!menu_model_)
    return;

  if (!window_->IsFocused())
    window_->Focus(true);

  int id = source->tag();
  AtomMenuModel::ItemType type = menu_model_->GetTypeAt(id);
  if (type != AtomMenuModel::TYPE_SUBMENU) {
    menu_model_->ActivatedAt(id, 0);
    return;
  }

  // Deleted in MenuDelegate::OnMenuClosed
  MenuDelegate* menu_delegate = new MenuDelegate(this);
  menu_delegate->RunMenu(menu_model_->GetSubmenuModelAt(id), source);
}

void MenuBar::OnNativeThemeChanged(const ui::NativeTheme* theme) {
  UpdateMenuBarColor();
}

void MenuBar::UpdateMenuBarColor() {
#if defined(OS_WIN)
  background_color_ = color_utils::GetSysSkColor(COLOR_MENUBAR);
#elif defined(USE_X11)
  GetMenuBarColor(&enabled_color_, &disabled_color_, &highlight_color_,
                  &hover_color_, &background_color_);
#endif
  set_background(views::Background::CreateSolidBackground(background_color_));
}

}  // namespace atom
<commit_msg>Changed top/bottom & left/right border parameters on BoxLayout to take single gfx::Insets parameter.<commit_after>// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/browser/ui/views/menu_bar.h"

#if defined(USE_X11)
#include "gtk/gtk.h"
#endif

#include "atom/browser/ui/views/menu_delegate.h"
#include "atom/browser/ui/views/submenu_button.h"
#include "ui/base/models/menu_model.h"
#include "ui/views/background.h"
#include "ui/views/layout/box_layout.h"

#if defined(OS_WIN)
#include "ui/gfx/color_utils.h"
#elif defined(USE_X11)
#include "chrome/browser/ui/libgtkui/skia_utils_gtk.h"
#endif

namespace atom {

namespace {

const char kViewClassName[] = "ElectronMenuBar";

// Default color of the menu bar.
const SkColor kDefaultColor = SkColorSetARGB(255, 233, 233, 233);

#if defined(USE_X11)
void GetMenuBarColor(SkColor* enabled, SkColor* disabled, SkColor* highlight,
                     SkColor* hover, SkColor* background) {
  GtkWidget* menu_bar = gtk_menu_bar_new();

  GtkStyle* style = gtk_rc_get_style(menu_bar);
  *enabled = libgtkui::GdkColorToSkColor(style->fg[GTK_STATE_NORMAL]);
  *disabled = libgtkui::GdkColorToSkColor(style->fg[GTK_STATE_INSENSITIVE]);
  *highlight = libgtkui::GdkColorToSkColor(style->fg[GTK_STATE_SELECTED]);
  *hover = libgtkui::GdkColorToSkColor(style->fg[GTK_STATE_PRELIGHT]);
  *background = libgtkui::GdkColorToSkColor(style->bg[GTK_STATE_NORMAL]);

  gtk_widget_destroy(menu_bar);
}
#endif

}  // namespace

MenuBar::MenuBar(NativeWindow* window)
    : background_color_(kDefaultColor),
      menu_model_(NULL),
      window_(window) {
  UpdateMenuBarColor();
  SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal));
}

MenuBar::~MenuBar() {
}

void MenuBar::SetMenu(AtomMenuModel* model) {
  menu_model_ = model;
  RemoveAllChildViews(true);

  for (int i = 0; i < model->GetItemCount(); ++i) {
    SubmenuButton* button = new SubmenuButton(model->GetLabelAt(i),
                                              this,
                                              background_color_);
    button->set_tag(i);

#if defined(USE_X11)
    button->SetTextColor(views::Button::STATE_NORMAL, enabled_color_);
    button->SetTextColor(views::Button::STATE_DISABLED, disabled_color_);
    button->SetTextColor(views::Button::STATE_PRESSED, highlight_color_);
    button->SetTextColor(views::Button::STATE_HOVERED, hover_color_);
    button->SetUnderlineColor(enabled_color_);
#elif defined(OS_WIN)
    button->SetUnderlineColor(color_utils::GetSysSkColor(COLOR_GRAYTEXT));
#endif

    AddChildView(button);
  }
}

void MenuBar::SetAcceleratorVisibility(bool visible) {
  for (int i = 0; i < child_count(); ++i)
    static_cast<SubmenuButton*>(child_at(i))->SetAcceleratorVisibility(visible);
}

int MenuBar::GetAcceleratorIndex(base::char16 key) {
  for (int i = 0; i < child_count(); ++i) {
    SubmenuButton* button = static_cast<SubmenuButton*>(child_at(i));
    if (button->accelerator() == key)
      return i;
  }
  return -1;
}

void MenuBar::ActivateAccelerator(base::char16 key) {
  int i = GetAcceleratorIndex(key);
  if (i != -1)
    static_cast<SubmenuButton*>(child_at(i))->Activate(nullptr);
}

int MenuBar::GetItemCount() const {
  return menu_model_->GetItemCount();
}

bool MenuBar::GetMenuButtonFromScreenPoint(const gfx::Point& point,
                                           AtomMenuModel** menu_model,
                                           views::MenuButton** button) {
  gfx::Point location(point);
  views::View::ConvertPointFromScreen(this, &location);

  if (location.x() < 0 || location.x() >= width() || location.y() < 0 ||
      location.y() >= height())
    return false;

  for (int i = 0; i < child_count(); ++i) {
    views::View* view = child_at(i);
    if (view->GetMirroredBounds().Contains(location) &&
        (menu_model_->GetTypeAt(i) == AtomMenuModel::TYPE_SUBMENU)) {
      *menu_model = menu_model_->GetSubmenuModelAt(i);
      *button = static_cast<views::MenuButton*>(view);
      return true;
    }
  }

  return false;
}

const char* MenuBar::GetClassName() const {
  return kViewClassName;
}

void MenuBar::OnMenuButtonClicked(views::MenuButton* source,
                                  const gfx::Point& point,
                                  const ui::Event* event) {
  // Hide the accelerator when a submenu is activated.
  SetAcceleratorVisibility(false);

  if (!menu_model_)
    return;

  if (!window_->IsFocused())
    window_->Focus(true);

  int id = source->tag();
  AtomMenuModel::ItemType type = menu_model_->GetTypeAt(id);
  if (type != AtomMenuModel::TYPE_SUBMENU) {
    menu_model_->ActivatedAt(id, 0);
    return;
  }

  // Deleted in MenuDelegate::OnMenuClosed
  MenuDelegate* menu_delegate = new MenuDelegate(this);
  menu_delegate->RunMenu(menu_model_->GetSubmenuModelAt(id), source);
}

void MenuBar::OnNativeThemeChanged(const ui::NativeTheme* theme) {
  UpdateMenuBarColor();
}

void MenuBar::UpdateMenuBarColor() {
#if defined(OS_WIN)
  background_color_ = color_utils::GetSysSkColor(COLOR_MENUBAR);
#elif defined(USE_X11)
  GetMenuBarColor(&enabled_color_, &disabled_color_, &highlight_color_,
                  &hover_color_, &background_color_);
#endif
  set_background(views::Background::CreateSolidBackground(background_color_));
}

}  // namespace atom
<|endoftext|>


<commit_before>//
// Aspia Project
// Copyright (C) 2020 Dmitry Chapyshev <dmitry@aspia.ru>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

#include "client/client.h"

#include "base/logging.h"
#include "build/version.h"
#include "client/status_window_proxy.h"

namespace client {

Client::Client(std::shared_ptr<base::TaskRunner> ui_task_runner)
    : ui_task_runner_(std::move(ui_task_runner))
{
    DCHECK(ui_task_runner_);
    DCHECK(ui_task_runner_->belongsToCurrentThread());
}

Client::~Client()
{
    DCHECK(ui_task_runner_->belongsToCurrentThread());
    stop();
}

bool Client::start(const Config& config)
{
    DCHECK(ui_task_runner_->belongsToCurrentThread());

    config_ = config;

    if (!status_window_proxy_)
    {
        DLOG(LS_ERROR) << "Attempt to start the client without status window";
        return false;
    }

    // Start the thread for IO.
    io_thread_.start(base::MessageLoop::Type::ASIO, this);
    return true;
}

void Client::stop()
{
    DCHECK(ui_task_runner_->belongsToCurrentThread());

    io_thread_.stop();
}

void Client::setStatusWindow(StatusWindow* status_window)
{
    DCHECK(ui_task_runner_->belongsToCurrentThread());
    DCHECK(!status_window_proxy_);

    status_window_proxy_ = StatusWindowProxy::create(ui_task_runner_, status_window);
}

// static
base::Version Client::version()
{
    return base::Version(ASPIA_VERSION_MAJOR, ASPIA_VERSION_MINOR, ASPIA_VERSION_PATCH);
}

std::shared_ptr<base::TaskRunner> Client::ioTaskRunner() const
{
    return io_task_runner_;
}

std::shared_ptr<base::TaskRunner> Client::uiTaskRunner() const
{
    return ui_task_runner_;
}

std::u16string Client::computerName() const
{
    return config_.computer_name;
}

proto::SessionType Client::sessionType() const
{
    return config_.session_type;
}

void Client::sendMessage(const google::protobuf::MessageLite& message)
{
    channel_->send(base::serialize(message));
}

void Client::onBeforeThreadRunning()
{
    // Initialize the task runner for IO.
    io_task_runner_ = io_thread_.taskRunner();

    // Show the status window.
    status_window_proxy_->onStarted(config_.address, config_.port);

    // Create a network channel for messaging.
    channel_ = std::make_unique<net::Channel>();

    // Set the listener for the network channel.
    channel_->setListener(this);

    // Now connect to the host.
    channel_->connect(config_.address, config_.port);
}

void Client::onAfterThreadRunning()
{
    authenticator_.reset();
    channel_.reset();

    if (session_started_)
    {
        // Session stopped.
        onSessionStopped();
    }
}

void Client::onConnected()
{
    channel_->setKeepAlive(true, std::chrono::minutes(1), std::chrono::seconds(1));
    channel_->setNoDelay(true);

    authenticator_ = std::make_unique<net::ClientAuthenticator>();

    authenticator_->setIdentify(proto::IDENTIFY_SRP);
    authenticator_->setUserName(config_.username);
    authenticator_->setPassword(config_.password);
    authenticator_->setSessionType(config_.session_type);

    authenticator_->start(std::move(channel_),
                          [this](net::ClientAuthenticator::ErrorCode error_code)
    {
        if (error_code == net::ClientAuthenticator::ErrorCode::SUCCESS)
        {
            // The authenticator takes the listener on itself, we return the receipt of
            // notifications.
            channel_ = authenticator_->takeChannel();
            channel_->setListener(this);

            status_window_proxy_->onConnected();

            session_started_ = true;

            // Signal that everything is ready to start the session (connection established,
            // authentication passed).
            onSessionStarted(authenticator_->peerVersion());

            // Now the session will receive incoming messages.
            channel_->resume();
        }
        else
        {
            status_window_proxy_->onAccessDenied(error_code);
        }

        // Authenticator is no longer needed.
        io_task_runner_->deleteSoon(std::move(authenticator_));
    });
}

void Client::onDisconnected(net::Channel::ErrorCode error_code)
{
    // Show an error to the user.
    status_window_proxy_->onDisconnected(error_code);
}

} // namespace client
<commit_msg>Increase the size of the read buffer.<commit_after>//
// Aspia Project
// Copyright (C) 2020 Dmitry Chapyshev <dmitry@aspia.ru>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

#include "client/client.h"

#include "base/logging.h"
#include "build/version.h"
#include "client/status_window_proxy.h"

namespace client {

Client::Client(std::shared_ptr<base::TaskRunner> ui_task_runner)
    : ui_task_runner_(std::move(ui_task_runner))
{
    DCHECK(ui_task_runner_);
    DCHECK(ui_task_runner_->belongsToCurrentThread());
}

Client::~Client()
{
    DCHECK(ui_task_runner_->belongsToCurrentThread());
    stop();
}

bool Client::start(const Config& config)
{
    DCHECK(ui_task_runner_->belongsToCurrentThread());

    config_ = config;

    if (!status_window_proxy_)
    {
        DLOG(LS_ERROR) << "Attempt to start the client without status window";
        return false;
    }

    // Start the thread for IO.
    io_thread_.start(base::MessageLoop::Type::ASIO, this);
    return true;
}

void Client::stop()
{
    DCHECK(ui_task_runner_->belongsToCurrentThread());

    io_thread_.stop();
}

void Client::setStatusWindow(StatusWindow* status_window)
{
    DCHECK(ui_task_runner_->belongsToCurrentThread());
    DCHECK(!status_window_proxy_);

    status_window_proxy_ = StatusWindowProxy::create(ui_task_runner_, status_window);
}

// static
base::Version Client::version()
{
    return base::Version(ASPIA_VERSION_MAJOR, ASPIA_VERSION_MINOR, ASPIA_VERSION_PATCH);
}

std::shared_ptr<base::TaskRunner> Client::ioTaskRunner() const
{
    return io_task_runner_;
}

std::shared_ptr<base::TaskRunner> Client::uiTaskRunner() const
{
    return ui_task_runner_;
}

std::u16string Client::computerName() const
{
    return config_.computer_name;
}

proto::SessionType Client::sessionType() const
{
    return config_.session_type;
}

void Client::sendMessage(const google::protobuf::MessageLite& message)
{
    channel_->send(base::serialize(message));
}

void Client::onBeforeThreadRunning()
{
    // Initialize the task runner for IO.
    io_task_runner_ = io_thread_.taskRunner();

    // Show the status window.
    status_window_proxy_->onStarted(config_.address, config_.port);

    // Create a network channel for messaging.
    channel_ = std::make_unique<net::Channel>();

    // Set the listener for the network channel.
    channel_->setListener(this);

    // Now connect to the host.
    channel_->connect(config_.address, config_.port);
}

void Client::onAfterThreadRunning()
{
    authenticator_.reset();
    channel_.reset();

    if (session_started_)
    {
        // Session stopped.
        onSessionStopped();
    }
}

void Client::onConnected()
{
    static const size_t kReadBufferSize = 1 * 1024 * 1024; // 1 Mb.
    static const std::chrono::minutes kKeepAliveTime{ 1 };
    static const std::chrono::seconds kKeepAliveInterval{ 3 };

    channel_->setReadBufferSize(kReadBufferSize);
    channel_->setKeepAlive(true, kKeepAliveTime, kKeepAliveInterval);
    channel_->setNoDelay(true);

    authenticator_ = std::make_unique<net::ClientAuthenticator>();

    authenticator_->setIdentify(proto::IDENTIFY_SRP);
    authenticator_->setUserName(config_.username);
    authenticator_->setPassword(config_.password);
    authenticator_->setSessionType(config_.session_type);

    authenticator_->start(std::move(channel_),
                          [this](net::ClientAuthenticator::ErrorCode error_code)
    {
        if (error_code == net::ClientAuthenticator::ErrorCode::SUCCESS)
        {
            // The authenticator takes the listener on itself, we return the receipt of
            // notifications.
            channel_ = authenticator_->takeChannel();
            channel_->setListener(this);

            status_window_proxy_->onConnected();

            session_started_ = true;

            // Signal that everything is ready to start the session (connection established,
            // authentication passed).
            onSessionStarted(authenticator_->peerVersion());

            // Now the session will receive incoming messages.
            channel_->resume();
        }
        else
        {
            status_window_proxy_->onAccessDenied(error_code);
        }

        // Authenticator is no longer needed.
        io_task_runner_->deleteSoon(std::move(authenticator_));
    });
}

void Client::onDisconnected(net::Channel::ErrorCode error_code)
{
    // Show an error to the user.
    status_window_proxy_->onDisconnected(error_code);
}

} // namespace client
<|endoftext|>