When renaming or removing an object, only refactor associated external events (#5155)

* The editor used to refactor every events that were used in the object layout even if they were associated to another layout which could result to errors.
This commit is contained in:
D8H
2023-03-27 12:55:00 +02:00
committed by GitHub
parent 89eb61b4a6
commit b94ce2b20d
3 changed files with 233 additions and 84 deletions

View File

@@ -1382,25 +1382,12 @@ void WholeProjectRefactorer::ObjectOrGroupRemovedInLayout(
// Remove object in external events
if (removeEventsAndGroups) {
DependenciesAnalyzer analyzer(project, layout);
if (analyzer.Analyze()) {
for (auto& externalEventsName :
analyzer.GetExternalEventsDependencies()) {
auto& externalEvents = project.GetExternalEvents(externalEventsName);
gd::EventsRefactorer::RemoveObjectInEvents(project.GetCurrentPlatform(),
project,
layout,
externalEvents.GetEvents(),
objectName);
}
for (auto& layoutName : analyzer.GetScenesDependencies()) {
auto& layout = project.GetLayout(layoutName);
gd::EventsRefactorer::RemoveObjectInEvents(project.GetCurrentPlatform(),
project,
layout,
layout.GetEvents(),
objectName);
}
for (auto &externalEventsName :
GetAssociatedExternalEvents(project, layout.GetName())) {
auto &externalEvents = project.GetExternalEvents(externalEventsName);
gd::EventsRefactorer::RemoveObjectInEvents(
project.GetCurrentPlatform(), project, layout,
externalEvents.GetEvents(), objectName);
}
}
@@ -1439,26 +1426,12 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
}
// Rename object in external events
DependenciesAnalyzer analyzer(project, layout);
if (analyzer.Analyze()) {
for (auto& externalEventsName : analyzer.GetExternalEventsDependencies()) {
auto& externalEvents = project.GetExternalEvents(externalEventsName);
gd::EventsRefactorer::RenameObjectInEvents(project.GetCurrentPlatform(),
project,
layout,
externalEvents.GetEvents(),
oldName,
newName);
}
for (auto& layoutName : analyzer.GetScenesDependencies()) {
auto& layout = project.GetLayout(layoutName);
gd::EventsRefactorer::RenameObjectInEvents(project.GetCurrentPlatform(),
project,
layout,
layout.GetEvents(),
oldName,
newName);
}
for (auto &externalEventsName :
GetAssociatedExternalEvents(project, layout.GetName())) {
auto &externalEvents = project.GetExternalEvents(externalEventsName);
gd::EventsRefactorer::RenameObjectInEvents(
project.GetCurrentPlatform(), project, layout,
externalEvents.GetEvents(), oldName, newName);
}
// Rename object in external layouts

View File

@@ -325,7 +325,7 @@ class GD_CORE_API WholeProjectRefactorer {
* \brief Refactor the project after an object is renamed in a layout
*
* This will update the layout, all external layouts associated with it
* and all external events used by the layout.
* and all external events associated with it.
*/
static void ObjectOrGroupRenamedInLayout(gd::Project& project,
gd::Layout& layout,
@@ -337,7 +337,7 @@ class GD_CORE_API WholeProjectRefactorer {
* \brief Refactor the project after an object is removed in a layout
*
* This will update the layout, all external layouts associated with it
* and all external events used by the layout.
* and all external events associated with it.
*/
static void ObjectOrGroupRemovedInLayout(gd::Project& project,
gd::Layout& layout,

View File

@@ -56,6 +56,12 @@ GetEventFirstActionFirstParameterString(const gd::BaseEvent &event) {
return actions.Get(0).GetParameter(0).GetPlainString();
}
bool
AreActionsEmpty(const gd::BaseEvent &event) {
auto &actions = EnsureStandardEvent(event).GetActions();
return actions.IsEmpty();
}
const gd::String &GetEventFirstConditionType(const gd::BaseEvent &event) {
auto &conditions = EnsureStandardEvent(event).GetConditions();
REQUIRE(conditions.IsEmpty() == false);
@@ -78,6 +84,8 @@ enum TestEvent {
FreeActionWithOperator,
FreeFunctionWithObjects,
FreeFunctionWithObjectExpression,
FreeFunctionWithGroup,
FreeFunctionWithObjectExpressionOnGroup,
BehaviorAction,
BehaviorPropertyAction,
@@ -107,11 +115,18 @@ enum TestEvent {
ObjectActionWithOperator,
};
const std::vector<const gd::EventsList *> GetEventsLists(gd::Project &project) {
const std::vector<const gd::EventsList *> GetEventsListsAssociatedToScene(gd::Project &project) {
std::vector<const gd::EventsList *> eventLists;
auto &scene = project.GetLayout("Scene").GetEvents();
auto &externalEvents =
project.GetExternalEvents("ExternalEvents").GetEvents();
eventLists.push_back(&scene);
eventLists.push_back(&externalEvents);
return eventLists;
}
const std::vector<const gd::EventsList *> GetEventsListsNotAssociatedToScene(gd::Project &project) {
std::vector<const gd::EventsList *> eventLists;
auto &eventsExtension = project.GetEventsFunctionsExtension("MyEventsExtension");
auto &objectFunctionEvents =
eventsExtension
@@ -128,14 +143,24 @@ const std::vector<const gd::EventsList *> GetEventsLists(gd::Project &project) {
.GetEvents();
auto &freeFunctionEvents =
eventsExtension.GetEventsFunction("MyOtherEventsFunction").GetEvents();
eventLists.push_back(&scene);
eventLists.push_back(&externalEvents);
eventLists.push_back(&objectFunctionEvents);
eventLists.push_back(&behaviorFunctionEvents);
eventLists.push_back(&freeFunctionEvents);
return eventLists;
}
const std::vector<const gd::EventsList *> GetEventsLists(gd::Project &project) {
std::vector<const gd::EventsList *> eventLists;
for (auto *eventsList : GetEventsListsAssociatedToScene(project)) {
eventLists.push_back(eventsList);
}
for (auto *eventsList : GetEventsListsNotAssociatedToScene(project)) {
eventLists.push_back(eventsList);
}
return eventLists;
}
const void SetupEvents(gd::EventsList &eventList) {
// Add some free functions usages in events
@@ -285,6 +310,38 @@ const void SetupEvents(gd::EventsList &eventList) {
event.GetActions().Insert(action);
eventList.InsertEvent(event);
}
if (eventList.GetEventsCount() != FreeFunctionWithGroup) {
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
}
// Create an event referring to a group.
{
gd::StandardEvent event;
gd::Instruction action;
action.SetType("MyExtension::DoSomethingWithObjects");
action.SetParametersCount(2);
action.SetParameter(0, gd::Expression("GroupWithMyBehavior"));
action.SetParameter(1, gd::Expression("MyCustomObject"));
event.GetActions().Insert(action);
eventList.InsertEvent(event);
}
if (eventList.GetEventsCount() != FreeFunctionWithObjectExpressionOnGroup) {
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
}
// Create an event referring to a group in an expression.
{
gd::StandardEvent event;
gd::Instruction action;
action.SetType("MyExtension::DoSomething");
action.SetParametersCount(1);
action.SetParameter(
0,
gd::Expression(
"GroupWithMyBehavior.GetObjectNumber()"));
event.GetActions().Insert(action);
eventList.InsertEvent(event);
}
}
// Add some events based behavior usages in events
@@ -821,7 +878,7 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior"));
behaviorAction.GetParameters().push_back(
gd::ParameterMetadata()
.SetName("OtherObject")
.SetName("ObjectWithMyBehavior")
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject"));
behaviorAction.GetParameters().push_back(
@@ -829,6 +886,8 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
.SetName("OtherBehavior")
.SetType("behavior")
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior"));
auto &group = behaviorAction.GetObjectGroups().InsertNew("GroupWithMyBehavior");
group.AddObject("ObjectWithMyBehavior");
auto &behaviorExpression =
behaviorEventsFunctions
@@ -1009,6 +1068,8 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
auto &childObject = eventsBasedObject.InsertNewObject(
project, "MyExtension::Sprite", "ObjectWithMyBehavior", 0);
childObject.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior", "MyBehavior");
auto &group = eventsBasedObject.GetObjectGroups().InsertNew("GroupWithMyBehavior");
group.AddObject(childObject.GetName());
eventsBasedObject.InsertNewObject(
project, "MyEventsExtension::MyEventsBasedObject", "MyCustomObject", 1);
@@ -1079,6 +1140,8 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
.SetName("MyCustomObject")
.SetType("object")
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject"));
auto &group = action.GetObjectGroups().InsertNew("GroupWithMyBehavior");
group.AddObject("ObjectWithMyBehavior");
}
// Add some usages in events
@@ -1091,6 +1154,8 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
auto &object = layout.InsertNewObject(project, "MyExtension::Sprite",
"ObjectWithMyBehavior", 0);
object.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior", "MyBehavior");
auto &group = layout.GetObjectGroups().InsertNew("GroupWithMyBehavior", 0);
group.AddObject("ObjectWithMyBehavior");
auto &globalObject = project.InsertNewObject(
project, "MyExtension::Sprite", "GlobalObjectWithMyBehavior", 0);
@@ -1229,6 +1294,29 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
REQUIRE(externalLayout2.GetInitialInstances().HasInstancesOfObject(
"GlobalObject1") == false);
}
SECTION("Events") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
auto &layout = project.GetLayout("Scene");
// Trigger the refactoring after removing an object
gd::WholeProjectRefactorer::ObjectOrGroupRemovedInLayout(
project, layout, "ObjectWithMyBehavior", /* isObjectGroup=*/false);
for (auto *eventsList : GetEventsListsAssociatedToScene(project)) {
// Check actions with the object in parameters have been removed.
REQUIRE(
AreActionsEmpty(eventsList->GetEvent(FreeFunctionWithObjects)));
// Check actions with the object in expressions have been removed.
REQUIRE(AreActionsEmpty(
eventsList->GetEvent(FreeFunctionWithObjectExpression)));
}
}
}
SECTION("Object renamed (in layout)") {
@@ -1347,7 +1435,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
REQUIRE(externalLayout2.GetInitialInstances().HasInstancesOfObject(
"GlobalObject3") == true);
}
SECTION("Events") {
gd::Project project;
gd::Platform platform;
@@ -1358,57 +1446,145 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
// Trigger the refactoring after the renaming of an object
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
project, layout, "ObjectWithMyBehavior", "RenamedObjectWithMyBehavior",
project, layout, "ObjectWithMyBehavior",
"RenamedObjectWithMyBehavior",
/* isObjectGroup=*/false);
// Check object name has been renamed in action parameters.
REQUIRE(GetEventFirstActionFirstParameterString(
layout.GetEvents().GetEvent(FreeFunctionWithObjects)) ==
"RenamedObjectWithMyBehavior");
for (auto *eventsList : GetEventsListsAssociatedToScene(project)) {
// Check object name has been renamed in action parameters.
REQUIRE(GetEventFirstActionFirstParameterString(eventsList->GetEvent(
FreeFunctionWithObjects)) == "RenamedObjectWithMyBehavior");
// Check object name has been renamed in expressions.
REQUIRE(GetEventFirstActionFirstParameterString(
layout.GetEvents().GetEvent(FreeFunctionWithObjectExpression)) ==
// Check object name has been renamed in expressions.
REQUIRE(GetEventFirstActionFirstParameterString(
eventsList->GetEvent(FreeFunctionWithObjectExpression)) ==
"RenamedObjectWithMyBehavior.GetObjectNumber()");
}
}
}
SECTION("Group deleted (in layout)") {
SECTION("Events") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
auto &layout = project.GetLayout("Scene");
// Trigger the refactoring after removing a group
gd::WholeProjectRefactorer::ObjectOrGroupRemovedInLayout(
project, layout, "GroupWithMyBehavior", /* isObjectGroup=*/true);
for (auto *eventsList : GetEventsListsAssociatedToScene(project)) {
// Check actions with the group in parameters have been removed.
REQUIRE(AreActionsEmpty(eventsList->GetEvent(FreeFunctionWithGroup)));
// Check actions with the group in expressions have been removed.
REQUIRE(AreActionsEmpty(
eventsList->GetEvent(FreeFunctionWithObjectExpressionOnGroup)));
}
}
}
SECTION("Group renamed (in layout)") {
SECTION("Events") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
auto &layout = project.GetLayout("Scene");
// Trigger the refactoring after the renaming of a group
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
project, layout, "GroupWithMyBehavior", "RenamedGroupWithMyBehavior",
/* isObjectGroup=*/true);
for (auto *eventsList : GetEventsListsAssociatedToScene(project)) {
// Check group name has been renamed in action parameters.
REQUIRE(GetEventFirstActionFirstParameterString(eventsList->GetEvent(
FreeFunctionWithGroup)) == "RenamedGroupWithMyBehavior");
// Check group name has been renamed in expressions.
REQUIRE(GetEventFirstActionFirstParameterString(eventsList->GetEvent(
FreeFunctionWithObjectExpressionOnGroup)) ==
"RenamedGroupWithMyBehavior.GetObjectNumber()");
}
}
}
SECTION("Object renamed (in events function)") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
SECTION("Group") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
// Add a (free) function with an object group
gd::EventsFunction &eventsFunction =
eventsExtension.InsertNewEventsFunction("MyEventsFunction", 0);
gd::ObjectGroup &objectGroup =
eventsFunction.GetObjectGroups().InsertNew("MyGroup", 0);
objectGroup.AddObject("Object1");
objectGroup.AddObject("Object2");
// In theory, we would add the object parameters, but we're not testing
// events in this test.
// Add a (free) function with an object group
gd::EventsFunction &eventsFunction =
eventsExtension.InsertNewEventsFunction("MyEventsFunction", 0);
gd::ObjectGroup &objectGroup =
eventsFunction.GetObjectGroups().InsertNew("MyGroup", 0);
objectGroup.AddObject("Object1");
objectGroup.AddObject("Object2");
// In theory, we would add the object parameters, but we're not testing
// events in this test.
// Create the objects container for the events function
gd::ObjectsContainer globalObjectsContainer;
gd::ObjectsContainer objectsContainer;
gd::ParameterMetadataTools::ParametersToObjectsContainer(
project, eventsFunction.GetParameters(), objectsContainer);
// (this is strictly not necessary because we're not testing events in this
// test)
// Create the objects container for the events function
gd::ObjectsContainer globalObjectsContainer;
gd::ObjectsContainer objectsContainer;
gd::ParameterMetadataTools::ParametersToObjectsContainer(
project, eventsFunction.GetParameters(), objectsContainer);
// (this is strictly not necessary because we're not testing events in
// this test)
// Trigger the refactoring after the renaming of an object
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
project, eventsFunction, globalObjectsContainer, objectsContainer,
"Object1", "RenamedObject1",
/* isObjectGroup=*/false);
// Trigger the refactoring after the renaming of an object
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
project, eventsFunction, globalObjectsContainer, objectsContainer,
"Object1", "RenamedObject1",
/* isObjectGroup=*/false);
REQUIRE(objectGroup.Find("Object1") == false);
REQUIRE(objectGroup.Find("RenamedObject1") == true);
REQUIRE(objectGroup.Find("Object2") == true);
REQUIRE(objectGroup.Find("Object1") == false);
REQUIRE(objectGroup.Find("RenamedObject1") == true);
REQUIRE(objectGroup.Find("Object2") == true);
// Events are not tested
// Events are not tested
}
SECTION("Events") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
auto &eventsFunction =
eventsExtension.GetEventsFunction("MyOtherEventsFunction");
// Create the objects container for the events function
gd::ObjectsContainer globalObjectsContainer;
gd::ObjectsContainer objectsContainer;
gd::ParameterMetadataTools::ParametersToObjectsContainer(
project, eventsFunction.GetParameters(), objectsContainer);
// Trigger the refactoring after the renaming of an object
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
project, eventsFunction, globalObjectsContainer, objectsContainer,
"ObjectWithMyBehavior", "RenamedObjectWithMyBehavior",
/* isObjectGroup=*/false);
// Check object name has been renamed in action parameters.
REQUIRE(
GetEventFirstActionFirstParameterString(
eventsFunction.GetEvents().GetEvent(FreeFunctionWithObjects)) ==
"RenamedObjectWithMyBehavior");
// Check object name has been renamed in expressions.
REQUIRE(GetEventFirstActionFirstParameterString(
eventsFunction.GetEvents().GetEvent(
FreeFunctionWithObjectExpression)) ==
"RenamedObjectWithMyBehavior.GetObjectNumber()");
}
}
SECTION("Object renamed (in events-based object)") {