Repository: 4ian/GDevelop
File: Core/GDCore/Events/CodeGeneration/EventsCodeGenerator.cpp (C++)

Code before:
  bool isAnyBehaviorMissing = false;
  gd::ParameterMetadataTools::IterateOverParametersWithIndex(
      instruction.GetParameters(), instrInfos.parameters,
      [this, &isAnyBehaviorMissing,
       &instrInfos](const gd::ParameterMetadata &parameterMetadata,
                    const gd::Expression &parameterValue, size_t parameterIndex,
                    const gd::String &lastObjectName, size_t lastObjectIndex) {
        if (ParameterMetadata::IsBehavior(parameterMetadata.GetType())) {
          const gd::String &behaviorName = parameterValue.GetPlainString();
          const gd::String &actualBehaviorType =
              GetObjectsContainersList().GetTypeOfBehaviorInObjectOrGroup(
                  lastObjectName, behaviorName);
          const gd::String &expectedBehaviorType =
              parameterMetadata.GetExtraInfo();

          if (!expectedBehaviorType.empty() &&
              actualBehaviorType != expectedBehaviorType) {
            const auto &objectParameterMetadata =
                instrInfos.GetParameter(lastObjectIndex);
            // Event-functions crashes if behaviors are missing on some object
            // of a group because they lose sight of the original objects.
            // Missing behaviors are only "fatal" for ObjectList parameters to
            // reduce side effects on built-in functions.
            if (objectParameterMetadata.GetType() == "objectList") {
              isAnyBehaviorMissing = true;
            }
            gd::ProjectDiagnostic projectDiagnostic(
                gd::ProjectDiagnostic::ErrorType::MissingBehavior, "",
                actualBehaviorType, expectedBehaviorType, lastObjectName);
            if (diagnosticReport)
              diagnosticReport->Add(projectDiagnostic);
          }
        }
      });
  return isAnyBehaviorMissing;
}

/**
 * Generate code for an action.
 */
gd::String EventsCodeGenerator::GenerateActionCode(
    gd::Instruction& action,
    EventsCodeGenerationContext& context,
    const gd::String& optionalAsyncCallbackName) {
  gd::String actionCode;

  const gd::InstructionMetadata& instrInfos =
      MetadataProvider::GetActionMetadata(platform, action.GetType());
  if (MetadataProvider::IsBadInstructionMetadata(instrInfos)) {
    return "/* Unknown instruction - skipped. */";
  }

Review comment (bug):
I think it's safe to stop generating the instruction in this case because:
- the only built-in functions which has an `objectList` and a `behavior` are Physics collision conditions
- the diagnostic report bullied users to make them fix their groups
- the events-functions crashed so it was not usable for them

Code after:
  bool isAnyBehaviorMissing = false;
  gd::ParameterMetadataTools::IterateOverParametersWithIndex(
      instruction.GetParameters(), instrInfos.parameters,
      [this, &isAnyBehaviorMissing,
       &instrInfos](const gd::ParameterMetadata &parameterMetadata,
                    const gd::Expression &parameterValue, size_t parameterIndex,
                    const gd::String &lastObjectName, size_t lastObjectIndex) {
        if (ParameterMetadata::IsBehavior(parameterMetadata.GetType())) {
          const gd::String &behaviorName = parameterValue.GetPlainString();
          const gd::String &actualBehaviorType =
              GetObjectsContainersList().GetTypeOfBehaviorInObjectOrGroup(
                  lastObjectName, behaviorName);
          const gd::String &expectedBehaviorType =
              parameterMetadata.GetExtraInfo();

          if (!expectedBehaviorType.empty() &&
              actualBehaviorType != expectedBehaviorType) {
            const auto &objectParameterMetadata =
                instrInfos.GetParameter(lastObjectIndex);
            // Event functions crash if some objects in a group are missing
            // the required behaviors, since they lose reference to the original
            // objects. Missing behaviors are considered "fatal" only for
            // ObjectList parameters, in order to minimize side effects on
            // built-in functions.
            if (objectParameterMetadata.GetType() == "objectList") {
              isAnyBehaviorMissing = true;
            }
            gd::ProjectDiagnostic projectDiagnostic(
                gd::ProjectDiagnostic::ErrorType::MissingBehavior, "",
                actualBehaviorType, expectedBehaviorType, lastObjectName);
            if (diagnosticReport)
              diagnosticReport->Add(projectDiagnostic);
          }
        }
      });
  return isAnyBehaviorMissing;
}

/**
 * Generate code for an action.
 */
gd::String EventsCodeGenerator::GenerateActionCode(
    gd::Instruction& action,
    EventsCodeGenerationContext& context,
    const gd::String& optionalAsyncCallbackName) {
  gd::String actionCode;

  const gd::InstructionMetadata& instrInfos =
      MetadataProvider::GetActionMetadata(platform, action.GetType());
  if (MetadataProvider::IsBadInstructionMetadata(instrInfos)) {
    return "/* Unknown instruction - skipped. */";