2023-06-24 13:21:40 +03:00
|
|
|
|
// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt)
|
2015-06-01 22:15:17 +03:00
|
|
|
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
2015-05-14 22:35:07 +03:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Text;
|
2024-03-13 22:16:40 +03:00
|
|
|
|
using PascalABCCompiler.TreeConverter;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
using PascalABCCompiler.TreeRealization;
|
|
|
|
|
|
|
|
|
|
|
|
namespace PascalABCCompiler
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public class Optimizer
|
|
|
|
|
|
{
|
|
|
|
|
|
private List<Errors.CompilerWarning> warns = new List<Errors.CompilerWarning>();
|
|
|
|
|
|
private OptimizerHelper helper = new OptimizerHelper();
|
2016-09-27 21:05:16 +03:00
|
|
|
|
private bool extended_mode = true;
|
|
|
|
|
|
private common_type_node current_type;
|
2017-06-11 13:50:08 +03:00
|
|
|
|
private bool condition_block = false;
|
2017-06-29 22:05:37 +03:00
|
|
|
|
private bool has_returns = false;
|
2017-07-02 11:44:59 +03:00
|
|
|
|
private bool has_goto = false;
|
2022-09-25 11:40:08 +03:00
|
|
|
|
private Dictionary<common_method_node, common_method_node> processed_methods = new Dictionary<common_method_node, common_method_node>();
|
2018-09-16 18:51:26 +03:00
|
|
|
|
private bool no_infinite_recursion;
|
|
|
|
|
|
|
2015-05-14 22:35:07 +03:00
|
|
|
|
public Optimizer()
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public List<Errors.CompilerWarning> Optimize(program_node p)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (common_namespace_node cnn in p.common_namespaces)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitCommonNamespaceHeader(cnn);
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (common_namespace_node cnn in p.common_namespaces)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitCommonNamespaceNode(cnn);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (p.main_function != null)
|
|
|
|
|
|
VisitStatement(p.main_function.function_code);
|
|
|
|
|
|
foreach (common_namespace_node cnn in p.common_namespaces)
|
|
|
|
|
|
{
|
|
|
|
|
|
CollectInfoNamespaces(cnn);
|
|
|
|
|
|
}
|
|
|
|
|
|
return warns;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
return warns;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-11-08 15:39:39 +03:00
|
|
|
|
private void AddWarning(string message, location loc)
|
|
|
|
|
|
{
|
|
|
|
|
|
warns.Add(new GenericWarning(message, loc));
|
|
|
|
|
|
}
|
2019-06-15 13:25:44 +03:00
|
|
|
|
private void AddWarningAssignWithoutUsing(string name, location loc)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (name.Contains("$"))
|
|
|
|
|
|
return;
|
|
|
|
|
|
warns.Add(new AssignWithoutUsing(name,loc));
|
|
|
|
|
|
}
|
2015-11-08 15:39:39 +03:00
|
|
|
|
|
|
|
|
|
|
private void AddHint(string message, location loc)
|
|
|
|
|
|
{
|
|
|
|
|
|
warns.Add(new GenericHint(message, loc));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-05-14 22:35:07 +03:00
|
|
|
|
private void VisitCommonNamespaceHeader(common_namespace_node cnn)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!cnn.from_pcu)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (namespace_variable vdn in cnn.variables)
|
2016-09-27 21:05:16 +03:00
|
|
|
|
{
|
2015-05-14 22:35:07 +03:00
|
|
|
|
helper.AddVariable(vdn);
|
2016-09-27 21:05:16 +03:00
|
|
|
|
CheckType(vdn.type, vdn.inital_value, vdn.loc);
|
2018-11-04 16:24:07 +03:00
|
|
|
|
if (vdn.inital_value != null)
|
|
|
|
|
|
VisitExpression(vdn.inital_value);
|
2016-09-27 21:05:16 +03:00
|
|
|
|
}
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-11-05 17:15:28 +03:00
|
|
|
|
private bool isUnused(VarInfo vi, var_definition_node vdn)
|
|
|
|
|
|
{
|
|
|
|
|
|
return vi.num_use == 0 && !vdn.is_special_name && !vdn.name.StartsWith("#");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-05-14 22:35:07 +03:00
|
|
|
|
private void CollectInfoNamespaces(common_namespace_node cnn)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!cnn.from_pcu)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (cnn.is_main)
|
|
|
|
|
|
foreach (var_definition_node vdn2 in cnn.variables)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (vdn2 is namespace_variable)
|
|
|
|
|
|
{
|
|
|
|
|
|
namespace_variable vdn = vdn2 as namespace_variable;
|
|
|
|
|
|
VarInfo vi = helper.GetVariable(vdn);
|
2017-11-05 17:15:28 +03:00
|
|
|
|
if (isUnused(vi, vdn)) warns.Add(new UnusedVariable(vdn.name, vdn.loc));
|
2019-06-15 13:25:44 +03:00
|
|
|
|
if (vi.num_ass > 0 && vi.act_num_use == 0) AddWarningAssignWithoutUsing(vdn.name, vi.last_ass_loc);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
//if (vi.num_ass == 0 && vi.act_num_use > 0) helper.AddRealWarning(vdn, warns);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (vdn2 is local_block_variable)
|
|
|
|
|
|
{
|
|
|
|
|
|
local_block_variable vdn = vdn2 as local_block_variable;
|
|
|
|
|
|
VarInfo vi = helper.GetVariable(vdn);
|
2017-11-05 17:15:28 +03:00
|
|
|
|
if (isUnused(vi, vdn)) warns.Add(new UnusedVariable(vdn.name, vdn.loc));
|
2019-06-15 13:25:44 +03:00
|
|
|
|
if (vi.num_ass > 0 && vi.act_num_use == 0) AddWarningAssignWithoutUsing(vdn.name, vi.last_ass_loc);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (common_type_node ctn in cnn.types)
|
|
|
|
|
|
CollectInfoFields(ctn);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitCommonNamespaceNode(common_namespace_node cnn)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!cnn.from_pcu)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (common_type_node ctn in cnn.types)
|
|
|
|
|
|
VisitCommonTypeHeader(ctn);
|
|
|
|
|
|
|
|
|
|
|
|
foreach (common_type_node ctn in cnn.types)
|
|
|
|
|
|
VisitCommonType(ctn);
|
|
|
|
|
|
|
|
|
|
|
|
foreach (common_namespace_function_node cnfn in cnn.functions)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitCommonNamespaceFunctionNode(cnfn);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitCommonType(common_type_node ctn)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (common_method_node cmn in ctn.methods)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitMethod(cmn);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitMethod(common_method_node cmn)
|
|
|
|
|
|
{
|
2022-09-25 11:40:08 +03:00
|
|
|
|
if (processed_methods.ContainsKey(cmn))
|
|
|
|
|
|
return;
|
|
|
|
|
|
processed_methods.Add(cmn, cmn);
|
2015-11-08 15:39:39 +03:00
|
|
|
|
if (extended_mode)
|
|
|
|
|
|
VisitVariables(cmn.var_definition_nodes_list);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
foreach (var_definition_node vdn in cmn.var_definition_nodes_list)
|
|
|
|
|
|
helper.AddVariable(vdn);
|
|
|
|
|
|
foreach (common_parameter prm in cmn.parameters)
|
|
|
|
|
|
helper.AddParameter(prm);
|
|
|
|
|
|
foreach (common_in_function_function_node nested in cmn.functions_nodes_list)
|
|
|
|
|
|
VisitNestedFunction(nested);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
current_function = cmn;
|
2017-06-29 22:05:37 +03:00
|
|
|
|
has_returns = false;
|
2017-07-02 11:44:59 +03:00
|
|
|
|
has_goto = false;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitStatement(cmn.function_code);
|
|
|
|
|
|
foreach (var_definition_node vdn2 in cmn.var_definition_nodes_list)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (vdn2 is local_variable)
|
|
|
|
|
|
{
|
|
|
|
|
|
local_variable vdn = vdn2 as local_variable;
|
|
|
|
|
|
VarInfo vi = helper.GetVariable(vdn);
|
2017-11-05 17:15:28 +03:00
|
|
|
|
if (isUnused(vi, vdn))
|
2016-09-27 21:42:57 +03:00
|
|
|
|
warns.Add(new UnusedVariable(vdn.name, vdn.loc));
|
|
|
|
|
|
else if (vi.num_ass == 0 &&
|
|
|
|
|
|
vdn.is_ret_value &&
|
|
|
|
|
|
!cmn.name.StartsWith("<") &&
|
|
|
|
|
|
!cmn.cont_type.IsInterface &&
|
|
|
|
|
|
cmn.polymorphic_state != SemanticTree.polymorphic_state.ps_virtual_abstract &&
|
|
|
|
|
|
cmn.return_value_type != null &&
|
|
|
|
|
|
!cmn.return_value_type.IsPointer &&
|
|
|
|
|
|
!cmn.is_constructor &&
|
|
|
|
|
|
cmn.return_value_type.type_special_kind != SemanticTree.type_special_kind.record &&
|
|
|
|
|
|
cmn.return_value_type.type_special_kind != SemanticTree.type_special_kind.array_wrapper
|
|
|
|
|
|
&& !helper.IsExternal(cmn))
|
|
|
|
|
|
warns.Add(new UndefinedReturnValue(cmn.name, cmn.function_code.location));
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
else if (vdn2 is local_block_variable)
|
|
|
|
|
|
{
|
|
|
|
|
|
local_block_variable vdn = vdn2 as local_block_variable;
|
|
|
|
|
|
VarInfo vi = helper.GetVariable(vdn);
|
2017-11-05 17:15:28 +03:00
|
|
|
|
if (isUnused(vi, vdn))
|
2016-09-27 21:42:57 +03:00
|
|
|
|
warns.Add(new UnusedVariable(vdn.name, vdn.loc));
|
|
|
|
|
|
else if (vi.num_ass == 0 &&
|
|
|
|
|
|
vdn.is_ret_value &&
|
|
|
|
|
|
!cmn.name.StartsWith("<") &&
|
|
|
|
|
|
!cmn.cont_type.IsInterface &&
|
|
|
|
|
|
cmn.polymorphic_state != SemanticTree.polymorphic_state.ps_virtual_abstract &&
|
|
|
|
|
|
cmn.return_value_type != null &&
|
|
|
|
|
|
!cmn.return_value_type.IsPointer &&
|
|
|
|
|
|
!cmn.is_constructor &&
|
|
|
|
|
|
cmn.return_value_type.type_special_kind != SemanticTree.type_special_kind.record &&
|
|
|
|
|
|
cmn.return_value_type.type_special_kind != SemanticTree.type_special_kind.array_wrapper
|
|
|
|
|
|
&& !helper.IsExternal(cmn))
|
|
|
|
|
|
warns.Add(new UndefinedReturnValue(cmn.name, cmn.function_code.location));
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
2016-09-27 21:42:57 +03:00
|
|
|
|
if (vdn2.inital_value != null)
|
|
|
|
|
|
VisitExpression(vdn2.inital_value);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
foreach (common_parameter prm in cmn.parameters)
|
|
|
|
|
|
{
|
|
|
|
|
|
ParamInfo vi = helper.GetParameter(prm);
|
|
|
|
|
|
if (prm.inital_value != null) VisitExpression(prm.inital_value);
|
|
|
|
|
|
//if (vi.num_use == 0 && !prm.name.Contains("$")) warns.Add(new UnusedParameter(prm.name, prm.loc));
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (var_definition_node vdn in cmn.var_definition_nodes_list)
|
|
|
|
|
|
{
|
|
|
|
|
|
VarInfo vi = helper.GetVariable(vdn);
|
|
|
|
|
|
if (vdn.inital_value != null) VisitExpression(vdn.inital_value);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitCommonTypeHeader(common_type_node ctn)
|
|
|
|
|
|
{
|
2016-09-27 21:05:16 +03:00
|
|
|
|
if (ctn.base_type != null && ctn.base_type is common_type_node)
|
|
|
|
|
|
VisitCommonTypeHeader(ctn.base_type as common_type_node);
|
|
|
|
|
|
current_type = ctn;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
foreach (class_field fld in ctn.fields)
|
2016-09-27 21:05:16 +03:00
|
|
|
|
{
|
2015-05-14 22:35:07 +03:00
|
|
|
|
helper.AddField(fld);
|
2016-09-27 21:05:16 +03:00
|
|
|
|
CheckType(fld.type, fld.inital_value, fld.loc);
|
|
|
|
|
|
}
|
|
|
|
|
|
current_type = null;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void CollectInfoFields(common_type_node ctn)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!ctn.comprehensive_namespace.from_pcu)
|
|
|
|
|
|
foreach (class_field fld in ctn.fields)
|
|
|
|
|
|
{
|
|
|
|
|
|
FldInfo fi = helper.GetField(fld);
|
|
|
|
|
|
// if (fi.num_use == 0 && !ctn.name.Contains("$") && fld.field_access_level == SemanticTree.field_access_level.fal_private) warns.Add(new UnusedField(fld.name, fld.loc));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-06-11 13:50:08 +03:00
|
|
|
|
private common_function_node current_function=null;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
|
2015-11-08 15:39:39 +03:00
|
|
|
|
private void CheckType(type_node type, expression_node initial_value, location loc)
|
|
|
|
|
|
{
|
2016-09-27 21:05:16 +03:00
|
|
|
|
/*if (type.IsPointer && type.element_type.is_value_type && type.element_type is common_type_node)
|
2015-11-08 15:39:39 +03:00
|
|
|
|
{
|
|
|
|
|
|
AddHint("DO_NOT_USE_POINTERS_TO_RECORDS", loc);
|
2016-09-27 21:05:16 +03:00
|
|
|
|
}*/
|
|
|
|
|
|
if (type.type_special_kind == SemanticTree.type_special_kind.short_string && !(current_type != null && current_type.is_value))
|
2015-11-08 15:39:39 +03:00
|
|
|
|
{
|
|
|
|
|
|
AddHint("DO_NOT_USE_SHORT_STRINGS", loc);
|
|
|
|
|
|
}
|
2016-09-27 21:05:16 +03:00
|
|
|
|
else if (type.type_special_kind == SemanticTree.type_special_kind.array_kind || type.type_special_kind == SemanticTree.type_special_kind.array_wrapper)
|
|
|
|
|
|
{
|
|
|
|
|
|
CheckType(type.element_type, initial_value, loc);
|
|
|
|
|
|
}
|
2015-11-08 15:39:39 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitVariables(local_variable_list var_list)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (local_variable lv in var_list)
|
|
|
|
|
|
{
|
|
|
|
|
|
CheckType(lv.type, lv.inital_value, lv.loc);
|
2018-11-04 16:24:07 +03:00
|
|
|
|
if (lv.inital_value != null)
|
|
|
|
|
|
VisitExpression(lv.inital_value);
|
2015-11-08 15:39:39 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-05-14 22:35:07 +03:00
|
|
|
|
private void VisitCommonNamespaceFunctionNode(common_namespace_function_node cnfn)
|
|
|
|
|
|
{
|
2015-11-08 15:39:39 +03:00
|
|
|
|
if (extended_mode)
|
|
|
|
|
|
VisitVariables(cnfn.var_definition_nodes_list);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
foreach (var_definition_node vdn in cnfn.var_definition_nodes_list)
|
|
|
|
|
|
helper.AddVariable(vdn);
|
|
|
|
|
|
foreach (common_parameter prm in cnfn.parameters)
|
|
|
|
|
|
helper.AddParameter(prm);
|
|
|
|
|
|
foreach (common_in_function_function_node nested in cnfn.functions_nodes_list)
|
|
|
|
|
|
VisitNestedFunction(nested);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
current_function = cnfn;
|
2017-06-29 22:05:37 +03:00
|
|
|
|
has_returns = false;
|
2017-07-02 11:44:59 +03:00
|
|
|
|
has_goto = false;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitStatement(cnfn.function_code);
|
|
|
|
|
|
foreach (var_definition_node vdn2 in cnfn.var_definition_nodes_list)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (vdn2 is local_variable)
|
|
|
|
|
|
{
|
|
|
|
|
|
local_variable vdn = vdn2 as local_variable;
|
|
|
|
|
|
VarInfo vi = helper.GetVariable(vdn);
|
2017-11-05 17:15:28 +03:00
|
|
|
|
if (isUnused(vi, vdn))
|
2016-09-27 21:42:57 +03:00
|
|
|
|
warns.Add(new UnusedVariable(vdn.name, vdn.loc));
|
|
|
|
|
|
else if (vi.num_ass == 0 &&
|
|
|
|
|
|
vdn.is_ret_value &&
|
|
|
|
|
|
!cnfn.name.StartsWith("<") &&
|
|
|
|
|
|
cnfn.return_value_type != null &&
|
|
|
|
|
|
cnfn.return_value_type.type_special_kind != SemanticTree.type_special_kind.record &&
|
|
|
|
|
|
!cnfn.return_value_type.IsPointer &&
|
|
|
|
|
|
cnfn.return_value_type.type_special_kind != SemanticTree.type_special_kind.array_wrapper &&
|
|
|
|
|
|
!helper.IsExternal(cnfn))
|
|
|
|
|
|
warns.Add(new UndefinedReturnValue(cnfn.name, cnfn.function_code.location));
|
|
|
|
|
|
if (vi.num_ass > 0 && vi.act_num_use == 0 && !vdn.is_special_name)
|
2019-06-15 13:25:44 +03:00
|
|
|
|
AddWarningAssignWithoutUsing(vdn.name, vi.last_ass_loc);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
else if (vdn2 is local_block_variable)
|
|
|
|
|
|
{
|
|
|
|
|
|
local_block_variable vdn = vdn2 as local_block_variable;
|
|
|
|
|
|
VarInfo vi = helper.GetVariable(vdn);
|
2017-11-05 17:15:28 +03:00
|
|
|
|
if (isUnused(vi, vdn))
|
2016-09-27 21:42:57 +03:00
|
|
|
|
warns.Add(new UnusedVariable(vdn.name, vdn.loc));
|
|
|
|
|
|
else if (vi.num_ass == 0 &&
|
|
|
|
|
|
vdn.is_ret_value &&
|
|
|
|
|
|
!cnfn.name.StartsWith("<") &&
|
|
|
|
|
|
cnfn.return_value_type != null &&
|
|
|
|
|
|
cnfn.return_value_type.type_special_kind != SemanticTree.type_special_kind.record &&
|
|
|
|
|
|
!cnfn.return_value_type.IsPointer &&
|
|
|
|
|
|
cnfn.return_value_type.type_special_kind != SemanticTree.type_special_kind.array_wrapper &&
|
|
|
|
|
|
!helper.IsExternal(cnfn))
|
|
|
|
|
|
warns.Add(new UndefinedReturnValue(cnfn.name, cnfn.function_code.location));
|
|
|
|
|
|
if (vi.num_ass > 0 && vi.act_num_use == 0 && !vdn.is_special_name)
|
2019-06-15 13:25:44 +03:00
|
|
|
|
AddWarningAssignWithoutUsing(vdn.name, vi.last_ass_loc);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
2016-09-27 21:42:57 +03:00
|
|
|
|
if (vdn2.inital_value != null)
|
|
|
|
|
|
VisitExpression(vdn2.inital_value);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
foreach (common_parameter prm in cnfn.parameters)
|
|
|
|
|
|
{
|
|
|
|
|
|
ParamInfo vi = helper.GetParameter(prm);
|
2016-09-27 21:42:57 +03:00
|
|
|
|
if (prm.inital_value != null)
|
|
|
|
|
|
VisitExpression(prm.inital_value);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
//if (vi.num_use == 0 && !prm.name.Contains("$")) warns.Add(new UnusedParameter(prm.name, prm.loc));
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (var_definition_node vdn in cnfn.var_definition_nodes_list)
|
|
|
|
|
|
{
|
|
|
|
|
|
VarInfo vi = helper.GetVariable(vdn);
|
2016-09-27 21:42:57 +03:00
|
|
|
|
if (vdn.inital_value != null)
|
|
|
|
|
|
VisitExpression(vdn.inital_value);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitNestedFunction(common_in_function_function_node cnfn)
|
|
|
|
|
|
{
|
2015-11-08 15:39:39 +03:00
|
|
|
|
if (extended_mode)
|
|
|
|
|
|
VisitVariables(cnfn.var_definition_nodes_list);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
foreach (var_definition_node vdn in cnfn.var_definition_nodes_list)
|
|
|
|
|
|
helper.AddVariable(vdn);
|
|
|
|
|
|
foreach (common_parameter prm in cnfn.parameters)
|
|
|
|
|
|
helper.AddParameter(prm);
|
|
|
|
|
|
foreach (common_in_function_function_node nested in cnfn.functions_nodes_list)
|
|
|
|
|
|
VisitNestedFunction(nested);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
current_function = cnfn;
|
2017-06-29 22:05:37 +03:00
|
|
|
|
has_returns = false;
|
2017-07-02 11:44:59 +03:00
|
|
|
|
has_goto = false;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitStatement(cnfn.function_code);
|
|
|
|
|
|
foreach (var_definition_node vdn2 in cnfn.var_definition_nodes_list)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (vdn2 is local_variable)
|
|
|
|
|
|
{
|
|
|
|
|
|
local_variable vdn = vdn2 as local_variable;
|
|
|
|
|
|
VarInfo vi = helper.GetVariable(vdn);
|
2017-11-05 17:15:28 +03:00
|
|
|
|
if (isUnused(vi, vdn))
|
2016-09-27 21:42:57 +03:00
|
|
|
|
warns.Add(new UnusedVariable(vdn.name, vdn.loc));
|
|
|
|
|
|
else if (vi.num_ass == 0 &&
|
|
|
|
|
|
vdn.is_ret_value &&
|
|
|
|
|
|
!cnfn.name.StartsWith("<") &&
|
|
|
|
|
|
cnfn.return_value_type.type_special_kind != SemanticTree.type_special_kind.record &&
|
|
|
|
|
|
!cnfn.return_value_type.IsPointer &&
|
|
|
|
|
|
cnfn.return_value_type.type_special_kind != SemanticTree.type_special_kind.array_wrapper &&
|
|
|
|
|
|
!helper.IsExternal(cnfn))
|
|
|
|
|
|
warns.Add(new UndefinedReturnValue(cnfn.name, cnfn.function_code.location));
|
|
|
|
|
|
if (vi.num_ass > 0 && vi.act_num_use == 0 && !vdn.is_special_name)
|
2019-06-15 13:25:44 +03:00
|
|
|
|
AddWarningAssignWithoutUsing(vdn.name, vi.last_ass_loc);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
else if (vdn2 is local_block_variable)
|
|
|
|
|
|
{
|
|
|
|
|
|
local_block_variable vdn = vdn2 as local_block_variable;
|
|
|
|
|
|
VarInfo vi = helper.GetVariable(vdn);
|
2017-11-05 17:15:28 +03:00
|
|
|
|
if (isUnused(vi, vdn))
|
2019-06-15 13:25:44 +03:00
|
|
|
|
AddWarningAssignWithoutUsing(vdn.name, vdn.loc);
|
2016-09-27 21:42:57 +03:00
|
|
|
|
else if (vi.num_ass == 0 &&
|
|
|
|
|
|
vdn.is_ret_value &&
|
|
|
|
|
|
!cnfn.name.StartsWith("<") &&
|
|
|
|
|
|
cnfn.return_value_type.type_special_kind != SemanticTree.type_special_kind.record &&
|
|
|
|
|
|
!cnfn.return_value_type.IsPointer &&
|
|
|
|
|
|
cnfn.return_value_type.type_special_kind != SemanticTree.type_special_kind.array_wrapper &&
|
|
|
|
|
|
!helper.IsExternal(cnfn))
|
|
|
|
|
|
warns.Add(new UndefinedReturnValue(cnfn.name, cnfn.function_code.location));
|
|
|
|
|
|
if (vi.num_ass > 0 && vi.act_num_use == 0 && !vdn.is_special_name)
|
2019-06-15 13:25:44 +03:00
|
|
|
|
AddWarningAssignWithoutUsing(vdn.name, vi.last_ass_loc);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
2016-09-27 21:42:57 +03:00
|
|
|
|
if (vdn2.inital_value != null)
|
|
|
|
|
|
VisitExpression(vdn2.inital_value);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
foreach (common_parameter prm in cnfn.parameters)
|
|
|
|
|
|
{
|
|
|
|
|
|
ParamInfo vi = helper.GetParameter(prm);
|
2016-09-27 21:42:57 +03:00
|
|
|
|
if (prm.inital_value != null)
|
|
|
|
|
|
VisitExpression(prm.inital_value);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
//if (vi.num_use == 0 && !prm.name.Contains("$")) warns.Add(new UnusedParameter(prm.name, prm.loc));
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (var_definition_node vdn in cnfn.var_definition_nodes_list)
|
|
|
|
|
|
{
|
|
|
|
|
|
VarInfo vi = helper.GetVariable(vdn);
|
2016-09-27 21:42:57 +03:00
|
|
|
|
if (vdn.inital_value != null)
|
|
|
|
|
|
VisitExpression(vdn.inital_value);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitStatement(statement_node sn)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (sn == null) return;
|
2017-07-06 21:33:38 +03:00
|
|
|
|
if (!(sn is statements_list) && is_break_stmt && !has_goto && !(sn is empty_statement))
|
2015-05-14 22:35:07 +03:00
|
|
|
|
{
|
|
|
|
|
|
warns.Add(new UnreachableCodeDetected(sn.location));
|
|
|
|
|
|
is_break_stmt = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (sn is expression_node)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitExpression((expression_node)sn);
|
|
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
switch (sn.semantic_node_type)
|
|
|
|
|
|
{
|
|
|
|
|
|
case semantic_node_type.if_node: VisitIf((if_node)sn); break;
|
|
|
|
|
|
case semantic_node_type.while_node: VisitWhile((while_node)sn); break;
|
|
|
|
|
|
case semantic_node_type.repeat_node: VisitRepeat((repeat_node)sn); break;
|
|
|
|
|
|
case semantic_node_type.for_node: VisitFor((for_node)sn); break;
|
|
|
|
|
|
case semantic_node_type.statements_list: VisitStatementList((statements_list)sn); break;
|
|
|
|
|
|
case semantic_node_type.empty_statement: VisitEmpty((empty_statement)sn); break;
|
|
|
|
|
|
case semantic_node_type.return_node: VisitReturnNode((return_node)sn); break;
|
|
|
|
|
|
case semantic_node_type.switch_node: VisitSwitchNode((switch_node)sn); break;
|
|
|
|
|
|
case semantic_node_type.external_statement_node: VisitExternalStatementNode((external_statement)sn); break;
|
|
|
|
|
|
case semantic_node_type.pinvoke_node: VisitPInvokeStatementNode((pinvoke_statement)sn); break;
|
|
|
|
|
|
case semantic_node_type.throw_statement: VisitThrow((throw_statement_node)sn); break;
|
|
|
|
|
|
case semantic_node_type.runtime_statement: VisitRuntimeStatement((runtime_statement)sn); break;
|
|
|
|
|
|
case semantic_node_type.try_block: VisitTryBlock((try_block)sn); break;
|
|
|
|
|
|
case semantic_node_type.labeled_statement: VisitLabeledStatement((labeled_statement)sn); break;
|
|
|
|
|
|
case semantic_node_type.goto_statement: VisitGoto((goto_statement)sn); break;
|
|
|
|
|
|
case semantic_node_type.foreach_node: VisitForeach((foreach_node)sn); break;
|
|
|
|
|
|
case semantic_node_type.lock_statement: VisitLockStatement((lock_statement)sn); break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
enum RetVal
|
|
|
|
|
|
{
|
|
|
|
|
|
True,
|
|
|
|
|
|
False,
|
|
|
|
|
|
Undef
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private RetVal GetConstantValue(expression_node en)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (en is bool_const_node)
|
|
|
|
|
|
{
|
|
|
|
|
|
if ((en as bool_const_node).constant_value) return RetVal.True;
|
|
|
|
|
|
else return RetVal.False;
|
|
|
|
|
|
}
|
|
|
|
|
|
else return RetVal.Undef;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-06-11 13:50:08 +03:00
|
|
|
|
private Stack<bool> condition_block_states = new Stack<bool>();
|
|
|
|
|
|
|
|
|
|
|
|
private void CheckInfiniteRecursion(common_namespace_function_call cnfc)
|
|
|
|
|
|
{
|
2018-11-07 21:44:13 +03:00
|
|
|
|
//if (!condition_block && !has_returns && cnfc.function_node == current_function && !no_infinite_recursion)
|
|
|
|
|
|
// warns.Add(new InfiniteRecursion(cnfc.location));
|
2017-06-11 13:50:08 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void CheckInfiniteRecursion(common_static_method_call cnfc)
|
|
|
|
|
|
{
|
2018-11-07 21:44:13 +03:00
|
|
|
|
//if (!condition_block && !has_returns && cnfc.function_node == current_function && !no_infinite_recursion)
|
|
|
|
|
|
// warns.Add(new InfiniteRecursion(cnfc.location));
|
2017-06-11 13:50:08 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void SaveConditionBlock()
|
|
|
|
|
|
{
|
|
|
|
|
|
condition_block_states.Push(condition_block);
|
|
|
|
|
|
condition_block = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void RestoreConditionBlock()
|
|
|
|
|
|
{
|
|
|
|
|
|
condition_block = condition_block_states.Pop();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void EnterConditionBlock()
|
|
|
|
|
|
{
|
|
|
|
|
|
condition_block = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-05-14 22:35:07 +03:00
|
|
|
|
private void VisitLockStatement(lock_statement stmt)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitExpression(stmt.lock_object);
|
|
|
|
|
|
VisitStatement(stmt.body);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitForeach(foreach_node stmt)
|
|
|
|
|
|
{
|
2017-06-11 13:50:08 +03:00
|
|
|
|
SaveConditionBlock();
|
|
|
|
|
|
IncreaseNumUseVar(stmt.ident);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitExpression(stmt.in_what);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
EnterConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitStatement(stmt.what_do);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
RestoreConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitIf(if_node stmt)
|
|
|
|
|
|
{
|
2017-06-11 13:50:08 +03:00
|
|
|
|
SaveConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
RetVal rv = GetConstantValue(stmt.condition);
|
|
|
|
|
|
VisitExpression(stmt.condition);
|
|
|
|
|
|
if (rv == RetVal.False)
|
|
|
|
|
|
is_break_stmt = true;
|
2017-06-11 13:50:08 +03:00
|
|
|
|
if (rv != RetVal.True)
|
|
|
|
|
|
EnterConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitStatement(stmt.then_body);
|
|
|
|
|
|
is_break_stmt = false;
|
|
|
|
|
|
if (rv == RetVal.True)
|
|
|
|
|
|
is_break_stmt = true;
|
2017-06-11 13:50:08 +03:00
|
|
|
|
if (rv != RetVal.False)
|
|
|
|
|
|
EnterConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitStatement(stmt.else_body);
|
|
|
|
|
|
is_break_stmt = false;
|
2017-06-11 13:50:08 +03:00
|
|
|
|
RestoreConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitWhile(while_node stmt)
|
|
|
|
|
|
{
|
2017-06-11 13:50:08 +03:00
|
|
|
|
SaveConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
RetVal rv = GetConstantValue(stmt.condition);
|
|
|
|
|
|
VisitExpression(stmt.condition);
|
|
|
|
|
|
if (rv == RetVal.False)
|
|
|
|
|
|
is_break_stmt = true;
|
2017-06-11 13:50:08 +03:00
|
|
|
|
if (rv != RetVal.True)
|
|
|
|
|
|
EnterConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitStatement(stmt.body);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
RestoreConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitRepeat(repeat_node stmt)
|
|
|
|
|
|
{
|
2017-06-11 13:50:08 +03:00
|
|
|
|
SaveConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
RetVal rv = GetConstantValue(stmt.condition);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
if (rv != RetVal.False)
|
|
|
|
|
|
EnterConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitStatement(stmt.body);
|
|
|
|
|
|
VisitExpression(stmt.condition);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
RestoreConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitFor(for_node stmt)
|
|
|
|
|
|
{
|
2017-06-11 13:50:08 +03:00
|
|
|
|
SaveConditionBlock();
|
2015-11-08 15:39:39 +03:00
|
|
|
|
VisitStatement(stmt.init_while_expr);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitStatement(stmt.initialization_statement);
|
|
|
|
|
|
VisitStatement(stmt.increment_statement);
|
|
|
|
|
|
VisitExpression(stmt.while_expr);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
EnterConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitStatement(stmt.body);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
RestoreConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool is_break_stmt = false;
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitStatementList(statements_list stmt)
|
|
|
|
|
|
{
|
|
|
|
|
|
statement_node sn = null;
|
2021-08-11 18:41:42 +03:00
|
|
|
|
bool tuple_decomp = false;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
foreach (local_block_variable lbv in stmt.local_variables)
|
|
|
|
|
|
{
|
2021-12-12 14:28:18 +03:00
|
|
|
|
if (lbv.name.StartsWith("#fpl") || lbv.name.StartsWith("#temp_var"))
|
2021-08-11 18:41:42 +03:00
|
|
|
|
tuple_decomp = true;
|
|
|
|
|
|
helper.AddVariable(lbv);
|
|
|
|
|
|
if (lbv.inital_value != null)
|
|
|
|
|
|
VisitExpression(lbv.inital_value);
|
2016-09-27 21:05:16 +03:00
|
|
|
|
CheckType(lbv.type, lbv.inital_value, lbv.loc);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
for (int i = 0; i < stmt.statements.Count; i++)
|
|
|
|
|
|
{
|
2017-07-02 11:44:59 +03:00
|
|
|
|
if (is_break_stmt && !has_goto && stmt.statements[i].semantic_node_type != semantic_node_type.empty_statement)
|
2015-05-14 22:35:07 +03:00
|
|
|
|
warns.Add(new UnreachableCodeDetected(stmt.statements[i].location));
|
2017-07-07 19:30:57 +03:00
|
|
|
|
if (stmt.statements[i].semantic_node_type != semantic_node_type.empty_statement)
|
2021-08-11 18:41:42 +03:00
|
|
|
|
is_break_stmt = false;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
sn = stmt.statements[i];
|
|
|
|
|
|
VisitStatement(sn);
|
2019-08-19 22:55:45 +03:00
|
|
|
|
if (is_break_stmt && !has_goto && i < stmt.statements.Count - 1 && stmt.statements[i + 1].semantic_node_type != semantic_node_type.empty_statement && stmt.statements[i + 1].location != null)
|
2021-08-11 18:41:42 +03:00
|
|
|
|
{
|
2019-08-19 22:55:45 +03:00
|
|
|
|
if (stmt.statements[i].location == null || stmt.statements[i + 1].location.ToString() != stmt.statements[i].location.ToString())
|
|
|
|
|
|
warns.Add(new UnreachableCodeDetected(stmt.statements[i + 1].location));
|
|
|
|
|
|
}
|
2017-07-07 19:30:57 +03:00
|
|
|
|
if (!(i < stmt.statements.Count - 1 && stmt.statements[i + 1].semantic_node_type == semantic_node_type.empty_statement))
|
2021-08-11 18:41:42 +03:00
|
|
|
|
is_break_stmt = false;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
2022-10-30 16:19:19 +03:00
|
|
|
|
int tuples_num = 0;
|
|
|
|
|
|
foreach (local_block_variable vdn in stmt.local_variables)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (vdn.name.StartsWith("#fpl") || vdn.name.StartsWith("#temp_var"))
|
2021-08-11 18:41:42 +03:00
|
|
|
|
{
|
2022-10-30 16:19:19 +03:00
|
|
|
|
tuple_decomp = true;
|
|
|
|
|
|
if (vdn.type is generic_instance_type_node)
|
2023-06-24 13:21:40 +03:00
|
|
|
|
tuples_num = (vdn.type as generic_instance_type_node).instance_params.Count;
|
2022-10-30 16:19:19 +03:00
|
|
|
|
else if (vdn.type is compiled_type_node)
|
|
|
|
|
|
tuples_num = (vdn.type as compiled_type_node).compiled_type.GetGenericArguments().Length;
|
|
|
|
|
|
continue;
|
2021-08-11 18:41:42 +03:00
|
|
|
|
}
|
2022-10-30 16:19:19 +03:00
|
|
|
|
else if (tuples_num > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
tuples_num--;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
VarInfo vi = helper.GetVariable(vdn);
|
|
|
|
|
|
if (isUnused(vi, vdn))
|
|
|
|
|
|
warns.Add(new UnusedVariable(vdn.name, vdn.loc));
|
|
|
|
|
|
|
|
|
|
|
|
if (vi.num_ass > 0 && vi.act_num_use == 0 && !vdn.is_special_name)
|
|
|
|
|
|
AddWarningAssignWithoutUsing(vdn.name, vi.last_ass_loc);
|
|
|
|
|
|
}
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitExternalStatementNode(external_statement sn)
|
|
|
|
|
|
{
|
2017-06-11 13:50:08 +03:00
|
|
|
|
helper.MarkAsExternal(current_function);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitPInvokeStatementNode(pinvoke_statement sn)
|
|
|
|
|
|
{
|
2017-06-11 13:50:08 +03:00
|
|
|
|
helper.MarkAsExternal(current_function);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitSwitchNode(switch_node stmt)
|
|
|
|
|
|
{
|
2017-06-11 13:50:08 +03:00
|
|
|
|
SaveConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitExpression(stmt.condition);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
EnterConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
for (int i = 0; i < stmt.case_variants.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitStatement(stmt.case_variants[i].case_statement);
|
|
|
|
|
|
is_break_stmt = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
VisitStatement(stmt.default_statement);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
RestoreConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitRuntimeStatement(runtime_statement sn)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitReturnNode(return_node stmt)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitExpression(stmt.return_expr);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitEmpty(empty_statement stmt)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitThrow(throw_statement_node stmt)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitExpression(stmt.excpetion);
|
|
|
|
|
|
is_break_stmt = true;
|
2017-06-29 22:05:37 +03:00
|
|
|
|
has_returns = true;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitTryBlock(try_block stmt)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitStatement(stmt.try_statements);
|
|
|
|
|
|
for (int i = 0; i < stmt.filters.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(stmt.filters[i].exception_var!=null)
|
|
|
|
|
|
IncreaseNumUseVar(stmt.filters[i].exception_var);
|
2018-07-18 22:47:10 +03:00
|
|
|
|
VisitStatement(stmt.filters[i].exception_handler);
|
2018-09-06 22:31:52 +03:00
|
|
|
|
is_break_stmt = false;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
2018-07-18 22:47:10 +03:00
|
|
|
|
VisitStatement(stmt.finally_statements);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitLabeledStatement(labeled_statement stmt)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitStatement(stmt.statement);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitGoto(goto_statement stmt)
|
|
|
|
|
|
{
|
2017-07-02 11:44:59 +03:00
|
|
|
|
has_goto = true;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void IncreaseNumUseVar(var_definition_node lvr)
|
|
|
|
|
|
{
|
|
|
|
|
|
VarInfo vi = helper.GetVariable(lvr);
|
|
|
|
|
|
vi.num_use++;
|
|
|
|
|
|
vi.act_num_use++;
|
|
|
|
|
|
vi.cur_use++;
|
|
|
|
|
|
//if (vi.cur_ass == 0 && !lvr.var.name.Contains("$")) helper.AddTempWarning(lvr.var,new UseWithoutAssign(lvr.var.name, lvr.location));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void IncreaseNumUseVar(local_variable_reference lvr)
|
|
|
|
|
|
{
|
|
|
|
|
|
VarInfo vi = helper.GetVariable(lvr.var);
|
|
|
|
|
|
vi.num_use++;
|
|
|
|
|
|
vi.act_num_use++;
|
|
|
|
|
|
vi.cur_use++;
|
|
|
|
|
|
//if (vi.cur_ass == 0 && !lvr.var.name.Contains("$")) helper.AddTempWarning(lvr.var,new UseWithoutAssign(lvr.var.name, lvr.location));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void IncreaseNumAssVar(local_variable_reference lvr)
|
|
|
|
|
|
{
|
|
|
|
|
|
VarInfo vi = helper.GetVariable(lvr.var);
|
|
|
|
|
|
vi.num_use++;
|
|
|
|
|
|
vi.cur_ass++;
|
|
|
|
|
|
vi.num_ass++;
|
|
|
|
|
|
vi.last_ass_loc = lvr.location;
|
|
|
|
|
|
if (vi.last_ass_loc == null && !lvr.var.is_ret_value) vi.num_ass--;
|
|
|
|
|
|
if (vi.cur_use > 0) vi.cur_use--;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void IncreaseNumAssVar(local_block_variable_reference lvr)
|
|
|
|
|
|
{
|
|
|
|
|
|
VarInfo vi = helper.GetVariable(lvr.var);
|
|
|
|
|
|
vi.num_use++;
|
|
|
|
|
|
vi.cur_ass++;
|
|
|
|
|
|
vi.num_ass++;
|
|
|
|
|
|
vi.last_ass_loc = lvr.location;
|
|
|
|
|
|
if (vi.last_ass_loc == null) vi.num_ass--;
|
|
|
|
|
|
if (vi.cur_use > 0) vi.cur_use--;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void IncreaseNumUseVar(namespace_variable_reference lvr)
|
|
|
|
|
|
{
|
|
|
|
|
|
VarInfo vi = helper.GetVariable(lvr.var);
|
|
|
|
|
|
if (vi == null) return;
|
|
|
|
|
|
vi.num_use++;
|
|
|
|
|
|
vi.act_num_use++;
|
|
|
|
|
|
vi.cur_use++;
|
|
|
|
|
|
//if (vi.cur_ass == 0 && !lvr.var.name.Contains("$")) helper.AddTempWarning(lvr.var,new UseWithoutAssign(lvr.var.name, lvr.location));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void IncreaseNumUseVar(local_block_variable_reference lvr)
|
|
|
|
|
|
{
|
|
|
|
|
|
VarInfo vi = helper.GetVariable(lvr.var);
|
2018-10-03 19:47:32 +03:00
|
|
|
|
if (vi == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
helper.AddVariable(lvr.var);
|
|
|
|
|
|
vi = helper.GetVariable(lvr.var);
|
|
|
|
|
|
}
|
2015-05-14 22:35:07 +03:00
|
|
|
|
if (vi == null) return;
|
|
|
|
|
|
vi.num_use++;
|
|
|
|
|
|
vi.act_num_use++;
|
|
|
|
|
|
vi.cur_use++;
|
|
|
|
|
|
//if (vi.cur_ass == 0 && !lvr.var.name.Contains("$")) helper.AddTempWarning(lvr.var,new UseWithoutAssign(lvr.var.name, lvr.location));
|
|
|
|
|
|
}
|
2017-06-11 13:50:08 +03:00
|
|
|
|
|
|
|
|
|
|
private void CheckVarParameter(expression_node expr, function_node func, int index)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (index < func.parameters.Count && func.parameters[index].parameter_type == SemanticTree.parameter_type.var
|
|
|
|
|
|
|| (func is compiled_function_node && (func as compiled_function_node).cont_type.compiled_type == typeof(Array) && index == 0))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (expr is local_block_variable_reference)
|
|
|
|
|
|
IncreaseNumAssVar(expr as local_block_variable_reference);
|
|
|
|
|
|
else if (expr is local_variable_reference)
|
|
|
|
|
|
IncreaseNumAssVar(expr as local_variable_reference);
|
|
|
|
|
|
else if (expr is namespace_variable_reference)
|
|
|
|
|
|
IncreaseNumAssVar(expr as namespace_variable_reference);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2015-05-14 22:35:07 +03:00
|
|
|
|
|
|
|
|
|
|
private void IncreaseNumAssVar(namespace_variable_reference lvr)
|
|
|
|
|
|
{
|
|
|
|
|
|
VarInfo vi = helper.GetVariable(lvr.var);
|
|
|
|
|
|
if (vi == null) return;
|
|
|
|
|
|
vi.num_use++;
|
|
|
|
|
|
vi.cur_ass++;
|
|
|
|
|
|
vi.num_ass++;
|
|
|
|
|
|
vi.last_ass_loc = lvr.location;
|
|
|
|
|
|
if (vi.last_ass_loc == null) vi.num_ass--;
|
|
|
|
|
|
if (vi.cur_use > 0) vi.cur_use--;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void IncreaseNumUseParam(common_parameter_reference cpr)
|
|
|
|
|
|
{
|
|
|
|
|
|
ParamInfo vi = helper.GetParameter(cpr.par);
|
|
|
|
|
|
if (vi == null) return;
|
|
|
|
|
|
vi.num_use++;
|
|
|
|
|
|
vi.cur_use++;
|
|
|
|
|
|
//if (vi.cur_ass == 0) warns.Add(new UseWithoutAssign(lvr.var.name, lvr.location));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void IncreaseNumAssParam(common_parameter_reference cpr)
|
|
|
|
|
|
{
|
|
|
|
|
|
ParamInfo vi = helper.GetParameter(cpr.par);
|
|
|
|
|
|
if (vi == null) return;
|
|
|
|
|
|
vi.num_use++;
|
|
|
|
|
|
vi.cur_ass++;
|
|
|
|
|
|
if (vi.cur_use > 0) vi.cur_use--;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void IncreaseNumUseField(class_field_reference fld)
|
|
|
|
|
|
{
|
|
|
|
|
|
FldInfo vi = helper.GetField(fld.field);
|
|
|
|
|
|
if (vi == null) return;
|
|
|
|
|
|
vi.num_use++;
|
|
|
|
|
|
vi.cur_use++;
|
|
|
|
|
|
//if (vi.cur_ass == 0) warns.Add(new UseWithoutAssign(lvr.var.name, lvr.location));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void IncreaseNumAssField(class_field_reference fld)
|
|
|
|
|
|
{
|
|
|
|
|
|
FldInfo vi = helper.GetField(fld.field);
|
|
|
|
|
|
if (vi == null)
|
|
|
|
|
|
return;
|
|
|
|
|
|
vi.num_use++;
|
|
|
|
|
|
vi.cur_ass++;
|
|
|
|
|
|
|
|
|
|
|
|
if (vi.cur_use > 0) vi.cur_use--;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void IncreaseNumUseField(static_class_field_reference fld)
|
|
|
|
|
|
{
|
|
|
|
|
|
FldInfo vi = helper.GetField(fld.static_field);
|
|
|
|
|
|
if (vi == null) return;
|
|
|
|
|
|
vi.num_use++;
|
|
|
|
|
|
vi.cur_use++;
|
|
|
|
|
|
//if (vi.cur_ass == 0) warns.Add(new UseWithoutAssign(lvr.var.name, lvr.location));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void IncreaseNumAssField(static_class_field_reference fld)
|
|
|
|
|
|
{
|
|
|
|
|
|
FldInfo vi = helper.GetField(fld.static_field);
|
|
|
|
|
|
if (vi == null) return;
|
|
|
|
|
|
vi.num_use++;
|
|
|
|
|
|
vi.cur_ass++;
|
|
|
|
|
|
if (vi.cur_use > 0) vi.cur_use--;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitExpression(expression_node en)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (en == null) return;
|
|
|
|
|
|
//WriteDebugInfo(en.location);
|
|
|
|
|
|
switch (en.semantic_node_type)
|
|
|
|
|
|
{
|
|
|
|
|
|
case semantic_node_type.exit_procedure:
|
2015-12-28 14:25:15 +03:00
|
|
|
|
/*ничего писать не надо*/
|
2017-06-29 22:05:37 +03:00
|
|
|
|
has_returns = true;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.typeof_operator:
|
|
|
|
|
|
//VisitTypeOfOperator((typeof_operator)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.statement_expression_node:
|
|
|
|
|
|
VisitStatementsExpressionNode((statements_expression_node)en); break;
|
|
|
|
|
|
case semantic_node_type.question_colon_expression:
|
|
|
|
|
|
VisitQuestionColonExpression((question_colon_expression)en); break;
|
|
|
|
|
|
case semantic_node_type.sizeof_operator:
|
|
|
|
|
|
VisitSizeOfOperator((sizeof_operator)en); break;
|
|
|
|
|
|
case semantic_node_type.is_node:
|
|
|
|
|
|
VisitIsNode((is_node)en); break;
|
|
|
|
|
|
case semantic_node_type.as_node:
|
|
|
|
|
|
VisitAsNode((as_node)en); break;
|
|
|
|
|
|
case semantic_node_type.compiled_static_method_call_node_as_constant:
|
|
|
|
|
|
//VisitCompiledStaticMethodCallNodeAsConstant((compiled_static_method_call_as_constant)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.array_initializer:
|
|
|
|
|
|
VisitArrayInitializer((array_initializer)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.record_initializer:
|
|
|
|
|
|
VisitRecordInitializer((record_initializer)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.array_const:
|
|
|
|
|
|
//VisitArrayConst((array_const)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.record_const:
|
|
|
|
|
|
//VisitRecordConst((record_constant)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.float_const_node:
|
|
|
|
|
|
//VisitFloatConst((float_const_node)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.byte_const_node:
|
|
|
|
|
|
//VisitByteConstNode((byte_const_node)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.int_const_node:
|
|
|
|
|
|
//VisitIntConstNode((int_const_node)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.sbyte_const_node:
|
|
|
|
|
|
//VisitSByteConstNode((sbyte_const_node)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.short_const_node:
|
|
|
|
|
|
//VisitShortConstNode((short_const_node)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.ushort_const_node:
|
|
|
|
|
|
//VisitUShortConstNode((ushort_const_node)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.uint_const_node:
|
|
|
|
|
|
//VisitUIntConstNode((uint_const_node)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.ulong_const_node:
|
|
|
|
|
|
//VisitULongConstNode((ulong_const_node)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.long_const_node:
|
|
|
|
|
|
//VisitLongConstNode((long_const_node)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.double_const_node:
|
|
|
|
|
|
//VisitDoubleConstNode((double_const_node)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.char_const_node:
|
|
|
|
|
|
//VisitCharConstNode((char_const_node)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.bool_const_node:
|
|
|
|
|
|
//VisitBoolConstNode((bool_const_node)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.string_const_node:
|
|
|
|
|
|
//VisitStringConstNode((string_const_node)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.local_variable_reference:
|
|
|
|
|
|
VisitLocalVariableReference((local_variable_reference)en); break;
|
|
|
|
|
|
case semantic_node_type.namespace_variable_reference:
|
|
|
|
|
|
VisitNamespaceVariableReference((namespace_variable_reference)en); break;
|
|
|
|
|
|
case semantic_node_type.basic_function_call:
|
|
|
|
|
|
VisitBasicFunctionCall((basic_function_call)en); break;
|
|
|
|
|
|
case semantic_node_type.common_parameter_reference:
|
|
|
|
|
|
VisitCommonParameterReference((common_parameter_reference)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.common_namespace_function_call:
|
|
|
|
|
|
VisitCommonNamespaceFunctionCall((common_namespace_function_call)en); break;
|
|
|
|
|
|
case semantic_node_type.basic_function_call_node_as_constant:
|
|
|
|
|
|
VisitBasicFunctionCall((en as basic_function_call_as_constant).method_call); break;
|
|
|
|
|
|
case semantic_node_type.common_namespace_function_call_node_as_constant:
|
|
|
|
|
|
VisitCommonNamespaceFunctionCallAsConstant((common_namespace_function_call_as_constant)en); break;
|
|
|
|
|
|
case semantic_node_type.common_in_function_function_call:
|
|
|
|
|
|
VisitCommonInFuncFuncCall((common_in_function_function_call)en); break;
|
|
|
|
|
|
case semantic_node_type.while_break_node:
|
|
|
|
|
|
//VisitWhileBreakNode((while_break_node)en);
|
|
|
|
|
|
is_break_stmt = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.while_continue_node:
|
|
|
|
|
|
//VisitWhileContinueNode((while_continue_node)en);
|
|
|
|
|
|
is_break_stmt = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.for_break_node:
|
|
|
|
|
|
//VisitForBreakNode((for_break_node)en);
|
|
|
|
|
|
is_break_stmt = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.for_continue_node:
|
|
|
|
|
|
//VisitForContinueNode((for_continue_node)en);
|
|
|
|
|
|
is_break_stmt = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.repeat_break_node:
|
|
|
|
|
|
//VisitRepeatBreakNode((repeat_break_node)en);
|
|
|
|
|
|
is_break_stmt = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.repeat_continue_node:
|
|
|
|
|
|
//VisitRepeatContinueNode((repeat_continue_node)en);
|
|
|
|
|
|
is_break_stmt = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.foreach_break_node:
|
|
|
|
|
|
is_break_stmt = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.foreach_continue_node:
|
|
|
|
|
|
is_break_stmt = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.common_static_method_call:
|
|
|
|
|
|
VisitCommonStaticMethodCall((common_static_method_call)en); break;
|
|
|
|
|
|
case semantic_node_type.compiled_static_method_call:
|
|
|
|
|
|
VisitCompiledStaticMethodCall((compiled_static_method_call)en); break;
|
|
|
|
|
|
case semantic_node_type.class_field_reference:
|
|
|
|
|
|
VisitClassFieldReference((class_field_reference)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.deref_node:
|
|
|
|
|
|
VisitDerefNode((dereference_node)en); break;
|
|
|
|
|
|
case semantic_node_type.common_method_call:
|
|
|
|
|
|
VisitCommonMethodCall((common_method_call)en); break;
|
|
|
|
|
|
case semantic_node_type.compiled_function_call:
|
|
|
|
|
|
VisitCompiledFunctionCall((compiled_function_call)en); break;
|
|
|
|
|
|
case semantic_node_type.get_addr_node:
|
|
|
|
|
|
VisitGetAddrNode((get_addr_node)en); break;
|
|
|
|
|
|
case semantic_node_type.common_constructor_call:
|
|
|
|
|
|
VisitCommonConstructorCall((common_constructor_call)en); break;
|
|
|
|
|
|
case semantic_node_type.compiled_constructor_call:
|
|
|
|
|
|
VisitCompiledConstructorCall((compiled_constructor_call)en); break;
|
|
|
|
|
|
case semantic_node_type.compiled_variable_reference:
|
|
|
|
|
|
VisitCompiledVariableReference((compiled_variable_reference)en); break;
|
|
|
|
|
|
case semantic_node_type.local_block_variable_reference:
|
|
|
|
|
|
VisitLocalBlockVariableReference((local_block_variable_reference)en); break;
|
|
|
|
|
|
case semantic_node_type.static_compiled_variable_reference:
|
|
|
|
|
|
//VisitStaticCompiledVariableReference((static_compiled_variable_reference)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.static_class_field_reference:
|
|
|
|
|
|
VisitStaticClassFieldReference((static_class_field_reference)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.non_static_property_reference:
|
|
|
|
|
|
VisitNonStaticPropertyReference((non_static_property_reference)en); break;
|
|
|
|
|
|
case semantic_node_type.simple_array_indexing:
|
|
|
|
|
|
VisitSimpleArrayIndexing((simple_array_indexing)en); break;
|
2021-12-12 14:35:02 +03:00
|
|
|
|
case semantic_node_type.double_question_colon_expression:
|
|
|
|
|
|
VisitDoubleQuestionColon((double_question_colon_expression)en);
|
|
|
|
|
|
break;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
case semantic_node_type.this_node:
|
|
|
|
|
|
//VisitThisNode((this_node)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case semantic_node_type.null_const_node:
|
|
|
|
|
|
//VisitNullConstNode((null_const_node)en);
|
|
|
|
|
|
break;
|
|
|
|
|
|
//default: ;//Console.WriteLine(en.semantic_node_type); throw new Exception("Unknown expression");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitLocalBlockVariableReference(local_block_variable_reference en)
|
|
|
|
|
|
{
|
|
|
|
|
|
IncreaseNumUseVar(en);
|
|
|
|
|
|
}
|
|
|
|
|
|
private void VisitCommonParameterReference(common_parameter_reference en)
|
|
|
|
|
|
{
|
|
|
|
|
|
IncreaseNumUseParam(en);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitStaticClassFieldReference(static_class_field_reference en)
|
|
|
|
|
|
{
|
|
|
|
|
|
IncreaseNumUseField(en);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitCompiledFunctionCall(compiled_function_call en)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitExpression(en.obj);
|
|
|
|
|
|
for (int i = 0; i < en.parameters.Count; i++)
|
2017-06-11 13:50:08 +03:00
|
|
|
|
{
|
|
|
|
|
|
CheckVarParameter(en.parameters[i], en.function_node, i);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitExpression(en.parameters[i]);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
}
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitCompiledConstructorCall(compiled_constructor_call en)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i < en.parameters.Count; i++)
|
2017-06-11 13:50:08 +03:00
|
|
|
|
{
|
|
|
|
|
|
CheckVarParameter(en.parameters[i], en.function_node, i);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitExpression(en.parameters[i]);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
}
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-12-12 14:35:02 +03:00
|
|
|
|
private void VisitDoubleQuestionColon(double_question_colon_expression en)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitExpression(en.internal_condition);
|
|
|
|
|
|
VisitExpression(en.internal_ret_if_null);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-05-14 22:35:07 +03:00
|
|
|
|
private void VisitSimpleArrayIndexing(simple_array_indexing en)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitExpression(en.simple_arr_expr);
|
|
|
|
|
|
VisitExpression(en.ind_expr);
|
2017-11-05 19:24:03 +03:00
|
|
|
|
if (en.expr_indices != null)
|
|
|
|
|
|
foreach (expression_node expr in en.expr_indices)
|
|
|
|
|
|
VisitExpression(expr);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitNonStaticPropertyReference(non_static_property_reference en)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitExpression(en.expression);
|
|
|
|
|
|
for (int i = 0; i < en.fact_parametres.Count; i++)
|
|
|
|
|
|
VisitExpression(en.fact_parametres[i]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitCompiledVariableReference(compiled_variable_reference en)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitExpression(en.obj);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitCommonConstructorCall(common_constructor_call en)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i < en.parameters.Count; i++)
|
2017-06-11 13:50:08 +03:00
|
|
|
|
{
|
|
|
|
|
|
CheckVarParameter(en.parameters[i], en.function_node, i);
|
2019-06-02 15:50:30 +03:00
|
|
|
|
//if (!(en.function_node.function_code is runtime_statement))
|
|
|
|
|
|
VisitExpression(en.parameters[i]);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
}
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitGetAddrNode(get_addr_node en)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitExpression(en.addr_of);
|
2018-09-16 12:34:56 +03:00
|
|
|
|
if (en.addr_of is local_variable_reference && (en.addr_of as local_variable_reference).var.is_ret_value)
|
|
|
|
|
|
IncreaseNumAssVar(en.addr_of as local_variable_reference);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitClassFieldReference(class_field_reference en)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitExpression(en.obj);
|
|
|
|
|
|
IncreaseNumUseField(en);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitCompiledStaticMethodCall(compiled_static_method_call en)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i < en.parameters.Count; i++)
|
2017-06-11 13:50:08 +03:00
|
|
|
|
{
|
|
|
|
|
|
CheckVarParameter(en.parameters[i], en.function_node, i);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitExpression(en.parameters[i]);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
}
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitCommonInFuncFuncCall(common_in_function_function_call en)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i < en.parameters.Count; i++)
|
2017-06-11 13:50:08 +03:00
|
|
|
|
{
|
|
|
|
|
|
CheckVarParameter(en.parameters[i], en.function_node, i);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitExpression(en.parameters[i]);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitCommonNamespaceFunctionCall(common_namespace_function_call en)
|
|
|
|
|
|
{
|
2017-06-11 13:50:08 +03:00
|
|
|
|
CheckInfiniteRecursion(en);
|
2024-05-04 20:21:50 +03:00
|
|
|
|
if ((en.function_node.name == "Reset" || en.function_node.name == "Rewrite" || en.function_node.name == "Assign") && en.function_node.comprehensive_namespace.namespace_name == StringConstants.pascalSystemUnitName)
|
2017-08-13 14:32:28 +03:00
|
|
|
|
{
|
|
|
|
|
|
expression_node p = en.parameters[0];
|
|
|
|
|
|
switch (p.semantic_node_type)
|
|
|
|
|
|
{
|
|
|
|
|
|
case semantic_node_type.local_variable_reference: IncreaseNumAssVar((local_variable_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.local_block_variable_reference: IncreaseNumAssVar((local_block_variable_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.namespace_variable_reference: IncreaseNumAssVar((namespace_variable_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.class_field_reference: VisitExpression((p as class_field_reference).obj); IncreaseNumAssField((class_field_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.static_class_field_reference: IncreaseNumAssField((static_class_field_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.common_parameter_reference: IncreaseNumAssParam((common_parameter_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.deref_node: CheckAssign(((dereference_node)p).deref_expr); break;
|
|
|
|
|
|
case semantic_node_type.simple_array_indexing: VisitSimpleArrayIndexing((simple_array_indexing)p); break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2015-05-14 22:35:07 +03:00
|
|
|
|
for (int i = 0; i < en.parameters.Count; i++)
|
2017-06-11 13:50:08 +03:00
|
|
|
|
{
|
|
|
|
|
|
CheckVarParameter(en.parameters[i], en.function_node, i);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitExpression(en.parameters[i]);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
}
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitCommonNamespaceFunctionCallAsConstant(common_namespace_function_call_as_constant en)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i < en.method_call.parameters.Count; i++)
|
2017-06-11 13:50:08 +03:00
|
|
|
|
{
|
|
|
|
|
|
CheckVarParameter(en.method_call.parameters[i], en.method_call.function_node, i);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitExpression(en.method_call.parameters[i]);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
}
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitCommonStaticMethodCall(common_static_method_call en)
|
|
|
|
|
|
{
|
2017-06-11 13:50:08 +03:00
|
|
|
|
CheckInfiniteRecursion(en);
|
|
|
|
|
|
for (int i = 0; i < en.parameters.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
CheckVarParameter(en.parameters[i], en.function_node, i);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitExpression(en.parameters[i]);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
}
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitCommonMethodCall(common_method_call en)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitExpression(en.obj);
|
|
|
|
|
|
for (int i = 0; i < en.parameters.Count; i++)
|
2017-06-11 13:50:08 +03:00
|
|
|
|
{
|
|
|
|
|
|
CheckVarParameter(en.parameters[i], en.function_node, i);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitExpression(en.parameters[i]);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
}
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitDerefNode(dereference_node en)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitExpression(en.deref_expr);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitStatementsExpressionNode(statements_expression_node en)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i < en.internal_statements.Count; i++)
|
|
|
|
|
|
VisitStatement(en.internal_statements[i]);
|
|
|
|
|
|
VisitExpression(en.internal_expression);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitQuestionColonExpression(question_colon_expression en)
|
|
|
|
|
|
{
|
2017-06-11 13:50:08 +03:00
|
|
|
|
SaveConditionBlock();
|
|
|
|
|
|
RetVal rv = GetConstantValue(en.internal_condition);
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitExpression(en.internal_condition);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
if (rv != RetVal.True)
|
|
|
|
|
|
EnterConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitExpression(en.internal_ret_if_true);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
if (rv != RetVal.False)
|
|
|
|
|
|
EnterConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitExpression(en.internal_ret_if_false);
|
2017-06-11 13:50:08 +03:00
|
|
|
|
RestoreConditionBlock();
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitSizeOfOperator(sizeof_operator en)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitIsNode(is_node en)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitExpression(en.left);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitAsNode(as_node en)
|
|
|
|
|
|
{
|
|
|
|
|
|
VisitExpression(en.left);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitLocalVariableReference(local_variable_reference en)
|
|
|
|
|
|
{
|
|
|
|
|
|
IncreaseNumUseVar(en);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitNamespaceVariableReference(namespace_variable_reference en)
|
|
|
|
|
|
{
|
|
|
|
|
|
IncreaseNumUseVar(en);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitAssignment(base_function_call en)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = 1; i < en.parameters.Count; i++)
|
|
|
|
|
|
VisitExpression(en.parameters[i]);
|
|
|
|
|
|
expression_node p = en.parameters[0];
|
2018-10-03 11:14:32 +03:00
|
|
|
|
if (en.parameters[1] is common_parameter_reference && (en.parameters[1] as common_parameter_reference).par.name.StartsWith("<>"))
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (p.semantic_node_type)
|
|
|
|
|
|
{
|
|
|
|
|
|
case semantic_node_type.local_variable_reference: IncreaseNumUseVar((local_variable_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.local_block_variable_reference: IncreaseNumUseVar((local_block_variable_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.namespace_variable_reference: IncreaseNumUseVar((namespace_variable_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.class_field_reference: VisitExpression((p as class_field_reference).obj); IncreaseNumUseField((class_field_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.static_class_field_reference: IncreaseNumUseField((static_class_field_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.common_parameter_reference: IncreaseNumUseParam((common_parameter_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.deref_node: VisitDerefNode(((dereference_node)p)); break;
|
|
|
|
|
|
case semantic_node_type.simple_array_indexing: VisitSimpleArrayIndexing((simple_array_indexing)p); break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
2015-05-14 22:35:07 +03:00
|
|
|
|
switch (p.semantic_node_type)
|
|
|
|
|
|
{
|
|
|
|
|
|
case semantic_node_type.local_variable_reference: IncreaseNumAssVar((local_variable_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.local_block_variable_reference: IncreaseNumAssVar((local_block_variable_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.namespace_variable_reference: IncreaseNumAssVar((namespace_variable_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.class_field_reference: VisitExpression((p as class_field_reference).obj); IncreaseNumAssField((class_field_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.static_class_field_reference: IncreaseNumAssField((static_class_field_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.common_parameter_reference: IncreaseNumAssParam((common_parameter_reference)p); break;
|
2018-08-19 13:32:24 +03:00
|
|
|
|
case semantic_node_type.deref_node: VisitDerefNode(((dereference_node)p)); break;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
case semantic_node_type.simple_array_indexing: VisitSimpleArrayIndexing((simple_array_indexing)p); break;
|
|
|
|
|
|
}
|
2020-08-16 15:05:32 +03:00
|
|
|
|
if (en.parameters[1] is local_block_variable_reference && (en.parameters[1] as local_block_variable_reference).var.name.StartsWith("$Ren"))
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (p.semantic_node_type)
|
|
|
|
|
|
{
|
|
|
|
|
|
case semantic_node_type.local_variable_reference: IncreaseNumUseVar((local_variable_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.local_block_variable_reference: IncreaseNumUseVar((local_block_variable_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.namespace_variable_reference: IncreaseNumUseVar((namespace_variable_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.class_field_reference: VisitExpression((p as class_field_reference).obj); IncreaseNumUseField((class_field_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.static_class_field_reference: IncreaseNumUseField((static_class_field_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.common_parameter_reference: IncreaseNumUseParam((common_parameter_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.deref_node: VisitDerefNode(((dereference_node)p)); break;
|
|
|
|
|
|
case semantic_node_type.simple_array_indexing: VisitSimpleArrayIndexing((simple_array_indexing)p); break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void CheckAssign(expression_node p)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (p.semantic_node_type)
|
|
|
|
|
|
{
|
|
|
|
|
|
case semantic_node_type.local_variable_reference: IncreaseNumAssVar((local_variable_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.namespace_variable_reference: IncreaseNumAssVar((namespace_variable_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.class_field_reference: VisitExpression((p as class_field_reference).obj); IncreaseNumAssField((class_field_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.static_class_field_reference: IncreaseNumAssField((static_class_field_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.common_parameter_reference: IncreaseNumAssParam((common_parameter_reference)p); break;
|
|
|
|
|
|
case semantic_node_type.deref_node: CheckAssign(((dereference_node)p).deref_expr); break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitArrayInitializer(array_initializer en)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (expression_node expr in en.element_values)
|
|
|
|
|
|
VisitExpression(expr);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitRecordInitializer(record_initializer en)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (expression_node expr in en.field_values)
|
|
|
|
|
|
VisitExpression(expr);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void VisitBasicFunctionCall(basic_function_call en)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (en.function_node.basic_function_type)
|
|
|
|
|
|
{
|
|
|
|
|
|
case SemanticTree.basic_function_type.iassign:
|
|
|
|
|
|
case SemanticTree.basic_function_type.bassign:
|
|
|
|
|
|
case SemanticTree.basic_function_type.boolassign:
|
|
|
|
|
|
case SemanticTree.basic_function_type.fassign:
|
|
|
|
|
|
case SemanticTree.basic_function_type.dassign:
|
|
|
|
|
|
case SemanticTree.basic_function_type.sassign:
|
|
|
|
|
|
case SemanticTree.basic_function_type.lassign:
|
|
|
|
|
|
case SemanticTree.basic_function_type.charassign:
|
|
|
|
|
|
case SemanticTree.basic_function_type.sbassign:
|
|
|
|
|
|
case SemanticTree.basic_function_type.uiassign:
|
|
|
|
|
|
case SemanticTree.basic_function_type.ulassign:
|
|
|
|
|
|
case SemanticTree.basic_function_type.usassign:
|
|
|
|
|
|
case SemanticTree.basic_function_type.objassign:
|
|
|
|
|
|
VisitAssignment(en); return;
|
|
|
|
|
|
}
|
2018-09-16 18:51:26 +03:00
|
|
|
|
bool tmp_no_infinite_recursion = no_infinite_recursion;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
for (int i = 0; i < en.parameters.Count; i++)
|
2018-09-16 18:51:26 +03:00
|
|
|
|
{
|
|
|
|
|
|
if (en.function_node.basic_function_type == SemanticTree.basic_function_type.booland
|
|
|
|
|
|
&& en.parameters[i] is bool_const_node && (en.parameters[i] as bool_const_node).constant_value == false)
|
|
|
|
|
|
no_infinite_recursion = true;
|
|
|
|
|
|
else if (en.function_node.basic_function_type == SemanticTree.basic_function_type.boolor
|
|
|
|
|
|
&& en.parameters[0] is bool_const_node && (en.parameters[0] as bool_const_node).constant_value == true)
|
|
|
|
|
|
no_infinite_recursion = true;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
VisitExpression(en.parameters[i]);
|
2018-09-16 18:51:26 +03:00
|
|
|
|
}
|
|
|
|
|
|
if (!tmp_no_infinite_recursion)
|
|
|
|
|
|
no_infinite_recursion = false;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|