-
Notifications
You must be signed in to change notification settings - Fork 885
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix variables from being renamed with a property #7186
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,13 +41,15 @@ class GD_CORE_API ExpressionPropertyReplacer | |
const gd::Platform& platform_, | ||
const gd::ProjectScopedContainers& projectScopedContainers_, | ||
const gd::PropertiesContainer& targetPropertiesContainer_, | ||
bool isParentTypeAVariable_, | ||
const std::unordered_map<gd::String, gd::String>& oldToNewPropertyNames_, | ||
const std::unordered_set<gd::String>& removedPropertyNames_) | ||
: hasDoneRenaming(false), | ||
removedPropertyUsed(false), | ||
platform(platform_), | ||
projectScopedContainers(projectScopedContainers_), | ||
targetPropertiesContainer(targetPropertiesContainer_), | ||
isParentTypeAVariable(isParentTypeAVariable_), | ||
oldToNewPropertyNames(oldToNewPropertyNames_), | ||
removedPropertyNames(removedPropertyNames_){}; | ||
virtual ~ExpressionPropertyReplacer(){}; | ||
|
@@ -69,16 +71,21 @@ class GD_CORE_API ExpressionPropertyReplacer | |
void OnVisitNumberNode(NumberNode& node) override {} | ||
void OnVisitTextNode(TextNode& node) override {} | ||
void OnVisitVariableNode(VariableNode& node) override { | ||
if (isParentTypeAVariable) { | ||
// Do nothing, it's a variable. | ||
if (node.child) node.child->Visit(*this); | ||
return; | ||
} | ||
|
||
auto& propertiesContainersList = | ||
projectScopedContainers.GetPropertiesContainersList(); | ||
|
||
// The node represents a variable or an object name on which a variable | ||
// will be accessed, or a property with a child. | ||
|
||
// Match the potential *new* name of the property, because refactorings are | ||
// done after changes in the variables container. | ||
projectScopedContainers.MatchIdentifierWithName<void>( | ||
GetPotentialNewName(node.name), | ||
// The property name is changed after the refactor operation. | ||
node.name, | ||
[&]() { | ||
// Do nothing, it's an object variable. | ||
if (node.child) node.child->Visit(*this); | ||
|
@@ -100,16 +107,7 @@ class GD_CORE_API ExpressionPropertyReplacer | |
// Do nothing, it's a parameter. | ||
if (node.child) node.child->Visit(*this); | ||
}, [&]() { | ||
// This is something else - potentially a deleted property. | ||
// Check if it's coming from the target container with | ||
// properties to replace. | ||
if (propertiesContainersList.HasPropertiesContainer( | ||
targetPropertiesContainer)) { | ||
// The node represents a property, that can come from the target | ||
// (because the target is in the scope), replace or remove it: | ||
RenameOrRemovePropertyOfTargetPropertyContainer(node.name); | ||
} | ||
|
||
// Do nothing, it's something else. | ||
if (node.child) node.child->Visit(*this); | ||
}); | ||
} | ||
|
@@ -118,17 +116,24 @@ class GD_CORE_API ExpressionPropertyReplacer | |
} | ||
void OnVisitVariableBracketAccessorNode( | ||
VariableBracketAccessorNode& node) override { | ||
bool isGrandParentTypeAVariable = isParentTypeAVariable; | ||
isParentTypeAVariable = false; | ||
node.expression->Visit(*this); | ||
isParentTypeAVariable = isGrandParentTypeAVariable; | ||
if (node.child) node.child->Visit(*this); | ||
} | ||
void OnVisitIdentifierNode(IdentifierNode& node) override { | ||
if (isParentTypeAVariable) { | ||
// Do nothing, it's a variable. | ||
return; | ||
} | ||
|
||
auto& propertiesContainersList = | ||
projectScopedContainers.GetPropertiesContainersList(); | ||
|
||
// Match the potential *new* name of the property, because refactorings are | ||
// done after changes in the variables container. | ||
projectScopedContainers.MatchIdentifierWithName<void>( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand why this "MatchIdentifierWithName" is not doing its job? If it's a variable, it should match it (and so do nothing), no? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think |
||
GetPotentialNewName(node.identifierName), | ||
// The property name is changed after the refactor operation | ||
node.identifierName, | ||
[&]() { | ||
// Do nothing, it's an object variable. | ||
}, [&]() { | ||
|
@@ -145,35 +150,36 @@ class GD_CORE_API ExpressionPropertyReplacer | |
}, [&]() { | ||
// Do nothing, it's a parameter. | ||
}, [&]() { | ||
// This is something else - potentially a deleted property. | ||
// Check if it's coming from the target container with | ||
// properties to replace. | ||
if (propertiesContainersList.HasPropertiesContainer( | ||
targetPropertiesContainer)) { | ||
// The node represents a property, that can come from the target | ||
// (because the target is in the scope), replace or remove it: | ||
RenameOrRemovePropertyOfTargetPropertyContainer(node.identifierName); | ||
} | ||
// Do nothing, it's something else. | ||
}); | ||
} | ||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {} | ||
void OnVisitFunctionCallNode(FunctionCallNode& node) override { | ||
for (auto& parameter : node.parameters) { | ||
parameter->Visit(*this); | ||
void OnVisitFunctionCallNode(FunctionCallNode &node) override { | ||
bool isGrandParentTypeAVariable = isParentTypeAVariable; | ||
for (auto ¶meter : node.parameters) { | ||
const auto ¶meterMetadata = | ||
gd::MetadataProvider::GetFunctionCallParameterMetadata( | ||
platform, projectScopedContainers.GetObjectsContainersList(), | ||
node, *parameter); | ||
if (!parameterMetadata) { | ||
continue; | ||
} | ||
const auto ¶meterTypeMetadata = | ||
parameterMetadata->GetValueTypeMetadata(); | ||
if (gd::EventsPropertyReplacer::CanContainProperty( | ||
parameterTypeMetadata)) { | ||
isParentTypeAVariable = parameterTypeMetadata.IsVariable(); | ||
parameter->Visit(*this); | ||
} | ||
} | ||
isParentTypeAVariable = isGrandParentTypeAVariable; | ||
} | ||
void OnVisitEmptyNode(EmptyNode& node) override {} | ||
|
||
private: | ||
bool hasDoneRenaming; | ||
bool removedPropertyUsed; | ||
|
||
const gd::String& GetPotentialNewName(const gd::String& oldName) { | ||
return oldToNewPropertyNames.count(oldName) >= 1 | ||
? oldToNewPropertyNames.find(oldName)->second | ||
: oldName; | ||
} | ||
|
||
bool RenameOrRemovePropertyOfTargetPropertyContainer( | ||
gd::String& propertyName) { | ||
if (oldToNewPropertyNames.count(propertyName) >= 1) { | ||
|
@@ -198,6 +204,7 @@ class GD_CORE_API ExpressionPropertyReplacer | |
const std::unordered_set<gd::String>& removedPropertyNames; | ||
|
||
gd::String objectNameToUseForVariableAccessor; | ||
bool isParentTypeAVariable; | ||
}; | ||
|
||
bool EventsPropertyReplacer::DoVisitInstruction(gd::Instruction& instruction, | ||
|
@@ -216,20 +223,16 @@ bool EventsPropertyReplacer::DoVisitInstruction(gd::Instruction& instruction, | |
const gd::Expression& parameterValue, | ||
size_t parameterIndex, | ||
const gd::String& lastObjectName) { | ||
const gd::String& type = parameterMetadata.GetType(); | ||
|
||
if (!gd::ParameterMetadata::IsExpression("variable", type) && | ||
!gd::ParameterMetadata::IsExpression("number", type) && | ||
!gd::ParameterMetadata::IsExpression("string", type)) | ||
return; // Not an expression that can contain properties. | ||
|
||
if (!gd::EventsPropertyReplacer::CanContainProperty( | ||
parameterMetadata.GetValueTypeMetadata())) { | ||
return; | ||
} | ||
auto node = parameterValue.GetRootNode(); | ||
if (node) { | ||
ExpressionPropertyReplacer renamer(platform, | ||
GetProjectScopedContainers(), | ||
targetPropertiesContainer, | ||
oldToNewPropertyNames, | ||
removedPropertyNames); | ||
ExpressionPropertyReplacer renamer( | ||
platform, GetProjectScopedContainers(), targetPropertiesContainer, | ||
parameterMetadata.GetValueTypeMetadata().IsVariable(), | ||
oldToNewPropertyNames, removedPropertyNames); | ||
node->Visit(renamer); | ||
|
||
if (renamer.IsRemovedPropertyUsed()) { | ||
|
@@ -246,20 +249,16 @@ bool EventsPropertyReplacer::DoVisitInstruction(gd::Instruction& instruction, | |
|
||
bool EventsPropertyReplacer::DoVisitEventExpression( | ||
gd::Expression& expression, const gd::ParameterMetadata& metadata) { | ||
const gd::String& type = metadata.GetType(); | ||
|
||
if (!gd::ParameterMetadata::IsExpression("variable", type) && | ||
!gd::ParameterMetadata::IsExpression("number", type) && | ||
!gd::ParameterMetadata::IsExpression("string", type)) | ||
return false; // Not an expression that can contain properties. | ||
|
||
if (!gd::EventsPropertyReplacer::CanContainProperty( | ||
metadata.GetValueTypeMetadata())) { | ||
return false; | ||
} | ||
auto node = expression.GetRootNode(); | ||
if (node) { | ||
ExpressionPropertyReplacer renamer(platform, | ||
GetProjectScopedContainers(), | ||
targetPropertiesContainer, | ||
oldToNewPropertyNames, | ||
removedPropertyNames); | ||
ExpressionPropertyReplacer renamer( | ||
platform, GetProjectScopedContainers(), targetPropertiesContainer, | ||
metadata.GetValueTypeMetadata().IsVariable(), oldToNewPropertyNames, | ||
removedPropertyNames); | ||
node->Visit(renamer); | ||
|
||
if (renamer.IsRemovedPropertyUsed()) { | ||
|
@@ -272,6 +271,12 @@ bool EventsPropertyReplacer::DoVisitEventExpression( | |
return false; | ||
} | ||
|
||
bool EventsPropertyReplacer::CanContainProperty( | ||
const gd::ValueTypeMetadata &valueTypeMetadata) { | ||
return valueTypeMetadata.IsVariable() || valueTypeMetadata.IsNumber() || | ||
valueTypeMetadata.IsString(); | ||
} | ||
|
||
EventsPropertyReplacer::~EventsPropertyReplacer() {} | ||
|
||
} // namespace gd |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it useful to explore the node's children if this one is __ (I'm not sure what it means)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, because of expression like:
MyVariable.MyChild[MyProperty]
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In other words, we must continue to explore because properties could be used in children (becuase a variable node can have sub variables, or bracket accessors, which allows to enter a sub-expression inside the brackets (
[MyProperty]
.[1 + MyProperty]
...), and this sub-expression must be explored to rename the property that could be there.