From c9a057ec58af01f2992c4e898a2e6f1f7917dd21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=BD=D0=B4=D0=B0=D1=80=D0=B5=D0=B2=20=D0=98?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD?= Date: Sun, 11 Jun 2017 12:50:08 +0200 Subject: [PATCH] infinite recursion warning --- Optimizer/Optimizer.cs | 121 ++++++++++++++++++++++++++++++++++--- Optimizer/Warnings.cs | 14 +++++ bin/Lng/Eng/Warning_ib.dat | 3 +- bin/Lng/Rus/Warning_ib.dat | 3 +- 4 files changed, 131 insertions(+), 10 deletions(-) diff --git a/Optimizer/Optimizer.cs b/Optimizer/Optimizer.cs index c9e607293..ec467d613 100644 --- a/Optimizer/Optimizer.cs +++ b/Optimizer/Optimizer.cs @@ -15,6 +15,7 @@ namespace PascalABCCompiler private OptimizerHelper helper = new OptimizerHelper(); private bool extended_mode = true; private common_type_node current_type; + private bool condition_block = false; public Optimizer() { @@ -131,7 +132,7 @@ namespace PascalABCCompiler helper.AddParameter(prm); foreach (common_in_function_function_node nested in cmn.functions_nodes_list) VisitNestedFunction(nested); - cur_func = cmn; + current_function = cmn; VisitStatement(cmn.function_code); foreach (var_definition_node vdn2 in cmn.var_definition_nodes_list) { @@ -212,7 +213,7 @@ namespace PascalABCCompiler } } - private common_function_node cur_func=null; + private common_function_node current_function=null; private void CheckType(type_node type, expression_node initial_value, location loc) { @@ -248,7 +249,7 @@ namespace PascalABCCompiler helper.AddParameter(prm); foreach (common_in_function_function_node nested in cnfn.functions_nodes_list) VisitNestedFunction(nested); - cur_func = cnfn; + current_function = cnfn; VisitStatement(cnfn.function_code); foreach (var_definition_node vdn2 in cnfn.var_definition_nodes_list) { @@ -316,7 +317,7 @@ namespace PascalABCCompiler helper.AddParameter(prm); foreach (common_in_function_function_node nested in cnfn.functions_nodes_list) VisitNestedFunction(nested); - cur_func = cnfn; + current_function = cnfn; VisitStatement(cnfn.function_code); foreach (var_definition_node vdn2 in cnfn.var_definition_nodes_list) { @@ -426,6 +427,36 @@ namespace PascalABCCompiler else return RetVal.Undef; } + private Stack condition_block_states = new Stack(); + + private void CheckInfiniteRecursion(common_namespace_function_call cnfc) + { + if (!condition_block && cnfc.function_node == current_function) + warns.Add(new InfiniteRecursion(cnfc.location)); + } + + private void CheckInfiniteRecursion(common_static_method_call cnfc) + { + if (!condition_block && cnfc.function_node == current_function) + warns.Add(new InfiniteRecursion(cnfc.location)); + } + + 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; + } + private void VisitLockStatement(lock_statement stmt) { VisitExpression(stmt.lock_object); @@ -434,48 +465,68 @@ namespace PascalABCCompiler private void VisitForeach(foreach_node stmt) { - IncreaseNumUseVar(stmt.ident); + SaveConditionBlock(); + IncreaseNumUseVar(stmt.ident); VisitExpression(stmt.in_what); + EnterConditionBlock(); VisitStatement(stmt.what_do); + RestoreConditionBlock(); } private void VisitIf(if_node stmt) { + SaveConditionBlock(); RetVal rv = GetConstantValue(stmt.condition); VisitExpression(stmt.condition); if (rv == RetVal.False) is_break_stmt = true; + if (rv != RetVal.True) + EnterConditionBlock(); VisitStatement(stmt.then_body); is_break_stmt = false; if (rv == RetVal.True) is_break_stmt = true; + if (rv != RetVal.False) + EnterConditionBlock(); VisitStatement(stmt.else_body); is_break_stmt = false; + RestoreConditionBlock(); } private void VisitWhile(while_node stmt) { + SaveConditionBlock(); RetVal rv = GetConstantValue(stmt.condition); VisitExpression(stmt.condition); if (rv == RetVal.False) is_break_stmt = true; + if (rv != RetVal.True) + EnterConditionBlock(); VisitStatement(stmt.body); + RestoreConditionBlock(); } private void VisitRepeat(repeat_node stmt) { + SaveConditionBlock(); RetVal rv = GetConstantValue(stmt.condition); + if (rv != RetVal.False) + EnterConditionBlock(); VisitStatement(stmt.body); VisitExpression(stmt.condition); + RestoreConditionBlock(); } private void VisitFor(for_node stmt) { + SaveConditionBlock(); VisitStatement(stmt.init_while_expr); VisitStatement(stmt.initialization_statement); VisitStatement(stmt.increment_statement); VisitExpression(stmt.while_expr); + EnterConditionBlock(); VisitStatement(stmt.body); + RestoreConditionBlock(); } private bool is_break_stmt = false; @@ -514,23 +565,26 @@ namespace PascalABCCompiler private void VisitExternalStatementNode(external_statement sn) { - helper.MarkAsExternal(cur_func); + helper.MarkAsExternal(current_function); } private void VisitPInvokeStatementNode(pinvoke_statement sn) { - helper.MarkAsExternal(cur_func); + helper.MarkAsExternal(current_function); } private void VisitSwitchNode(switch_node stmt) { + SaveConditionBlock(); VisitExpression(stmt.condition); + EnterConditionBlock(); 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); + RestoreConditionBlock(); } private void VisitRuntimeStatement(runtime_statement sn) @@ -635,6 +689,20 @@ namespace PascalABCCompiler 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 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); + } + } private void IncreaseNumAssVar(namespace_variable_reference lvr) { @@ -891,13 +959,19 @@ namespace PascalABCCompiler { VisitExpression(en.obj); for (int i = 0; i < en.parameters.Count; i++) + { + CheckVarParameter(en.parameters[i], en.function_node, i); VisitExpression(en.parameters[i]); + } } private void VisitCompiledConstructorCall(compiled_constructor_call en) { for (int i = 0; i < en.parameters.Count; i++) + { + CheckVarParameter(en.parameters[i], en.function_node, i); VisitExpression(en.parameters[i]); + } } private void VisitSimpleArrayIndexing(simple_array_indexing en) @@ -921,7 +995,10 @@ namespace PascalABCCompiler private void VisitCommonConstructorCall(common_constructor_call en) { for (int i = 0; i < en.parameters.Count; i++) + { + CheckVarParameter(en.parameters[i], en.function_node, i); VisitExpression(en.parameters[i]); + } } private void VisitGetAddrNode(get_addr_node en) @@ -938,38 +1015,59 @@ namespace PascalABCCompiler private void VisitCompiledStaticMethodCall(compiled_static_method_call en) { for (int i = 0; i < en.parameters.Count; i++) + { + CheckVarParameter(en.parameters[i], en.function_node, i); VisitExpression(en.parameters[i]); + } } private void VisitCommonInFuncFuncCall(common_in_function_function_call en) { for (int i = 0; i < en.parameters.Count; i++) + { + CheckVarParameter(en.parameters[i], en.function_node, i); VisitExpression(en.parameters[i]); + } + } private void VisitCommonNamespaceFunctionCall(common_namespace_function_call en) { + CheckInfiniteRecursion(en); for (int i = 0; i < en.parameters.Count; i++) + { + CheckVarParameter(en.parameters[i], en.function_node, i); VisitExpression(en.parameters[i]); + } } private void VisitCommonNamespaceFunctionCallAsConstant(common_namespace_function_call_as_constant en) { for (int i = 0; i < en.method_call.parameters.Count; i++) + { + CheckVarParameter(en.method_call.parameters[i], en.method_call.function_node, i); VisitExpression(en.method_call.parameters[i]); + } } private void VisitCommonStaticMethodCall(common_static_method_call en) { - for (int i = 0; i < en.parameters.Count; i++) + CheckInfiniteRecursion(en); + for (int i = 0; i < en.parameters.Count; i++) + { + CheckVarParameter(en.parameters[i], en.function_node, i); VisitExpression(en.parameters[i]); + } } private void VisitCommonMethodCall(common_method_call en) { VisitExpression(en.obj); for (int i = 0; i < en.parameters.Count; i++) + { + CheckVarParameter(en.parameters[i], en.function_node, i); VisitExpression(en.parameters[i]); + } } private void VisitDerefNode(dereference_node en) @@ -986,9 +1084,16 @@ namespace PascalABCCompiler private void VisitQuestionColonExpression(question_colon_expression en) { + SaveConditionBlock(); + RetVal rv = GetConstantValue(en.internal_condition); VisitExpression(en.internal_condition); + if (rv != RetVal.True) + EnterConditionBlock(); VisitExpression(en.internal_ret_if_true); + if (rv != RetVal.False) + EnterConditionBlock(); VisitExpression(en.internal_ret_if_false); + RestoreConditionBlock(); } private void VisitSizeOfOperator(sizeof_operator en) diff --git a/Optimizer/Warnings.cs b/Optimizer/Warnings.cs index a0ccfc9f9..a31c8cfce 100644 --- a/Optimizer/Warnings.cs +++ b/Optimizer/Warnings.cs @@ -101,6 +101,20 @@ namespace PascalABCCompiler } } + public class InfiniteRecursion : CompilerWarningWithLocation + { + public InfiniteRecursion(location loc) + { + this.loc = loc; + } + + public override string ToString() + { + //return ("Possible two type convertions\n"+_en.location.ToString()); + return (WarningStringResources.Get("INFINITE_RECURSION")); + } + } + public class UndefinedReturnValue : CompilerWarningWithLocation { string name; diff --git a/bin/Lng/Eng/Warning_ib.dat b/bin/Lng/Eng/Warning_ib.dat index 329d47296..e3a0a8903 100644 --- a/bin/Lng/Eng/Warning_ib.dat +++ b/bin/Lng/Eng/Warning_ib.dat @@ -7,4 +7,5 @@ ASS_WITHOUT_USE_{0}=The variable '{0}' is assigned but its value is never used UNREACHABLE_CODE_DETECTED=Unreachable code detected UNDEFINED_RETURN_VALUE_{0}=Return value of function '{0}' is not to be set DO_NOT_USE_SHORT_STRINGS=Don't use short strings -DO_NOT_USE_POINTERS_TO_RECORDS=Don't use pointers to records. You classes instead \ No newline at end of file +DO_NOT_USE_POINTERS_TO_RECORDS=Don't use pointers to records. You classes instead +INFINITE_RECURSION=Infinite recursion detected \ No newline at end of file diff --git a/bin/Lng/Rus/Warning_ib.dat b/bin/Lng/Rus/Warning_ib.dat index 674757538..c22dea529 100644 --- a/bin/Lng/Rus/Warning_ib.dat +++ b/bin/Lng/Rus/Warning_ib.dat @@ -7,4 +7,5 @@ ASS_WITHOUT_USE_{0}=Переменной '{0}' присвоено значени UNREACHABLE_CODE_DETECTED=Обнаружен недостижимый код UNDEFINED_RETURN_VALUE_{0}=Возвращаемое значение функции '{0}' не определено DO_NOT_USE_SHORT_STRINGS=Не используйте короткие строки нигде кроме как в записях для сохранения в типизированный файл -DO_NOT_USE_POINTERS_TO_RECORDS=Не используйте указатели на записи. Используйте классы. \ No newline at end of file +DO_NOT_USE_POINTERS_TO_RECORDS=Не используйте указатели на записи. Используйте классы. +INFINITE_RECURSION=Обнаружена бесконечная рекурсия \ No newline at end of file