Repository: google/flatbuffers
File: src/idl_parser.cpp (C++)

Code before:
    if (fname.length() > len &&
        fname.compare(fname.length() - len, len, suffix) == 0 &&
        (*it)->value.type.base_type != BASE_TYPE_UTYPE) {
      auto field =
          struct_def->fields.Lookup(fname.substr(0, fname.length() - len));
      if (field && field->value.type.base_type == basetype)
        return Error("Field " + fname +
                     " would clash with generated functions for field " +
                     field->name);
    }
  }
  return NoError();
}

std::vector<IncludedFile> Parser::GetIncludedFiles() const {
  const auto it = files_included_per_file_.find(file_being_parsed_);
  if (it == files_included_per_file_.end()) {
    return {};
  }

  return {it->second.cbegin(), it->second.cend()};
}

bool Parser::HasCircularStructDependency() const {
  // Simple DFS to detect cycles in the struct dependency graph.
  std::set<const StructDef*> visited;
  std::set<const StructDef*> stack;

  std::function<bool(const StructDef*)> visit =
      [&](const StructDef* struct_def) {
        // Only consider fixed structs
        if (!struct_def->fixed) {
          return false;
        }

        if (stack.count(struct_def)) {
          return true;  // Cycle detected.
        }
        if (visited.count(struct_def)) {
          return false;  // Already processed.
        }

        visited.insert(struct_def);
        stack.insert(struct_def);

        for (const auto& field : struct_def->fields.vec) {
          if (field->value.type.base_type == BASE_TYPE_STRUCT) {
            if (visit(field->value.type.struct_def)) {
              return true;  // Cycle detected in recursion.
            }
          }

Review comment (suggestion):
You don't need either of these data structures. Just stick an enum inside `StructDef` with these 3 values:

* `CycleNotChecked` : you call visit.
* `CycleChecked`: (set at the end of visit). If you encounter it, you return false
* `CycleBeingChecked`: (set at the start of visit). If you encounter it, you found a cycle, return true.

Code after:
    if (fname.length() > len &&
        fname.compare(fname.length() - len, len, suffix) == 0 &&
        (*it)->value.type.base_type != BASE_TYPE_UTYPE) {
      auto field =
          struct_def->fields.Lookup(fname.substr(0, fname.length() - len));
      if (field && field->value.type.base_type == basetype)
        return Error("Field " + fname +
                     " would clash with generated functions for field " +
                     field->name);
    }
  }
  return NoError();
}

std::vector<IncludedFile> Parser::GetIncludedFiles() const {
  const auto it = files_included_per_file_.find(file_being_parsed_);
  if (it == files_included_per_file_.end()) {
    return {};
  }

  return {it->second.cbegin(), it->second.cend()};
}

bool Parser::HasCircularStructDependency() {
  std::function<bool(StructDef*)> visit =
      [&](StructDef* struct_def) {
        // Only consider fixed structs and structs we have yet to check
        if (!struct_def->fixed || struct_def->cycle_status == StructDef::CycleStatus::Checked) {
          return false;
        }

        if (struct_def->cycle_status == StructDef::CycleStatus::InProgress) {
          // cycle found
          return true;
        }

        struct_def->cycle_status = StructDef::CycleStatus::InProgress;

        for (const auto& field : struct_def->fields.vec) {
          if (field->value.type.base_type == BASE_TYPE_STRUCT) {
            if (visit(field->value.type.struct_def)) {
              return true;  // Cycle detected in recursion.
            }
          }
        }

        struct_def->cycle_status = StructDef::CycleStatus::Checked;
        return false;  // No cycle detected.
      };

  for (const auto& struct_def : structs_.vec) {