infinite recursion warning

This commit is contained in:
Бондарев Иван 2017-06-11 12:50:08 +02:00
parent 3f58cf8aec
commit c9a057ec58
4 changed files with 131 additions and 10 deletions

View file

@ -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<bool> condition_block_states = new Stack<bool>();
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)

View file

@ -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;

View file

@ -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
DO_NOT_USE_POINTERS_TO_RECORDS=Don't use pointers to records. You classes instead
INFINITE_RECURSION=Infinite recursion detected

View file

@ -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=Не используйте указатели на записи. Используйте классы.
DO_NOT_USE_POINTERS_TO_RECORDS=Не используйте указатели на записи. Используйте классы.
INFINITE_RECURSION=Обнаружена бесконечная рекурсия