summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp200
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp19
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.cpp13
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/auto_inferred_type_dont_error.out4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.gd11
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.gd14
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.out2
8 files changed, 182 insertions, 83 deletions
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index bc026146ef..3fbd315aec 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -131,6 +131,7 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na
return false;
}
+ // ID and size related properties.
if (tiles.size() == 1) {
const Vector2i &coords = tiles.front()->get().tile;
const int &alternative = tiles.front()->get().alternative;
@@ -160,36 +161,6 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na
tile_set_atlas_source->move_tile_in_atlas(coords, TileSetSource::INVALID_ATLAS_COORDS, as_vector2i);
emit_signal(SNAME("changed"), "size_in_atlas");
return true;
- } else if (p_name == "animation_columns") {
- bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(coords, tile_set_atlas_source->get_tile_size_in_atlas(coords), p_value, tile_set_atlas_source->get_tile_animation_separation(coords), tile_set_atlas_source->get_tile_animation_frames_count(coords), coords);
- ERR_FAIL_COND_V(!has_room_for_tile, false);
- tile_set_atlas_source->set_tile_animation_columns(coords, p_value);
- emit_signal(SNAME("changed"), "animation_columns");
- return true;
- } else if (p_name == "animation_separation") {
- bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(coords, tile_set_atlas_source->get_tile_size_in_atlas(coords), tile_set_atlas_source->get_tile_animation_columns(coords), p_value, tile_set_atlas_source->get_tile_animation_frames_count(coords), coords);
- ERR_FAIL_COND_V(!has_room_for_tile, false);
- tile_set_atlas_source->set_tile_animation_separation(coords, p_value);
- emit_signal(SNAME("changed"), "animation_separation");
- return true;
- } else if (p_name == "animation_speed") {
- tile_set_atlas_source->set_tile_animation_speed(coords, p_value);
- emit_signal(SNAME("changed"), "animation_speed");
- return true;
- } else if (p_name == "animation_frames_count") {
- bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(coords, tile_set_atlas_source->get_tile_size_in_atlas(coords), tile_set_atlas_source->get_tile_animation_columns(coords), tile_set_atlas_source->get_tile_animation_separation(coords), p_value, coords);
- ERR_FAIL_COND_V(!has_room_for_tile, false);
- tile_set_atlas_source->set_tile_animation_frames_count(coords, p_value);
- notify_property_list_changed();
- emit_signal(SNAME("changed"), "animation_separation");
- return true;
- } else if (components.size() == 2 && components[0].begins_with("animation_frame_") && components[0].trim_prefix("animation_frame_").is_valid_int()) {
- int frame = components[0].trim_prefix("animation_frame_").to_int();
- ERR_FAIL_INDEX_V(frame, tile_set_atlas_source->get_tile_animation_frames_count(coords), false);
- if (components[1] == "duration") {
- tile_set_atlas_source->set_tile_animation_frame_duration(coords, frame, p_value);
- return true;
- }
}
} else if (alternative > 0) {
if (p_name == "alternative_id") {
@@ -213,6 +184,74 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na
}
}
+ // Animation.
+ // Check if all tiles have an alternative_id of 0.
+ bool all_alternatve_id_zero = true;
+ for (TileSelection tile : tiles) {
+ if (tile.alternative != 0) {
+ all_alternatve_id_zero = false;
+ break;
+ }
+ }
+
+ if (all_alternatve_id_zero) {
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (p_name == "animation_columns") {
+ for (TileSelection tile : tiles) {
+ bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(tile.tile, tile_set_atlas_source->get_tile_size_in_atlas(tile.tile), p_value, tile_set_atlas_source->get_tile_animation_separation(tile.tile), tile_set_atlas_source->get_tile_animation_frames_count(tile.tile), tile.tile);
+ if (!has_room_for_tile) {
+ ERR_PRINT("No room for tile");
+ } else {
+ tile_set_atlas_source->set_tile_animation_columns(tile.tile, p_value);
+ }
+ }
+ emit_signal(SNAME("changed"), "animation_columns");
+ return true;
+ } else if (p_name == "animation_separation") {
+ for (TileSelection tile : tiles) {
+ bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(tile.tile, tile_set_atlas_source->get_tile_size_in_atlas(tile.tile), tile_set_atlas_source->get_tile_animation_columns(tile.tile), p_value, tile_set_atlas_source->get_tile_animation_frames_count(tile.tile), tile.tile);
+ if (!has_room_for_tile) {
+ ERR_PRINT("No room for tile");
+ } else {
+ tile_set_atlas_source->set_tile_animation_separation(tile.tile, p_value);
+ }
+ }
+ emit_signal(SNAME("changed"), "animation_separation");
+ return true;
+ } else if (p_name == "animation_speed") {
+ for (TileSelection tile : tiles) {
+ tile_set_atlas_source->set_tile_animation_speed(tile.tile, p_value);
+ }
+ emit_signal(SNAME("changed"), "animation_speed");
+ return true;
+ } else if (p_name == "animation_frames_count") {
+ for (TileSelection tile : tiles) {
+ bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(tile.tile, tile_set_atlas_source->get_tile_size_in_atlas(tile.tile), tile_set_atlas_source->get_tile_animation_columns(tile.tile), tile_set_atlas_source->get_tile_animation_separation(tile.tile), p_value, tile.tile);
+ if (!has_room_for_tile) {
+ ERR_PRINT("No room for tile");
+ } else {
+ tile_set_atlas_source->set_tile_animation_frames_count(tile.tile, p_value);
+ }
+ }
+ notify_property_list_changed();
+ emit_signal(SNAME("changed"), "animation_separation");
+ return true;
+ } else if (components.size() == 2 && components[0].begins_with("animation_frame_") && components[0].trim_prefix("animation_frame_").is_valid_int()) {
+ for (TileSelection tile : tiles) {
+ int frame = components[0].trim_prefix("animation_frame_").to_int();
+ if (frame < 0 || frame >= tile_set_atlas_source->get_tile_animation_frames_count(tile.tile)) {
+ ERR_PRINT(vformat("No tile animation frame with index %d", frame));
+ } else {
+ if (components[1] == "duration") {
+ tile_set_atlas_source->set_tile_animation_frame_duration(tile.tile, frame, p_value);
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ // Other properties.
bool any_valid = false;
for (Set<TileSelection>::Element *E = tiles.front(); E; E = E->next()) {
const Vector2i &coords = E->get().tile;
@@ -238,6 +277,7 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_get(const StringName &p_na
return false;
}
+ // ID and size related properties.s
if (tiles.size() == 1) {
const Vector2i &coords = tiles.front()->get().tile;
const int &alternative = tiles.front()->get().alternative;
@@ -250,27 +290,6 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_get(const StringName &p_na
} else if (p_name == "size_in_atlas") {
r_ret = tile_set_atlas_source->get_tile_size_in_atlas(coords);
return true;
- } else if (p_name == "animation_columns") {
- r_ret = tile_set_atlas_source->get_tile_animation_columns(coords);
- return true;
- } else if (p_name == "animation_separation") {
- r_ret = tile_set_atlas_source->get_tile_animation_separation(coords);
- return true;
- } else if (p_name == "animation_speed") {
- r_ret = tile_set_atlas_source->get_tile_animation_speed(coords);
- return true;
- } else if (p_name == "animation_frames_count") {
- r_ret = tile_set_atlas_source->get_tile_animation_frames_count(coords);
- return true;
- } else if (components.size() == 2 && components[0].begins_with("animation_frame_") && components[0].trim_prefix("animation_frame_").is_valid_int()) {
- int frame = components[0].trim_prefix("animation_frame_").to_int();
- if (components[1] == "duration") {
- if (frame < 0 || frame >= tile_set_atlas_source->get_tile_animation_frames_count(coords)) {
- return false;
- }
- r_ret = tile_set_atlas_source->get_tile_animation_frame_duration(coords, frame);
- return true;
- }
}
} else if (alternative > 0) {
if (p_name == "alternative_id") {
@@ -280,6 +299,44 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_get(const StringName &p_na
}
}
+ // Animation.
+ // Check if all tiles have an alternative_id of 0.
+ bool all_alternatve_id_zero = true;
+ for (TileSelection tile : tiles) {
+ if (tile.alternative != 0) {
+ all_alternatve_id_zero = false;
+ break;
+ }
+ }
+
+ if (all_alternatve_id_zero) {
+ const Vector2i &coords = tiles.front()->get().tile;
+
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (p_name == "animation_columns") {
+ r_ret = tile_set_atlas_source->get_tile_animation_columns(coords);
+ return true;
+ } else if (p_name == "animation_separation") {
+ r_ret = tile_set_atlas_source->get_tile_animation_separation(coords);
+ return true;
+ } else if (p_name == "animation_speed") {
+ r_ret = tile_set_atlas_source->get_tile_animation_speed(coords);
+ return true;
+ } else if (p_name == "animation_frames_count") {
+ r_ret = tile_set_atlas_source->get_tile_animation_frames_count(coords);
+ return true;
+ } else if (components.size() == 2 && components[0].begins_with("animation_frame_") && components[0].trim_prefix("animation_frame_").is_valid_int()) {
+ int frame = components[0].trim_prefix("animation_frame_").to_int();
+ if (components[1] == "duration") {
+ if (frame < 0 || frame >= tile_set_atlas_source->get_tile_animation_frames_count(coords)) {
+ return false;
+ }
+ r_ret = tile_set_atlas_source->get_tile_animation_frame_duration(coords, frame);
+ return true;
+ }
+ }
+ }
+
for (Set<TileSelection>::Element *E = tiles.front(); E; E = E->next()) {
// Return the first tile with a property matching the name.
// Note: It's a little bit annoying, but the behavior is the same the one in MultiNodeEdit.
@@ -304,29 +361,42 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::_get_property_list(List<Pro
return;
}
+ // ID and size related properties.
if (tiles.size() == 1) {
if (tiles.front()->get().alternative == 0) {
p_list->push_back(PropertyInfo(Variant::VECTOR2I, "atlas_coords", PROPERTY_HINT_NONE, ""));
p_list->push_back(PropertyInfo(Variant::VECTOR2I, "size_in_atlas", PROPERTY_HINT_NONE, ""));
-
- // Animation.
- p_list->push_back(PropertyInfo(Variant::NIL, "Animation", PROPERTY_HINT_NONE, "animation_", PROPERTY_USAGE_GROUP));
- p_list->push_back(PropertyInfo(Variant::INT, "animation_columns", PROPERTY_HINT_NONE, ""));
- p_list->push_back(PropertyInfo(Variant::VECTOR2I, "animation_separation", PROPERTY_HINT_NONE, ""));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "animation_speed", PROPERTY_HINT_NONE, ""));
- p_list->push_back(PropertyInfo(Variant::INT, "animation_frames_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, "Frames,animation_frame_"));
- if (tile_set_atlas_source->get_tile_animation_frames_count(tiles.front()->get().tile) == 1) {
- p_list->push_back(PropertyInfo(Variant::FLOAT, "animation_frame_0/duration", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY));
- } else {
- for (int i = 0; i < tile_set_atlas_source->get_tile_animation_frames_count(tiles.front()->get().tile); i++) {
- p_list->push_back(PropertyInfo(Variant::FLOAT, vformat("animation_frame_%d/duration", i), PROPERTY_HINT_NONE, ""));
- }
- }
} else {
p_list->push_back(PropertyInfo(Variant::INT, "alternative_id", PROPERTY_HINT_NONE, ""));
}
}
+ // Animation.
+ // Check if all tiles have an alternative_id of 0.
+ bool all_alternatve_id_zero = true;
+ for (TileSelection tile : tiles) {
+ if (tile.alternative != 0) {
+ all_alternatve_id_zero = false;
+ break;
+ }
+ }
+
+ if (all_alternatve_id_zero) {
+ p_list->push_back(PropertyInfo(Variant::NIL, "Animation", PROPERTY_HINT_NONE, "animation_", PROPERTY_USAGE_GROUP));
+ p_list->push_back(PropertyInfo(Variant::INT, "animation_columns", PROPERTY_HINT_NONE, ""));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2I, "animation_separation", PROPERTY_HINT_NONE, ""));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "animation_speed", PROPERTY_HINT_NONE, ""));
+ p_list->push_back(PropertyInfo(Variant::INT, "animation_frames_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, "Frames,animation_frame_"));
+ // Not optimal, but returns value for the first tile. This is similar to what MultiNodeEdit does.
+ if (tile_set_atlas_source->get_tile_animation_frames_count(tiles.front()->get().tile) == 1) {
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "animation_frame_0/duration", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY));
+ } else {
+ for (int i = 0; i < tile_set_atlas_source->get_tile_animation_frames_count(tiles.front()->get().tile); i++) {
+ p_list->push_back(PropertyInfo(Variant::FLOAT, vformat("animation_frame_%d/duration", i), PROPERTY_HINT_NONE, ""));
+ }
+ }
+ }
+
// Get the list of properties common to all tiles (similar to what's done in MultiNodeEdit).
struct PropertyId {
int occurence_id = 0;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index fa0236075c..3abd8672fa 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -1743,7 +1743,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
push_error("Cannot assign a new value to a constant.", p_assignment->assignee);
}
- if (!assignee_type.is_variant() && !assigned_value_type.is_variant()) {
+ if (!assignee_type.is_variant() && assigned_value_type.is_hard_type()) {
bool compatible = true;
GDScriptParser::DataType op_type = assigned_value_type;
if (p_assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
@@ -1795,27 +1795,24 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
case GDScriptParser::IdentifierNode::FUNCTION_PARAMETER: {
GDScriptParser::DataType id_type = identifier->parameter_source->get_datatype();
if (!id_type.is_hard_type()) {
- id_type = assigned_value_type;
- id_type.type_source = GDScriptParser::DataType::INFERRED;
- id_type.is_constant = false;
+ id_type.kind = GDScriptParser::DataType::VARIANT;
+ id_type.type_source = GDScriptParser::DataType::UNDETECTED;
identifier->parameter_source->set_datatype(id_type);
}
} break;
case GDScriptParser::IdentifierNode::LOCAL_VARIABLE: {
GDScriptParser::DataType id_type = identifier->variable_source->get_datatype();
if (!id_type.is_hard_type()) {
- id_type = assigned_value_type;
- id_type.type_source = GDScriptParser::DataType::INFERRED;
- id_type.is_constant = false;
+ id_type.kind = GDScriptParser::DataType::VARIANT;
+ id_type.type_source = GDScriptParser::DataType::UNDETECTED;
identifier->variable_source->set_datatype(id_type);
}
} break;
case GDScriptParser::IdentifierNode::LOCAL_ITERATOR: {
GDScriptParser::DataType id_type = identifier->bind_source->get_datatype();
if (!id_type.is_hard_type()) {
- id_type = assigned_value_type;
- id_type.type_source = GDScriptParser::DataType::INFERRED;
- id_type.is_constant = false;
+ id_type.kind = GDScriptParser::DataType::VARIANT;
+ id_type.type_source = GDScriptParser::DataType::UNDETECTED;
identifier->variable_source->set_datatype(id_type);
}
} break;
@@ -2942,7 +2939,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
} else {
GDScriptParser::DataType base_type = p_subscript->base->get_datatype();
- if (base_type.is_variant()) {
+ if (base_type.is_variant() || !base_type.is_hard_type()) {
result_type.kind = GDScriptParser::DataType::VARIANT;
mark_node_unsafe(p_subscript);
} else {
diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp
index c383830c82..50c1f68440 100644
--- a/modules/gdscript/tests/gdscript_test_runner.cpp
+++ b/modules/gdscript/tests/gdscript_test_runner.cpp
@@ -133,13 +133,12 @@ GDScriptTestRunner::GDScriptTestRunner(const String &p_source_dir, bool p_init_l
if (do_init_languages) {
init_language(p_source_dir);
-
- // Enable all warnings for GDScript, so we can test them.
- ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/enable", true);
- for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {
- String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower();
- ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/" + warning, true);
- }
+ }
+ // Enable all warnings for GDScript, so we can test them.
+ ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/enable", true);
+ for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {
+ String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower();
+ ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/" + warning, true);
}
// Enable printing to show results
diff --git a/modules/gdscript/tests/scripts/analyzer/features/auto_inferred_type_dont_error.out b/modules/gdscript/tests/scripts/analyzer/features/auto_inferred_type_dont_error.out
index 0e9f482af4..481016138a 100644
--- a/modules/gdscript/tests/scripts/analyzer/features/auto_inferred_type_dont_error.out
+++ b/modules/gdscript/tests/scripts/analyzer/features/auto_inferred_type_dont_error.out
@@ -1,2 +1,6 @@
GDTEST_OK
+>> WARNING
+>> Line: 6
+>> UNSAFE_METHOD_ACCESS
+>> The method 'free' is not present on the inferred type 'Variant' (but may be present on a subtype).
Ok
diff --git a/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.gd b/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.gd
new file mode 100644
index 0000000000..630b20c282
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.gd
@@ -0,0 +1,11 @@
+# https://github.com/godotengine/godot/issues/43503
+
+var test_var = null
+
+
+func test():
+ print(test_var.x)
+
+
+func _init():
+ test_var = Vector3()
diff --git a/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.out b/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.out
new file mode 100644
index 0000000000..94e2ec2af8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+0
diff --git a/modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.gd b/modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.gd
new file mode 100644
index 0000000000..b3784dffa3
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.gd
@@ -0,0 +1,14 @@
+# https://github.com/godotengine/godot/issues/41064
+var x = true
+
+func test():
+ var int_var: int = 0
+ var dyn_var = 2
+
+ if x:
+ dyn_var = 5
+ else:
+ dyn_var = Node.new()
+
+ int_var = dyn_var
+ print(int_var)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.out b/modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.out
new file mode 100644
index 0000000000..952029f665
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+5